<commit_before>extern crate mio;
extern crate bytes;

use mio::*;
use mio::tcp::*;
use mio::util::Slab;
use bytes::{ByteBuf, MutByteBuf, SliceBuf};
use std::io;

const SERVER : Token = Token(0);

enum State {
    Init,
    Headers,
    Body
}

struct Header {
    name: String,
    content: String
}

struct HttpPacket {
    request_line: String,
    headers: Vec<Header>,
    body: Option<String>
}

struct HttpConnection {
    sock: TcpStream,
    buf: Option<ByteBuf>,
    mut_buf: Option<MutByteBuf>,
    token: Option<Token>,
    interest: EventSet
}

impl HttpConnection {
    fn new(sock: TcpStream) -> HttpConnection {
        HttpConnection {
            sock: sock,
            buf: None,
            mut_buf: Some(ByteBuf::mut_with_capacity(2048*8)),
            token: None,
            interest: EventSet::hup()
        }
    }

    fn readable(&mut self, event_loop: &mut EventLoop<HttpHandler>) -> io::Result<()> {
        let mut buf = self.mut_buf.take().unwrap();

        match self.sock.try_read_buf(&mut buf) {
            Ok(None) => {
                panic!("Received readable notification but was unable to read from socket");
            }
            Ok(Some(r)) => {
                println!("CONN: we read {} bytes!", r);
                //Check if end of request
                let mut read_buffer = buf.flip();
                let remaining = read_buffer.remaining();
                read_buffer.mark();
                let mut method : [u8;3] = [0;3];
                read_buffer.read_slice(&mut method);

                if std::str::from_utf8(&method) == Ok("GET") {
                    println!("Beginning get")
                } else {
                    panic!("Unsupported method encountered - {:?}", method)
                }

                self.mut_buf = Some(read_buffer.flip());
            }
            Err(e) => {
                println!("Error encountered {:?}", e);
            }
        }

        Ok(())
    }

    fn process(buffer: &ByteBuf) -> Option<()>{
        let mut length = 0u32;
        let mut state = 0;

        Some(())
    }

    fn read_line(buffer: &mut ByteBuf) -> Option<String> {
        let mut length = 0;

        loop {
            match buffer.read_byte() {
                Some(0x0D) => (),
                Some(0x0A) => {
                    return None;
                },
                Some(_) => length+=1,
                None => return None
            }
        }
    }
}

struct HttpServer {
    sock: TcpListener,
    conns: Slab<HttpConnection>
}

impl HttpServer {
    fn accept(&mut self, event_loop: &mut EventLoop<HttpHandler>) -> io::Result<()> {
        let sock = self.sock.accept().unwrap().unwrap();
        let conn = HttpConnection::new(sock);
        let tok = self.conns.insert(conn)
            .ok().expect("Could not add connection to slab");

        self.conns[tok].token = Some(tok);
        event_loop.register_opt(&self.conns[tok].sock, tok, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).ok().expect("Could not register socket with event loop");

        Ok(())
    }

    fn conn_readable(&mut self, event_loop: &mut EventLoop<HttpHandler>, tok: Token) -> io::Result<()> {
        println!("Reading from connection");
        self.conn(tok).readable(event_loop)
    }

    fn conn<'a>(&'a mut self, tok: Token) -> &'a mut HttpConnection {
        &mut self.conns[tok]
    }
}

struct HttpHandler {
    server: HttpServer
}

impl HttpHandler {
    fn new(srv: TcpListener) -> HttpHandler {
        HttpHandler {
            server: HttpServer {
                sock: srv,
                conns: Slab::new_starting_at(Token(1), 128)
            }
        }
    }
}

impl Handler for HttpHandler {

    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<HttpHandler>, token: Token, events:EventSet) {
        if events.is_readable() {
            match token {
                SERVER => self.server.accept(event_loop).unwrap(),
                i => self.server.conn_readable(event_loop, i).unwrap()
            }
        }
    }
}

fn main() {
    start();
}

fn start() {
    println!("Starting event loop");
    let addr = "127.0.0.1:8080".parse().unwrap();
    let server = TcpListener::bind(&addr).unwrap();
    let mut event_loop = EventLoop::new().unwrap();
    event_loop.register(&server, SERVER).unwrap();

    let mut handler = HttpHandler::new(server);
    event_loop.run(&mut handler).unwrap();
}
<commit_msg>Adding some initial tests<commit_after>extern crate mio;
extern crate bytes;

use mio::*;
use mio::tcp::*;
use mio::util::Slab;
use bytes::{ByteBuf, MutByteBuf};
use std::io;

const SERVER : Token = Token(0);

enum State {
    Init,
    Headers,
    Body
}

struct Header {
    name: String,
    content: String
}

struct HttpPacket {
    request_line: String,
    headers: Vec<Header>,
    body: Option<String>
}

struct HttpConnection {
    sock: TcpStream,
    buf: Option<ByteBuf>,
    mut_buf: Option<MutByteBuf>,
    token: Option<Token>,
    interest: EventSet
}

#[derive(PartialEq)]
enum SectionStates {
    State_0, State_1, State_2
}

fn find_section_end(data:&mut ByteBuf) -> Option<u16> {
    let mut state = SectionStates::State_0;
    let mut position = 0;
    let data2 : &[u8] = data.bytes();

    for byte in data.bytes().iter() {
        state = match (state, byte) {
            (SectionStates::State_0, 0x0A) => SectionStates::State_1,
            (SectionStates::State_1, 0x0D) => SectionStates::State_1,
            (SectionStates::State_1, 0x0A) => SectionStates::State_2,
            _ => SectionStates::State_0
        };

        if state == SectionStates::State_2 {
            return Some(position)
        }

        position += 1
    }

    return None
}

#[cfg(test)]
mod tests {

    use super::find_section_end;
    use bytes::ByteBuf;

    #[test]
    fn test_find_section_end_complete_empty_request() {
        let buffer = ByteBuf::mut_with_capacity(128);
        let mut written_buffer = buffer.flip();

        let result = find_section_end(&mut written_buffer);

        assert_eq!(result, None);
    }

    #[test]
    fn test_find_section_end_complete() {
        let data = "DATA\r\nDATA2\r\nDATA3\r\n\r\n".as_bytes();

        let mut buffer = ByteBuf::mut_with_capacity(128);
        buffer.write_slice(data);
        let mut written_buffer = buffer.flip();

        let result = find_section_end(&mut written_buffer);

        assert_eq!(result, Some(22))
    }

}

impl HttpConnection {
    fn new(sock: TcpStream) -> HttpConnection {
        HttpConnection {
            sock: sock,
            buf: None,
            mut_buf: Some(ByteBuf::mut_with_capacity(2048*8)),
            token: None,
            interest: EventSet::hup()
        }
    }

    fn readable(&mut self, event_loop: &mut EventLoop<HttpHandler>) -> io::Result<()> {
        let mut buf = self.mut_buf.take().unwrap();

        match self.sock.try_read_buf(&mut buf) {
            Ok(None) => {
                panic!("Received readable notification but was unable to read from socket");
            }
            Ok(Some(r)) => {
                println!("CONN: we read {} bytes!", r);
                //Check if end of request
                let mut read_buffer = buf.flip();
                let remaining = read_buffer.remaining();
                read_buffer.mark();
                let mut method : [u8;3] = [0;3];
                read_buffer.read_slice(&mut method);

                if std::str::from_utf8(&method) == Ok("GET") {
                    println!("Beginning get")
                } else {
                    panic!("Unsupported method encountered - {:?}", method)
                }

                self.mut_buf = Some(read_buffer.flip());
            }
            Err(e) => {
                println!("Error encountered {:?}", e);
            }
        }

        Ok(())
    }

    fn read_line(buffer: &mut ByteBuf) -> Option<String> {
        let mut length = 0;

        loop {
            match buffer.read_byte() {
                Some(0x0D) => (),
                Some(0x0A) => {
                    return None;
                },
                Some(_) => length+=1,
                None => return None
            }
        }
    }
}

struct HttpServer {
    sock: TcpListener,
    conns: Slab<HttpConnection>
}

impl HttpServer {
    fn accept(&mut self, event_loop: &mut EventLoop<HttpHandler>) -> io::Result<()> {
        let sock = self.sock.accept().unwrap().unwrap();
        let conn = HttpConnection::new(sock);
        let tok = self.conns.insert(conn)
            .ok().expect("Could not add connection to slab");

        self.conns[tok].token = Some(tok);
        event_loop.register_opt(&self.conns[tok].sock, tok, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).ok().expect("Could not register socket with event loop");

        Ok(())
    }

    fn conn_readable(&mut self, event_loop: &mut EventLoop<HttpHandler>, tok: Token) -> io::Result<()> {
        println!("Reading from connection");
        self.conn(tok).readable(event_loop)
    }

    fn conn<'a>(&'a mut self, tok: Token) -> &'a mut HttpConnection {
        &mut self.conns[tok]
    }
}

struct HttpHandler {
    server: HttpServer
}

impl HttpHandler {
    fn new(srv: TcpListener) -> HttpHandler {
        HttpHandler {
            server: HttpServer {
                sock: srv,
                conns: Slab::new_starting_at(Token(1), 128)
            }
        }
    }
}

impl Handler for HttpHandler {

    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<HttpHandler>, token: Token, events:EventSet) {
        if events.is_readable() {
            match token {
                SERVER => self.server.accept(event_loop).unwrap(),
                i => self.server.conn_readable(event_loop, i).unwrap()
            }
        }
    }
}

fn main() {
    start();
}

fn start() {
    println!("Starting event loop");
    let addr = "127.0.0.1:8080".parse().unwrap();
    let server = TcpListener::bind(&addr).unwrap();
    let mut event_loop = EventLoop::new().unwrap();
    event_loop.register(&server, SERVER).unwrap();

    let mut handler = HttpHandler::new(server);
    event_loop.run(&mut handler).unwrap();
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;
extern crate guzuta;

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

    let app = clap::App::new("guzuta")
        .version("0.0.0")
        .about("Custom repository manager for ArchLinux pacman")
        .setting(clap::AppSettings::SubcommandRequired)
        .subcommand(clap::SubCommand::with_name("build")
            .about("Build package in systemd-nspawn environment")
            .arg(clap::Arg::with_name("chroot-dir")
                .long("chroot-dir")
                .takes_value(true)
                .required(true)
                .help("Path to chroot top"))
            .arg(clap::Arg::with_name("package-key")
                .long("package-key")
                .takes_value(true)
                .help("GPG key to sign packages"))
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("logdest")
                .long("logdest")
                .takes_value(true)
                .help("Path to the directory to store logs"))
            .arg(clap::Arg::with_name("repo-dir")
                .long("repo-dir")
                .takes_value(true)
                .required(true)
                .help("Path to the repository directory"))
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("arch")
                .long("arch")
                .takes_value(true)
                .required(true)
                .help("Architecture"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD")))
        .subcommand(clap::SubCommand::with_name("repo-add")
            .about("Add PACKAGE_PATH to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("repo-remove")
            .about("Remove PACKAGE_NAME from DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-add")
            .about("Add PACKAGE_PATH to FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("FILES_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-remove")
            .about("Remove PACKAGE_NAME from FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("abs-add")
            .about("Add source package to abs tarball")
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")))
        .subcommand(clap::SubCommand::with_name("abs-remove")
            .about("Remove source package from abs tarball")
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Package name to be removed"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")));
    let matches = app.get_matches();

    run_subcommand(matches.subcommand());
}

fn run_subcommand(subcommand: (&str, Option<&clap::ArgMatches>)) {
    match subcommand {
        ("build", Some(build_command)) => build(build_command),
        ("repo-add", Some(repo_add_command)) => {
            repo_add(repo_add_command);
        }
        ("repo-remove", Some(repo_remove_command)) => {
            repo_remove(repo_remove_command);
        }
        ("files-add", Some(files_add_command)) => {
            files_add(files_add_command);
        }
        ("files-remove", Some(files_remove_command)) => {
            files_remove(files_remove_command);
        }
        ("abs-add", Some(abs_add_command)) => {
            abs_add(abs_add_command);
        }
        ("abs-remove", Some(abs_remove_command)) => {
            abs_remove(abs_remove_command);
        }
        _ => {
            panic!("Unknown subcommand");
        }
    }
}

fn build(args: &clap::ArgMatches) {
    let arch = match args.value_of("arch").unwrap() {
        "i686" => guzuta::Arch::I686,
        "x86_64" => guzuta::Arch::X86_64,
        arch => panic!("Unknown architecture: {}", arch),
    };
    let chroot = guzuta::ChrootHelper::new(args.value_of("chroot-dir").unwrap(), arch);
    let package_signer = args.value_of("package-key").map(|key| guzuta::Signer::new(key));
    let builder = guzuta::Builder::new(package_signer.as_ref(),
                                       args.value_of("srcdest").unwrap_or("."),
                                       args.value_of("logdest").unwrap_or("."));
    let repo_dir = std::path::Path::new(args.value_of("repo-dir").unwrap());
    let repo_name = args.value_of("repo-name").unwrap();

    let repo_signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let mut db_path = repo_dir.join(repo_name).into_os_string();
    db_path.push(".db");
    let mut files_path = repo_dir.join(repo_name).into_os_string();
    files_path.push(".files");
    let mut db_repo = guzuta::Repository::new(std::path::PathBuf::from(db_path),
                                              repo_signer.as_ref());
    let mut files_repo = guzuta::Repository::new(std::path::PathBuf::from(files_path),
                                                 repo_signer.as_ref());
    db_repo.load();
    files_repo.load();

    let package_paths =
        builder.build_package(args.value_of("PACKAGE_DIR").unwrap(), &repo_dir, &chroot);

    for path in package_paths {
        let package = guzuta::Package::load(&path);
        db_repo.add(&package);
        files_repo.add(&package);
    }

    db_repo.save(false);
    files_repo.save(true);
}

fn repo_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load();
    repository.add(&package);
    repository.save(false);
}

fn repo_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load();
    repository.remove(&package_name);
    repository.save(false);
}

fn files_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load();
    repository.add(&package);
    repository.save(true);
}

fn files_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load();
    repository.remove(&package_name);
    repository.save(true);
}

fn abs_add(args: &clap::ArgMatches) {
    let srcdest = std::path::PathBuf::from(args.value_of("srcdest").unwrap_or("."));
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.add(package_dir, srcdest);
}

fn abs_remove(args: &clap::ArgMatches) {
    let repo_name = args.value_of("repo-name").unwrap();
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.remove(package_name);
}
<commit_msg>Update abs tarball after build<commit_after>extern crate clap;
extern crate env_logger;
extern crate guzuta;

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

    let app = clap::App::new("guzuta")
        .version("0.0.0")
        .about("Custom repository manager for ArchLinux pacman")
        .setting(clap::AppSettings::SubcommandRequired)
        .subcommand(clap::SubCommand::with_name("build")
            .about("Build package in systemd-nspawn environment")
            .arg(clap::Arg::with_name("chroot-dir")
                .long("chroot-dir")
                .takes_value(true)
                .required(true)
                .help("Path to chroot top"))
            .arg(clap::Arg::with_name("package-key")
                .long("package-key")
                .takes_value(true)
                .help("GPG key to sign packages"))
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("logdest")
                .long("logdest")
                .takes_value(true)
                .help("Path to the directory to store logs"))
            .arg(clap::Arg::with_name("repo-dir")
                .long("repo-dir")
                .takes_value(true)
                .required(true)
                .help("Path to the repository directory"))
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("arch")
                .long("arch")
                .takes_value(true)
                .required(true)
                .help("Architecture"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD")))
        .subcommand(clap::SubCommand::with_name("repo-add")
            .about("Add PACKAGE_PATH to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("repo-remove")
            .about("Remove PACKAGE_NAME from DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-add")
            .about("Add PACKAGE_PATH to FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("FILES_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-remove")
            .about("Remove PACKAGE_NAME from FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("abs-add")
            .about("Add source package to abs tarball")
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")))
        .subcommand(clap::SubCommand::with_name("abs-remove")
            .about("Remove source package from abs tarball")
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Package name to be removed"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")));
    let matches = app.get_matches();

    run_subcommand(matches.subcommand());
}

fn run_subcommand(subcommand: (&str, Option<&clap::ArgMatches>)) {
    match subcommand {
        ("build", Some(build_command)) => build(build_command),
        ("repo-add", Some(repo_add_command)) => {
            repo_add(repo_add_command);
        }
        ("repo-remove", Some(repo_remove_command)) => {
            repo_remove(repo_remove_command);
        }
        ("files-add", Some(files_add_command)) => {
            files_add(files_add_command);
        }
        ("files-remove", Some(files_remove_command)) => {
            files_remove(files_remove_command);
        }
        ("abs-add", Some(abs_add_command)) => {
            abs_add(abs_add_command);
        }
        ("abs-remove", Some(abs_remove_command)) => {
            abs_remove(abs_remove_command);
        }
        _ => {
            panic!("Unknown subcommand");
        }
    }
}

fn build(args: &clap::ArgMatches) {
    let arch = match args.value_of("arch").unwrap() {
        "i686" => guzuta::Arch::I686,
        "x86_64" => guzuta::Arch::X86_64,
        arch => panic!("Unknown architecture: {}", arch),
    };
    let chroot = guzuta::ChrootHelper::new(args.value_of("chroot-dir").unwrap(), arch);
    let package_signer = args.value_of("package-key").map(|key| guzuta::Signer::new(key));
    let srcdest = args.value_of("srcdest").unwrap_or(".");
    let builder = guzuta::Builder::new(package_signer.as_ref(),
                                       srcdest,
                                       args.value_of("logdest").unwrap_or("."));
    let repo_dir = std::path::Path::new(args.value_of("repo-dir").unwrap());
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();

    let repo_signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let mut db_path = repo_dir.join(repo_name).into_os_string();
    db_path.push(".db");
    let mut files_path = repo_dir.join(repo_name).into_os_string();
    files_path.push(".files");
    let mut db_repo = guzuta::Repository::new(std::path::PathBuf::from(db_path),
                                              repo_signer.as_ref());
    let mut files_repo = guzuta::Repository::new(std::path::PathBuf::from(files_path),
                                                 repo_signer.as_ref());
    db_repo.load();
    files_repo.load();
    let mut abs_path = repo_dir.join(repo_name).into_os_string();
    abs_path.push(".abs.tar.gz");
    let abs = guzuta::Abs::new(repo_name, abs_path);

    let package_paths = builder.build_package(package_dir, repo_dir, &chroot);

    for path in package_paths {
        let package = guzuta::Package::load(&path);
        db_repo.add(&package);
        files_repo.add(&package);
    }

    abs.add(package_dir, srcdest);
    db_repo.save(false);
    files_repo.save(true);
}

fn repo_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load();
    repository.add(&package);
    repository.save(false);
}

fn repo_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load();
    repository.remove(&package_name);
    repository.save(false);
}

fn files_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load();
    repository.add(&package);
    repository.save(true);
}

fn files_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load();
    repository.remove(&package_name);
    repository.save(true);
}

fn abs_add(args: &clap::ArgMatches) {
    let srcdest = std::path::PathBuf::from(args.value_of("srcdest").unwrap_or("."));
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.add(package_dir, srcdest);
}

fn abs_remove(args: &clap::ArgMatches) {
    let repo_name = args.value_of("repo-name").unwrap();
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.remove(package_name);
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

#[derive(Debug)]
enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(u32),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
}

#[derive(Debug)]
struct TokenWithContext {
    token: Token,
    lexeme: String, // TODO: make a reference
    line: usize,
}

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}
impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 0,
            source: source.clone(),
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        self.source.chars().nth(self.current - 1).unwrap()
    }

    fn add_simple_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: self.source.chars().skip(self.start).take(self.current - self.start).collect(),
            line: self.line,
        }
    }

    fn scan_next(&mut self) -> TokenWithContext {
        self.start = self.current;
        match self.advance() {
            '(' => self.add_simple_context(Token::LeftParen),
            ')' => self.add_simple_context(Token::RightParen),
            '{' => self.add_simple_context(Token::LeftBrace),
            '}' => self.add_simple_context(Token::RightBrace),
            ',' => self.add_simple_context(Token::Comma),
            '.' => self.add_simple_context(Token::Dot),
            '-' => self.add_simple_context(Token::Minus),
            '+' => self.add_simple_context(Token::Plus),
            ';' => self.add_simple_context(Token::Semicolon),
            '*' => self.add_simple_context(Token::Star),
            _ => unimplemented!(),
        }
    }
}

fn tokenize(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        tokens.push(scanner.scan_next());
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

fn run(source: &String) -> Result<(), String> {
    let tokens = try!(tokenize(source));
    for token in tokens {
        println!("{:?}", token);
    }
    Ok(())
}

fn run_file(file_name: &String) -> Result<(), String> {
    match File::open(file_name) {
        Err(_) => {
            Err("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), String> {
    loop {
        print!("> ");
        io::stdout().flush();
        let mut source = String::new();
        io::stdin().read_line(&mut source);
        try!(run(&source));
        ()
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    };
    std::process::exit(exit_code)
}
<commit_msg>Lexical errors<commit_after>use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

#[derive(Debug)]
enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(u32),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
}

#[derive(Debug)]
struct TokenWithContext {
    token: Token,
    lexeme: String, // TODO: make a reference
    line: usize,
}

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}
impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 0,
            source: source.clone(),
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        self.source.chars().nth(self.current - 1).unwrap()
    }

    fn add_simple_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: self.source.chars().skip(self.start).take(self.current - self.start).collect(),
            line: self.line,
        }
    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        self.start = self.current;
        match self.advance() {
            '(' => Ok(self.add_simple_context(Token::LeftParen)),
            ')' => Ok(self.add_simple_context(Token::RightParen)),
            '{' => Ok(self.add_simple_context(Token::LeftBrace)),
            '}' => Ok(self.add_simple_context(Token::RightBrace)),
            ',' => Ok(self.add_simple_context(Token::Comma)),
            '.' => Ok(self.add_simple_context(Token::Dot)),
            '-' => Ok(self.add_simple_context(Token::Minus)),
            '+' => Ok(self.add_simple_context(Token::Plus)),
            ';' => Ok(self.add_simple_context(Token::Semicolon)),
            '*' => Ok(self.add_simple_context(Token::Star)),
            _ => Err(format!("Unexpected character at line {}, pos {}", self.line, self.current))
        }
    }
}

fn tokenize(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        match scanner.scan_next(){
            Ok(token) => tokens.push(token),
            Err(message) => return Err(message)
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

fn run(source: &String) -> Result<(), String> {
    let tokens = try!(tokenize(source));
    for token in tokens {
        println!("{:?}", token);
    }
    Ok(())
}

fn run_file(file_name: &String) -> Result<(), String> {
    match File::open(file_name) {
        Err(_) => {
            Err("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), String> {
    loop {
        print!("> ");
        io::stdout().flush();
        let mut source = String::new();
        io::stdin().read_line(&mut source);
        try!(run(&source));
        ()
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    };
    std::process::exit(exit_code)
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate time;

use std::collections::LinkedList;
use std::str::Split;

mod args;

fn main() {
    let args: std::env::Args = std::env::args();
    let opts = args::parse_args(args);
    let dow = ["Duinday", "Sitaday", "Wikiday", "Tuxday", "Gnuday", "Commonday"];
    let moy = ["Jabim", "Zodrak", "Trogool", "Yanar", "Shkumbe", "Habniah", "Skarl", "Mikon", "Pertunda", "Kib", "Broket"];
    let dpm = 33;
    let dpw = dow.len();
    let mpy = moy.len();
    let (year, month, day, yoff) = current_day(time::now());
    let wd = (yoff + month * 3 + day - 1) % dpw;
    let mut moff = yoff;
    let mut months_across = LinkedList::<String>::new();

    if opts.exit {
        return;
    }

    if !opts.date_only {
		for mm in 0..mpy {
		    let spaces = (17 - moy[mm].len()) / 2;
		    let mut month_text = format!("");
		    for _ in 0..spaces {
		        month_text = format!("{} ", month_text);
		    }

		    month_text = format!("{}{}", month_text, moy[mm]);
		    for _ in 0..(18 - spaces - moy[mm].len()) {
		        month_text = format!("{} ", month_text);
		    }

		    month_text = format!("{}\n", month_text);
		    for dd in 0..dpw {
		        let mut abbrd = String::from(dow[dd]);
		        abbrd.truncate(2);
		        month_text = format!("{}{} ", month_text, abbrd);
		    }

		    let dd = if mm == month { day } else { 1000 };
		    let days = format_days(moff, dpm, dpw, dd);
		    month_text = format!("{}{}", month_text, days.0);
		    moff = days.1;
		    if mm == 2 {
		        month_text = format!("{}--  Peer  Day  --", month_text);
		    }
		    else if mm == 6 {
		        month_text = format!("{}--Torrent Feast--", month_text);
		    }
		    else if is_leap_year(year) && mm == 10 {
		        month_text = format!("{}--Immersion Day--", month_text);
		    }

		    month_text = format!("{}\n", month_text);
		    months_across.push_back(month_text);
		    if mm % 4 == 3 {
		        month_zipper(months_across.clone(), "   ", 1);
		        months_across.clear();
		    }
		}

		month_zipper(months_across.clone(), "   ", 11);
    }

	let mut datestr = format!("{}, {:02} of {}", dow[wd], day, moy[month]);
	let mut daystr = format!("{:02}.{:02}", month + 1, day);
	if day == 34 {
	    if month == 2 {
	        datestr = format!("Peer Day");
	        daystr = format!("P");
	    }
	    else if month == 6 {
	        datestr = format!("Torrent Feast");
	        daystr = format!("T");
	    }
	    else if month == 10 {
	        datestr = format!("Immersion Feast");
	        daystr = format!("T");
	    }
	}

    let hol = format!("{}", what_holiday(month, day));
    println!("Today is {} {}{}.  [{}.{}]", datestr, year, hol, year, daystr);
}

fn format_days(moff: usize, dpm: usize, dpw: usize, highlight: usize) -> (String, usize) {
    let mut month = format!("");

    if moff != 0 {
        month = format!("{}\n", month);
    }

    for _ in 0 .. moff {
        month = format!("{}   ", month);
    }

    for day in 1 .. dpm + 1 {
        if (day + moff) % dpw == 1 {
            month = format!("{}\n", month);
        }

        let ch = if day == highlight { ">" } else if day + 1 == highlight { "<" } else { " " };
        month = format!("{}{:2}{}", month, day, ch);
    }

    for _ in 0 .. (3 - moff) {
        month = format!("{}   ", month);
    }

    month = format!("{}\n", month);
    return (month, if moff == 0 { 3 } else { 0 });
}

fn current_day(current_time: time::Tm) -> (usize, usize, usize, usize) {
    let epoch_days_offset = 1483889;
    let seconds_per_day = 86400;
    let now = current_time.to_timespec();
    let days_since_epoch = (epoch_days_offset + now.sec / seconds_per_day) as i32;
    let days_per_year = 365;
    let leap_year = 4;
    let not_leap_year = 33;
    let days_per_month = 33;

    let mut count = 1;
    let mut days_remaining = days_since_epoch;
    let mut year = 0;
    while days_remaining > days_per_year + 1 {
        days_remaining -= days_per_year;
        year += 1;
        if count > not_leap_year {
            count = 1;
        }
        if count % leap_year == 0 {
            days_remaining -= 1;
        }
        count += 1;
    }
    if days_remaining == days_per_year + 1 && count % leap_year == 0 {
        days_remaining = 0;
        year += 1;
    }

    let mut month = 0;
    while days_remaining > days_per_month {
        month += 1;
        days_remaining -= days_per_month;
        if month == 3 || month == 7 || month == 11 {
            days_remaining -= 1;
        }
    }

    let day = days_remaining;
    return (year, month as usize, day as usize + 1, (year % 2 * 3) as usize);
}

fn is_leap_year(year: usize) -> bool {
    let rem = year % 33;
    return rem != 0 && rem % 4 == 0;
}

fn what_holiday(month: usize, day: usize) -> String {
    let mut result = format!("");
    if month == 0 && day == 1 {
        result = format!(", New Year's Day");
    }
    else if month == 2 && day == 12 {
        result = format!(", Purification Day");
    }
    else if month == 2 && day == 24 {
        result = format!(", Document Freedom Day");
    }
    else if month == 3 && day == 33 {
        result = format!(", Hardware Freedom Day");
    }
    else if month == 5 && day == 4 {
        result = format!(", Harvest Gift");
    }
    else if month == 5 && day == 9 {
        result = format!(", Culture Freedom Day");
    }
    else if month == 7 && day == 29 {
        result = format!(", Familytide");
    }
    else if month == 8 && day == 33 {
        result = format!(", Software Freedom Day");
    }
    else if month == 9 && day == 30 {
        result = format!(", Open Access Day");
    }
    else if month == 10 && day == 21 {
        result = format!(", Freedom Day");
    }
    else if month == 0 && day == 27 {
        result = format!(", International Workers' Day");
    }
    return result;
}

fn month_zipper(months: LinkedList<String>, buffer: &str, front: usize) {
    let month_iterator = months.iter();
    let mut length = 0;
    let mut split_months = LinkedList::<Split<&str>>::new();
    for m in month_iterator {
        let split = m.split("\n");
        if split.clone().count() > length {
            length = split.clone().count();
        }
        split_months.push_back(split);
    }

    for i in 0..(length - 1) {
        for _ in 0..front {
            print!(" ");
        }

        let split_iterator = split_months.iter();
        let mut full_line = format!("");
        for m in split_iterator {
            let line = m.clone().nth(i);
            match line {
                Some(l) => {
                    let part = if l == "" { "                  " } else { l };
                    full_line = format!("{}{}{}", full_line, part, buffer);
                },
                None => {},
            }
        }

        println!("{}", full_line.trim_right());
    }
}

<commit_msg>Only print date when month and year aren't selected<commit_after>extern crate getopts;
extern crate time;

use std::collections::LinkedList;
use std::str::Split;

mod args;

fn main() {
    let args: std::env::Args = std::env::args();
    let opts = args::parse_args(args);
    let dow = ["Duinday", "Sitaday", "Wikiday", "Tuxday", "Gnuday", "Commonday"];
    let moy = ["Jabim", "Zodrak", "Trogool", "Yanar", "Shkumbe", "Habniah", "Skarl", "Mikon", "Pertunda", "Kib", "Broket"];
    let dpm = 33;
    let dpw = dow.len();
    let mpy = moy.len();
    let (year, month, day, yoff) = current_day(time::now());
    let wd = (yoff + month * 3 + day - 1) % dpw;
    let mut moff = yoff;
    let mut months_across = LinkedList::<String>::new();

    if opts.exit {
        return;
    }

    if !opts.date_only {
		for mm in 0..mpy {
		    let spaces = (17 - moy[mm].len()) / 2;
		    let mut month_text = format!("");
		    for _ in 0..spaces {
		        month_text = format!("{} ", month_text);
		    }

		    month_text = format!("{}{}", month_text, moy[mm]);
		    for _ in 0..(18 - spaces - moy[mm].len()) {
		        month_text = format!("{} ", month_text);
		    }

		    month_text = format!("{}\n", month_text);
		    for dd in 0..dpw {
		        let mut abbrd = String::from(dow[dd]);
		        abbrd.truncate(2);
		        month_text = format!("{}{} ", month_text, abbrd);
		    }

		    let dd = if mm == month { day } else { 1000 };
		    let days = format_days(moff, dpm, dpw, dd);
		    month_text = format!("{}{}", month_text, days.0);
		    moff = days.1;
		    if mm == 2 {
		        month_text = format!("{}--  Peer  Day  --", month_text);
		    }
		    else if mm == 6 {
		        month_text = format!("{}--Torrent Feast--", month_text);
		    }
		    else if is_leap_year(year) && mm == 10 {
		        month_text = format!("{}--Immersion Day--", month_text);
		    }

		    month_text = format!("{}\n", month_text);
		    months_across.push_back(month_text);
		    if mm % 4 == 3 {
		        month_zipper(months_across.clone(), "   ", 1);
		        months_across.clear();
		    }
		}

		month_zipper(months_across.clone(), "   ", 11);
    }

    if !opts.has_year || !opts.has_month {
		let mut datestr = format!("{}, {:02} of {}", dow[wd], day, moy[month]);
		let mut daystr = format!("{:02}.{:02}", month + 1, day);
		if day == 34 {
			if month == 2 {
			    datestr = format!("Peer Day");
			    daystr = format!("P");
			}
			else if month == 6 {
			    datestr = format!("Torrent Feast");
			    daystr = format!("T");
			}
			else if month == 10 {
			    datestr = format!("Immersion Feast");
			    daystr = format!("T");
			}
		}

		let hol = format!("{}", what_holiday(month, day));
		println!("Today is {} {}{}.  [{}.{}]", datestr, year, hol, year, daystr);
    }
}

fn format_days(moff: usize, dpm: usize, dpw: usize, highlight: usize) -> (String, usize) {
    let mut month = format!("");

    if moff != 0 {
        month = format!("{}\n", month);
    }

    for _ in 0 .. moff {
        month = format!("{}   ", month);
    }

    for day in 1 .. dpm + 1 {
        if (day + moff) % dpw == 1 {
            month = format!("{}\n", month);
        }

        let ch = if day == highlight { ">" } else if day + 1 == highlight { "<" } else { " " };
        month = format!("{}{:2}{}", month, day, ch);
    }

    for _ in 0 .. (3 - moff) {
        month = format!("{}   ", month);
    }

    month = format!("{}\n", month);
    return (month, if moff == 0 { 3 } else { 0 });
}

fn current_day(current_time: time::Tm) -> (usize, usize, usize, usize) {
    let epoch_days_offset = 1483889;
    let seconds_per_day = 86400;
    let now = current_time.to_timespec();
    let days_since_epoch = (epoch_days_offset + now.sec / seconds_per_day) as i32;
    let days_per_year = 365;
    let leap_year = 4;
    let not_leap_year = 33;
    let days_per_month = 33;

    let mut count = 1;
    let mut days_remaining = days_since_epoch;
    let mut year = 0;
    while days_remaining > days_per_year + 1 {
        days_remaining -= days_per_year;
        year += 1;
        if count > not_leap_year {
            count = 1;
        }
        if count % leap_year == 0 {
            days_remaining -= 1;
        }
        count += 1;
    }
    if days_remaining == days_per_year + 1 && count % leap_year == 0 {
        days_remaining = 0;
        year += 1;
    }

    let mut month = 0;
    while days_remaining > days_per_month {
        month += 1;
        days_remaining -= days_per_month;
        if month == 3 || month == 7 || month == 11 {
            days_remaining -= 1;
        }
    }

    let day = days_remaining;
    return (year, month as usize, day as usize + 1, (year % 2 * 3) as usize);
}

fn is_leap_year(year: usize) -> bool {
    let rem = year % 33;
    return rem != 0 && rem % 4 == 0;
}

fn what_holiday(month: usize, day: usize) -> String {
    let mut result = format!("");
    if month == 0 && day == 1 {
        result = format!(", New Year's Day");
    }
    else if month == 2 && day == 12 {
        result = format!(", Purification Day");
    }
    else if month == 2 && day == 24 {
        result = format!(", Document Freedom Day");
    }
    else if month == 3 && day == 33 {
        result = format!(", Hardware Freedom Day");
    }
    else if month == 5 && day == 4 {
        result = format!(", Harvest Gift");
    }
    else if month == 5 && day == 9 {
        result = format!(", Culture Freedom Day");
    }
    else if month == 7 && day == 29 {
        result = format!(", Familytide");
    }
    else if month == 8 && day == 33 {
        result = format!(", Software Freedom Day");
    }
    else if month == 9 && day == 30 {
        result = format!(", Open Access Day");
    }
    else if month == 10 && day == 21 {
        result = format!(", Freedom Day");
    }
    else if month == 0 && day == 27 {
        result = format!(", International Workers' Day");
    }
    return result;
}

fn month_zipper(months: LinkedList<String>, buffer: &str, front: usize) {
    let month_iterator = months.iter();
    let mut length = 0;
    let mut split_months = LinkedList::<Split<&str>>::new();
    for m in month_iterator {
        let split = m.split("\n");
        if split.clone().count() > length {
            length = split.clone().count();
        }
        split_months.push_back(split);
    }

    for i in 0..(length - 1) {
        for _ in 0..front {
            print!(" ");
        }

        let split_iterator = split_months.iter();
        let mut full_line = format!("");
        for m in split_iterator {
            let line = m.clone().nth(i);
            match line {
                Some(l) => {
                    let part = if l == "" { "                  " } else { l };
                    full_line = format!("{}{}{}", full_line, part, buffer);
                },
                None => {},
            }
        }

        println!("{}", full_line.trim_right());
    }
}

<|endoftext|>


<commit_before>extern crate toml;
extern crate clap;

use std::process::{Command, exit, Stdio};
use std::io::{stderr, Write, Read, BufRead, BufReader};
use std::sync::mpsc::{channel, Sender};
use std::fs::File;
use std::path::PathBuf;
use std::thread::{self, sleep};
use std::time::Duration;

use clap::{App, Arg};

mod configuration;

#[derive(Debug)]
struct BarItem {
    path: Vec<String>,
    duration: Option<u64>,
    position: usize,
}

#[derive(Debug)]
struct Update {
    position: usize,
    message: String,
}

fn execute_script(config_file: PathBuf, script: BarItem, sender: Sender<Update>,) {
    let path = if PathBuf::from(&script.path[0]).is_relative() {
        PathBuf::from(config_file.parent().unwrap().join(&script.path[0]))
    } else {
        PathBuf::from(&script.path[0])
    };

    let arguments = &script.path[1..];

    match script.duration {
        Some(time) => {
            loop {
                let output = Command::new(&path).args(arguments).output().expect(&format!("Failed to run {}", path.display()));
                let _ = sender.send(Update { position: script.position, message: String::from_utf8_lossy(&output.stdout).trim().to_owned(), });
                sleep(Duration::from_millis(time));
            }
        },
        None => {
            loop {
                let output = Command::new(&path).args(arguments).stdout(Stdio::piped()).spawn().expect(&format!("Failed to run {}", path.display()));
                let reader = BufReader::new(output.stdout.unwrap());
                for line in reader.lines().flat_map(Result::ok) {
                    let _ = sender.send(Update { position: script.position, message: line.trim().to_owned(), });
                }
                sleep(Duration::from_millis(10));
            }
        },
    }
}

fn toml_as_number(val: &toml::Value) -> Option<f64> {
    match val {
        &toml::Value::Integer(i) => Some(i as f64),
        &toml::Value::Float(f) => Some(f),
        _ => None,
    }
}

fn main() {
    let matches = App::new("admiral")
        .arg(Arg::with_name("config")
             .help("Specify alternate config file")
             .short("c")
             .long("config-file")
             .takes_value(true))
        .get_matches();

    let config_file = match matches.value_of("config") {
        Some(file) => PathBuf::from(file),
        None => {
            match configuration::get_config_file() {
                Some(file) => file,
                None => {
                    let _ = stderr().write("Configuration file not found\n".as_bytes());
                    exit(1);
                },
            }
        }
    };

    if ! config_file.is_file() {
        let _ = stderr().write("Invalid configuration file specified\n".as_bytes());
        exit(1);
    }

    let mut buffer = String::new();
    if let Ok(mut file) = File::open(&config_file) {
        file.read_to_string(&mut buffer).expect("Could not read configuration file");
    }

    let config_toml = toml::Parser::new(&buffer).parse().unwrap();

    let admiral_config = config_toml.get("admiral").unwrap();
    let items = admiral_config.as_table().unwrap().get("items").unwrap().as_slice().unwrap().iter().map(|x| x.as_str().unwrap()).collect::<Vec<_>>();

    let (sender, receiver) = channel::<Update>();

    let mut message_vec: Vec<String> = Vec::new();
    let mut print_message = String::new();

    let mut position: usize = 0;
    for value in items {
        match config_toml.get(value) {
            Some(script) => {
                let command = BarItem {
                    path: {
                        match script.as_table().expect("Invalid toml table").get("path").unwrap().to_owned() {
                            toml::Value::Array(array) => {
                                array.iter().flat_map(|x| toml::Value::as_str(x)).map(|x| x.to_owned()).collect::<Vec<_>>()
                            },

                            toml::Value::String(string) => {
                                vec![string]
                            },

                            _ => {
                                let _ = stderr().write(format!("Invalid path used for {}\n", value).as_bytes()).unwrap();
                                continue
                            }
                        }
                    },
                        // script.as_table().unwrap()
                        //         .get("path").unwrap()
                        //         .as_slice().unwrap()
                        //         .iter().flat_map(|x| toml::Value::as_str(x)).map(|x| x.to_owned()).collect::<Vec<_>>()
                    duration: script.as_table().expect("Invalid toml table").get("reload").and_then(toml_as_number).map(|x| (x * 1000f64) as u64),
                    position: position,
                };

                position += 1;

                // Annoying stuff because of how ownership works with closures
                let clone = sender.clone();
                let config_file = config_file.to_owned();
                let _ = thread::spawn(move || {
                    execute_script(config_file, command, clone);
                });

                message_vec.push(String::new());
            },
            None => {
                let _ = stderr().write(format!("No {} found\n", value).as_bytes());
                continue;
            },
        }
    }

    for line in receiver.iter() {
        let position = line.position;
        message_vec[position] = line.message;
        if print_message != message_vec.iter().cloned().collect::<String>() {
            print_message = message_vec.iter().cloned().collect::<String>();
            sleep(Duration::from_millis(5));
            println!("{}", print_message);
        }
    }
}
<commit_msg>Less potential to panic in main thread<commit_after>extern crate toml;
extern crate clap;

use std::process::{Command, exit, Stdio};
use std::io::{stderr, Write, Read, BufRead, BufReader};
use std::sync::mpsc::{channel, Sender};
use std::fs::File;
use std::path::PathBuf;
use std::thread::{self, sleep};
use std::time::Duration;

use clap::{App, Arg};

mod configuration;

#[derive(Debug)]
struct Update {
    position: usize,
    message: String,
}

fn execute_script(section_name: &str, config_root: PathBuf, configuration: Option<&toml::Table>, position: usize, sender: Sender<Update>,) {
    let configuration = configuration.expect(&format!("Failed to find valid section for {}", section_name));

    let path_vector = match configuration.get("path") {
        Some(value) => {
            let value = value.to_owned();
            match value {
                toml::Value::Array(array) => {
                    array.iter().flat_map(toml::Value::as_str).map(|x| x.to_owned()).collect::<Vec<_>>()
                },

                toml::Value::String(string) => {
                    vec![string]
                },

                _ => {
                    let _ = stderr().write(format!("Invalid path found for {}\n", section_name).as_bytes());
                    panic!();
                },
            }
        },
        None => {
            let _ = stderr().write(format!("No path found for {}\n", section_name).as_bytes());
            panic!();
        },
    };

    let mut path = PathBuf::from(&path_vector[0]);
    if path.is_relative() {
        path = config_root.join(path);
    }
    let arguments = &path_vector[1..];

    let duration: Option<u64> = match configuration.get("reload") {
        Some(value) => {
            let value = value.to_owned();
            match value {
                toml::Value::Float(float) => {
                    Some((float * 1000f64) as u64)
                },

                toml::Value::Integer(int) => {
                    Some((int as f64 * 1000f64) as u64)
                },
                _ => None,
            }
        },
        None => None,
    };

    match duration {
        Some(time) => {
            loop {
                let output = Command::new(&path).args(arguments).output().expect(&format!("Failed to run {}", path.display()));
                let _ = sender.send(Update { position: position, message: String::from_utf8_lossy(&output.stdout).trim().to_owned(), });
                sleep(Duration::from_millis(time));
            }
        },
        None => {
            loop {
                let output = Command::new(&path).args(arguments).stdout(Stdio::piped()).spawn().expect(&format!("Failed to run {}", path.display()));
                let reader = BufReader::new(output.stdout.unwrap());
                for line in reader.lines().flat_map(Result::ok) {
                    let _ = sender.send(Update { position: position, message: line.trim().to_owned(), });
                }
                sleep(Duration::from_millis(10));
            }
        },
    }
}

fn main() {
    let matches = App::new("admiral")
        .arg(Arg::with_name("config")
             .help("Specify alternate config file")
             .short("c")
             .long("config-file")
             .takes_value(true))
        .get_matches();

    let config_file = match matches.value_of("config") {
        Some(file) => PathBuf::from(file),
        None => {
            match configuration::get_config_file() {
                Some(file) => file,
                None => {
                    let _ = stderr().write("Configuration file not found\n".as_bytes());
                    exit(1);
                },
            }
        }
    };

    if ! config_file.is_file() {
        let _ = stderr().write("Invalid configuration file specified\n".as_bytes());
        exit(1);
    }

    let config_root = PathBuf::from(&config_file.parent().unwrap());

    let mut buffer = String::new();
    if let Ok(mut file) = File::open(&config_file) {
        file.read_to_string(&mut buffer).expect("Could not read configuration file");
    }

    let config_toml = toml::Parser::new(&buffer).parse().unwrap();

    let admiral_config = config_toml.get("admiral").unwrap();
    let items = admiral_config.as_table().unwrap().get("items").unwrap().as_slice().unwrap().iter().map(|x| x.as_str().unwrap()).collect::<Vec<_>>();

    let (sender, receiver) = channel::<Update>();

    let mut message_vec: Vec<String> = Vec::new();
    let mut print_message = String::new();

    let mut position: usize = 0;
    for value in items {
        match config_toml.get(value) {
            Some(script) => {
                // Annoying stuff because of how ownership works with closures
                let script = script.to_owned();
                let value = value.to_owned();
                let config_root = config_root.clone();
                let clone = sender.clone();

                let _ = thread::spawn(move || {
                    execute_script(&value, config_root, script.as_table(), position, clone);
                });

                position += 1;
                message_vec.push(String::new());
            },
            None => {
                let _ = stderr().write(format!("No {} found\n", value).as_bytes());
                continue;
            },
        }
    }

    for line in receiver.iter() {
        let position = line.position;
        message_vec[position] = line.message;
        if print_message != message_vec.iter().cloned().collect::<String>() {
            print_message = message_vec.iter().cloned().collect::<String>();
            sleep(Duration::from_millis(5));
            println!("{}", print_message);
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate ini;
extern crate sha1;

use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
use std::io::{self, Read, Write, BufWriter};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};

use ini::Ini;
use ini::ini::Error as IniError;

type Sha1DigestBytes = [u8; 20];
type ModList = Vec<String>;
type MediaSet = Vec<Asset>;

struct Asset {
	path: PathBuf,
	hash: Sha1DigestBytes,
}

impl Asset {
	pub fn new(pb: PathBuf, h: Sha1DigestBytes) -> Self {
		Asset {
			path: pb,
			hash: h,
		}
	}
}

impl PartialEq for Asset {
	fn eq(&self, other: &Self) -> bool {
		self.hash == other.hash
	}
}

enum AssetCopyMode {
	Symlink,
	Hardlink,
	Copy,
	None,
}

fn to_hex(input: &[u8]) -> String {
	String::from_iter(input.iter().map(|b| format!("{:02x}", b)))
}

fn make_absolute(path: &Path) -> PathBuf {
	if path.is_absolute() {
		path.to_path_buf()
	} else {
		std::env::current_dir()
			.and_then(|cd| Ok(cd.join(path)))
			.or_else(|_err| -> io::Result<_> {
				Ok(path.to_path_buf())
			})
			.unwrap()
	}
}

fn hash_file(path: &Path) -> io::Result<Sha1DigestBytes> {
	let mut buf = [0u8; 8192];
	let mut hash = sha1::Sha1::new();
	let mut file = File::open(&path)?;
	loop {
		match file.read(&mut buf) {
			Ok(0) => break,
			Ok(len) => hash.update(&buf[..len]),
			Err(e) => return Err(e),
		}
	}
	Ok(hash.digest().bytes())
}

fn search_media_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	for entry in path.read_dir()? {
		let pb = entry?.path();
		if pb.is_file() {
			let h = hash_file(pb.as_path())?;
			ms.push(Asset::new(pb, h));
		}
	}
	Ok(())
}

fn search_mod_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	static MEDIA_DIRS: &'static [&'static str] = &["textures", "models", "sounds"];
	for media_dir in MEDIA_DIRS {
		let media_pb = path.join(media_dir);
		if media_pb.is_dir() {
			search_media_dir(ms, media_pb.as_path())?;
		}
	}
	Ok(())
}

fn search_modpack_dir(ms: &mut MediaSet, path: &Path, mods: Option<&ModList>) -> io::Result<()> {
	for entry in path.read_dir()? {
		let entry_path = entry?.path();
		if !entry_path.is_dir() {
			continue;
		} else if entry_path.join("modpack.txt").exists() {
			search_modpack_dir(ms, entry_path.as_path(), mods)?;
		} else if entry_path.join("init.lua").exists() {
			if let Some(mod_list) = mods {
				let mod_name = &entry_path.file_name()
					.expect("Mod directory has no name!")
					.to_str()
					.expect("Mod directory name is not valid Unicode")
					.to_string();
				if !mod_list.contains(mod_name) {
					continue;
				}
			}
			search_mod_dir(ms, entry_path.as_path())?;
		}
		// Otherwise it's probably a VCS directory or something similar
	}
	Ok(())
}

fn write_index(ms: &MediaSet, path: &Path) -> io::Result<()> {
	let file = File::create(&path)?;
	let mut writer = BufWriter::new(file);
	writer.write_all(b"MTHS\x00\x01")?;
	for asset in ms {
		writer.write_all(&asset.hash)?;
	}
	Ok(())
}

fn copy_assets(ms: &MediaSet, path: &Path, mode: AssetCopyMode) -> io::Result<()> {
	fn copy_no_result<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		fs::copy(src, dst).map(|_| ())
	}

	#[cfg(unix)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::unix::fs::symlink(src, dst)
	}

	#[cfg(windows)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::windows::fs::symlink_file(src, dst)
	}

	#[cfg(not(any(unix, windows)))]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		Err(io::Error::new(io::ErrorKind::Other,
				"Symlinking not supported on this platform!"))
	}

	let copy_func = match mode {
		AssetCopyMode::Symlink => symlink_file,
		AssetCopyMode::Hardlink => fs::hard_link,
		AssetCopyMode::Copy => copy_no_result,
		AssetCopyMode::None => return Ok(()),
	};

	for asset in ms {
		copy_func(&asset.path, path.join(to_hex(&asset.hash)))?;
	}
	Ok(())
}

fn get_mod_list(path: &Path) -> Result<ModList, IniError> {
	let world_mt = Ini::load_from_file(path.join("world.mt"))?;
	let main_sec = world_mt.general_section();

	let mut list: ModList = vec![];
	for (key, value) in main_sec {
		if !key.starts_with("load_mod_") || value != "true" {
			continue;
		}
		let (_, mod_name) = key.split_at(9);
		list.push(mod_name.to_string());
	}
	Ok(list)
}

fn get_args<'a>() -> clap::ArgMatches<'a> {
	use clap::{App, Arg, ArgGroup};

	fn check_new_dir(s: &OsStr) -> Result<(), OsString> {
		let p = make_absolute(Path::new(&s));
		if p.is_dir() {
			return Ok(())
		}
		if let Some(parent) = p.parent() {
			if parent.is_dir() {
				return Ok(())
			}
		}
		return Err("Invalid path.".into())
	}

	fn check_existing_dir(s: &OsStr) -> Result<(), OsString> {
		if make_absolute(Path::new(&s)).is_dir() {
			Ok(())
		} else {
			Err("Invalid path.".into())
		}
	}

	let app = clap_app! { @app (app_from_crate!())
		(version_short: "v")

		(@arg mod_paths: [PATHS] ... validator_os(check_existing_dir) "Additional mod paths to search.")

		(@arg out:   -o --out   <PATH> validator_os(check_new_dir) "Path to the output directory.")
		(@arg world: -w --world <PATH> validator_os(check_existing_dir) "Path to the world directory.")
		(@arg game:  -g --game  <PATH> validator_os(check_existing_dir) "Path to the game directory.")

		// Group these together with display_order
		(@arg copy: -c --copy display_order(1000) "Copy assets to output folder.")
		// Symlink added below if applicable
		(@arg hardlink: -l --hardlink display_order(1000) "Hard link assets to output folder.")
	};

	// Add symlink option if supported
	#[cfg(not(any(unix, windows)))]
	let add_symlink_arg = |app| app;

	#[cfg(any(unix, windows))]
	fn add_symlink_arg<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
		app.arg(Arg::with_name("symlink")
			.short("s")
			.long("symlink")
			.display_order(1000)
			.help("Symbolically link assets to output folder."))
	}

	add_symlink_arg(app)
		// Link group has to be added manually because the
		// symlink argument is added conditionally.
		.group(ArgGroup::with_name("link")
			.args(&["copy", "symlink", "hardlink"]))

		.get_matches()
}

fn run(args: clap::ArgMatches) -> i32 {
	macro_rules! handle_result {
		( $x:expr, $m:expr ) => {
			match $x {
				Ok(val) => val,
				Err(e) => {
					println!($m, e);
					return 1;
				}
			};
		}
	}

	// These unwraps are safe since the values are required
	// and clap will exit if the value is missing.
	let out_opt = args.value_of_os("out").unwrap();
	let out_path = Path::new(&out_opt);
	let world_opt = args.value_of_os("world").unwrap();
	let world_path = Path::new(&world_opt);
	let game_opt = args.value_of_os("game").unwrap();
	let game_path = Path::new(&game_opt);

	let copy_type = if args.is_present("copy") {
			AssetCopyMode::Copy
		} else if args.is_present("symlink") {
			AssetCopyMode::Symlink
		} else if args.is_present("hardlink") {
			AssetCopyMode::Hardlink
		} else {
			AssetCopyMode::None
		};

	let mut ms = MediaSet::new();
	let mods = handle_result!(get_mod_list(world_path), "Error getting mod list: {}");

	// Search world mods.
	let worldmods_path = world_path.join("worldmods");
	if worldmods_path.exists() {
		handle_result!(search_modpack_dir(&mut ms, worldmods_path.as_path(), Some(&mods)),
				"Error searching world mods: {}");
	}

	// Search game mods.
	// Note: Game mods can not currently be disabled.
	handle_result!(search_modpack_dir(&mut ms, game_path.join("mods").as_path(), None),
			"Error searching game mods: {}");

	if let Some(mod_paths) = args.values_of_os("mod_paths") {
		for mod_path in mod_paths {
			handle_result!(search_modpack_dir(&mut ms,
					Path::new(&mod_path),
					Some(&mods)),
					"Error searching other mods: {}");
		}
	}

	// Deduplicate list.  Otherwise linking will fail and the index will
	// be unnecessarily large.
	ms.sort_by(|a, b| a.hash.cmp(&b.hash));
	ms.dedup();

	if !out_path.exists() {
		handle_result!(fs::create_dir(out_path), "{}");
	}

	handle_result!(write_index(&ms, out_path.join("index.mth").as_path()),
			"Error writing asset index: {}");

	handle_result!(copy_assets(&ms, out_path, copy_type),
			"Error linking assets: {}");

	0
}

fn main() {
	// Rust (stable) only supports setting the exit code by calling this
	// function, but it doesn't do cleanup, so it can't be run until all
	// resources have already been destroyed.
	std::process::exit(run(get_args()))
}
<commit_msg>Change top-level error handling<commit_after>#[macro_use] extern crate clap;
extern crate ini;
extern crate sha1;

use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write, BufWriter};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};

use ini::Ini;
use ini::ini::Error as IniError;

type Sha1DigestBytes = [u8; 20];
type ModList = Vec<String>;
type MediaSet = Vec<Asset>;

struct Asset {
	path: PathBuf,
	hash: Sha1DigestBytes,
}

impl Asset {
	pub fn new(pb: PathBuf, h: Sha1DigestBytes) -> Self {
		Asset {
			path: pb,
			hash: h,
		}
	}
}

impl PartialEq for Asset {
	fn eq(&self, other: &Self) -> bool {
		self.hash == other.hash
	}
}

enum Error {
	Io(io::Error),
	Ini(IniError),
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::Io(ref e)  => write!(f, "IO error: {}", e),
			Error::Ini(ref e) => write!(f, "Settings file error: {}", e),
		}
	}
}

impl From<io::Error> for Error {
	fn from(e: io::Error) -> Self { Error::Io(e) }
}

impl From<IniError> for Error {
	fn from(e: IniError) -> Self { Error::Ini(e) }
}

enum AssetCopyMode {
	Symlink,
	Hardlink,
	Copy,
	None,
}

fn to_hex(input: &[u8]) -> String {
	String::from_iter(input.iter().map(|b| format!("{:02x}", b)))
}

fn make_absolute(path: &Path) -> PathBuf {
	if path.is_absolute() {
		path.to_path_buf()
	} else {
		std::env::current_dir()
			.and_then(|cd| Ok(cd.join(path)))
			.or_else(|_err| -> io::Result<_> {
				Ok(path.to_path_buf())
			})
			.unwrap()
	}
}

fn hash_file(path: &Path) -> io::Result<Sha1DigestBytes> {
	let mut buf = [0u8; 8192];
	let mut hash = sha1::Sha1::new();
	let mut file = File::open(&path)?;
	loop {
		match file.read(&mut buf) {
			Ok(0) => break,
			Ok(len) => hash.update(&buf[..len]),
			Err(e) => return Err(e),
		}
	}
	Ok(hash.digest().bytes())
}

fn search_media_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	for entry in path.read_dir()? {
		let pb = entry?.path();
		if pb.is_file() {
			let h = hash_file(pb.as_path())?;
			ms.push(Asset::new(pb, h));
		}
	}
	Ok(())
}

fn search_mod_dir(ms: &mut MediaSet, path: &Path) -> io::Result<()> {
	static MEDIA_DIRS: &'static [&'static str] = &["textures", "models", "sounds"];
	for media_dir in MEDIA_DIRS {
		let media_pb = path.join(media_dir);
		if media_pb.is_dir() {
			search_media_dir(ms, media_pb.as_path())?;
		}
	}
	Ok(())
}

fn search_modpack_dir(ms: &mut MediaSet, path: &Path, mods: Option<&ModList>) -> io::Result<()> {
	for entry in path.read_dir()? {
		let entry_path = entry?.path();
		if !entry_path.is_dir() {
			continue;
		} else if entry_path.join("modpack.txt").exists() {
			search_modpack_dir(ms, entry_path.as_path(), mods)?;
		} else if entry_path.join("init.lua").exists() {
			if let Some(mod_list) = mods {
				let mod_name = &entry_path.file_name()
					.expect("Mod directory has no name!")
					.to_str()
					.expect("Mod directory name is not valid Unicode")
					.to_string();
				if !mod_list.contains(mod_name) {
					continue;
				}
			}
			search_mod_dir(ms, entry_path.as_path())?;
		}
		// Otherwise it's probably a VCS directory or something similar
	}
	Ok(())
}

fn write_index(ms: &MediaSet, path: &Path) -> io::Result<()> {
	let file = File::create(&path)?;
	let mut writer = BufWriter::new(file);
	writer.write_all(b"MTHS\x00\x01")?;
	for asset in ms {
		writer.write_all(&asset.hash)?;
	}
	Ok(())
}

fn copy_assets(ms: &MediaSet, path: &Path, mode: AssetCopyMode) -> io::Result<()> {
	fn copy_no_result<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		fs::copy(src, dst).map(|_| ())
	}

	#[cfg(unix)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::unix::fs::symlink(src, dst)
	}

	#[cfg(windows)]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		std::os::windows::fs::symlink_file(src, dst)
	}

	#[cfg(not(any(unix, windows)))]
	fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
		Err(io::Error::new(io::ErrorKind::Other,
				"Symlinking not supported on this platform!"))
	}

	let copy_func = match mode {
		AssetCopyMode::Symlink => symlink_file,
		AssetCopyMode::Hardlink => fs::hard_link,
		AssetCopyMode::Copy => copy_no_result,
		AssetCopyMode::None => return Ok(()),
	};

	for asset in ms {
		copy_func(&asset.path, path.join(to_hex(&asset.hash)))?;
	}
	Ok(())
}

fn get_mod_list(path: &Path) -> Result<ModList, IniError> {
	let world_mt = Ini::load_from_file(path.join("world.mt"))?;
	let main_sec = world_mt.general_section();

	let mut list: ModList = vec![];
	for (key, value) in main_sec {
		if !key.starts_with("load_mod_") || value != "true" {
			continue;
		}
		let (_, mod_name) = key.split_at(9);
		list.push(mod_name.to_string());
	}
	Ok(list)
}

fn get_args<'a>() -> clap::ArgMatches<'a> {
	use clap::{App, Arg, ArgGroup};

	fn check_new_dir(s: &OsStr) -> Result<(), OsString> {
		let p = make_absolute(Path::new(&s));
		if p.is_dir() {
			return Ok(())
		}
		if let Some(parent) = p.parent() {
			if parent.is_dir() {
				return Ok(())
			}
		}
		return Err("Invalid path.".into())
	}

	fn check_existing_dir(s: &OsStr) -> Result<(), OsString> {
		if make_absolute(Path::new(&s)).is_dir() {
			Ok(())
		} else {
			Err("Invalid path.".into())
		}
	}

	let app = clap_app! { @app (app_from_crate!())
		(version_short: "v")

		(@arg mod_paths: [PATHS] ... validator_os(check_existing_dir) "Additional mod paths to search.")

		(@arg out:   -o --out   <PATH> validator_os(check_new_dir) "Path to the output directory.")
		(@arg world: -w --world <PATH> validator_os(check_existing_dir) "Path to the world directory.")
		(@arg game:  -g --game  <PATH> validator_os(check_existing_dir) "Path to the game directory.")

		// Group these together with display_order
		(@arg copy: -c --copy display_order(1000) "Copy assets to output folder.")
		// Symlink added below if applicable
		(@arg hardlink: -l --hardlink display_order(1000) "Hard link assets to output folder.")
	};

	// Add symlink option if supported
	#[cfg(not(any(unix, windows)))]
	let add_symlink_arg = |app| app;

	#[cfg(any(unix, windows))]
	fn add_symlink_arg<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
		app.arg(Arg::with_name("symlink")
			.short("s")
			.long("symlink")
			.display_order(1000)
			.help("Symbolically link assets to output folder."))
	}

	add_symlink_arg(app)
		// Link group has to be added manually because the
		// symlink argument is added conditionally.
		.group(ArgGroup::with_name("link")
			.args(&["copy", "symlink", "hardlink"]))

		.get_matches()
}

fn run(args: clap::ArgMatches) -> Result<(), Error> {
	// These unwraps are safe since the values are required
	// and clap will exit if the value is missing.
	let out_opt = args.value_of_os("out").unwrap();
	let out_path = Path::new(&out_opt);
	let world_opt = args.value_of_os("world").unwrap();
	let world_path = Path::new(&world_opt);
	let game_opt = args.value_of_os("game").unwrap();
	let game_path = Path::new(&game_opt);

	let copy_type = if args.is_present("copy") {
			AssetCopyMode::Copy
		} else if args.is_present("symlink") {
			AssetCopyMode::Symlink
		} else if args.is_present("hardlink") {
			AssetCopyMode::Hardlink
		} else {
			AssetCopyMode::None
		};

	let mut ms = MediaSet::new();
	let mods = get_mod_list(world_path)?;

	// Search world mods.
	let worldmods_path = world_path.join("worldmods");
	if worldmods_path.exists() {
		search_modpack_dir(&mut ms, worldmods_path.as_path(), Some(&mods))?;
	}

	// Search game mods.
	// Note: Game mods can not currently be disabled.
	search_modpack_dir(&mut ms, game_path.join("mods").as_path(), None)?;

	if let Some(mod_paths) = args.values_of_os("mod_paths") {
		for mod_path in mod_paths {
			search_modpack_dir(&mut ms,
					Path::new(&mod_path),
					Some(&mods))?;
		}
	}

	// Deduplicate list.  Otherwise linking will fail and the index will
	// be unnecessarily large.
	ms.sort_by(|a, b| a.hash.cmp(&b.hash));
	ms.dedup();

	if !out_path.exists() {
		fs::create_dir(out_path)?;
	}

	write_index(&ms, out_path.join("index.mth").as_path())?;

	copy_assets(&ms, out_path, copy_type)?;

	Ok(())
}

fn main() {
	match run(get_args()) {
		Ok(()) => return,
		Err(e) => {
			println!("{}", e);
			std::process::exit(1)
		}
	}
}
<|endoftext|>


<commit_before>mod diag;
mod nameck;
mod parser;
mod scopeck;
mod segment_set;
mod util;
mod verify;

use segment_set::SegmentSet;
use nameck::Nameset;
use diag::Notation;
use std::env;
use std::path::PathBuf;

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut set = SegmentSet::new();
    if args.len() > 2 {
        let mut data = Vec::new();
        let mut i = 1;
        while i + 1 < args.len() {
            data.push((PathBuf::from(&args[i]), args[i + 1].clone().into_bytes()));
            i += 2;
        }
        set.read(data[0].0.clone(), data);
    } else {
        set.read(PathBuf::from(&args[1]).to_path_buf(), Vec::new());
    }

    let mut ns = Nameset::new();
    ns.update(&set);
    let sr = scopeck::scope_check(&set, &ns);
    let vr = verify::verify(&set, &sr);

    let mut diags = Vec::new();
    diags.extend(set.parse_diagnostics());
    diags.extend(sr.diagnostics());
    diags.extend(vr.diagnostics());

    for notation in diag::to_annotations(&set, diags) {
        print_annotation(notation);
    }
    // println!("{:#?}", set);
}

fn print_annotation(ann: Notation) {
    let mut args = String::new();
    for (id, val) in ann.args {
        args.push_str(&format!(" {}={}", id, val));
    }
    println!("{}:{}-{}:{:?}:{}{}",
             ann.source.filepath,
             ann.span.start,
             ann.span.end,
             ann.level,
             ann.message,
             args);
}
<commit_msg>now with timing<commit_after>mod diag;
mod nameck;
mod parser;
mod scopeck;
mod segment_set;
mod util;
mod verify;

use diag::Notation;
use nameck::Nameset;
use segment_set::SegmentSet;
use std::env;
use std::mem;
use std::path::PathBuf;
use std::time::Instant;

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut set = SegmentSet::new();
    let now = Instant::now();
    if args.len() > 2 {
        let mut data = Vec::new();
        let mut i = 1;
        while i + 1 < args.len() {
            data.push((PathBuf::from(&args[i]), args[i + 1].clone().into_bytes()));
            i += 2;
        }
        set.read(data[0].0.clone(), data);
    } else {
        set.read(PathBuf::from(&args[1]).to_path_buf(), Vec::new());
    }

    println!("parse {}ms", (now.elapsed() * 1000).as_secs());
    let now = Instant::now();

    let mut ns = Nameset::new();
    ns.update(&set);

    println!("nameck {}ms", (now.elapsed() * 1000).as_secs());
    let now = Instant::now();

    let sr = scopeck::scope_check(&set, &ns);

    println!("scopeck {}ms", (now.elapsed() * 1000).as_secs());
    let now = Instant::now();

    let vr = verify::verify(&set, &sr);

    println!("verify {}ms", (now.elapsed() * 1000).as_secs());
    let now = Instant::now();

    let mut diags = Vec::new();
    diags.extend(set.parse_diagnostics());
    diags.extend(sr.diagnostics());
    diags.extend(vr.diagnostics());

    for notation in diag::to_annotations(&set, diags) {
        print_annotation(notation);
    }
    // println!("{:#?}", set);

    println!("diag {}ms", (now.elapsed() * 1000).as_secs());
    let now = Instant::now();

    mem::drop(vr);
    mem::drop(sr);
    mem::drop(ns);
    mem::drop(set);

    println!("free {}ms", (now.elapsed() * 1000).as_secs());
}

fn print_annotation(ann: Notation) {
    let mut args = String::new();
    for (id, val) in ann.args {
        args.push_str(&format!(" {}={}", id, val));
    }
    println!("{}:{}-{}:{:?}:{}{}",
             ann.source.filepath,
             ann.span.start,
             ann.span.end,
             ann.level,
             ann.message,
             args);
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate rusqlite;
#[macro_use]

extern crate rustc_serialize;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;

fn main() {
    let conn = db::connect();
    let session_uuid = "".to_string();
    db::create_tables(&conn);

    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    loader::deligate(&conn, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
}
<commit_msg>Use uuid<commit_after>extern crate clap;
extern crate rusqlite;
#[macro_use]

extern crate rustc_serialize;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;

use uuid::Uuid;

fn main() {
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.simple().to_string();
    let conn = db::connect();
    db::create_tables(&conn);
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    loader::deligate(&conn, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
}
<|endoftext|>


<commit_before>extern crate image;

use std::env::args;
use std::process::exit;
use std::fs::File;
use std::path::Path;
use image::{
		GenericImage,
//		imageops
};

fn get_top_left(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	for x in 0..(im.dimensions().1) {
		for y in 0..(im.dimensions().0) {
			let col = im.get_pixel(y, x);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y;
			}
		}
	}
	unreachable!();
}

fn get_top_right(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	for x in 0..(im.dimensions().0) {
		for y in 0..(im.dimensions().1) {
			let col = im.get_pixel(x, y);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y;
			}
		}
	}
	unreachable!();
}

fn get_lower_left(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	let mut x = im.dimensions().1 as i32 - 1;
	let mut y = im.dimensions().0 as i32 - 1;
	while x >= 0 {
		while y >= 0 {
			let col = im.get_pixel(y as u32, x as u32);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y as u32 + 1;
			}
			x -= 1;
			y -= 1;
		}
	}
	unreachable!();
}

fn get_lower_right(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	let mut x = im.dimensions().0 as i32 - 1;
	let mut y = im.dimensions().1 as i32 - 1;
	while x >= 0 {
		while y >= 0 {
			let col = im.get_pixel(x as u32, y as u32);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y as u32 + 1;
			}
			x -= 1;
			y -= 1;
		}
	}
	unreachable!();
}

fn main() {
	let args: Vec<_> = args().collect();

	let (in_path, out_path) = if args.len() == 3 {
		(args[1].as_str(), args[2].as_str())
	} else {
		println!("usage: {} <input_image> <output_image>", args[0]);
		exit(1)
	};

	let (a, b) = (get_top_left(in_path), get_top_right(in_path));
	let (x, y) = (get_lower_left(in_path), get_lower_right(in_path));
	println!("({0}, {1}, {2}, {3})", a, b, x, y);

	let mut im = image::open(&Path::new(in_path)).unwrap();
	let subim = im.crop(a, b, x - a, y - b);

	let ref mut fout = File::create(&Path::new(out_path)).unwrap();

	let _ = subim.save(fout, image::PNG).unwrap();
}
<commit_msg>Fix saving output image<commit_after>extern crate image;

use std::env::args;
use std::process::exit;
use std::fs::File;
use std::path::Path;
use image::GenericImage;

fn get_top_left(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	for x in 0..(im.dimensions().1) {
		for y in 0..(im.dimensions().0) {
			let col = im.get_pixel(y, x);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y;
			}
		}
	}
	unreachable!();
}

fn get_top_right(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	for x in 0..(im.dimensions().0) {
		for y in 0..(im.dimensions().1) {
			let col = im.get_pixel(x, y);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y;
			}
		}
	}
	unreachable!();
}

fn get_lower_left(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	let mut x = im.dimensions().1 as i32 - 1;
	let mut y = im.dimensions().0 as i32 - 1;
	// Using while loop as there is no reliable way
	// to use custom steps in range() currently
	while x >= 0 {
		while y >= 0 {
			let col = im.get_pixel(y as u32, x as u32);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y as u32 + 1;
			}
			x -= 1;
			y -= 1;
		}
	}
	unreachable!();
}

fn get_lower_right(in_path: &str) -> u32 {
	let im = image::open(&Path::new(in_path)).unwrap();
	let mut x = im.dimensions().0 as i32 - 1;
	let mut y = im.dimensions().1 as i32 - 1;
	// Using while loop as there is no reliable way
	// to use custom steps in range() currently
	while x >= 0 {
		while y >= 0 {
			let col = im.get_pixel(x as u32, y as u32);
			if col[0] != 255 && col[1] != 255 && col[2] != 255 {
				return y as u32 + 1;
			}
			x -= 1;
			y -= 1;
		}
	}
	unreachable!();
}

fn main() {
	let args: Vec<_> = args().collect();

	let (in_path, out_path) = if args.len() == 3 {
		(args[1].as_str(), args[2].as_str())
	} else {
		println!("usage: {} <input_image> <output_image>", args[0]);
		exit(1)
	};

	// Top left corner
	let (a, b) = (get_top_left(in_path), get_top_right(in_path));
	// Lower right corner
	let (x, y) = (get_lower_left(in_path), get_lower_right(in_path));

	println!("Cropping area ({0}, {1}, {2}, {3}) from {4} to {5}",
	a, b, x, y, in_path, out_path);

	let mut im = image::open(&Path::new(in_path)).unwrap();
	let subim = im.crop(a, b, x - a, y - b);

	let ref mut fout = File::create(&Path::new(out_path)).unwrap();

	let _ = subim.save(fout, image::PNG).unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

#[derive(Debug)]
enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(u32),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof
}

fn tokenize(source: &String) -> Result<Vec<Token>, String> {
    unimplemented!();
}

fn run(source: &String) -> Result<(), String> {
    let tokens = try!(tokenize(source));
    for token in tokens {
        println!("{:?}", token);
    }
    Ok(())
}

fn run_file(file_name: &String) -> Result<(), String> {
    match File::open(file_name) {
        Err(_) => {
            Err("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), String> {
    loop {
        print!("> ");
        io::stdout().flush();
        let mut source = String::new();
        io::stdin().read_line(&mut source);
        try!(run(&source));
        ()
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    };
    std::process::exit(exit_code)
}
<commit_msg>Added TokenWithContext for better feedback<commit_after>use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

#[derive(Debug)]
enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(u32),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof
}

#[derive(Debug)]
struct TokenWithContext{
    token: Token,
    lexeme: String,
    line: u32
}

fn tokenize(source: &String) -> Result<Vec<TokenWithContext>, String> {
    unimplemented!();
}

fn run(source: &String) -> Result<(), String> {
    let tokens = try!(tokenize(source));
    for token in tokens {
        println!("{:?}", token);
    }
    Ok(())
}

fn run_file(file_name: &String) -> Result<(), String> {
    match File::open(file_name) {
        Err(_) => {
            Err("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), String> {
    loop {
        print!("> ");
        io::stdout().flush();
        let mut source = String::new();
        io::stdin().read_line(&mut source);
        try!(run(&source));
        ()
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    };
    std::process::exit(exit_code)
}
<|endoftext|>