<commit_before>#![feature(box_syntax)]
#![feature(plugin)]
#![plugin(regex_macros)]

use irc::event_stream::{Action, HandlerAction, Response};
use irc::protocol;
use regex::Regex;
use rand::{thread_rng, Rng};
use std::ascii::AsciiExt;
use std::collections::{hash_map, HashMap};
use std::env;
use std::str::FromStr;
use std::sync::{Arc, Mutex};

extern crate env_logger;
extern crate getopts;
extern crate irc;
extern crate rand;
extern crate regex;

#[macro_use]
extern crate log;

fn main() {
    env_logger::init().unwrap();

    let mut opts = getopts::Options::new();
    opts.reqopt("", "host", "irc server hostname", "HOSTNAME");
    opts.optopt("", "port", "irc server port", "PORT");
    opts.reqopt("n", "nick", "nickname", "NICK");
    opts.optmulti("c", "chan", "channels to join", "CHAN");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..]).unwrap();

    let host = matches.opt_str("host").expect("must provide --host");
    let mut port = 6667;
    if matches.opt_present("port") {
        port = u16::from_str(&matches.opt_str("port").expect("must provide argument to --port")).unwrap();
    }

    let addr = (host.as_ref(), port);
    let nick = matches.opt_str("nick").expect("must provide --nick");
    let channels = matches.opt_strs("chan");

    let knowledge_mutex: Arc<Mutex<HashMap<String, Vec<String>>>> = Arc::new(Mutex::new(HashMap::new()));

    let choice_nick = nick.clone();
    let choice_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&choice_nick)) {
            let choices: Vec<_> = regex!(r"\s+or\s+")
                .split(pm.msg)
                .map(|s| s.trim())
                .filter(|s| !s.is_empty())
                .collect();
            if choices.len() > 1 {
                let mut rng = thread_rng();
                if let Some(reply_to) = pm.reply_target(&choice_nick) {
                    return Response::respond(protocol::Privmsg::new(reply_to, rng.choose(&choices).unwrap()).format());
                }
            }
        }
        Response::nothing()
    };

    let knowledge_mutex_1 = knowledge_mutex.clone();
    let learning_nick = nick.clone();
    let learning_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&learning_nick)) {
            let assignment: Vec<_> = regex!(r"\s+is\s+")
                .splitn(pm.msg, 2)
                .map(|s| s.trim())
                .filter(|s| !s.is_empty())
                .collect();
            if assignment.len() == 2 {
                let mut knowledge = knowledge_mutex_1.lock().unwrap();
                match knowledge.entry(assignment[0].to_string()) {
                    hash_map::Entry::Occupied(mut e) => {
                        e.get_mut().push(assignment[1].to_string());
                    },
                    hash_map::Entry::Vacant(e) => {
                        e.insert(vec![assignment[1].to_string()]);
                    }
                }
            }
        }
        Response::nothing()
    };

    let knowledge_mutex_2 = knowledge_mutex.clone();
    let info_nick = nick.clone();
    let info_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line) {
            if let Some(reply_to) = pm.reply_target(&info_nick) {
                let knowledge = knowledge_mutex_2.lock().unwrap();
                if let Some(choices) = knowledge.get(pm.msg) {
                    let mut rng = thread_rng();
                    let choice = rng.choose(choices).unwrap();
                    if let Some(c) = regex!(r"^<action>\s+(.*)$").captures(choice) {
                        return Response::respond(protocol::Privmsg::new(reply_to, &protocol::ctcp_action(c.at(1).expect("Bad regex match"))).format());
                    } else {
                        return Response::respond(protocol::Privmsg::new(reply_to, choice).format());
                    }
                }
            }
        }
        Response::nothing()
    };

    let join_nick = nick.clone();
    let join_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&join_nick)) {
            if let Some(c) = regex!(r"^(join|part) (#[^\s]+)").captures(pm.msg) {
                let action = c.at(1).expect("Bad match group");
                let chan = c.at(2).expect("Bad match group");
                let success_msg = format!("{} channel {}!", if action == "join" { "Joined" } else { "Left" }, chan);
                if let Ok(joined_regex) = Regex::new(&format!(r"{}\s+:?{}", action.to_ascii_uppercase(), chan)) {
                    let joined_handler = box move |joined_line: &str| {
                        if joined_regex.is_match(joined_line) {
                            info!("{}", success_msg);
                            return Response(None, HandlerAction::Remove, Action::Skip);
                        }
                        Response::nothing()
                    };
                    info!("{} channel {}...", if action == "join" { "Joining" } else { "Leaving" }, chan);
                    return Response(Some(format!("{} {}", action.to_ascii_uppercase(), chan)), HandlerAction::Add(joined_handler), Action::Skip);
                }
            }
        }
        Response::nothing()
    };

    let echo_nick = nick.clone();
    let echo_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&echo_nick)) {
            if regex!(r"^[Hh]i$").is_match(pm.msg) {
                if let Some(reply_to) = pm.reply_target(&echo_nick) {
                    if let Some(protocol::Source::User(ref user_info)) = pm.src {
                        return Response::respond(protocol::Privmsg::new(reply_to, &format!("Hi, {}!", user_info.nick)).format());
                    }
                }
            } else if regex!(r"^go away$").is_match(pm.msg) {
                return Response(None, HandlerAction::Keep, Action::Stop);
            }
        }
        Response::nothing()
    };

    let (mut client, join_handle) = irc::Client::connect(
        &addr, &nick, &channels.iter().map(|s| s.as_ref()).collect::<Vec<&str>>(), "leifw_rustbot", "leifw's rust robot")
        .ok().expect(&format!("Error connecting to {:?}.", addr));

    client.add_handler(choice_handler);
    client.add_handler(learning_handler);
    client.add_handler(info_handler);
    client.add_handler(join_handler);
    client.add_handler(echo_handler);
    join_handle.join().unwrap_or_else(|_| { error!("Unknown error!"); });
}
<commit_msg>added info about self<commit_after>#![feature(box_syntax)]
#![feature(plugin)]
#![plugin(regex_macros)]

use irc::event_stream::{Action, HandlerAction, Response};
use irc::protocol;
use regex::Regex;
use rand::{thread_rng, Rng};
use std::ascii::AsciiExt;
use std::collections::{hash_map, HashMap};
use std::env;
use std::str::FromStr;
use std::sync::{Arc, Mutex};

extern crate env_logger;
extern crate getopts;
extern crate irc;
extern crate rand;
extern crate regex;

#[macro_use]
extern crate log;

fn main() {
    env_logger::init().unwrap();

    let mut opts = getopts::Options::new();
    opts.reqopt("", "host", "irc server hostname", "HOSTNAME");
    opts.optopt("", "port", "irc server port", "PORT");
    opts.reqopt("n", "nick", "nickname", "NICK");
    opts.optmulti("c", "chan", "channels to join", "CHAN");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..]).unwrap();

    let host = matches.opt_str("host").expect("must provide --host");
    let mut port = 6667;
    if matches.opt_present("port") {
        port = u16::from_str(&matches.opt_str("port").expect("must provide argument to --port")).unwrap();
    }

    let addr = (host.as_ref(), port);
    let nick = matches.opt_str("nick").expect("must provide --nick");
    let channels = matches.opt_strs("chan");

    let knowledge_mutex: Arc<Mutex<HashMap<String, Vec<String>>>> = Arc::new(Mutex::new(HashMap::new()));

    let choice_nick = nick.clone();
    let choice_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&choice_nick)) {
            let choices: Vec<_> = regex!(r"\s+or\s+")
                .split(pm.msg)
                .map(|s| s.trim())
                .filter(|s| !s.is_empty())
                .collect();
            if choices.len() > 1 {
                let mut rng = thread_rng();
                if let Some(reply_to) = pm.reply_target(&choice_nick) {
                    return Response::respond(protocol::Privmsg::new(reply_to, rng.choose(&choices).unwrap()).format());
                }
            }
        }
        Response::nothing()
    };

    let knowledge_mutex_1 = knowledge_mutex.clone();
    let learning_nick = nick.clone();
    let learning_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&learning_nick)) {
            let assignment: Vec<_> = regex!(r"\s+is\s+")
                .splitn(pm.msg, 2)
                .map(|s| s.trim())
                .filter(|s| !s.is_empty())
                .collect();
            if assignment.len() == 2 {
                let mut knowledge = knowledge_mutex_1.lock().unwrap();
                match knowledge.entry(assignment[0].to_string()) {
                    hash_map::Entry::Occupied(mut e) => {
                        e.get_mut().push(assignment[1].to_string());
                    },
                    hash_map::Entry::Vacant(e) => {
                        e.insert(vec![assignment[1].to_string()]);
                    }
                }
            }
        }
        Response::nothing()
    };

    {
        // Seed our knowledge
        let mut knowledge = knowledge_mutex.lock().unwrap();
        knowledge.insert(format!("{}: info", nick), vec!["I'm a robot running https://github.com/leifwalsh/irc, feel free to contribute!".to_string()]);
        knowledge.insert(format!("{}, info", nick), vec!["I'm a robot running https://github.com/leifwalsh/irc, feel free to contribute!".to_string()]);
    }

    let knowledge_mutex_2 = knowledge_mutex.clone();
    let info_nick = nick.clone();
    let info_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line) {
            if let Some(reply_to) = pm.reply_target(&info_nick) {
                let knowledge = knowledge_mutex_2.lock().unwrap();
                if let Some(choices) = knowledge.get(pm.msg) {
                    let mut rng = thread_rng();
                    let choice = rng.choose(choices).unwrap();
                    if let Some(c) = regex!(r"^<action>\s+(.*)$").captures(choice) {
                        return Response::respond(protocol::Privmsg::new(reply_to, &protocol::ctcp_action(c.at(1).expect("Bad regex match"))).format());
                    } else {
                        return Response::respond(protocol::Privmsg::new(reply_to, choice).format());
                    }
                }
            }
        }
        Response::nothing()
    };

    let join_nick = nick.clone();
    let join_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&join_nick)) {
            if let Some(c) = regex!(r"^(join|part) (#[^\s]+)").captures(pm.msg) {
                let action = c.at(1).expect("Bad match group");
                let chan = c.at(2).expect("Bad match group");
                let success_msg = format!("{} channel {}!", if action == "join" { "Joined" } else { "Left" }, chan);
                if let Ok(joined_regex) = Regex::new(&format!(r"{}\s+:?{}", action.to_ascii_uppercase(), chan)) {
                    let joined_handler = box move |joined_line: &str| {
                        if joined_regex.is_match(joined_line) {
                            info!("{}", success_msg);
                            return Response(None, HandlerAction::Remove, Action::Skip);
                        }
                        Response::nothing()
                    };
                    info!("{} channel {}...", if action == "join" { "Joining" } else { "Leaving" }, chan);
                    return Response(Some(format!("{} {}", action.to_ascii_uppercase(), chan)), HandlerAction::Add(joined_handler), Action::Skip);
                }
            }
        }
        Response::nothing()
    };

    let echo_nick = nick.clone();
    let echo_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(&echo_nick)) {
            if regex!(r"^[Hh]i$").is_match(pm.msg) {
                if let Some(reply_to) = pm.reply_target(&echo_nick) {
                    if let Some(protocol::Source::User(ref user_info)) = pm.src {
                        return Response::respond(protocol::Privmsg::new(reply_to, &format!("Hi, {}!", user_info.nick)).format());
                    }
                }
            } else if regex!(r"^go away$").is_match(pm.msg) {
                return Response(None, HandlerAction::Keep, Action::Stop);
            }
        }
        Response::nothing()
    };

    let (mut client, join_handle) = irc::Client::connect(
        &addr, &nick, &channels.iter().map(|s| s.as_ref()).collect::<Vec<&str>>(), "leifw_rustbot", "leifw's rust robot")
        .ok().expect(&format!("Error connecting to {:?}.", addr));

    client.add_handler(choice_handler);
    client.add_handler(learning_handler);
    client.add_handler(info_handler);
    client.add_handler(join_handler);
    client.add_handler(echo_handler);
    join_handle.join().unwrap_or_else(|_| { error!("Unknown error!"); });
}
<|endoftext|>


<commit_before>use std::cmp;
use std::fmt::{mod, Show, Formatter};
use std::io::fs;
use glob::Pattern;
use git2;

use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry};
use ops;
use util::{CargoResult, internal, internal_error};

pub struct PathSource {
    id: SourceId,
    path: Path,
    updated: bool,
    packages: Vec<Package>
}

// TODO: Figure out if packages should be discovered in new or self should be
// mut and packages are discovered in update
impl PathSource {

    pub fn for_path(path: &Path) -> CargoResult<PathSource> {
        log!(5, "PathSource::for_path; path={}", path.display());
        Ok(PathSource::new(path, &try!(SourceId::for_path(path))))
    }

    /// Invoked with an absolute path to a directory that contains a Cargo.toml.
    /// The source will read the manifest and find any other packages contained
    /// in the directory structure reachable by the root manifest.
    pub fn new(path: &Path, id: &SourceId) -> PathSource {
        log!(5, "new; id={}", id);

        PathSource {
            id: id.clone(),
            path: path.clone(),
            updated: false,
            packages: Vec::new()
        }
    }

    pub fn get_root_package(&self) -> CargoResult<Package> {
        log!(5, "get_root_package; source={}", self);

        if !self.updated {
            return Err(internal("source has not been updated"))
        }

        match self.packages.as_slice().head() {
            Some(pkg) => Ok(pkg.clone()),
            None => Err(internal("no package found in source"))
        }
    }

    fn read_packages(&self) -> CargoResult<Vec<Package>> {
        if self.updated {
            Ok(self.packages.clone())
        } else {
            ops::read_packages(&self.path, &self.id)
        }
    }

    /// List all files relevant to building this package inside this source.
    ///
    /// This function will use the appropriate methods to determine what is the
    /// set of files underneath this source's directory which are relevant for
    /// building `pkg`.
    ///
    /// The basic assumption of this method is that all files in the directory
    /// are relevant for building this package, but it also contains logic to
    /// use other methods like .gitignore to filter the list of files.
    pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<Path>> {
        let candidates = match git2::Repository::open(&self.path) {
            Ok(repo) => try!(self.list_files_git(pkg, repo)),
            Err(..) => try!(self.list_files_walk(pkg)),
        };

        let pats = pkg.get_manifest().get_exclude().iter().map(|p| {
            Pattern::new(p.as_slice())
        }).collect::<Vec<Pattern>>();

        let root = pkg.get_manifest_path().dir_path();
        Ok(candidates.move_iter().filter(|candidate| {
            let candidate = candidate.path_relative_from(&root).unwrap();
            !pats.iter().any(|p| p.matches_path(&candidate)) &&
                candidate.is_file()
        }).collect())
    }

    fn list_files_git(&self, pkg: &Package, repo: git2::Repository)
                      -> CargoResult<Vec<Path>> {
        let index = try!(repo.index());
        let mut ret = Vec::new();
        'outer: for i in range(0, index.len()) {
            let entry = match index.get(i) { Some(e) => e, None => continue };
            let fname = entry.path.as_bytes_no_nul();
            let path = pkg.get_manifest_path().dir_path().join(fname);

            // Filter out Cargo.lock and target always
            if fname == b"Cargo.lock" { continue }
            if fname == b"target" { continue }

            // Filter out all other packages
            for pkg in self.packages.iter().filter(|p| *p != pkg) {
                let pkg_path = pkg.get_manifest_path().dir_path();
                if pkg_path.is_ancestor_of(&path) { continue 'outer; }
            }

            // We found a file!
            ret.push(path);
        }
        Ok(ret)
    }

    fn list_files_walk(&self, pkg: &Package) -> CargoResult<Vec<Path>> {
        let mut ret = Vec::new();
        for pkg in self.packages.iter().filter(|p| *p == pkg) {
            let loc = pkg.get_manifest_path().dir_path();
            try!(walk(&loc, &mut ret, true));
        }
        return Ok(ret);

        fn walk(path: &Path, ret: &mut Vec<Path>,
                is_root: bool) -> CargoResult<()> {
            if !path.is_dir() {
                ret.push(path.clone());
                return Ok(())
            }
            // Don't recurse into any sub-packages that we have
            if !is_root && path.join("Cargo.toml").exists() { return Ok(()) }
            for dir in try!(fs::readdir(path)).iter() {
                match (is_root, dir.filename_str()) {
                    (_,    Some(".git")) |
                    (true, Some("target")) |
                    (true, Some("Cargo.lock")) => continue,
                    _ => {}
                }
                try!(walk(dir, ret, false));
            }
            return Ok(())
        }
    }
}

impl Show for PathSource {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "the paths source")
    }
}

impl Registry for PathSource {
    fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
        let mut summaries: Vec<Summary> = self.packages.iter()
                                              .map(|p| p.get_summary().clone())
                                              .collect();
        summaries.query(dep)
    }
}

impl Source for PathSource {
    fn update(&mut self) -> CargoResult<()> {
        if !self.updated {
            let packages = try!(self.read_packages());
            self.packages.push_all_move(packages);
            self.updated = true;
        }

        Ok(())
    }

    fn download(&self, _: &[PackageId])  -> CargoResult<()>{
        // TODO: assert! that the PackageId is contained by the source
        Ok(())
    }

    fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
        log!(5, "getting packages; ids={}", ids);

        Ok(self.packages.iter()
           .filter(|pkg| ids.iter().any(|id| pkg.get_package_id() == id))
           .map(|pkg| pkg.clone())
           .collect())
    }

    fn fingerprint(&self, pkg: &Package) -> CargoResult<String> {
        if !self.updated {
            return Err(internal_error("BUG: source was not updated", ""));
        }

        let mut max = 0;
        for file in try!(self.list_files(pkg)).iter() {
            // An fs::stat error here is either because path is a
            // broken symlink, a permissions error, or a race
            // condition where this path was rm'ed - either way,
            // we can ignore the error and treat the path's mtime
            // as 0.
            max = cmp::max(max, file.stat().map(|s| s.modified).unwrap_or(0));
        }
        log!(5, "fingerprint {}: {}", self.path.display(), max);
        Ok(max.to_string())
    }
}
<commit_msg>Fix bug in list_file_walk when cwd != path<commit_after>use std::cmp;
use std::fmt::{mod, Show, Formatter};
use std::io::fs;
use glob::Pattern;
use git2;

use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry};
use ops;
use util::{CargoResult, internal, internal_error};

pub struct PathSource {
    id: SourceId,
    path: Path,
    updated: bool,
    packages: Vec<Package>
}

// TODO: Figure out if packages should be discovered in new or self should be
// mut and packages are discovered in update
impl PathSource {

    pub fn for_path(path: &Path) -> CargoResult<PathSource> {
        log!(5, "PathSource::for_path; path={}", path.display());
        Ok(PathSource::new(path, &try!(SourceId::for_path(path))))
    }

    /// Invoked with an absolute path to a directory that contains a Cargo.toml.
    /// The source will read the manifest and find any other packages contained
    /// in the directory structure reachable by the root manifest.
    pub fn new(path: &Path, id: &SourceId) -> PathSource {
        log!(5, "new; id={}", id);

        PathSource {
            id: id.clone(),
            path: path.clone(),
            updated: false,
            packages: Vec::new()
        }
    }

    pub fn get_root_package(&self) -> CargoResult<Package> {
        log!(5, "get_root_package; source={}", self);

        if !self.updated {
            return Err(internal("source has not been updated"))
        }

        match self.packages.as_slice().head() {
            Some(pkg) => Ok(pkg.clone()),
            None => Err(internal("no package found in source"))
        }
    }

    fn read_packages(&self) -> CargoResult<Vec<Package>> {
        if self.updated {
            Ok(self.packages.clone())
        } else {
            ops::read_packages(&self.path, &self.id)
        }
    }

    /// List all files relevant to building this package inside this source.
    ///
    /// This function will use the appropriate methods to determine what is the
    /// set of files underneath this source's directory which are relevant for
    /// building `pkg`.
    ///
    /// The basic assumption of this method is that all files in the directory
    /// are relevant for building this package, but it also contains logic to
    /// use other methods like .gitignore to filter the list of files.
    pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<Path>> {
        let candidates = match git2::Repository::open(&self.path) {
            Ok(repo) => try!(self.list_files_git(pkg, repo)),
            Err(..) => try!(self.list_files_walk(pkg)),
        };

        let pats = pkg.get_manifest().get_exclude().iter().map(|p| {
            Pattern::new(p.as_slice())
        }).collect::<Vec<Pattern>>();

        let root = pkg.get_manifest_path().dir_path();
        Ok(candidates.move_iter().filter(|candidate| {
            let relative_path = candidate.path_relative_from(&root).unwrap();
            !pats.iter().any(|p| p.matches_path(&relative_path)) &&
                candidate.is_file()
        }).collect())
    }

    fn list_files_git(&self, pkg: &Package, repo: git2::Repository)
                      -> CargoResult<Vec<Path>> {
        let index = try!(repo.index());
        let mut ret = Vec::new();
        'outer: for i in range(0, index.len()) {
            let entry = match index.get(i) { Some(e) => e, None => continue };
            let fname = entry.path.as_bytes_no_nul();
            let path = pkg.get_manifest_path().dir_path().join(fname);

            // Filter out Cargo.lock and target always
            if fname == b"Cargo.lock" { continue }
            if fname == b"target" { continue }

            // Filter out all other packages
            for pkg in self.packages.iter().filter(|p| *p != pkg) {
                let pkg_path = pkg.get_manifest_path().dir_path();
                if pkg_path.is_ancestor_of(&path) { continue 'outer; }
            }

            // We found a file!
            ret.push(path);
        }
        Ok(ret)
    }

    fn list_files_walk(&self, pkg: &Package) -> CargoResult<Vec<Path>> {
        let mut ret = Vec::new();
        for pkg in self.packages.iter().filter(|p| *p == pkg) {
            let loc = pkg.get_manifest_path().dir_path();
            try!(walk(&loc, &mut ret, true));
        }
        return Ok(ret);

        fn walk(path: &Path, ret: &mut Vec<Path>,
                is_root: bool) -> CargoResult<()> {
            if !path.is_dir() {
                ret.push(path.clone());
                return Ok(())
            }
            // Don't recurse into any sub-packages that we have
            if !is_root && path.join("Cargo.toml").exists() { return Ok(()) }
            for dir in try!(fs::readdir(path)).iter() {
                match (is_root, dir.filename_str()) {
                    (_,    Some(".git")) |
                    (true, Some("target")) |
                    (true, Some("Cargo.lock")) => continue,
                    _ => {}
                }
                try!(walk(dir, ret, false));
            }
            return Ok(())
        }
    }
}

impl Show for PathSource {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "the paths source")
    }
}

impl Registry for PathSource {
    fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
        let mut summaries: Vec<Summary> = self.packages.iter()
                                              .map(|p| p.get_summary().clone())
                                              .collect();
        summaries.query(dep)
    }
}

impl Source for PathSource {
    fn update(&mut self) -> CargoResult<()> {
        if !self.updated {
            let packages = try!(self.read_packages());
            self.packages.push_all_move(packages);
            self.updated = true;
        }

        Ok(())
    }

    fn download(&self, _: &[PackageId])  -> CargoResult<()>{
        // TODO: assert! that the PackageId is contained by the source
        Ok(())
    }

    fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
        log!(5, "getting packages; ids={}", ids);

        Ok(self.packages.iter()
           .filter(|pkg| ids.iter().any(|id| pkg.get_package_id() == id))
           .map(|pkg| pkg.clone())
           .collect())
    }

    fn fingerprint(&self, pkg: &Package) -> CargoResult<String> {
        if !self.updated {
            return Err(internal_error("BUG: source was not updated", ""));
        }

        let mut max = 0;
        for file in try!(self.list_files(pkg)).iter() {
            // An fs::stat error here is either because path is a
            // broken symlink, a permissions error, or a race
            // condition where this path was rm'ed - either way,
            // we can ignore the error and treat the path's mtime
            // as 0.
            max = cmp::max(max, file.stat().map(|s| s.modified).unwrap_or(0));
        }
        log!(5, "fingerprint {}: {}", self.path.display(), max);
        Ok(max.to_string())
    }
}
<|endoftext|>


<commit_before>use std::old_io;
use std::iter;
use std::fmt;

use common;
use name::Name;
use attribute::Attribute;
use escape::escape_str;
use common::XmlVersion;
use namespace::{NamespaceStack, NamespaceIterable, UriMapping};

use writer::config::EmitterConfig;

pub enum EmitterErrorKind {
    IoError,
    DocumentStartAlreadyEmitted,
    UnexpectedEvent,
    InvalidWhitespaceEvent
}

pub struct EmitterError {
    kind: EmitterErrorKind,
    message: &'static str,
    cause: Option<old_io::IoError>
}

impl fmt::Show for EmitterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Emitter error: {:?}", self.message));
        if self.cause.is_some() {
            write!(f, "; caused by: {:?}", *self.cause.as_ref().unwrap())
        } else {
            Ok(())
        }
    }
}

pub fn error(kind: EmitterErrorKind, message: &'static str) -> EmitterError {
    EmitterError {
        kind: kind,
        message: message,
        cause: None
    }
}

#[inline]
fn io_error(err: old_io::IoError) -> EmitterError {
    EmitterError { kind: EmitterErrorKind::IoError, message: "Input/output error", cause: Some(err) }
}

pub type EmitterResult<T> = Result<T, EmitterError>;

#[inline]
pub fn io_wrap<T>(result: old_io::IoResult<T>) -> EmitterResult<T> {
    result.map_err(io_error)
}

pub struct Emitter {
    config: EmitterConfig,

    nst: NamespaceStack,

    indent_level: usize,
    indent_stack: Vec<IndentFlags>,

    start_document_emitted: bool
}

impl Emitter {
    pub fn new(config: EmitterConfig) -> Emitter {
        Emitter {
            config: config,

            nst: NamespaceStack::empty(),

            indent_level: 0,
            indent_stack: vec!(IndentFlags::empty()),

            start_document_emitted: false
        }
    }
}

macro_rules! io_try(
    ($e:expr) => (
        match $e {
            Ok(value) => value,
            Err(err) => return Err(io_error(err))
        }
    )
);

macro_rules! io_chain(
    ($e:expr) => (io_wrap($e));
    ($e:expr, $($rest:expr),+) => ({
        io_try!($e);
        io_chain!($($rest),+)
    })
);

macro_rules! wrapped_with(
    ($_self:ident; $before_name:ident ($arg:expr) and $after_name:ident, $body:expr) => ({
        try!($_self.$before_name($arg));
        let result = $body;
        $_self.$after_name();
        result
    })
);

macro_rules! if_present(
    ($opt:ident, $body:expr) => ($opt.map(|$opt| $body).unwrap_or(Ok(())))
);

bitflags!(
    flags IndentFlags: u8 {
        const WROTE_NOTHING = 0,
        const WROTE_MARKUP  = 1,
        const WROTE_TEXT    = 2
    }
);

impl Emitter {
    /// Returns current state of namespaces.
    #[inline]
    pub fn namespace_stack<'a>(&'a self) -> &'a NamespaceStack {
        & self.nst
    }

    #[inline]
    fn wrote_text(&self) -> bool {
        self.indent_stack.last().unwrap().contains(WROTE_TEXT)
    }

    #[inline]
    fn wrote_markup(&self) -> bool {
        self.indent_stack.last().unwrap().contains(WROTE_MARKUP)
    }

    #[inline]
    fn set_wrote_text(&mut self) {
        *self.indent_stack.last_mut().unwrap() = WROTE_TEXT;
    }

    #[inline]
    fn set_wrote_markup(&mut self) {
        *self.indent_stack.last_mut().unwrap() = WROTE_MARKUP;
    }

    #[inline]
    fn reset_state(&mut self) {
        *self.indent_stack.last_mut().unwrap() = WROTE_NOTHING;
    }

    fn write_newline<W: Writer>(&mut self, target: &mut W, level: usize) -> EmitterResult<()> {
        io_try!(target.write_str(self.config.line_separator.as_slice()));
        for _ in iter::range(0, level) {
            io_try!(target.write_str(self.config.indent_string.as_slice()));
        }
        Ok(())
    }

    fn before_markup<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        if !self.wrote_text() && (self.indent_level > 0 || self.wrote_markup()) {
            let indent_level = self.indent_level;
            try!(self.write_newline(target, indent_level));
            if self.indent_level > 0 && self.config.indent_string.len() > 0 {
                self.after_markup();
            }
        }
        Ok(())
    }

    fn after_markup(&mut self) {
        self.set_wrote_markup();
    }

    fn before_start_element<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        try!(self.before_markup(target));
        self.indent_stack.push(WROTE_NOTHING);
        Ok(())
    }

    fn after_start_element(&mut self) {
        self.after_markup();
        self.indent_level += 1;
    }

    fn before_end_element<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        if self.indent_level > 0 && self.wrote_markup() && !self.wrote_text() {
            let indent_level = self.indent_level;
            self.write_newline(target, indent_level - 1)
        } else {
            Ok(())
        }
    }

    fn after_end_element(&mut self) {
        if self.indent_level > 0 {
            self.indent_level -= 1;
            self.indent_stack.pop();
        }
        self.set_wrote_markup();
    }

    fn after_text(&mut self) {
        self.set_wrote_text();
    }

    pub fn emit_start_document<W: Writer>(&mut self, target: &mut W,
                                          version: XmlVersion,
                                          encoding: &str,
                                          standalone: Option<bool>) -> EmitterResult<()> {
        if self.start_document_emitted {
            return Err(error(
                EmitterErrorKind::DocumentStartAlreadyEmitted,
                "Document start is already emitted"
            ));
        }
        self.start_document_emitted = true;

        wrapped_with!(self; before_markup(target) and after_markup,
            io_chain!(
                write!(target, "<?xml version=\"{}\" encoding=\"{}\"", version.to_string(), encoding),

                if_present!(standalone,
                            write!(target, " standalone=\"{}\"",
                                   if standalone { "yes" } else { "no" })),

                write!(target, "?>")
            )
        )
    }

    fn check_document_started<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        if !self.start_document_emitted && self.config.write_document_declaration {
            self.emit_start_document(target, common::XmlVersion::Version10, "utf-8", None)
        } else {
            Ok(())
        }
    }

    pub fn emit_processing_instruction<W: Writer>(&mut self,
                                                  target: &mut W,
                                                  name: &str,
                                                  data: Option<&str>) -> EmitterResult<()> {
        try!(self.check_document_started(target));

        wrapped_with!(self; before_markup(target) and after_markup,
            io_chain!(
                write!(target, "<?{}", name),

                if_present!(data, write!(target, " {}", data)),

                write!(target, "?>")
            )
        )
    }

    fn emit_start_element_initial<'a, 'b, W, N, I>(&mut self, target: &mut W,
                                                   name: Name<'b>,
                                                   attributes: &[Attribute],
                                                   namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        try!(self.check_document_started(target));

        try!(self.before_start_element(target));

        io_try!(write!(target, "<{}", name.to_repr()));

        try!(self.emit_namespace_attributes(target, namespace));

        self.emit_attributes(target, attributes)
    }

    pub fn emit_empty_element<'a, 'b, W, N, I>(&mut self, target: &mut W,
                                               name: Name<'b>,
                                               attributes: &[Attribute],
                                               namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        try!(self.emit_start_element_initial(target, name, attributes, namespace));

        io_wrap(write!(target, "/>"))
    }

    pub fn emit_start_element<'a, 'b, W, N, I>(&mut self, target: &mut W,
                                               name: Name<'b>,
                                               attributes: &[Attribute],
                                               namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        try!(self.emit_start_element_initial(target, name, attributes, namespace));

        io_wrap(write!(target, ">"))
    }

    pub fn emit_namespace_attributes<'a, W, N, I>(&mut self, target: &mut W,
                                                  namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        for (prefix, uri) in namespace.uri_mappings() {
            io_try!(match prefix {
                Some("xmlns") | Some("xml") => Ok(()),  // emit nothing
                Some(prefix) => write!(target, " xmlns:{}=\"{}\"", prefix, uri),
                None => if !uri.is_empty() {  // emit xmlns only if it is overridden
                    write!(target, " xmlns=\"{}\"", uri)
                } else { Ok(()) }
            });
        }
        Ok(())
    }

    pub fn emit_attributes<W: Writer>(&mut self, target: &mut W,
                                      attributes: &[Attribute]) -> EmitterResult<()> {
        for attr in attributes.iter() {
            io_try!(write!(target, " {}=\"{}\"", attr.name.to_repr(), escape_str(attr.value)))
        }
        Ok(())
    }

    pub fn emit_end_element<W: Writer>(&mut self, target: &mut W,
                                       name: Name) -> EmitterResult<()> {
        wrapped_with!(self; before_end_element(target) and after_end_element,
            io_wrap(write!(target, "</{}>", name.to_repr()))
        )
    }

    pub fn emit_cdata<W: Writer>(&mut self, target: &mut W, content: &str) -> EmitterResult<()> {
        if self.config.cdata_to_characters {
            self.emit_characters(target, content)
        } else {
            io_try!(target.write_str("<![CDATA["));
            io_try!(target.write_str(content));
            io_try!(target.write_str("]]>"));
            self.after_text();
            Ok(())
        }
    }

    pub fn emit_characters<W: Writer>(&mut self, target: &mut W,
                                      content: &str) -> EmitterResult<()> {
        io_try!(target.write_str(escape_str(content).as_slice()));
        self.after_text();
        Ok(())
    }

    pub fn emit_comment<W: Writer>(&mut self, target: &mut W, content: &str) -> EmitterResult<()> {
        Ok(())  // TODO: proper write
    }
}
<commit_msg>Show was renamed to Debug<commit_after>use std::old_io;
use std::iter;
use std::fmt;

use common;
use name::Name;
use attribute::Attribute;
use escape::escape_str;
use common::XmlVersion;
use namespace::{NamespaceStack, NamespaceIterable, UriMapping};

use writer::config::EmitterConfig;

pub enum EmitterErrorKind {
    IoError,
    DocumentStartAlreadyEmitted,
    UnexpectedEvent,
    InvalidWhitespaceEvent
}

pub struct EmitterError {
    kind: EmitterErrorKind,
    message: &'static str,
    cause: Option<old_io::IoError>
}

impl fmt::Debug for EmitterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Emitter error: {:?}", self.message));
        if self.cause.is_some() {
            write!(f, "; caused by: {:?}", *self.cause.as_ref().unwrap())
        } else {
            Ok(())
        }
    }
}

pub fn error(kind: EmitterErrorKind, message: &'static str) -> EmitterError {
    EmitterError {
        kind: kind,
        message: message,
        cause: None
    }
}

#[inline]
fn io_error(err: old_io::IoError) -> EmitterError {
    EmitterError { kind: EmitterErrorKind::IoError, message: "Input/output error", cause: Some(err) }
}

pub type EmitterResult<T> = Result<T, EmitterError>;

#[inline]
pub fn io_wrap<T>(result: old_io::IoResult<T>) -> EmitterResult<T> {
    result.map_err(io_error)
}

pub struct Emitter {
    config: EmitterConfig,

    nst: NamespaceStack,

    indent_level: usize,
    indent_stack: Vec<IndentFlags>,

    start_document_emitted: bool
}

impl Emitter {
    pub fn new(config: EmitterConfig) -> Emitter {
        Emitter {
            config: config,

            nst: NamespaceStack::empty(),

            indent_level: 0,
            indent_stack: vec!(IndentFlags::empty()),

            start_document_emitted: false
        }
    }
}

macro_rules! io_try(
    ($e:expr) => (
        match $e {
            Ok(value) => value,
            Err(err) => return Err(io_error(err))
        }
    )
);

macro_rules! io_chain(
    ($e:expr) => (io_wrap($e));
    ($e:expr, $($rest:expr),+) => ({
        io_try!($e);
        io_chain!($($rest),+)
    })
);

macro_rules! wrapped_with(
    ($_self:ident; $before_name:ident ($arg:expr) and $after_name:ident, $body:expr) => ({
        try!($_self.$before_name($arg));
        let result = $body;
        $_self.$after_name();
        result
    })
);

macro_rules! if_present(
    ($opt:ident, $body:expr) => ($opt.map(|$opt| $body).unwrap_or(Ok(())))
);

bitflags!(
    flags IndentFlags: u8 {
        const WROTE_NOTHING = 0,
        const WROTE_MARKUP  = 1,
        const WROTE_TEXT    = 2
    }
);

impl Emitter {
    /// Returns current state of namespaces.
    #[inline]
    pub fn namespace_stack<'a>(&'a self) -> &'a NamespaceStack {
        & self.nst
    }

    #[inline]
    fn wrote_text(&self) -> bool {
        self.indent_stack.last().unwrap().contains(WROTE_TEXT)
    }

    #[inline]
    fn wrote_markup(&self) -> bool {
        self.indent_stack.last().unwrap().contains(WROTE_MARKUP)
    }

    #[inline]
    fn set_wrote_text(&mut self) {
        *self.indent_stack.last_mut().unwrap() = WROTE_TEXT;
    }

    #[inline]
    fn set_wrote_markup(&mut self) {
        *self.indent_stack.last_mut().unwrap() = WROTE_MARKUP;
    }

    #[inline]
    fn reset_state(&mut self) {
        *self.indent_stack.last_mut().unwrap() = WROTE_NOTHING;
    }

    fn write_newline<W: Writer>(&mut self, target: &mut W, level: usize) -> EmitterResult<()> {
        io_try!(target.write_str(self.config.line_separator.as_slice()));
        for _ in iter::range(0, level) {
            io_try!(target.write_str(self.config.indent_string.as_slice()));
        }
        Ok(())
    }

    fn before_markup<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        if !self.wrote_text() && (self.indent_level > 0 || self.wrote_markup()) {
            let indent_level = self.indent_level;
            try!(self.write_newline(target, indent_level));
            if self.indent_level > 0 && self.config.indent_string.len() > 0 {
                self.after_markup();
            }
        }
        Ok(())
    }

    fn after_markup(&mut self) {
        self.set_wrote_markup();
    }

    fn before_start_element<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        try!(self.before_markup(target));
        self.indent_stack.push(WROTE_NOTHING);
        Ok(())
    }

    fn after_start_element(&mut self) {
        self.after_markup();
        self.indent_level += 1;
    }

    fn before_end_element<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        if self.indent_level > 0 && self.wrote_markup() && !self.wrote_text() {
            let indent_level = self.indent_level;
            self.write_newline(target, indent_level - 1)
        } else {
            Ok(())
        }
    }

    fn after_end_element(&mut self) {
        if self.indent_level > 0 {
            self.indent_level -= 1;
            self.indent_stack.pop();
        }
        self.set_wrote_markup();
    }

    fn after_text(&mut self) {
        self.set_wrote_text();
    }

    pub fn emit_start_document<W: Writer>(&mut self, target: &mut W,
                                          version: XmlVersion,
                                          encoding: &str,
                                          standalone: Option<bool>) -> EmitterResult<()> {
        if self.start_document_emitted {
            return Err(error(
                EmitterErrorKind::DocumentStartAlreadyEmitted,
                "Document start is already emitted"
            ));
        }
        self.start_document_emitted = true;

        wrapped_with!(self; before_markup(target) and after_markup,
            io_chain!(
                write!(target, "<?xml version=\"{}\" encoding=\"{}\"", version.to_string(), encoding),

                if_present!(standalone,
                            write!(target, " standalone=\"{}\"",
                                   if standalone { "yes" } else { "no" })),

                write!(target, "?>")
            )
        )
    }

    fn check_document_started<W: Writer>(&mut self, target: &mut W) -> EmitterResult<()> {
        if !self.start_document_emitted && self.config.write_document_declaration {
            self.emit_start_document(target, common::XmlVersion::Version10, "utf-8", None)
        } else {
            Ok(())
        }
    }

    pub fn emit_processing_instruction<W: Writer>(&mut self,
                                                  target: &mut W,
                                                  name: &str,
                                                  data: Option<&str>) -> EmitterResult<()> {
        try!(self.check_document_started(target));

        wrapped_with!(self; before_markup(target) and after_markup,
            io_chain!(
                write!(target, "<?{}", name),

                if_present!(data, write!(target, " {}", data)),

                write!(target, "?>")
            )
        )
    }

    fn emit_start_element_initial<'a, 'b, W, N, I>(&mut self, target: &mut W,
                                                   name: Name<'b>,
                                                   attributes: &[Attribute],
                                                   namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        try!(self.check_document_started(target));

        try!(self.before_start_element(target));

        io_try!(write!(target, "<{}", name.to_repr()));

        try!(self.emit_namespace_attributes(target, namespace));

        self.emit_attributes(target, attributes)
    }

    pub fn emit_empty_element<'a, 'b, W, N, I>(&mut self, target: &mut W,
                                               name: Name<'b>,
                                               attributes: &[Attribute],
                                               namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        try!(self.emit_start_element_initial(target, name, attributes, namespace));

        io_wrap(write!(target, "/>"))
    }

    pub fn emit_start_element<'a, 'b, W, N, I>(&mut self, target: &mut W,
                                               name: Name<'b>,
                                               attributes: &[Attribute],
                                               namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        try!(self.emit_start_element_initial(target, name, attributes, namespace));

        io_wrap(write!(target, ">"))
    }

    pub fn emit_namespace_attributes<'a, W, N, I>(&mut self, target: &mut W,
                                                  namespace: &'a N) -> EmitterResult<()>
        where W: Writer,
              N: NamespaceIterable<'a, Iter=I>,
              I: Iterator<Item=UriMapping<'a>>
    {
        for (prefix, uri) in namespace.uri_mappings() {
            io_try!(match prefix {
                Some("xmlns") | Some("xml") => Ok(()),  // emit nothing
                Some(prefix) => write!(target, " xmlns:{}=\"{}\"", prefix, uri),
                None => if !uri.is_empty() {  // emit xmlns only if it is overridden
                    write!(target, " xmlns=\"{}\"", uri)
                } else { Ok(()) }
            });
        }
        Ok(())
    }

    pub fn emit_attributes<W: Writer>(&mut self, target: &mut W,
                                      attributes: &[Attribute]) -> EmitterResult<()> {
        for attr in attributes.iter() {
            io_try!(write!(target, " {}=\"{}\"", attr.name.to_repr(), escape_str(attr.value)))
        }
        Ok(())
    }

    pub fn emit_end_element<W: Writer>(&mut self, target: &mut W,
                                       name: Name) -> EmitterResult<()> {
        wrapped_with!(self; before_end_element(target) and after_end_element,
            io_wrap(write!(target, "</{}>", name.to_repr()))
        )
    }

    pub fn emit_cdata<W: Writer>(&mut self, target: &mut W, content: &str) -> EmitterResult<()> {
        if self.config.cdata_to_characters {
            self.emit_characters(target, content)
        } else {
            io_try!(target.write_str("<![CDATA["));
            io_try!(target.write_str(content));
            io_try!(target.write_str("]]>"));
            self.after_text();
            Ok(())
        }
    }

    pub fn emit_characters<W: Writer>(&mut self, target: &mut W,
                                      content: &str) -> EmitterResult<()> {
        io_try!(target.write_str(escape_str(content).as_slice()));
        self.after_text();
        Ok(())
    }

    pub fn emit_comment<W: Writer>(&mut self, target: &mut W, content: &str) -> EmitterResult<()> {
        Ok(())  // TODO: proper write
    }
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {
	Server::http(login).listen("0.0.0.0:8080").unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let mut client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {

											// Form the response headers
											let mut headers = Headers::new();
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];
											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let mut create_eveusers_table = create_table(&table_name,&table_fields,None);
											create_eveusers_table = insert_fact(&"tag",&vec!["view","tag"],&vec![Value::String("eveusers".to_string()),Value::String("remote".to_string())],Some(create_eveusers_table));
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&create_eveusers_table,&mut sender);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));

											// Serve the editor
											// TODO Should serve a requested file
											serve_local_or_file(res, &path_info.path, "../ui/editor.html");
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<commit_msg>Revert "Serve file instead of redirect on login."<commit_after>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {
	Server::http(login).listen("0.0.0.0:8080").unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let mut client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let location = Location("http://192.168.137.38:1234/editor.html".to_string());
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];
											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let mut create_eveusers_table = create_table(&table_name,&table_fields,None);
											create_eveusers_table = insert_fact(&"tag",&vec!["view","tag"],&vec![Value::String("eveusers".to_string()),Value::String("remote".to_string())],Some(create_eveusers_table));
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&create_eveusers_table,&mut sender);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<|endoftext|>


<commit_before>use kernel_micro::{include_file, MicroKernel};

/// A microkernel for R
pub fn new() -> MicroKernel {
    MicroKernel::new(
        "r-micro",
        &["r"],
        &["linux", "macos", "windows"],
        ("Rscript", "*"),
        &["{{script}}"],
        include_file!("r-kernel.r"),
        &[include_file!("r-codec.r")],
        "{{name}} <- decode_value(\"{{json}}\")",
        "{{name}}",
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{
        eyre::{bail, Result},
        stencila_schema::Node,
        KernelTrait,
    };
    use once_cell::sync::Lazy;
    use test_utils::{assert_json_eq, print_logs, serde_json::json};
    use tokio::sync::Mutex;

    // Make sure that only one test runs at any one time
    // This is to avoid `install.packages` being run in parallel.
    // Previous the `serial_test` crate was used for this but did not
    // seem to provide necessary guarantee.
    static QUEUE: Lazy<Mutex<()>> = Lazy::new(Mutex::default);

    async fn skip_or_kernel() -> Result<MicroKernel> {
        let mut kernel = new();
        if !kernel.available().await {
            eprintln!("R not available on this machine");
            bail!("Skipping")
        } else {
            kernel.start().await?;
        }

        Ok(kernel)
    }

    // Run these tests serially to avoid parallel installation of dependencies
    // which may interfere with each other.

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        let _guard = QUEUE.lock().await;

        print_logs();

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a = 2\na").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[2]]);

        // Print the variable twice and then output it
        let (outputs, messages) = kernel.exec("print(a)\nprint(a)\na").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[2], [2], [2]]);

        // Syntax error
        let (outputs, messages) = kernel.exec("bad ^ # syntax").await?;
        assert_json_eq!(messages[0].error_type, "SyntaxError");
        assert_json_eq!(
            messages[0].error_message,
            "<text>:2:0: unexpected end of input\n1: bad ^ # syntax\n   ^"
        );
        assert_json_eq!(outputs, json!([]));

        // Runtime error
        let (outputs, messages) = kernel.exec("foo").await?;
        assert_json_eq!(messages[0].error_type, "RuntimeError");
        assert_json_eq!(messages[0].error_message, "object 'foo' not found");
        assert_json_eq!(outputs, json!([]));

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_eq!(b, [3]);

        // Use both variables
        let (outputs, messages) = kernel.exec("a*b").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[6]]);

        Ok(())
    }

    /// Test that an assignment on the last line does not generate an output
    #[tokio::test]
    async fn assignment_no_output() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel.exec("a <- 1").await?;
        assert!(messages.is_empty());
        assert_json_eq!(outputs, json!([]));

        let (outputs, messages) = kernel.exec("b = 2").await?;
        assert!(messages.is_empty());
        assert_json_eq!(outputs, json!([]));

        let (outputs, messages) = kernel.exec("print(a)\nprint(b)\na_b <- a + b").await?;
        assert!(messages.is_empty());
        assert_json_eq!(outputs, [[1], [2]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_general() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // Null, booleans, integers, numbers, strings
        let (outputs, messages) = kernel
            .exec("list(NULL, TRUE, FALSE, 1, 1.23456789, 'str')")
            .await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(
            outputs,
            json!([[null, [true], [false], [1], [1.23456789], ["str"]]])
        );

        // Arrays
        let (outputs, messages) = kernel.exec("1:5").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[1, 2, 3, 4, 5]]);

        // Objects
        let (outputs, messages) = kernel.exec("list(a=1, b=list(c=2))").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, json!([{"type": "Entity"}]));
        // TODO: correct output when deserialization of Node::Object is working
        //assert_json_eq!(outputs, json!([{"a": [1], "b": {"c": [2]}}]));

        // Matrix
        let (outputs, messages) = kernel.exec("matrix(c(1:4), 2, 2)").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[[1, 3], [2, 4]]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_dataframes() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel
            .exec(
                r#"data.frame(
    a = 1:2,
    b = c(TRUE, FALSE),
    c = c("x", "y"),
    d = factor(c("X", "Y"), levels = c("X", "Y", "Z")),
    stringsAsFactors = FALSE
)"#,
            )
            .await?;
        assert_json_eq!(messages, json!([]));
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["a", "b", "c", "d"]
        );
        assert_json_eq!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            json!({ "type": "NumberValidator"})
        );
        assert_json_eq!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            json!({ "type": "BooleanValidator"})
        );
        assert_json_eq!(
            dt.columns[2].validator.as_ref().unwrap().items_validator,
            json!({ "type": "StringValidator"})
        );
        assert_json_eq!(
            dt.columns[3].validator.as_ref().unwrap().items_validator,
            json!({
                "type": "EnumValidator",
                "values": ["X", "Y", "Z"]
            })
        );

        let (outputs, messages) = kernel.exec("mtcars").await?;
        assert_json_eq!(messages, json!([]));
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec![
                "name", "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear",
                "carb"
            ]
        );
        assert_json_eq!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            json!({ "type": "StringValidator"})
        );
        assert_json_eq!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            json!({ "type": "NumberValidator"})
        );

        let (outputs, messages) = kernel.exec("chickwts").await?;
        assert_json_eq!(messages, json!([]));
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["weight", "feed"]
        );
        assert_json_eq!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            json!({ "type": "NumberValidator"})
        );
        assert_json_eq!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            json!({
                "type": "EnumValidator",
                "values": ["casein", "horsebean", "linseed", "meatmeal", "soybean", "sunflower"]
            })
        );

        Ok(())
    }

    #[tokio::test]
    async fn encode_plots() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        for code in ["plot(1)", "hist(rnorm(1000), breaks=30)"] {
            let (outputs, messages) = kernel.exec(code).await?;
            assert_json_eq!(messages, json!([]));
            let image = match &outputs[0] {
                Node::ImageObject(dt) => dt.clone(),
                _ => bail!("unexpected type {:?}", outputs[0]),
            };
            assert!(image.content_url.starts_with("data:image/png;base64,"));
        }

        Ok(())
    }
}
<commit_msg>test(R microkernel): Remove print logs<commit_after>use kernel_micro::{include_file, MicroKernel};

/// A microkernel for R
pub fn new() -> MicroKernel {
    MicroKernel::new(
        "r-micro",
        &["r"],
        &["linux", "macos", "windows"],
        ("Rscript", "*"),
        &["{{script}}"],
        include_file!("r-kernel.r"),
        &[include_file!("r-codec.r")],
        "{{name}} <- decode_value(\"{{json}}\")",
        "{{name}}",
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{
        eyre::{bail, Result},
        stencila_schema::Node,
        KernelTrait,
    };
    use once_cell::sync::Lazy;
    use test_utils::{assert_json_eq, serde_json::json};
    use tokio::sync::Mutex;

    // Make sure that only one test runs at any one time
    // This is to avoid `install.packages` being run in parallel.
    // Previous the `serial_test` crate was used for this but did not
    // seem to provide necessary guarantee.
    static QUEUE: Lazy<Mutex<()>> = Lazy::new(Mutex::default);

    async fn skip_or_kernel() -> Result<MicroKernel> {
        let mut kernel = new();
        if !kernel.available().await {
            eprintln!("R not available on this machine");
            bail!("Skipping")
        } else {
            kernel.start().await?;
        }

        Ok(kernel)
    }

    // Run these tests serially to avoid parallel installation of dependencies
    // which may interfere with each other.

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a = 2\na").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[2]]);

        // Print the variable twice and then output it
        let (outputs, messages) = kernel.exec("print(a)\nprint(a)\na").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[2], [2], [2]]);

        // Syntax error
        let (outputs, messages) = kernel.exec("bad ^ # syntax").await?;
        assert_json_eq!(messages[0].error_type, "SyntaxError");
        assert_json_eq!(
            messages[0].error_message,
            "<text>:2:0: unexpected end of input\n1: bad ^ # syntax\n   ^"
        );
        assert_json_eq!(outputs, json!([]));

        // Runtime error
        let (outputs, messages) = kernel.exec("foo").await?;
        assert_json_eq!(messages[0].error_type, "RuntimeError");
        assert_json_eq!(messages[0].error_message, "object 'foo' not found");
        assert_json_eq!(outputs, json!([]));

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_eq!(b, [3]);

        // Use both variables
        let (outputs, messages) = kernel.exec("a*b").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[6]]);

        Ok(())
    }

    /// Test that an assignment on the last line does not generate an output
    #[tokio::test]
    async fn assignment_no_output() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel.exec("a <- 1").await?;
        assert!(messages.is_empty());
        assert_json_eq!(outputs, json!([]));

        let (outputs, messages) = kernel.exec("b = 2").await?;
        assert!(messages.is_empty());
        assert_json_eq!(outputs, json!([]));

        let (outputs, messages) = kernel.exec("print(a)\nprint(b)\na_b <- a + b").await?;
        assert!(messages.is_empty());
        assert_json_eq!(outputs, [[1], [2]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_general() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // Null, booleans, integers, numbers, strings
        let (outputs, messages) = kernel
            .exec("list(NULL, TRUE, FALSE, 1, 1.23456789, 'str')")
            .await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(
            outputs,
            json!([[null, [true], [false], [1], [1.23456789], ["str"]]])
        );

        // Arrays
        let (outputs, messages) = kernel.exec("1:5").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[1, 2, 3, 4, 5]]);

        // Objects
        let (outputs, messages) = kernel.exec("list(a=1, b=list(c=2))").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, json!([{"type": "Entity"}]));
        // TODO: correct output when deserialization of Node::Object is working
        //assert_json_eq!(outputs, json!([{"a": [1], "b": {"c": [2]}}]));

        // Matrix
        let (outputs, messages) = kernel.exec("matrix(c(1:4), 2, 2)").await?;
        assert_json_eq!(messages, json!([]));
        assert_json_eq!(outputs, [[[1, 3], [2, 4]]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_dataframes() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel
            .exec(
                r#"data.frame(
    a = 1:2,
    b = c(TRUE, FALSE),
    c = c("x", "y"),
    d = factor(c("X", "Y"), levels = c("X", "Y", "Z")),
    stringsAsFactors = FALSE
)"#,
            )
            .await?;
        assert_json_eq!(messages, json!([]));
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["a", "b", "c", "d"]
        );
        assert_json_eq!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            json!({ "type": "NumberValidator"})
        );
        assert_json_eq!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            json!({ "type": "BooleanValidator"})
        );
        assert_json_eq!(
            dt.columns[2].validator.as_ref().unwrap().items_validator,
            json!({ "type": "StringValidator"})
        );
        assert_json_eq!(
            dt.columns[3].validator.as_ref().unwrap().items_validator,
            json!({
                "type": "EnumValidator",
                "values": ["X", "Y", "Z"]
            })
        );

        let (outputs, messages) = kernel.exec("mtcars").await?;
        assert_json_eq!(messages, json!([]));
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec![
                "name", "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear",
                "carb"
            ]
        );
        assert_json_eq!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            json!({ "type": "StringValidator"})
        );
        assert_json_eq!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            json!({ "type": "NumberValidator"})
        );

        let (outputs, messages) = kernel.exec("chickwts").await?;
        assert_json_eq!(messages, json!([]));
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["weight", "feed"]
        );
        assert_json_eq!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            json!({ "type": "NumberValidator"})
        );
        assert_json_eq!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            json!({
                "type": "EnumValidator",
                "values": ["casein", "horsebean", "linseed", "meatmeal", "soybean", "sunflower"]
            })
        );

        Ok(())
    }

    #[tokio::test]
    async fn encode_plots() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        for code in ["plot(1)", "hist(rnorm(1000), breaks=30)"] {
            let (outputs, messages) = kernel.exec(code).await?;
            assert_json_eq!(messages, json!([]));
            let image = match &outputs[0] {
                Node::ImageObject(dt) => dt.clone(),
                _ => bail!("unexpected type {:?}", outputs[0]),
            };
            assert!(image.content_url.starts_with("data:image/png;base64,"));
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate rustc_serialize;
extern crate queryst;

use rustc_serialize::json;
use iron::prelude::*;
use iron::status;
use queryst::parse;

#[derive(RustcEncodable)]
pub struct PadJson {
    str: String
}

fn main() {
    fn handler(req: &mut Request) -> IronResult<Response> {
        let padded_resp = PadJson {
            str: "Hallo".to_string(),
        };

        let query = req.url.query.clone().unwrap();

        let query_params = parse(&query.to_string());

        Ok(Response::with((status::Ok, json::encode(&padded_resp).unwrap())))
    }

    Iron::new(handler).http("localhost:3000").unwrap();
}
<commit_msg>Don't panic on missing query<commit_after>extern crate iron;
extern crate rustc_serialize;
extern crate queryst;

use rustc_serialize::json;
use iron::prelude::*;
use iron::status;
use queryst::parse;

#[derive(RustcEncodable)]
pub struct PadJson {
    str: String
}

fn main() {
    fn handler(req: &mut Request) -> IronResult<Response> {
        let padded_resp = PadJson {
            str: "Hallo".to_string(),
        };

        let query = req.url.query.clone().unwrap_or("".to_string());

        let query_params = parse(&query.to_string());

        Ok(Response::with((status::Ok, json::encode(&padded_resp).unwrap())))
    }

    Iron::new(handler).http("localhost:3000").unwrap();
}
<|endoftext|>