<commit_before>//! Our main CLI tool.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![deny(warnings)]

#[macro_use]
extern crate conductor;
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate rustc_serialize;

use docopt::Docopt;
use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::process;

use conductor::command_runner::{Command, CommandRunner, OsCommandRunner};
use conductor::cmd::*;
use conductor::Result;

/// Our version number, set by Cargo at compile time.
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// Our help string.
const USAGE: &'static str = "
conductor: Manage large, multi-pod docker-compose apps

Usage:
  conductor [options] new <name>
  conductor [options] build
  conductor [options] pull
  conductor [options] up [<pods>..]
  conductor [options] stop
  conductor [options] run [exec options] <pod> [<command> [--] [<args>...]]
  conductor [options] exec [exec options] <pod> <service> <command> [--] [<args>..]
  conductor [options] shell [exec options] <pod> <service>
  conductor [options] test <pod> <service>
  conductor [options] repo list
  conductor [options] repo clone <repo>
  conductor [options] generate list
  conductor [options] generate <generator>
  conductor [options] export <dir>
  conductor (--help | --version | --all-versions)

Commands:
  new               Create a directory containing a new sample project
  build             Build images for the containers associated with this project
  pull              Pull Docker images used by project
  up                Run project
  stop              Stop all containers associated with project
  run               Run a specific pod as a one-shot task
  exec              Run a command inside a container
  shell             Run an interactive shell inside a running container
  test              Run the tests associated with a service, if any
  repo list         List all git repository aliases and URLs
  repo clone        Clone a git repository using its short alias and mount it
                    into the containers that use it
  generate list     List all available generators
  generate          Run the specified generator
  export            Export to the named directory as flattened *.yml files

Arguments:
  <dir>             The name of a directory
  <name>            The name of the project directory to create
  <pod>, <pods>     The name of a pod specified in `pods/`
  <repo>            Short alias for a repo (see `repo list`)
  <service>         The name of a service in a pod
  <generator>       The name of a generator

Exec options:
  -d                Run command detached in background
  --privileged      Run a command with elevated privileges
  --user <user>     User as which to run a command
  -T                Do not allocate a TTY when running a command

General options:
  -h, --help        Show this message
  --version         Show the version of conductor
  --all-versions    Show the version of conductor and supporting tools
  -p, --project-name <project_name>
                    The name of this project.  Defaults to the current
                    directory name.
  --override=<override>
                    Use overrides from the specified subdirectory of
                    `pods/overrides`.  Defaults to `development` unless
                    running tests.
  --default-tags=<tag_file>
                    A list of tagged image names, one per line, to
                    be used as defaults for images

Run conductor in a directory containing a `pods` subdirectory.  For more
information, see https://github.com/faradayio/conductor.
";

/// Our parsed command-line arguments.  See [docopt.rs][] for an
/// explanation of how this works.
///
/// [docopt.rs]: https://github.com/docopt/docopt.rs
#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)] // Allow uppercase options without warnings.
struct Args {
    cmd_build: bool,
    cmd_pull: bool,
    cmd_up: bool,
    cmd_stop: bool,
    cmd_run: bool,
    cmd_exec: bool,
    cmd_shell: bool,
    cmd_test: bool,
    cmd_repo: bool,
    cmd_list: bool,
    cmd_clone: bool,
    cmd_new: bool,
    cmd_generate: bool,
    cmd_export: bool,

    arg_args: Option<Vec<String>>,
    arg_command: Option<String>,
    arg_dir: Option<String>,
    arg_generator: Option<String>,
    arg_name: Option<String>,
    arg_pod: Option<String>,
    arg_pods: Vec<String>,
    arg_repo: Option<String>,
    arg_service: Option<String>,

    // Exec options.
    flag_d: bool,
    flag_privileged: bool,
    flag_user: Option<String>,
    flag_T: bool,

    // General options.
    flag_version: bool,
    flag_all_versions: bool,
    flag_default_tags: Option<String>,
    flag_override: Option<String>,
    flag_project_name: Option<String>,
}

impl Args {
    /// Get either the specified override name, or a reasonable default.
    fn override_name(&self) -> &str {
        self.flag_override.as_ref().map_or_else(|| {
            if self.cmd_test {
                "test"
            } else {
                "development"
            }
        }, |s| &s[..])
    }

    /// Extract `exec::Options` from our command-line arguments.
    fn to_exec_options(&self) -> conductor::exec::Options {
        conductor::exec::Options {
            detached: self.flag_d,
            privileged: self.flag_privileged,
            user: self.flag_user.clone(),
            allocate_tty: !self.flag_T,
            ..Default::default()
        }
    }

    /// Extract `exec::Target` from our command-line arguments.
    fn to_exec_target<'a>(&'a self,
                          project: &'a conductor::Project,
                          ovr: &'a conductor::Override)
                          -> Result<Option<conductor::exec::Target<'a>>> {
        match (&self.arg_pod, &self.arg_service) {
            (&Some(ref pod), &Some(ref service)) => {
                Ok(Some(try!(conductor::exec::Target::new(project,
                                                          ovr,
                                                          pod,
                                                          service))))
            }
            _ => Ok(None),
        }
    }

    /// Extract `exec::Command` from our command-line arguments.
    fn to_exec_command(&self) -> Option<conductor::exec::Command> {
        // We have an `Option<Vec<String>>` and we want a `&[String]`,
        // so do a little munging.
        let args = self.arg_args
            .as_ref()
            .map_or(&[] as &[_], |v| (v as &[_]));
        if let Some(ref command) = self.arg_command {
            Some(conductor::exec::Command::new(command).with_args(args))
        } else {
            None
        }
    }
}

/// The function which does the real work.  Unlike `main`, we have a return
/// type of `Result` and may therefore use `try!` to handle errors.
fn run(args: &Args) -> Result<()> {

    // Handle any flags or arguments we can handle without a project
    // directory.
    if args.flag_all_versions {
        try!(all_versions());
        return Ok(());
    } else if args.flag_version {
        version();
        return Ok(());
    } else if args.cmd_new {
        try!(conductor::Project::generate_new(&try!(env::current_dir()),
                                              args.arg_name.as_ref().unwrap()));
        return Ok(());
    }

    let mut proj = try!(conductor::Project::from_current_dir());
    if let Some(ref project_name) = args.flag_project_name {
        proj.set_name(project_name);
    }
    if let Some(ref default_tags_path) = args.flag_default_tags {
        let file = try!(fs::File::open(default_tags_path));
        proj.set_default_tags(try!(conductor::DefaultTags::read(file)));
    }
    let override_name = args.override_name();
    let ovr = try!(proj.ovr(override_name)
        .ok_or_else(|| err!("override {} is not defined", override_name)));
    try!(proj.output(ovr));
    let runner = OsCommandRunner::new();

    if args.cmd_pull {
        try!(proj.pull(&runner, &ovr));
    } else if args.cmd_build {
        try!(proj.build(&runner, &ovr));
    } else if args.cmd_up {
        if args.arg_pods.is_empty() {
            try!(proj.up_all(&runner, &ovr));
        } else {
            let pods: Vec<&str> = args.arg_pods
                .iter()
                .map(|p| &p[..])
                .collect();
            try!(proj.up(&runner, &ovr, &pods));
        }
    } else if args.cmd_stop {
        try!(proj.stop(&runner, &ovr));
    } else if args.cmd_run {
        let opts = args.to_exec_options();
        let cmd = args.to_exec_command();
        try!(proj.run(&runner,
                      &ovr,
                      args.arg_pod.as_ref().unwrap(),
                      cmd.as_ref(),
                      &opts));
    } else if args.cmd_exec {
        let target = try!(args.to_exec_target(&proj, &ovr)).unwrap();
        let opts = args.to_exec_options();
        let cmd = args.to_exec_command().unwrap();
        try!(proj.exec(&runner, &target, &cmd, &opts));
    } else if args.cmd_shell {
        let target = try!(args.to_exec_target(&proj, &ovr)).unwrap();
        let opts = args.to_exec_options();
        try!(proj.shell(&runner, &target, &opts));
    } else if args.cmd_test {
        let test_ovr = try!(proj.ovr("test")
            .ok_or_else(|| conductor::err("override test is required to run tests")));
        let target = try!(args.to_exec_target(&proj, &test_ovr)).unwrap();
        try!(proj.test(&runner, &target));
    } else if args.cmd_repo && args.cmd_list {
        try!(proj.repo_list(&runner));
    } else if args.cmd_repo && args.cmd_clone {
        try!(proj.repo_clone(&runner, args.arg_repo.as_ref().unwrap()));
        // Regenerate our output now that we've cloned.
        try!(proj.output(ovr));
    } else if args.cmd_generate && args.cmd_list {
        try!(proj.generate_list())
    } else if args.cmd_generate {
        try!(proj.generate(&args.arg_generator.as_ref().unwrap()))
    } else if args.cmd_export {
        try!(proj.export(&ovr, &Path::new(args.arg_dir.as_ref().unwrap())));
    } else {
        // The above cases should be exhaustive.
        unreachable!()
    }

    Ok(())
}

/// Print the version of this executable.
fn version() {
    println!("conductor {}", VERSION);
}

/// Print the version of this executable and also the versions of several
/// tools we use.
fn all_versions() -> Result<()> {
    version();

    let runner = OsCommandRunner::new();
    for tool in &["docker", "docker-compose", "git"] {
        let status = try!(runner.build(tool)
            .arg("--version")
            .status());
        if !status.success() {
            return Err(err!("Could not run {} (is it installed?)", tool));
        }
    }
    Ok(())
}

/// Our main entry point.
fn main() {
    // Initialize logging with some custom options, mostly so we can see
    // our own warnings.
    let mut builder = env_logger::LogBuilder::new();
    builder.filter(Some("compose_yml"), log::LogLevelFilter::Warn);
    builder.filter(Some("conductor"), log::LogLevelFilter::Warn);
    if let Ok(config) = env::var("RUST_LOG") {
        builder.parse(&config);
    }
    builder.init().unwrap();

    // Parse our args using docopt.rs.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    debug!("Arguments: {:?}", &args);

    // Defer all our real work to `run`, and handle any errors.  This is a
    // standard Rust pattern to make error-handling in `main` nicer.
    if let Err(ref err) = run(&args) {
        // We use `unwrap` here to turn I/O errors into application panics.
        // If we can't print a message to stderr without an I/O error,
        // the situation is hopeless.
        write!(io::stderr(), "Error: {}\n", err).unwrap();
        process::exit(1);
    }
}
<commit_msg>errors: Print lovely backtraces if `RUST_BACKTRACE=1` is set<commit_after>//! Our main CLI tool.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![deny(warnings)]

#[macro_use]
extern crate conductor;
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate rustc_serialize;

use docopt::Docopt;
use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::process;

use conductor::command_runner::{Command, CommandRunner, OsCommandRunner};
use conductor::cmd::*;
use conductor::Result;

/// Our version number, set by Cargo at compile time.
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// Our help string.
const USAGE: &'static str = "
conductor: Manage large, multi-pod docker-compose apps

Usage:
  conductor [options] new <name>
  conductor [options] build
  conductor [options] pull
  conductor [options] up [<pods>..]
  conductor [options] stop
  conductor [options] run [exec options] <pod> [<command> [--] [<args>...]]
  conductor [options] exec [exec options] <pod> <service> <command> [--] [<args>..]
  conductor [options] shell [exec options] <pod> <service>
  conductor [options] test <pod> <service>
  conductor [options] repo list
  conductor [options] repo clone <repo>
  conductor [options] generate list
  conductor [options] generate <generator>
  conductor [options] export <dir>
  conductor (--help | --version | --all-versions)

Commands:
  new               Create a directory containing a new sample project
  build             Build images for the containers associated with this project
  pull              Pull Docker images used by project
  up                Run project
  stop              Stop all containers associated with project
  run               Run a specific pod as a one-shot task
  exec              Run a command inside a container
  shell             Run an interactive shell inside a running container
  test              Run the tests associated with a service, if any
  repo list         List all git repository aliases and URLs
  repo clone        Clone a git repository using its short alias and mount it
                    into the containers that use it
  generate list     List all available generators
  generate          Run the specified generator
  export            Export to the named directory as flattened *.yml files

Arguments:
  <dir>             The name of a directory
  <name>            The name of the project directory to create
  <pod>, <pods>     The name of a pod specified in `pods/`
  <repo>            Short alias for a repo (see `repo list`)
  <service>         The name of a service in a pod
  <generator>       The name of a generator

Exec options:
  -d                Run command detached in background
  --privileged      Run a command with elevated privileges
  --user <user>     User as which to run a command
  -T                Do not allocate a TTY when running a command

General options:
  -h, --help        Show this message
  --version         Show the version of conductor
  --all-versions    Show the version of conductor and supporting tools
  -p, --project-name <project_name>
                    The name of this project.  Defaults to the current
                    directory name.
  --override=<override>
                    Use overrides from the specified subdirectory of
                    `pods/overrides`.  Defaults to `development` unless
                    running tests.
  --default-tags=<tag_file>
                    A list of tagged image names, one per line, to
                    be used as defaults for images

Run conductor in a directory containing a `pods` subdirectory.  For more
information, see https://github.com/faradayio/conductor.
";

/// Our parsed command-line arguments.  See [docopt.rs][] for an
/// explanation of how this works.
///
/// [docopt.rs]: https://github.com/docopt/docopt.rs
#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)] // Allow uppercase options without warnings.
struct Args {
    cmd_build: bool,
    cmd_pull: bool,
    cmd_up: bool,
    cmd_stop: bool,
    cmd_run: bool,
    cmd_exec: bool,
    cmd_shell: bool,
    cmd_test: bool,
    cmd_repo: bool,
    cmd_list: bool,
    cmd_clone: bool,
    cmd_new: bool,
    cmd_generate: bool,
    cmd_export: bool,

    arg_args: Option<Vec<String>>,
    arg_command: Option<String>,
    arg_dir: Option<String>,
    arg_generator: Option<String>,
    arg_name: Option<String>,
    arg_pod: Option<String>,
    arg_pods: Vec<String>,
    arg_repo: Option<String>,
    arg_service: Option<String>,

    // Exec options.
    flag_d: bool,
    flag_privileged: bool,
    flag_user: Option<String>,
    flag_T: bool,

    // General options.
    flag_version: bool,
    flag_all_versions: bool,
    flag_default_tags: Option<String>,
    flag_override: Option<String>,
    flag_project_name: Option<String>,
}

impl Args {
    /// Get either the specified override name, or a reasonable default.
    fn override_name(&self) -> &str {
        self.flag_override.as_ref().map_or_else(|| {
            if self.cmd_test {
                "test"
            } else {
                "development"
            }
        }, |s| &s[..])
    }

    /// Extract `exec::Options` from our command-line arguments.
    fn to_exec_options(&self) -> conductor::exec::Options {
        conductor::exec::Options {
            detached: self.flag_d,
            privileged: self.flag_privileged,
            user: self.flag_user.clone(),
            allocate_tty: !self.flag_T,
            ..Default::default()
        }
    }

    /// Extract `exec::Target` from our command-line arguments.
    fn to_exec_target<'a>(&'a self,
                          project: &'a conductor::Project,
                          ovr: &'a conductor::Override)
                          -> Result<Option<conductor::exec::Target<'a>>> {
        match (&self.arg_pod, &self.arg_service) {
            (&Some(ref pod), &Some(ref service)) => {
                Ok(Some(try!(conductor::exec::Target::new(project,
                                                          ovr,
                                                          pod,
                                                          service))))
            }
            _ => Ok(None),
        }
    }

    /// Extract `exec::Command` from our command-line arguments.
    fn to_exec_command(&self) -> Option<conductor::exec::Command> {
        // We have an `Option<Vec<String>>` and we want a `&[String]`,
        // so do a little munging.
        let args = self.arg_args
            .as_ref()
            .map_or(&[] as &[_], |v| (v as &[_]));
        if let Some(ref command) = self.arg_command {
            Some(conductor::exec::Command::new(command).with_args(args))
        } else {
            None
        }
    }
}

/// The function which does the real work.  Unlike `main`, we have a return
/// type of `Result` and may therefore use `try!` to handle errors.
fn run(args: &Args) -> Result<()> {

    // Handle any flags or arguments we can handle without a project
    // directory.
    if args.flag_all_versions {
        try!(all_versions());
        return Ok(());
    } else if args.flag_version {
        version();
        return Ok(());
    } else if args.cmd_new {
        try!(conductor::Project::generate_new(&try!(env::current_dir()),
                                              args.arg_name.as_ref().unwrap()));
        return Ok(());
    }

    let mut proj = try!(conductor::Project::from_current_dir());
    if let Some(ref project_name) = args.flag_project_name {
        proj.set_name(project_name);
    }
    if let Some(ref default_tags_path) = args.flag_default_tags {
        let file = try!(fs::File::open(default_tags_path));
        proj.set_default_tags(try!(conductor::DefaultTags::read(file)));
    }
    let override_name = args.override_name();
    let ovr = try!(proj.ovr(override_name)
        .ok_or_else(|| err!("override {} is not defined", override_name)));
    try!(proj.output(ovr));
    let runner = OsCommandRunner::new();

    if args.cmd_pull {
        try!(proj.pull(&runner, &ovr));
    } else if args.cmd_build {
        try!(proj.build(&runner, &ovr));
    } else if args.cmd_up {
        if args.arg_pods.is_empty() {
            try!(proj.up_all(&runner, &ovr));
        } else {
            let pods: Vec<&str> = args.arg_pods
                .iter()
                .map(|p| &p[..])
                .collect();
            try!(proj.up(&runner, &ovr, &pods));
        }
    } else if args.cmd_stop {
        try!(proj.stop(&runner, &ovr));
    } else if args.cmd_run {
        let opts = args.to_exec_options();
        let cmd = args.to_exec_command();
        try!(proj.run(&runner,
                      &ovr,
                      args.arg_pod.as_ref().unwrap(),
                      cmd.as_ref(),
                      &opts));
    } else if args.cmd_exec {
        let target = try!(args.to_exec_target(&proj, &ovr)).unwrap();
        let opts = args.to_exec_options();
        let cmd = args.to_exec_command().unwrap();
        try!(proj.exec(&runner, &target, &cmd, &opts));
    } else if args.cmd_shell {
        let target = try!(args.to_exec_target(&proj, &ovr)).unwrap();
        let opts = args.to_exec_options();
        try!(proj.shell(&runner, &target, &opts));
    } else if args.cmd_test {
        let test_ovr = try!(proj.ovr("test")
            .ok_or_else(|| conductor::err("override test is required to run tests")));
        let target = try!(args.to_exec_target(&proj, &test_ovr)).unwrap();
        try!(proj.test(&runner, &target));
    } else if args.cmd_repo && args.cmd_list {
        try!(proj.repo_list(&runner));
    } else if args.cmd_repo && args.cmd_clone {
        try!(proj.repo_clone(&runner, args.arg_repo.as_ref().unwrap()));
        // Regenerate our output now that we've cloned.
        try!(proj.output(ovr));
    } else if args.cmd_generate && args.cmd_list {
        try!(proj.generate_list())
    } else if args.cmd_generate {
        try!(proj.generate(&args.arg_generator.as_ref().unwrap()))
    } else if args.cmd_export {
        try!(proj.export(&ovr, &Path::new(args.arg_dir.as_ref().unwrap())));
    } else {
        // The above cases should be exhaustive.
        unreachable!()
    }

    Ok(())
}

/// Print the version of this executable.
fn version() {
    println!("conductor {}", VERSION);
}

/// Print the version of this executable and also the versions of several
/// tools we use.
fn all_versions() -> Result<()> {
    version();

    let runner = OsCommandRunner::new();
    for tool in &["docker", "docker-compose", "git"] {
        let status = try!(runner.build(tool)
            .arg("--version")
            .status());
        if !status.success() {
            return Err(err!("Could not run {} (is it installed?)", tool));
        }
    }
    Ok(())
}

/// Our main entry point.
fn main() {
    // Initialize logging with some custom options, mostly so we can see
    // our own warnings.
    let mut builder = env_logger::LogBuilder::new();
    builder.filter(Some("compose_yml"), log::LogLevelFilter::Warn);
    builder.filter(Some("conductor"), log::LogLevelFilter::Warn);
    if let Ok(config) = env::var("RUST_LOG") {
        builder.parse(&config);
    }
    builder.init().unwrap();

    // Parse our args using docopt.rs.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    debug!("Arguments: {:?}", &args);

    // Defer all our real work to `run`, and handle any errors.  This is a
    // standard Rust pattern to make error-handling in `main` nicer.
    if let Err(ref err) = run(&args) {
        // We use `unwrap` here to turn I/O errors into application panics.
        // If we can't print a message to stderr without an I/O error,
        // the situation is hopeless.
        write!(io::stderr(), "Error: {}\n", err).unwrap();
        if let Some(backtrace) = err.backtrace() {
            write!(io::stderr(), "{:?}\n", backtrace).unwrap();
        }
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{stdin, Read, BufReader,BufRead};
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Stdio, Command, exit};

// trait methods
use std::io::Write; // flush stdout

static BUILTINS: [&'static str; 3] = ["exit", "cd", "pwd"];

struct CommandLine {
    // command name
    cmd: String,
    // arguments, starting directly with the first actual argument
    args: Vec<String>,
    // whether to execute as background process
    bg: bool
}

// probaby doesn't need to be a macro
macro_rules! printerr {
    ($msg:expr) => (println!("relish: {}", $msg));
}

/*
 * get_pwd - returns String containing pwd or "???" if there was an error
 */
fn get_pwd() -> String {
    match env::current_dir() {
        Ok(pwd) => {
            pwd.to_string_lossy().to_string()
        }
        Err(_) => {
            "???".to_string()
        }
    }
}

/*
 * execute - execute shell command line based on input CommandLine
 */
fn execute(cmdline: &CommandLine) {
    let mut _cmd = Command::new(&cmdline.cmd);
    let cmd = _cmd.args(&cmdline.args);

    if cmdline.bg {
        if let Err(why) = cmd.spawn() {
            printerr!(why);
        }
    } else {
        if let Err(why) = cmd.stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .output() {
            if let Some(errno) = why.raw_os_error() {
                match errno {
                    2 => printerr!(format!("{}: {}", cmdline.cmd,
                                           "Command not found")),
                    _  => printerr!(format!("{}: {}", cmdline.cmd, why)),
                }
                return
            }

            // getting here is pretty rare, means error didn't have os errno
            printerr!(why);
        }
    }
}

/*
 * builtin - implement shell builtins
 */
fn builtin(cmdline: &CommandLine) {
    match &cmdline.cmd[..] {
        "exit" => {
            println!("So long, and thanks for all the fish!");
            exit(0);
        }
        "cd" => {
            // get dir to change to based on the length of cmdline.args
            let dir = if cmdline.args.len() == 0 {
                env::home_dir().unwrap_or(PathBuf::from("."))
            } else {
                // if they say `cd -`
                if cmdline.args[0] == "-" {
                    // return $OLDPWD, or "." if it's not available
                    PathBuf::from(&env::var("OLDPWD")
                                             .unwrap_or(".".to_string()))
                } else {
                    // create PathBuf from what they actually said
                    PathBuf::from(&cmdline.args[0])
                }
            };

            // set $OLDPWD
            env::set_var("OLDPWD", &env::current_dir()
                                        .unwrap_or(PathBuf::from(".".to_string())));
            // change directory
            if let Err(why) = env::set_current_dir(&dir) {
                printerr!(why);
            }
        }
        "pwd" => println!("{}", get_pwd()),
        _ => {}
    }
}

/*
 * get_prompt - generate and return shell prompt
 */
fn get_prompt() -> String {
    // get username
    let username = env::var("USER").unwrap_or("???".to_string());

    // get hostname
    let hostname = Command::new("/bin/hostname").output().unwrap();
    let hostname = String::from_utf8_lossy(&hostname.stdout);
    let hostname = hostname.trim();

    format!("{}@{} {} $ ", username, hostname, get_pwd())
}

/*
 * preprocess - main parsing routine responsible for populating CommandLine
 * struct
 */
fn preprocess(cmdline: &mut CommandLine) {
    let tmp = cmdline.cmd.clone();
    // TODO: this is awful, refactor to not use a loop
    for (i, each) in tmp.split(' ').enumerate() {

        if each.trim() == "" {
            // eat extra tabs/spaces
            continue;
        } else if each.trim().chars().nth(0).unwrap() == '#' {
            // stop parsing if there's a comment
            // ok to use unwrap because we've guaranteed input isn't empty
            break;
        } else if each.trim().chars().nth(0).unwrap() == '&'  {
            // background process, ignoring rest of input
            // TODO: probably shouldn't just ignore rest of input. also,
            // the & has to have a space before it right now

            if cmdline.bg == true {
                printerr!("background symbol `&` specified twice");
            }
            cmdline.bg = true;
            break;
        } else {
            // ok, this is real input

            let mut tmp = each.trim().to_string();

            // did they not include a space before the bg symbol?
            if each.trim().chars().nth(each.len()-1).unwrap() == '&' {
                if cmdline.bg == true {
                    printerr!("background symbol `&` specified twice");
                }
                cmdline.bg = true;
                tmp.pop();
            }

            // if it's the very first split word
            if i == 0 {
                cmdline.cmd = tmp;
                // handle `exit` builtin so we can handle it ASAP
                if each.trim() == "exit" {
                    builtin(&cmdline);
                }
            } else {
                // regular argument
                cmdline.args.push(tmp);
            }
        }
    }
}

fn read_line(cmd: &mut String, script_arg: Option<&mut File>) -> Result<usize, io::Error>  {
    match script_arg {
        Some(file) => {
            match file.read_to_string(cmd) {
                Ok(bytes_read) => Ok(bytes_read),
                Err(why) => Err(why)
            }
        }
        None => {
            match io::stdin().read_line(cmd) {
                Ok(bytes_read) => Ok(bytes_read),
                Err(why) => Err(why)
            }
        }
    }
}

fn main() {
    if env::args().count() > 2 {
        printerr!(format!("Usage: {} [script]", env::args().nth(0).unwrap()));
        exit(1);
    }

    let reader: Box<BufRead> = if env::args().count() == 2 {
        let path = &env::args().nth(1).unwrap();
        let file = match File::open(path) {
            Ok(file) => file,
            Err(why) => {
                printerr!(format!("couldn't open {}", path));
                exit(1);
            }
        };
        Box::new(BufReader::new(file))
    } else {
        let i = io::stdin();
        Box::new(BufReader::new(i))
    };

    // main shell loop
    for line in reader.lines() {
        let line = match line {
            Ok(l) => l,
            Err(why) => {
                exit(0);
            }
        };

        let mut cmdline: CommandLine = CommandLine {
            cmd: line,
            args: Vec::new(),
            bg: false
        };

        // print prompt
        print!("{}", get_prompt());
        if let Err(why) = io::stdout().flush() {
            printerr!(why);
            continue;
        }

        // check if blank/comment
        cmdline.cmd = cmdline.cmd.trim().to_string();
        match cmdline.cmd.chars().nth(0) {
            Some(first) =>
                if first == '#' {
                    continue
                },
            None => continue // empty string
        }

        // parse
        preprocess(&mut cmdline);

        // handle builtins
        // NOTE: `exit` is handled in preprocess() for efficiency
        if BUILTINS.contains(&&cmdline.cmd[..]) {
            builtin(&cmdline)
        } else {
            execute(&cmdline);
        }
    }
}
<commit_msg>Add print_prompt function, remove read_line,<commit_after>use std::io;
use std::io::{stdin, Read, BufReader,BufRead};
use std::env;
use std::fs::File;
use std::path::{PathBuf};
use std::process::{Stdio, Command, exit};

// trait methods
use std::io::Write; // flush stdout

static BUILTINS: [&'static str; 3] = ["exit", "cd", "pwd"];

struct CommandLine {
    // command name
    cmd: String,
    // arguments, starting directly with the first actual argument
    args: Vec<String>,
    // whether to execute as background process
    bg: bool
}

// probaby doesn't need to be a macro
macro_rules! printerr {
    ($msg:expr) => (println!("relish: {}", $msg));
}

/*
 * get_pwd - returns String containing pwd or "???" if there was an error
 */
fn get_pwd() -> String {
    match env::current_dir() {
        Ok(pwd) => {
            pwd.to_string_lossy().to_string()
        }
        Err(_) => {
            "???".to_string()
        }
    }
}

/*
 * execute - execute shell command line based on input CommandLine
 */
fn execute(cmdline: &CommandLine) {
    let mut _cmd = Command::new(&cmdline.cmd);
    let cmd = _cmd.args(&cmdline.args);

    if cmdline.bg {
        if let Err(why) = cmd.spawn() {
            printerr!(why);
        }
    } else {
        if let Err(why) = cmd.stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .output() {
            if let Some(errno) = why.raw_os_error() {
                match errno {
                    2 => printerr!(format!("{}: {}", cmdline.cmd,
                                           "Command not found")),
                    _  => printerr!(format!("{}: {}", cmdline.cmd, why)),
                }
                return
            }

            // getting here is pretty rare, means error didn't have os errno
            printerr!(why);
        }
    }
}

/*
 * builtin - implement shell builtins
 */
fn builtin(cmdline: &CommandLine) {
    match &cmdline.cmd[..] {
        "exit" => {
            println!("So long, and thanks for all the fish!");
            exit(0);
        }
        "cd" => {
            // get dir to change to based on the length of cmdline.args
            let dir = if cmdline.args.len() == 0 {
                env::home_dir().unwrap_or(PathBuf::from("."))
            } else {
                // if they say `cd -`
                if cmdline.args[0] == "-" {
                    // return $OLDPWD, or "." if it's not available
                    PathBuf::from(&env::var("OLDPWD")
                                             .unwrap_or(".".to_string()))
                } else {
                    // create PathBuf from what they actually said
                    PathBuf::from(&cmdline.args[0])
                }
            };

            // set $OLDPWD
            env::set_var("OLDPWD", &env::current_dir()
                                        .unwrap_or(PathBuf::from(".".to_string())));
            // change directory
            if let Err(why) = env::set_current_dir(&dir) {
                printerr!(why);
            }
        }
        "pwd" => println!("{}", get_pwd()),
        _ => {}
    }
}

fn print_prompt() {
    print!("{}", get_prompt());
    if let Err(_) = io::stdout().flush() {
    }
}

/*
 * get_prompt - generate and return shell prompt
 */
fn get_prompt() -> String {
    // get username
    let username = env::var("USER").unwrap_or("???".to_string());

    // get hostname
    let hostname = Command::new("/bin/hostname").output().unwrap();
    let hostname = String::from_utf8_lossy(&hostname.stdout);
    let hostname = hostname.trim();

    format!("{}@{} {} $ ", username, hostname, get_pwd())
}

/*
 * preprocess - main parsing routine responsible for populating CommandLine
 * struct
 */
fn preprocess(cmdline: &mut CommandLine) {
    let tmp = cmdline.cmd.clone();
    // TODO: this is awful, refactor to not use a loop
    for (i, each) in tmp.split(' ').enumerate() {

        if each.trim() == "" {
            // eat extra tabs/spaces
            continue;
        } else if each.trim().chars().nth(0).unwrap() == '#' {
            // stop parsing if there's a comment
            // ok to use unwrap because we've guaranteed input isn't empty
            break;
        } else if each.trim().chars().nth(0).unwrap() == '&'  {
            // background process, ignoring rest of input
            // TODO: probably shouldn't just ignore rest of input. also,
            // the & has to have a space before it right now

            if cmdline.bg == true {
                printerr!("background symbol `&` specified twice");
            }
            cmdline.bg = true;
            break;
        } else {
            // ok, this is real input

            let mut tmp = each.trim().to_string();

            // did they not include a space before the bg symbol?
            if each.trim().chars().nth(each.len()-1).unwrap() == '&' {
                if cmdline.bg == true {
                    printerr!("background symbol `&` specified twice");
                }
                cmdline.bg = true;
                tmp.pop();
            }

            // if it's the very first split word
            if i == 0 {
                cmdline.cmd = tmp;
                // handle `exit` builtin so we can handle it ASAP
                if each.trim() == "exit" {
                    builtin(&cmdline);
                }
            } else {
                // regular argument
                cmdline.args.push(tmp);
            }
        }
    }
}

fn main() {
    if env::args().count() > 2 {
        printerr!(format!("Usage: {} [script]", env::args().nth(0).unwrap()));
        exit(1);
    }

    let reader: Box<BufRead> = if env::args().count() == 2 {
        let path = &env::args().nth(1).unwrap();
        let file = match File::open(path) {
            Ok(file) => file,
            Err(_) => {
                printerr!(format!("couldn't open {}", path));
                exit(1);
            }
        };
        Box::new(BufReader::new(file))
    } else {
        let i = io::stdin();
        Box::new(BufReader::new(i))
    };

    print_prompt();

    // main shell loop
    for line in reader.lines() {
        let line = match line {
            Ok(l) => l,
            Err(_) => {
                exit(0);
            }
        };

        let mut cmdline: CommandLine = CommandLine {
            cmd: line,
            args: Vec::new(),
            bg: false
        };

        print_prompt();

        // check if blank/comment
        cmdline.cmd = cmdline.cmd.trim().to_string();
        match cmdline.cmd.chars().nth(0) {
            Some(first) =>
                if first == '#' {
                    continue
                },
            None => continue // empty string
        }

        // parse
        preprocess(&mut cmdline);

        // handle builtins
        // NOTE: `exit` is handled in preprocess() for efficiency
        if BUILTINS.contains(&&cmdline.cmd[..]) {
            builtin(&cmdline)
        } else {
            execute(&cmdline);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(vec_push_all)]

use std::{cmp, mem};

use self::pair::*;
use self::Leading::*;

mod pair;

#[derive(Copy, Clone)]
enum Leading {
    Top,
    Bot,
}

impl Leading {
    pub fn switched(self) -> Leading {
        match self {
            Top => Bot,
            Bot => Top,
        }
    }
}

struct Problem {
    pairs: Box<[SPair]>,
}

impl Problem {
    fn solve(&self, max_depth: u32) {
        let mut depth = 0;

        let mut current_working_set = Vec::new();
        let mut next_working_set = Vec::new();

        current_working_set.push(VPair::new());

        while depth <= max_depth {
            println!("Now at depth {}", depth);

            for e in current_working_set.iter() {
                for p in self.pairs.iter() {
                    if let Some(ne) = e.apply(p) {
                        if ne.is_complete() {
                            println!("success!");
                            return;
                        }

                        next_working_set.push(ne);
                    }
                }
            }

            mem::swap(&mut current_working_set, &mut next_working_set);
            next_working_set.clear();

            depth += 1;
        }
        println!("no success");
    }
}

fn main() {
    let p = Problem::from([("010", "0"), ("0", "01"), ("101", "0100")].as_ref());
    // let p = Problem::from([("1", "101"), ("10", "00"), ("011", "11")].as_ref());
    // let p = Problem::from([("001", "0"), ("01", "011"), ("01", "101"), ("10", "001")].as_ref());
    p.solve(300);
}

impl<'a> From<&'a [(&'a str, &'a str)]> for Problem {
    fn from(s: &'a [(&'a str, &'a str)]) -> Problem {
        let mut pairs = Vec::with_capacity(s.len());

        for &p in s {
            pairs.push(p.into());
        }

        Problem {
            pairs: pairs.into_boxed_slice(),
        }
    }
}
<commit_msg>remove unused feature<commit_after>
use std::{cmp, mem};

use self::pair::*;
use self::Leading::*;

mod pair;

#[derive(Copy, Clone)]
enum Leading {
    Top,
    Bot,
}

impl Leading {
    pub fn switched(self) -> Leading {
        match self {
            Top => Bot,
            Bot => Top,
        }
    }
}

struct Problem {
    pairs: Box<[SPair]>,
}

impl Problem {
    fn solve(&self, max_depth: u32) {
        let mut depth = 0;

        let mut current_working_set = Vec::new();
        let mut next_working_set = Vec::new();

        current_working_set.push(VPair::new());

        while depth <= max_depth {
            println!("Now at depth {}", depth);

            for e in current_working_set.iter() {
                for p in self.pairs.iter() {
                    if let Some(ne) = e.apply(p) {
                        if ne.is_complete() {
                            println!("success!");
                            return;
                        }

                        next_working_set.push(ne);
                    }
                }
            }

            mem::swap(&mut current_working_set, &mut next_working_set);
            next_working_set.clear();

            depth += 1;
        }
        println!("no success");
    }
}

fn main() {
    let p = Problem::from([("010", "0"), ("0", "01"), ("101", "0100")].as_ref());
    // let p = Problem::from([("1", "101"), ("10", "00"), ("011", "11")].as_ref());
    // let p = Problem::from([("001", "0"), ("01", "011"), ("01", "101"), ("10", "001")].as_ref());
    p.solve(300);
}

impl<'a> From<&'a [(&'a str, &'a str)]> for Problem {
    fn from(s: &'a [(&'a str, &'a str)]) -> Problem {
        let mut pairs = Vec::with_capacity(s.len());

        for &p in s {
            pairs.push(p.into());
        }

        Problem {
            pairs: pairs.into_boxed_slice(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate glob;
use glob::glob;

//use std::error::Error;
//use std::fs::File;
//use std::io::prelude::*;
use std::path::Path;

fn main() {
    for entry in glob("data/*.pgn").unwrap() {
        match entry {
            Ok(path) => load_pgn(path.as_path()),
            Err(e)   => println!("{:?}", e),
        }
    }
}

fn load_pgn(path: &Path) {
    println!("{:?}", path.display());
}
<commit_msg>Finally reading file<commit_after>// Attempt #4
// #![feature(io)]
// #![feature(path)]
// use std::old_io::File;

// Attempt #1
//extern crate glob;
//use glob::glob;

// Attempt #3
// use std::str::from_utf8_owned;
// use std::fs::File;

// Attempts #1 and #2
// use std::error::Error;
// use std::path::Path;
// use std::io;
// use std::io::prelude::*;
// use std::io::BufReader;

fn main() {
    let mut file = std::fs::File::open("data/gm1931.pgn").unwrap();
    let mut stdout = std::io::stdout();
    std::io::copy(&mut file, &mut stdout).unwrap();

    // Attempt #4
    // // Create a path to the desired file
    // let path = Path::new("data/gm1931.pgn");
    // let display = path.display();
    // // Open the path in read-only mode, returns `IoResult<File>`
    // let mut file = match File::open(&path) {
    //     // The `desc` field of `IoError` is a string that describes the error
    //     Err(why) => panic!("couldn't open {}: {}", display, why.desc),
    //     Ok(file) => file,
    // };
    // // Read the file contents into a string, returns `IoResult<String>`
    // match file.read_to_string() {
    //     Err(why) => panic!("couldn't read {}: {}", display, why.desc),
    //     Ok(string) => print!("{} contains:\n{}", display, string),
    // }

    // Attempt #1
    // for entry in glob("data/*.pgn").unwrap() {
    //     match entry {
    //         Ok(path) => load_pgn(path.as_path()),
    //         Err(e)   => println!("{:?}", e),
    //     }
    // }

    // Attempt #2
    // fn foo() -> io::Result<()> {
    //     let f = try!(File::open("data/gm1931.pgn"));
    //     let mut reader = BufReader::new(f);
    //     let mut buffer = String::new();

    //     // read a line into buffer
    //     try!(reader.read_line(&mut buffer));

    //     println!("{}", buffer);
    //     Ok(())
    // }
    // Ok(foo());

    // Attempt #3
    // let path = Path::new("data/gm1931.pgn");
    // let mut hw_file = File::open(&path);
    // let data = from_utf8_owned(hw_file.read_to_end());
    // println!("{}", data);
}

// Attempt #1
// fn load_pgn(path: &Path) -> Result<(), Error> {
//     // println!("{:?}", path.display());
// }
<|endoftext|>


<commit_before>// Copyright © 2016 Bart Massey
// [This program is licensed under the "MIT License"]
// Please see the file COPYING in the source
// distribution of this software for license terms.

// Rocket pastebin demo

#![feature(plugin)]
#![feature(plugin, custom_derive)]
#![feature(proc_macro)]
#![plugin(rocket_codegen)]

static UPLOAD: &'static str = "upload";
static NID: usize = 8;

extern crate rocket;
extern crate rocket_contrib;
extern crate rand;
extern crate serde;
#[macro_use] extern crate serde_derive;

use std::io;
use std::io::{Read, BufRead, Write};
use std::path::Path;
use std::collections::HashMap;
use std::fs::{File, create_dir, metadata, remove_file};

use rocket::Data;
use rocket::response::NamedFile;
use rocket_contrib::Template;
use rocket::request::Form;
use rocket::response::Redirect;

mod paste_id;
use paste_id::PasteID;

#[derive(Serialize)]
struct PasteInfo {
    paste_id: String,
    snippet: String,
    ellipsis: bool
}

#[get("/")]
fn index() -> io::Result<Template> {
    let dirents = std::fs::read_dir(UPLOAD)
                  .expect("could not open upload directory");
    let pastes = dirents.map(|d| {
        let paste_id = d.unwrap().file_name().into_string().unwrap();
        let paste_filename = Path::new(UPLOAD).join(&paste_id);
        let paste_file = NamedFile::open(&paste_filename)
                         .expect("could not open paste file");
        let mut paste_reader = io::BufReader::new(paste_file);
        let mut paste_line = String::new();
        let paste_len = paste_reader.read_line(&mut paste_line)
                        .expect("could not read first line of paste");
        let (ellipsis, snippet) =
            if paste_len < 24 {
                (false, paste_line)
            } else {
                let result = (&paste_line)[0..24].to_string();
                (true, result)
            };
        PasteInfo { paste_id: paste_id, snippet: snippet, ellipsis: ellipsis }
    }).collect::<Vec<PasteInfo>>();
    let mut context: HashMap<&str, _> = HashMap::new();
    context.insert("pastes", &pastes);
    Ok(Template::render("index", &context))
}

#[post("/", data = "<paste>")]
fn upload(paste: Data) -> io::Result<String> {
    let paste_id = PasteID::new(NID);
    let path = Path::new(UPLOAD).join(&paste_id.to_string());
    paste.stream_to_file(path)?;
    Ok(format!("/{}\n", paste_id))
}

fn open_paste(id: &PasteID) -> io::Result<NamedFile> {
    let filename = Path::new(UPLOAD).join(id.to_string());
    NamedFile::open(&filename)
}

fn create_paste(id: &PasteID) -> io::Result<File> {
    let filename = Path::new(UPLOAD).join(id.to_string());
    File::create(&filename)
}

#[get("/<id>")]
fn retrieve(id: PasteID) -> Option<NamedFile> {
    open_paste(&id).ok()
}

#[get("/new")]
fn edit_new() -> io::Result<Redirect> {
    let paste_id = PasteID::new(NID);
    let f = try!(create_paste(&paste_id));
    drop(f);
    Ok(Redirect::to(&format!("/edit/{}", paste_id.to_string())))
}

#[get("/edit/<id>")]
fn make_edit(id: PasteID) -> io::Result<Template> {
    let paste = open_paste(&id)?;
    let mut paste_reader = io::BufReader::new(paste);
    let mut paste_contents = String::new();
    paste_reader.read_to_string(&mut paste_contents)?;
    let paste_id = id.to_string();
    let paste_rows = format!("{}", 100);
    let mut context: HashMap<&str, _> = HashMap::new();
    context.insert("contents", &paste_contents);
    context.insert("paste_id", &paste_id);
    context.insert("paste_rows", &paste_rows);
    Ok(Template::render("edit", &context))
}

#[derive(FromForm)]
struct EditForm {
    paste: String
}

#[post("/edit/<id>", data = "<form>")]
fn accept_edit(id: PasteID, form: Form<EditForm>) -> io::Result<Redirect> {
    let edit = form.get();
    let paste = create_paste(&id)?;
    let mut paste_writer = io::BufWriter::new(paste);
    let paste_contents =
        edit.paste.chars().map(|c|{c as u8}).collect::<Vec<u8>>();
    paste_writer.write_all(paste_contents.as_slice())?;
    paste_writer.flush()?;
    Ok(Redirect::to("/"))
}

#[get("/delete/<id>")]
fn delete(id: PasteID) -> io::Result<Redirect> {
    let filename = Path::new(UPLOAD).join(id.to_string());
    try!(remove_file(&filename));
    Ok(Redirect::to("/"))
}

fn ok_dir<P: AsRef<Path>>(path: P) -> bool {
    match metadata(path.as_ref()) {
        Ok(md) => md.is_dir(),
        _ => false
    }
}

fn check_upload_dir() {
    if !ok_dir(UPLOAD) {
        create_dir(UPLOAD).expect("could not create upload directory");
    }
}

fn main() {
    check_upload_dir();
    let rocket = rocket::ignite();
    let rocket = rocket.mount("/", routes![index, upload, edit_new, retrieve,
                                           make_edit, accept_edit, delete]);
    rocket.launch()
}

#[cfg(test)]
mod test {
    extern crate scraper;

    use super::rocket;
    use rocket::testing::MockRequest;
    use rocket::http::{Status, Method};
    use self::scraper::{Html, Selector};

    #[test]
    fn index() {
        let rocket = rocket::ignite().mount("/", routes![super::index]);

        let mut req = MockRequest::new(Method::Get, "/");
        let mut response = req.dispatch_with(&rocket);

        assert_eq!(response.status(), Status::Ok);

        let body_str = response.body().and_then(|b| b.into_string()).unwrap_or(String::from(""));
        assert_has_text(&body_str, &"Pastebin!");
        assert_has_selector(&body_str, &"ul");
        assert_no_selector(&body_str, &"ul li");
    }

    fn assert_has_text(body: &str, expected: &str) {
      let body_html = Html::parse_fragment(body);
      let selector = Selector::parse("*").unwrap();
      let elements = body_html.select(&selector);
      let texts = elements.map(|e| e.text().collect::<Vec<_>>().concat());
      let actual = texts.fold(String::new(), |acc, s| format!("{}:{}", acc, s));
      assert!(&actual.contains(expected));
    }

    fn assert_has_selector(body: &str, selector_text: &str) {
      let body_html = Html::parse_fragment(body);
      let selector = Selector::parse(selector_text).unwrap();
      let count = body_html.select(&selector).count();
      assert!(count > 0);
    }

    fn assert_no_selector(body: &str, selector_text: &str) {
      let body_html = Html::parse_fragment(body);
      let selector = Selector::parse(selector_text).unwrap();
      let count = body_html.select(&selector).count();
      assert_eq!(0, count);
    }
}
<commit_msg>multibyte write with no copying, please.<commit_after>// Copyright © 2016 Bart Massey
// [This program is licensed under the "MIT License"]
// Please see the file COPYING in the source
// distribution of this software for license terms.

// Rocket pastebin demo

#![feature(plugin)]
#![feature(plugin, custom_derive)]
#![feature(proc_macro)]
#![plugin(rocket_codegen)]

static UPLOAD: &'static str = "upload";
static NID: usize = 8;

extern crate rocket;
extern crate rocket_contrib;
extern crate rand;
extern crate serde;
#[macro_use] extern crate serde_derive;

use std::io;
use std::io::{Read, BufRead, Write};
use std::path::Path;
use std::collections::HashMap;
use std::fs::{File, create_dir, metadata, remove_file};

use rocket::Data;
use rocket::response::NamedFile;
use rocket_contrib::Template;
use rocket::request::Form;
use rocket::response::Redirect;

mod paste_id;
use paste_id::PasteID;

#[derive(Serialize)]
struct PasteInfo {
    paste_id: String,
    snippet: String,
    ellipsis: bool
}

#[get("/")]
fn index() -> io::Result<Template> {
    let dirents = std::fs::read_dir(UPLOAD)
                  .expect("could not open upload directory");
    let pastes = dirents.map(|d| {
        let paste_id = d.unwrap().file_name().into_string().unwrap();
        let paste_filename = Path::new(UPLOAD).join(&paste_id);
        let paste_file = NamedFile::open(&paste_filename)
                         .expect("could not open paste file");
        let mut paste_reader = io::BufReader::new(paste_file);
        let mut paste_line = String::new();
        let paste_len = paste_reader.read_line(&mut paste_line)
                        .expect("could not read first line of paste");
        let (ellipsis, snippet) =
            if paste_len < 24 {
                (false, paste_line)
            } else {
                let result = (&paste_line)[0..24].to_string();
                (true, result)
            };
        PasteInfo { paste_id: paste_id, snippet: snippet, ellipsis: ellipsis }
    }).collect::<Vec<PasteInfo>>();
    let mut context: HashMap<&str, _> = HashMap::new();
    context.insert("pastes", &pastes);
    Ok(Template::render("index", &context))
}

#[post("/", data = "<paste>")]
fn upload(paste: Data) -> io::Result<String> {
    let paste_id = PasteID::new(NID);
    let path = Path::new(UPLOAD).join(&paste_id.to_string());
    paste.stream_to_file(path)?;
    Ok(format!("/{}\n", paste_id))
}

fn open_paste(id: &PasteID) -> io::Result<NamedFile> {
    let filename = Path::new(UPLOAD).join(id.to_string());
    NamedFile::open(&filename)
}

fn create_paste(id: &PasteID) -> io::Result<File> {
    let filename = Path::new(UPLOAD).join(id.to_string());
    File::create(&filename)
}

#[get("/<id>")]
fn retrieve(id: PasteID) -> Option<NamedFile> {
    open_paste(&id).ok()
}

#[get("/new")]
fn edit_new() -> io::Result<Redirect> {
    let paste_id = PasteID::new(NID);
    let f = try!(create_paste(&paste_id));
    drop(f);
    Ok(Redirect::to(&format!("/edit/{}", paste_id.to_string())))
}

#[get("/edit/<id>")]
fn make_edit(id: PasteID) -> io::Result<Template> {
    let paste = open_paste(&id)?;
    let mut paste_reader = io::BufReader::new(paste);
    let mut paste_contents = String::new();
    paste_reader.read_to_string(&mut paste_contents)?;
    let paste_id = id.to_string();
    let paste_rows = format!("{}", 100);
    let mut context: HashMap<&str, _> = HashMap::new();
    context.insert("contents", &paste_contents);
    context.insert("paste_id", &paste_id);
    context.insert("paste_rows", &paste_rows);
    Ok(Template::render("edit", &context))
}

#[derive(FromForm)]
struct EditForm {
    paste: String
}

#[post("/edit/<id>", data = "<form>")]
fn accept_edit(id: PasteID, form: Form<EditForm>) -> io::Result<Redirect> {
    let edit = form.get();
    let paste = create_paste(&id)?;
    let mut paste_writer = io::BufWriter::new(paste);
    paste_writer.write_all(edit.paste.as_bytes())?;
    paste_writer.flush()?;
    Ok(Redirect::to("/"))
}

#[get("/delete/<id>")]
fn delete(id: PasteID) -> io::Result<Redirect> {
    let filename = Path::new(UPLOAD).join(id.to_string());
    try!(remove_file(&filename));
    Ok(Redirect::to("/"))
}

fn ok_dir<P: AsRef<Path>>(path: P) -> bool {
    match metadata(path.as_ref()) {
        Ok(md) => md.is_dir(),
        _ => false
    }
}

fn check_upload_dir() {
    if !ok_dir(UPLOAD) {
        create_dir(UPLOAD).expect("could not create upload directory");
    }
}

fn main() {
    check_upload_dir();
    let rocket = rocket::ignite();
    let rocket = rocket.mount("/", routes![index, upload, edit_new, retrieve,
                                           make_edit, accept_edit, delete]);
    rocket.launch()
}

#[cfg(test)]
mod test {
    extern crate scraper;

    use super::rocket;
    use rocket::testing::MockRequest;
    use rocket::http::{Status, Method};
    use self::scraper::{Html, Selector};

    #[test]
    fn index() {
        let rocket = rocket::ignite().mount("/", routes![super::index]);

        let mut req = MockRequest::new(Method::Get, "/");
        let mut response = req.dispatch_with(&rocket);

        assert_eq!(response.status(), Status::Ok);

        let body_str = response.body().and_then(|b| b.into_string()).unwrap_or(String::from(""));
        assert_has_text(&body_str, &"Pastebin!");
        assert_has_selector(&body_str, &"ul");
        assert_no_selector(&body_str, &"ul li");
    }

    fn assert_has_text(body: &str, expected: &str) {
      let body_html = Html::parse_fragment(body);
      let selector = Selector::parse("*").unwrap();
      let elements = body_html.select(&selector);
      let texts = elements.map(|e| e.text().collect::<Vec<_>>().concat());
      let actual = texts.fold(String::new(), |acc, s| format!("{}:{}", acc, s));
      assert!(&actual.contains(expected));
    }

    fn assert_has_selector(body: &str, selector_text: &str) {
      let body_html = Html::parse_fragment(body);
      let selector = Selector::parse(selector_text).unwrap();
      let count = body_html.select(&selector).count();
      assert!(count > 0);
    }

    fn assert_no_selector(body: &str, selector_text: &str) {
      let body_html = Html::parse_fragment(body);
      let selector = Selector::parse(selector_text).unwrap();
      let count = body_html.select(&selector).count();
      assert_eq!(0, count);
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate quick_error;

extern crate clap;
extern crate html5ever;
extern crate rsdocs2docset;
extern crate sqlite;
extern crate url;

use clap::Shell;
use html5ever::driver::{ParseOpts, parse_document};
use html5ever::rcdom::RcDom;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;
use std::ffi::OsStr;
use std::fs::{self, DirBuilder, DirEntry, File};
use std::io::{self,Write};
use std::path::Path;

use rsdocs2docset::dom::{manipulator, parser};

mod cli;

type Result = std::result::Result<(), RsDoc2DocsetError>;

quick_error! {
    #[derive(Debug)]
    pub enum RsDoc2DocsetError {
        Io(err: std::io::Error) {
            from()
                cause(err)
                description(err.description())
        }
        Utf8(err: std::string::FromUtf8Error) {
            from()
                cause(err)
                description(err.description())
        }
        Sqlite(err: sqlite::Error) {
            from()
                cause(err)
                description(err.description())
        }
    }
}

fn main() {
    let mut app = cli::build();
    let args = app.clone().get_matches();

    if args.is_present("bash-completion-code") {
        cli::build_cli().gen_completions_to(env!("CARGO_PKG_NAME"), Shell::Bash, &mut io::stdout());
        return
    }

    if !args.is_present("indir") || !args.is_present("name") {
        app.print_help();
        println!();
        std::process::exit(1);
    }

    create_docset(args.value_of("indir").unwrap(), args.value_of("name").unwrap()).expect("error creating docset");
    println!("\n{}.docset successfully created!", args.value_of("name").unwrap())
}

fn create_docset(indir: &str, name: &str) -> Result {
    let db_filename = format!("{}.docset/Contents/Resources/docSet.dsidx", name);
    let db_path = Path::new(&db_filename);

    try!(write_file(Path::new(format!("{}.docset/Contents/Info.plist", name).as_str()), format!(include_str!("Info.plist.tmpl"), name = name, identifier = name.replace(" ", "_").replace("-", "_").to_lowercase()).as_ref()));
    try!(write_file(Path::new(format!("{}.docset/icon.png", name).as_str()), include_bytes!("icon.png")));
    try!(write_file(Path::new(format!("{}.docset/icon@2x.png", name).as_str()), include_bytes!("icon@2x.png")));

    try!(mkdir_parent_p(db_path));
    try!(sqlite::open(db_path).and_then(|c| c.execute("CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);")));

    try!(docset_from_rs_doc_tree(&Path::new(indir), format!("{}.docset/Contents/Resources/Documents/", name).as_str(), Path::new(db_path)));

    Ok(())
}

// recursivly creates the parent dir of `path`
fn mkdir_parent_p(path: &Path) -> Result {
    let dir = path.parent().expect(format!("can't create parent dir of {}", path.to_str().unwrap()).as_str());

    try!(DirBuilder::new()
         .recursive(true)
         .create(dir));
    Ok(())
}

fn write_file(path: &Path, data: &[u8]) -> Result {
    try!(mkdir_parent_p(path));
    try!(File::create(path).and_then(|mut f| f.write_all(data)));
    Ok(())
}

fn docset_from_rs_doc_tree(source_dir: &Path, out_dir: &str, db_path: &Path) -> Result {
    if !source_dir.exists() {
        return Err(io::Error::new(io::ErrorKind::NotFound, format!("{} does not exist", source_dir.to_str().unwrap())).into());
    }

    if source_dir.is_dir() {
        for entry in fs::read_dir(source_dir)? {
            let entry = entry?;
            if entry.path().is_dir() {
                try!(docset_from_rs_doc_tree(&entry.path(), &out_dir, &db_path));
            } else {
                try!(annotate_file(&entry, &out_dir, &db_path));
            }
        }
    }
    Ok(())
}

fn annotate_file(in_file: &DirEntry, output_prefix: &str, db_path: &Path) -> Result {
    let out_file = Path::new(output_prefix).join(in_file.path());

    if in_file.path().extension() == Some(OsStr::new("html")) {
        let mut dom = parse_document(RcDom::default(), ParseOpts::default())
            .from_utf8()
            .read_from( &mut File::open(&in_file.path())? )?;

        let entries = parser::find_entry_elements(&mut dom);
        for entry in entries.iter().filter_map(|x| x.as_ref()).filter(|x| !x.is_section) {
            //println!("{:70} | {}", in_file.path().display(), entry);

            let sql_cmd = format!("INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES (\"{}\", \"{}\", \"{}#{}\");", entry.entry_name, entry.entry_type, in_file.path().to_str().unwrap(), entry.anchor_name);
            try!(sqlite::open(db_path).and_then(|c| c.execute(&sql_cmd)))
        }
        manipulator::add_dash_links(&mut dom, &entries);

        let mut bytes = vec![];
        try!(serialize(&mut bytes, &dom.document, SerializeOpts::default()));
        try!(write_file(&out_file, bytes.as_ref()));

        print!("o"); io::stdout().flush().expect("error flushing stdout?!");
    } else {
        try!(mkdir_parent_p(&out_file));
        try!(fs::copy(in_file.path(), &out_file));
        //println!("{:70} | ", in_file.path().display());
        print!("."); io::stdout().flush().expect("error flushing stdout?!");
    }

    Ok(())
}
<commit_msg>[lint] get rid of unwraps<commit_after>#[macro_use] extern crate quick_error;

extern crate clap;
extern crate html5ever;
extern crate rsdocs2docset;
extern crate sqlite;
extern crate url;

use clap::Shell;
use html5ever::driver::{ParseOpts, parse_document};
use html5ever::rcdom::RcDom;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;
use std::ffi::OsStr;
use std::fs::{self, DirBuilder, DirEntry, File};
use std::io::{self,Write};
use std::path::Path;

use rsdocs2docset::dom::{manipulator, parser};

mod cli;

type Result = std::result::Result<(), RsDoc2DocsetError>;

quick_error! {
    #[derive(Debug)]
    pub enum RsDoc2DocsetError {
        Io(err: std::io::Error) {
            from()
                cause(err)
                description(err.description())
        }
        Utf8(err: std::string::FromUtf8Error) {
            from()
                cause(err)
                description(err.description())
        }
        Sqlite(err: sqlite::Error) {
            from()
                cause(err)
                description(err.description())
        }
    }
}

fn main() {
    let mut app = cli::build();
    let args = app.clone().get_matches();

    if args.is_present("bash-completion-code") {
        app.gen_completions_to(env!("CARGO_PKG_NAME"), Shell::Bash, &mut io::stdout());
        return
    }

    match (args.value_of("indir"), args.value_of("name")) {
        (Some(indir), Some(name)) => {
            create_docset(indir, name).expect("error creating docset");
            println!("\n{}.docset successfully created!", name)
        }
        (_, _) => {
            let _ = app.print_help();
            println!();
            std::process::exit(1);
        }
    }
}

fn create_docset(indir: &str, name: &str) -> Result {
    let db_filename = format!("{}.docset/Contents/Resources/docSet.dsidx", name);
    let db_path = Path::new(&db_filename);

    try!(write_file(Path::new(format!("{}.docset/Contents/Info.plist", name).as_str()), format!(include_str!("Info.plist.tmpl"), name = name, identifier = name.replace(" ", "_").replace("-", "_").to_lowercase()).as_ref()));
    try!(write_file(Path::new(format!("{}.docset/icon.png", name).as_str()), include_bytes!("icon.png")));
    try!(write_file(Path::new(format!("{}.docset/icon@2x.png", name).as_str()), include_bytes!("icon@2x.png")));

    try!(mkdir_parent_p(db_path));
    try!(sqlite::open(db_path).and_then(|c| c.execute("CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);")));

    try!(docset_from_rs_doc_tree(&Path::new(indir), format!("{}.docset/Contents/Resources/Documents/", name).as_str(), Path::new(db_path)));

    Ok(())
}

// recursivly creates the parent dir of `path`
fn mkdir_parent_p(path: &Path) -> Result {
    let dir = path.parent().expect(format!("can't create parent dir of {}", path.to_str().unwrap()).as_str());

    try!(DirBuilder::new()
         .recursive(true)
         .create(dir));
    Ok(())
}

fn write_file(path: &Path, data: &[u8]) -> Result {
    try!(mkdir_parent_p(path));
    try!(File::create(path).and_then(|mut f| f.write_all(data)));
    Ok(())
}

fn docset_from_rs_doc_tree(source_dir: &Path, out_dir: &str, db_path: &Path) -> Result {
    if !source_dir.exists() {
        return Err(io::Error::new(io::ErrorKind::NotFound, format!("{} does not exist", source_dir.to_str().unwrap())).into());
    }

    if source_dir.is_dir() {
        for entry in fs::read_dir(source_dir)? {
            let entry = entry?;
            if entry.path().is_dir() {
                try!(docset_from_rs_doc_tree(&entry.path(), &out_dir, &db_path));
            } else {
                try!(annotate_file(&entry, &out_dir, &db_path));
            }
        }
    }
    Ok(())
}

fn annotate_file(in_file: &DirEntry, output_prefix: &str, db_path: &Path) -> Result {
    let out_file = Path::new(output_prefix).join(in_file.path());

    if in_file.path().extension() == Some(OsStr::new("html")) {
        let mut dom = parse_document(RcDom::default(), ParseOpts::default())
            .from_utf8()
            .read_from( &mut File::open(&in_file.path())? )?;

        let entries = parser::find_entry_elements(&mut dom);
        for entry in entries.iter().filter_map(|x| x.as_ref()).filter(|x| !x.is_section) {
            //println!("{:70} | {}", in_file.path().display(), entry);

            let sql_cmd = format!("INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES (\"{}\", \"{}\", \"{}#{}\");", entry.entry_name, entry.entry_type, in_file.path().to_str().unwrap(), entry.anchor_name);
            try!(sqlite::open(db_path).and_then(|c| c.execute(&sql_cmd)))
        }
        manipulator::add_dash_links(&mut dom, &entries);

        let mut bytes = vec![];
        try!(serialize(&mut bytes, &dom.document, SerializeOpts::default()));
        try!(write_file(&out_file, bytes.as_ref()));

        print!("o"); io::stdout().flush().expect("error flushing stdout?!");
    } else {
        try!(mkdir_parent_p(&out_file));
        try!(fs::copy(in_file.path(), &out_file));
        //println!("{:70} | ", in_file.path().display());
        print!("."); io::stdout().flush().expect("error flushing stdout?!");
    }

    Ok(())
}
<|endoftext|>


<commit_before>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

#![feature(io, core, path, os, collections)]

use std::old_io::fs;
use std::os;
use std::path::posix::Path;
use std::old_io::fs::PathExtensions;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.as_str().unwrap());
        match std::old_io::stdio::stdin().read_line() {
            Ok(s) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s.as_slice() == "y" || tmp_s.as_slice() == "yes" {
                    return true;
                } else if tmp_s.as_slice() == "n" || tmp_s.as_slice() == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path) {
    if entry.exists() {
        if entry.is_dir() {
            if options.recursive || entry.as_str().unwrap() == "." {
                match fs::readdir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.as_str().unwrap());
                        }
                        for tmp in res.iter() {
                            start_clean(options, tmp);
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.as_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.as_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.filename() {
                Some(s) => {
                    if s.last().unwrap() == &('~' as u8) {
                        if !options.confirmation || ask_confirmation(&Path::new(s)) {
                            match fs::unlink(entry) {
                                Ok(_) => {
                                    if options.verbose {
                                        println!("\x1b[32;1m{} deleted\x1b[0m", entry.as_str().unwrap());
                                    }
                                }
                                Err(e) => {
                                    println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.as_str().unwrap(), e);
                                }
                            }
                        }
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.as_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.as_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r : recursive mode");
    println!("    -v : verbose mode");
    println!("    -i : prompt before every removal");
    println!("--help : print this help");
}

fn main() {
    let mut args = os::args().clone();
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = String::from_str(tmp.as_slice());

            tmp_arg.remove(0);
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if tmp.as_slice() == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        _ => {
                            panic!("Unknown option: '{}', to have the options list, please launch with '-h' option\n", character);
                        }
                    }
                }
            } else {
                files.push(Path::new(tmp.as_slice()));
            }
        }
    }
    if files.len() == 0 {
        files.push(Path::new(String::from_str(".").as_slice()));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<commit_msg>Update to last rustc version<commit_after>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

#![feature(core, path, os, collections, fs, old_io, env)]

use std::fs::{self, PathExt};
use std::path::Path;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.to_str().unwrap());
        match std::old_io::stdio::stdin().read_line() {
            Ok(s) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s.as_slice() == "y" || tmp_s.as_slice() == "yes" {
                    return true;
                } else if tmp_s.as_slice() == "n" || tmp_s.as_slice() == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path) {
    if entry.exists() {
        if entry.is_dir() {
            if options.recursive || entry.to_str().unwrap() == "." {
                match fs::read_dir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.to_str().unwrap());
                        }
                        for tmp in res {
                            match tmp {
                                Ok(current) => start_clean(options, &current.path()),
                                Err(e) => println!("Error: {:?}", e)
                            };
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.to_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.file_name() {
                Some(s) => {
                    match s.to_str() {
                        Some(ss) => if ss.ends_with("~") {
                            if !options.confirmation || ask_confirmation(&Path::new(s)) {
                                match fs::remove_file(entry) {
                                    Ok(_) => {
                                        if options.verbose {
                                            println!("\x1b[32;1m{} deleted\x1b[0m", entry.to_str().unwrap());
                                        }
                                    }
                                    Err(e) => {
                                        println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                                    }
                                }
                            }
                        },
                        _ => {}
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.to_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.to_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r : recursive mode");
    println!("    -v : verbose mode");
    println!("    -i : prompt before every removal");
    println!("--help : print this help");
}

fn main() {
    let mut args = Vec::new();

    for argument in std::env::args() {
        args.push(argument);
    }
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = String::from_str(tmp.as_slice());

            tmp_arg.remove(0);
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if tmp.as_slice() == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        _ => {
                            panic!("Unknown option: '{}', to have the options list, please launch with '-h' option\n", character);
                        }
                    }
                }
            } else {
                files.push(Path::new(tmp.as_slice()));
            }
        }
    }
    if files.len() == 0 {
        files.push(Path::new("."));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<|endoftext|>