<commit_before>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro, type_alias_impl_trait)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[cfg(feature = "profile-index")]
#[macro_use]
extern crate flamer;

#[cfg(unix)]
use log::error;
#[cfg(unix)]
use sd_notify::{self, NotifyState};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use anyhow::*;
use getopts::Options;
use log::info;
use simplelog::{LevelFilter, SimpleLogger, TermLogger, TerminalMode};
use std::path::Path;

mod config;
mod db;
mod ddns;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod service;

mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;

fn log_config() -> simplelog::Config {
	simplelog::ConfigBuilder::new()
		.set_location_level(LevelFilter::Error)
		.build()
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(e) => bail!("Daemonize error: {:#?}", e),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, log_config(), TerminalMode::Stdout) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, log_config()) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	if TermLogger::init(log_level, log_config(), TerminalMode::Stdout).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, log_config()) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

#[cfg(unix)]
fn notify_ready() {
	if let Ok(true) = sd_notify::booted() {
		if let Err(e) = sd_notify::notify(true, &[NotifyState::Ready]) {
			error!("Unable to send ready notification: {}", e);
		}
	}
}

#[cfg(not(unix))]
fn notify_ready() {}

fn main() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = db::DB::new(&db_path)?;

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		info!("Applying configuration");
		config::amend(&db, &config)?;
	}
	let config = config::read(&db)?;
	let auth_secret = config::get_auth_secret(&db)?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(&db_auto_index, &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.with_context(|| "Invalid port number")?;
	let db_server = db.clone();
	std::thread::spawn(move || {
		let _ = service::server::run(
			port,
			&auth_secret,
			api_url,
			web_url,
			web_dir_path,
			swagger_url,
			swagger_dir_path,
			db_server,
			command_sender,
		);
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(&db_ddns);
	});

	// Send readiness notification
	notify_ready();

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<commit_msg>Removed unused feature<commit_after>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[cfg(feature = "profile-index")]
#[macro_use]
extern crate flamer;

#[cfg(unix)]
use log::error;
#[cfg(unix)]
use sd_notify::{self, NotifyState};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use anyhow::*;
use getopts::Options;
use log::info;
use simplelog::{LevelFilter, SimpleLogger, TermLogger, TerminalMode};
use std::path::Path;

mod config;
mod db;
mod ddns;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod service;

mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;

fn log_config() -> simplelog::Config {
	simplelog::ConfigBuilder::new()
		.set_location_level(LevelFilter::Error)
		.build()
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(e) => bail!("Daemonize error: {:#?}", e),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, log_config(), TerminalMode::Stdout) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, log_config()) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	if TermLogger::init(log_level, log_config(), TerminalMode::Stdout).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, log_config()) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

#[cfg(unix)]
fn notify_ready() {
	if let Ok(true) = sd_notify::booted() {
		if let Err(e) = sd_notify::notify(true, &[NotifyState::Ready]) {
			error!("Unable to send ready notification: {}", e);
		}
	}
}

#[cfg(not(unix))]
fn notify_ready() {}

fn main() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = db::DB::new(&db_path)?;

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		info!("Applying configuration");
		config::amend(&db, &config)?;
	}
	let config = config::read(&db)?;
	let auth_secret = config::get_auth_secret(&db)?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(&db_auto_index, &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.with_context(|| "Invalid port number")?;
	let db_server = db.clone();
	std::thread::spawn(move || {
		let _ = service::server::run(
			port,
			&auth_secret,
			api_url,
			web_url,
			web_dir_path,
			swagger_url,
			swagger_dir_path,
			db_server,
			command_sender,
		);
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(&db_ddns);
	});

	// Send readiness notification
	notify_ready();

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

mod action;
mod opts;
mod session;

use std::fs::File;
use std::io::Result;

use log::error;
use opts::{Opts};

use crate::session::{Action};

fn main() -> Result<()> {
    let opts = opts::from_args();
    init(&opts);

    fleetspeak::startup(env!("CARGO_PKG_VERSION"))?;

    use session::Error::*;
    match action::startup::handle(&mut session::startup(), ()) {
        Err(Action(error)) => {
            error!("failed to collect startup metadata: {}", error);
        }
        Err(Send(error)) => {
            // Fleetspeak errors are critical, better to fail hard and
            // force agent restart.
            return Err(error.into());
        }
        Err(Encode(error)) => {
            error!("failed to encode startup metadata: {}", error);
        }
        Ok(()) => (),
    }

    loop {
        let packet = fleetspeak::collect(opts.heartbeat_rate)?;
        handle(packet.data);
    }
}

fn init(opts: &Opts) {
    init_log(opts);
}

fn init_log(opts: &Opts) {
    let level = opts.log_verbosity.level();

    let mut loggers = Vec::<Box<dyn simplelog::SharedLogger>>::new();

    if let Some(std) = &opts.log_std {
        let config = Default::default();
        let logger = simplelog::TermLogger::new(level, config, std.mode())
            .expect("failed to create a terminal logger");

        loggers.push(logger);
    }

    if let Some(path) = &opts.log_file {
        let file = File::create(path)
            .expect("failed to create the log file");

        let config = Default::default();
        let logger = simplelog::WriteLogger::new(level, config, file);

        loggers.push(logger);
    }

    simplelog::CombinedLogger::init(loggers)
        .expect("failed to init logging");
}

fn handle(message: rrg_proto::GrrMessage) {
    let name = match message.name {
        Some(name) => name,
        None => {
            eprintln!("action request without an action name");
            return;
        },
    };

    let session_id = match message.session_id {
        Some(session_id) => session_id,
        None => {
            eprintln!("'{}' action request without a session id", name);
            return;
        },
    };

    let request_id = match message.request_id {
        Some(request_id) => request_id,
        None => {
            eprintln!("'{}' action request without a request id", name);
            return;
        },
    };

    let mut session = Action::new(session_id, request_id);
    let result = match name.as_str() {
        "SendStartupInfo" => action::startup::handle(&mut session, ()),
        _ => {
            // TODO: Report this error to the GRR server.
            eprintln!("unsupported action '{}'", name);
            Ok(())
        }
    };

    use session::Error;
    match result {
        Ok(()) => (),
        Err(Error::Action(error)) => {
            error!("failed to execute the '{}' action: {}",
                   name, error);
        }
        Err(Error::Send(error)) => {
            panic!("failed to send a response for the '{}' action: {}",
                   name, error);
        }
        Err(Error::Encode(error)) => {
            error!("failed to encode a response for the '{}' action: {}",
                   name, error);
        }
    }
}
<commit_msg>Improve tolerance to Fleetspeak errors.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

mod action;
mod opts;
mod session;

use std::fs::File;
use std::io::Result;

use log::error;
use opts::{Opts};

use crate::session::{Action};

fn main() -> Result<()> {
    let opts = opts::from_args();
    init(&opts);

    fleetspeak::startup(env!("CARGO_PKG_VERSION"))?;

    use session::Error::*;
    match action::startup::handle(&mut session::startup(), ()) {
        Err(Action(error)) => {
            error!("failed to collect startup metadata: {}", error);
        }
        Err(Send(error)) => {
            // Fleetspeak errors are critical, better to fail hard and
            // force agent restart.
            return Err(error.into());
        }
        Err(Encode(error)) => {
            error!("failed to encode startup metadata: {}", error);
        }
        Ok(()) => (),
    }

    loop {
        use fleetspeak::ReadError::*;
        let packet = match fleetspeak::collect(opts.heartbeat_rate) {
            Ok(packet) => packet,
            Err(Malformed(error)) => {
                error!("received a malformed message: {}", error);
                continue;
            }
            Err(Decode(error)) => {
                error!("failed to decode the message: {}", error);
                continue;
            }
            Err(error) => return Err(error.into()),
        };

        handle(packet.data);
    }
}

fn init(opts: &Opts) {
    init_log(opts);
}

fn init_log(opts: &Opts) {
    let level = opts.log_verbosity.level();

    let mut loggers = Vec::<Box<dyn simplelog::SharedLogger>>::new();

    if let Some(std) = &opts.log_std {
        let config = Default::default();
        let logger = simplelog::TermLogger::new(level, config, std.mode())
            .expect("failed to create a terminal logger");

        loggers.push(logger);
    }

    if let Some(path) = &opts.log_file {
        let file = File::create(path)
            .expect("failed to create the log file");

        let config = Default::default();
        let logger = simplelog::WriteLogger::new(level, config, file);

        loggers.push(logger);
    }

    simplelog::CombinedLogger::init(loggers)
        .expect("failed to init logging");
}

fn handle(message: rrg_proto::GrrMessage) {
    let name = match message.name {
        Some(name) => name,
        None => {
            eprintln!("action request without an action name");
            return;
        },
    };

    let session_id = match message.session_id {
        Some(session_id) => session_id,
        None => {
            eprintln!("'{}' action request without a session id", name);
            return;
        },
    };

    let request_id = match message.request_id {
        Some(request_id) => request_id,
        None => {
            eprintln!("'{}' action request without a request id", name);
            return;
        },
    };

    let mut session = Action::new(session_id, request_id);
    let result = match name.as_str() {
        "SendStartupInfo" => action::startup::handle(&mut session, ()),
        _ => {
            // TODO: Report this error to the GRR server.
            eprintln!("unsupported action '{}'", name);
            Ok(())
        }
    };

    use session::Error;
    match result {
        Ok(()) => (),
        Err(Error::Action(error)) => {
            error!("failed to execute the '{}' action: {}",
                   name, error);
        }
        Err(Error::Send(error)) => {
            panic!("failed to send a response for the '{}' action: {}",
                   name, error);
        }
        Err(Error::Encode(error)) => {
            error!("failed to encode a response for the '{}' action: {}",
                   name, error);
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustyline;
use rustyline::Editor;
use rustyline::error::ReadlineError;
use rustyline::completion::Completer;
use std::env::args;
use std::process::Command;

struct BashCompleter{
    command: String,
}

impl Completer for BashCompleter {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let words: Vec<&str> = line.split(" ").collect();
        let last_word = words.iter().nth(words.len()-1).unwrap();
        let count_words = words.len();

        let script = format!(
                    // COMP_WORDS must be specified in a bash context because normal environment
                    // variables can't be arrays
                    "
                    COMP_CWORD={}
                    COMP_POINT={}
                    COMP_LINE=\"{} {}\"
                    COMP_WORDS=({} {})
                    _xfunc git _git
                    printf \"%s\\n\" \"${{COMPREPLY[@]}}\"
                    ",
                    count_words,
                    pos + self.command.len() + 1,
                    self.command,
                    line,
                    self.command,
                    line,
                );
        let completion_result = Command::new("bash")
            .args(vec![
                "-lic",
                script.as_str(),
            ])
            .output();
        let completion_str = match completion_result {
            Ok(completion_string) => String::from_utf8(completion_string.stdout).unwrap(),
            Err(err) => {
                return Err(ReadlineError::Io(err));
            },
        };

        let word_len = last_word.len();
        let completions: Vec<String> = completion_str.split("\n").map(|s| s.to_string()).collect();

        Ok((pos-word_len, completions))
    }
}

fn main() {
    // TODO use a real arg parser
    let program = args().nth(1).expect("no program specified");
    let mut line_editor = Editor::<BashCompleter>::new();
    line_editor.set_completer(Some(BashCompleter{command: program.to_string()}));
    loop {
        let line_result = line_editor.readline(format!(">{} ", program.clone()).as_str());
        match line_result {
            Ok(line) => {
                let mut process_result = Command::new(&program)
                    // TODO deal with quoted strings
                    .args(line.split(" ").collect::<Vec<&str>>())
                    .spawn();
                match process_result {
                    Ok(mut process) => {
                        // TODO maybe display return code?
                        let _ = process.wait();
                    },
                    Err(err) => println!("error while trying to run command: {:?}", err),
                }
            },
            Err(ReadlineError::Interrupted) => {
                return;
            },
            Err(ReadlineError::Eof) => {
                return;
            },
            Err(err) => {
                eprintln!("{:?}", err);
                return;
            }
        }
    }
}
<commit_msg>add history file support<commit_after>extern crate rustyline;
use rustyline::Editor;
use rustyline::error::ReadlineError;
use rustyline::completion::Completer;
use std::env::args;
use std::path::PathBuf;
use std::process::Command;
use std::env::home_dir;
use std::fs::create_dir;
use std::fs::File;

struct BashCompleter{
    command: String,
}

impl Completer for BashCompleter {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let words: Vec<&str> = line.split(" ").collect();
        let last_word = words.iter().nth(words.len()-1).unwrap();
        let count_words = words.len();

        let script = format!(
                    // COMP_WORDS must be specified in a bash context because normal environment
                    // variables can't be arrays
                    "
                    COMP_CWORD={}
                    COMP_POINT={}
                    COMP_LINE=\"{} {}\"
                    COMP_WORDS=({} {})
                    _xfunc git _git
                    printf \"%s\\n\" \"${{COMPREPLY[@]}}\"
                    ",
                    count_words,
                    pos + self.command.len() + 1,
                    self.command,
                    line,
                    self.command,
                    line,
                );
        let completion_result = Command::new("bash")
            .args(vec![
                "-lic",
                script.as_str(),
            ])
            .output();
        let completion_str = match completion_result {
            Ok(completion_string) => String::from_utf8(completion_string.stdout).unwrap(),
            Err(err) => {
                return Err(ReadlineError::Io(err));
            },
        };

        let word_len = last_word.len();
        let completions: Vec<String> = completion_str.split("\n").map(|s| s.to_string()).collect();

        Ok((pos-word_len, completions))
    }
}

fn main() {
    // TODO use a real arg parser
    let program = args().nth(1).expect("no program specified");

    let mut line_editor = Editor::<BashCompleter>::new();
    line_editor.set_completer(Some(BashCompleter{command: program.to_string()}));

    let history_file_option = match home_dir() {
        Some(home) => {
            let config_dir: PathBuf = [home, PathBuf::from(".tpol")].iter().collect();
            if !config_dir.exists() {
                println!("creating config dir at {}", config_dir.to_str().unwrap());
                create_dir(&config_dir).unwrap();
            }

            let history_dir: PathBuf = [config_dir, PathBuf::from("history")].iter().collect();
            if !history_dir.exists() {
                println!("creating history dir at {}", history_dir.to_str().unwrap());
                create_dir(&history_dir).unwrap();
            }

            let command_history: PathBuf = [history_dir, PathBuf::from(&program)].iter().collect();
            if !command_history.exists() {
                println!("creating history file for {} at {}", &program, command_history.to_str().unwrap());
                let _ = File::create(&command_history).unwrap();
            }

            Some(command_history)
        }
        None => None,
    };

    if let Some(ref history_file) = history_file_option.clone() {
        if let Err(err) = line_editor.load_history(history_file) {
            eprintln!("Warning: error while trying to load history file {}: {}", history_file.to_str().unwrap(), err);
        }
    } else {
        eprintln!("Warning: can't find home directory, no history will be saved");
    }

    loop {
        let line_result = line_editor.readline(format!(">{} ", program.clone()).as_str());
        match line_result {
            Ok(line) => {
                let mut process_result = Command::new(&program)
                    // TODO deal with quoted strings
                    .args(line.split(" ").collect::<Vec<&str>>())
                    .spawn();
                match process_result {
                    Ok(mut process) => {
                        // TODO maybe display return code?
                        let _ = process.wait();
                        // TODO maybe only save in history if it's successful?
                        line_editor.add_history_entry(&line);
                    },
                    Err(err) => println!("error while trying to run command: {:?}", err),
                }
            },
            Err(ReadlineError::Interrupted) => {
                break;
            },
            Err(ReadlineError::Eof) => {
                break;
            },
            Err(err) => {
                eprintln!("{:?}", err);
                break;
            }
        }
    }

    if let Some(ref history_file) = history_file_option {
        if let Err(err) = line_editor.save_history(history_file) {
            eprintln!("Warning: error while trying to load history file {}: {}", history_file.to_str().unwrap(), err);
        }
    }
}
<|endoftext|>


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

extern crate rustc_serialize;
extern crate walkdir;
extern crate clap;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::{Command, Output};
use walkdir::{DirEntry, WalkDirIterator};
use clap::{Arg, App, SubCommand, AppSettings};

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}", line);
    println!("{}", banner);
    println!("{}", line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn display_path(path: &PathBuf) {
    path.file_name()
        .and_then(|p| p.to_str())
        .map(|p| println!("{}:", p));
}

fn report_output(output: Output) {
    if output.status.success() {
        print_ident(output.stdout);
    } else {
        print_ident(output.stderr);
    }
    // match output.status.success() {
    //     true => print_ident(output.stdout),
    //     false => print_ident(output.stderr),
    // }
    println!("");
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {

    let version = env!("CARGO_PKG_VERSION");

    let app_m = App::new("cargo multi")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(
            SubCommand::with_name("multi")
                .setting(AppSettings::ArgRequiredElseHelp)
                .setting(AppSettings::TrailingVarArg)
                .about("Run cargo command on multiple crates")
                .version(version)
                .arg(Arg::from_usage("<cmd>... 'cargo command to run'"))
        )
        .get_matches();

    let arg_cmd = app_m.subcommand_matches("multi").unwrap().values_of("cmd").unwrap();

    let mut cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;

    for arg in arg_cmd {
        cmd.arg(OsString::from(&arg));
        banner = banner + " " + arg;
    }

    announce(&banner);

    let is_crate = |e: &DirEntry| e.path().join("Cargo.toml").exists();
    let to_path_buf = |e: DirEntry| e.path().to_path_buf();
    let execute = move |p| cmd.current_dir(p).output().map(report_output);

    let cwd = env::current_dir().unwrap();
    walkdir::WalkDir::new(cwd)
        .min_depth(MIN_DEPTH)
        .max_depth(MAX_DEPTH)
        .into_iter()
        .filter_entry(is_crate)
        .filter_map(|e| e.ok())
        .map(to_path_buf)
        .inspect(display_path)
        .map(execute)
        .last(); // XXX Non-idiomatic perhaps, but gets the job done. May need to revisit later.
}
<commit_msg>Cleanups<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate rustc_serialize;
extern crate walkdir;
extern crate clap;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::{Command, Output};
use clap::{App, SubCommand, AppSettings};
use walkdir::{DirEntry, WalkDirIterator};

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}", line);
    println!("{}", banner);
    println!("{}", line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn display_path(path: &PathBuf) {
    path.file_name()
        .and_then(|p| p.to_str())
        .map(|p| println!("{}:", p));
}

fn report_output(output: Output) {
    if output.status.success() {
        print_ident(output.stdout);
    } else {
        print_ident(output.stderr);
    }
    // match output.status.success() {
    //     true => print_ident(output.stdout),
    //     false => print_ident(output.stderr),
    // }
    println!("");
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {

    let version = env!("CARGO_PKG_VERSION");
    let mut cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;

    let matches = App::new("cargo-multi")
                      .version(version)
                      .about("Run cargo command on multiple crates")
                      .setting(AppSettings::SubcommandRequired)
                      .setting(AppSettings::ArgRequiredElseHelp)
                      .setting(AppSettings::VersionlessSubcommands)
                      .subcommand(SubCommand::with_name("multi")
                                      .setting(AppSettings::ArgRequiredElseHelp)
                                      .setting(AppSettings::TrailingVarArg)
                                      .arg_from_usage("<cmd>... 'cargo command to run'"))
                      .get_matches();

    if let Some(arg_cmd) = matches.subcommand_matches("multi")
                                  .and_then(|m| m.values_of("cmd")) {
        for arg in arg_cmd {
            cmd.arg(OsString::from(&arg));
            banner = banner + " " + arg;
        }
    }

    announce(&banner);

    let is_crate = |e: &DirEntry| e.path().join("Cargo.toml").exists();
    let to_path_buf = |e: DirEntry| e.path().to_path_buf();
    let execute = move |p| cmd.current_dir(p).output().map(report_output);

    let cwd = env::current_dir().unwrap();
    walkdir::WalkDir::new(cwd)
        .min_depth(MIN_DEPTH)
        .max_depth(MAX_DEPTH)
        .into_iter()
        .filter_entry(is_crate)
        .filter_map(|e| e.ok())
        .map(to_path_buf)
        .inspect(display_path)
        .map(execute)
        .last(); // XXX Non-idiomatic perhaps, but gets the job done. May need to revisit later.
}
<|endoftext|>


<commit_before>// Clippy settings, full list here:
// <https://rust-lang.github.io/rust-clippy/master/index.html>
#![allow(clippy::clippy::clippy::needless_return)]
//
// Fail build on Clippy warnings
#![deny(warnings)]

#[macro_use]
extern crate lazy_static;

use backtrace::Backtrace;
use constants::*;
use git_version::git_version;
use isatty::{stdin_isatty, stdout_isatty};
use refiner::Refiner;
use regex::Regex;
use std::env;
use std::fs;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::panic;
use std::process::exit;
use std::process::{Command, Stdio};
use std::str;

mod constants;
mod refiner;
mod tokenizer;

const HELP_TEXT: &str = r#"
Usage: diff ... | riff

Colors diff and highlights what parts of changed lines have changed.

Git integration:
    git config --global pager.diff riff
    git config --global pager.show riff
    git config --global interactive.filter riff

Options:
    --help:    Print this text
    --version: Print version number
"#;

const HELP_TEXT_FOOTER: &str = r#"
Report issues at <https://github.com/walles/riff>.
"#;

const CRASH_FOOTER: &str = r#"
Please copy all of the above up to the --- RIFF CRASHED --- marker and report it at one of:
* <https://github.com/walles/riff/issues> (preferred)
* <johan.walles@gmail.com>
"#;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan
const PAGER_FORKBOMB_STOP: &str = "_RIFF_IGNORE_PAGER";

const GIT_VERSION: &str = git_version!();

lazy_static! {
    static ref STATIC_HEADERS: Vec<(Regex, &'static str)> = vec![
        (Regex::new("^diff ").unwrap(), BOLD),
        (Regex::new("^index ").unwrap(), BOLD),
        (Regex::new("^--- ").unwrap(), BOLD),
        (Regex::new("^\\+\\+\\+ ").unwrap(), BOLD),
        (Regex::new("^@@ ").unwrap(), HUNK_HEADER),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

enum LastLineKind {
    Initial,
    Add,
    Remove,
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header in STATIC_HEADERS.iter() {
        let re = &static_header.0;
        if re.is_match(line) {
            return static_header.1;
        }
    }

    return "";
}

fn print(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    stream.write_all(text.as_bytes()).unwrap();
}

fn println(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    print(stream, &text);
    print(stream, "\n");
}

fn highlight_diff(input: &mut dyn io::Read, output: &mut dyn io::Write) {
    let mut adds = String::new();
    let mut removes = String::new();
    let input = BufReader::new(input);
    let output = &mut BufWriter::new(output);
    let mut last_line_kind = LastLineKind::Initial;
    for line in input.lines() {
        let line = line.unwrap();

        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            // Drain outstanding adds / removes
            for line in Refiner::create(&adds, &removes).format() {
                println(output, &line);
            }
            adds.clear();
            removes.clear();

            print(output, fixed_highlight);
            print(output, &line);
            println(output, NORMAL);
            continue;
        }

        // Collect adds / removes
        if !line.is_empty() && line.chars().next().unwrap() == '+' {
            adds.push_str(&line[1..]);
            adds.push('\n');
            last_line_kind = LastLineKind::Add;
            continue;
        } else if !line.is_empty() && line.chars().next().unwrap() == '-' {
            removes.push_str(&line[1..]);
            removes.push('\n');
            last_line_kind = LastLineKind::Remove;
            continue;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            match last_line_kind {
                LastLineKind::Add => {
                    assert!(adds.pop().unwrap() == '\n');
                    continue;
                }
                LastLineKind::Remove => {
                    assert!(removes.pop().unwrap() == '\n');
                    continue;
                }
                LastLineKind::Initial => {
                    // This block intentionally left blank
                }
            }
        }

        last_line_kind = LastLineKind::Initial;

        // Drain outstanding adds / removes
        for line in Refiner::create(&adds, &removes).format() {
            println(output, &line);
        }
        adds.clear();
        removes.clear();

        // Print current line
        if line == NO_EOF_NEWLINE_MARKER {
            print(output, NO_EOF_NEWLINE_COLOR);
            print(output, &line);
            println(output, NORMAL);
        } else {
            println(output, &line);
        }
    }
    for line in Refiner::create(&adds, &removes).format() {
        println(output, &line);
    }
}

/// Try paging using the named pager (`$PATH` will be searched).
///
/// Returns `true` if the pager was found, `false` otherwise.
#[must_use]
fn try_pager(pager_name: &str) -> bool {
    let mut command = Command::new(pager_name);

    if env::var(PAGER_FORKBOMB_STOP).is_ok() {
        // Try preventing fork bombing if $PAGER is set to riff
        return false;
    }
    command.env(PAGER_FORKBOMB_STOP, "1");

    if !env::var("LESS").is_ok() {
        // Set by git when paging
        command.env("LESS", "FRX");
    }

    if !env::var("LV").is_ok() {
        // Set by git when paging
        command.env("LV", "-c");
    }

    command.stdin(Stdio::piped());

    match command.spawn() {
        Ok(mut pager) => {
            let pager_stdin = pager.stdin.as_mut().unwrap();
            highlight_diff(&mut io::stdin().lock(), pager_stdin);

            // FIXME: Report pager exit status if non-zero, together with
            // contents of pager stderr as well if possible.
            pager.wait().expect("Waiting for pager failed");

            return true;
        }
        Err(_) => {
            return false;
        }
    }
}

/// If `option` is found in `argv`, all instances of `option` will be removed
/// from `argv`.
///
/// Returns `true` if `option` was found and consumed, false otherwise.
#[must_use]
fn consume(option: &str, argv: &mut Vec<String>) -> bool {
    if !argv.contains(&option.to_string()) {
        // Not found
        return false;
    }

    argv.retain(|x| x != option);
    return true;
}

fn print_help(output: &mut dyn io::Write) {
    output.write_all(HELP_TEXT.trim().as_bytes()).unwrap();
    output.write_all(b"\n").unwrap();
    output.write_all(b"\n").unwrap();

    let self_path = env::args().into_iter().next().unwrap();
    let self_path = fs::canonicalize(self_path).unwrap();
    let self_path = self_path.as_path().to_str().unwrap();

    // FIXME: Do this only if we aren't already in the $PATH
    output
        .write_all("Installing riff in the $PATH:\n".as_bytes())
        .unwrap();
    output
        .write_all(&format!("  * sudo cp {} /usr/local/bin\n", self_path).as_bytes())
        .unwrap();
    output.write_all(b"\n").unwrap();

    output
        .write_all(HELP_TEXT_FOOTER.trim().as_bytes())
        .unwrap();
    output.write_all(b"\n").unwrap();
}

fn panic_handler(panic_info: &panic::PanicInfo) {
    let stderr: &mut dyn Write = &mut io::stderr();
    let stderr = &mut BufWriter::new(stderr);
    println(stderr, "\n\n------------ RIFF CRASHED -------------------");

    // Panic message
    if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
        println(stderr, &format!("Panic message: <{:?}>", s));
        println(stderr, "");
    }

    // Backtrace
    // FIXME: Ditch the Backtrace-internal frames from this backtrace
    // FIXME: Ditch the panic internal frames at the end of the backtrace
    println(stderr, &format!("{:?}", Backtrace::new()));

    println(stderr, &format!("Riff version: {}", GIT_VERSION));

    println(stderr, CRASH_FOOTER);
}

fn main() {
    panic::set_hook(Box::new(|panic_info: &panic::PanicInfo| {
        panic_handler(panic_info);
    }));

    let mut args: Vec<String> = env::args().collect();
    if consume("--help", &mut args) || consume("-h", &mut args) {
        print_help(&mut io::stdout());
        return;
    }

    if consume("--version", &mut args) {
        println!("riff {}", GIT_VERSION);
        println!();
        println!("Source code available at <https://github.com/walles/riff>.");
        return;
    }

    if stdin_isatty() {
        eprintln!("ERROR: Expected input from a pipe");
        eprintln!("");
        print_help(&mut io::stderr());
        exit(1);
    }

    if !stdout_isatty() {
        // We're being piped, just do stdin -> stdout
        highlight_diff(&mut io::stdin().lock(), &mut io::stdout());
        return;
    }

    let pager_env_var = env::var("PAGER");
    if pager_env_var.is_ok() {
        let pager_value = pager_env_var.unwrap();
        if try_pager(&pager_value) {
            return;
        }

        // FIXME: Print warning at the end if $PAGER was set to something that
        // doesn't exist.
    }

    if try_pager("moar") {
        return;
    }

    if try_pager("less") {
        return;
    }

    // No pager found, wth?
    highlight_diff(&mut io::stdin().lock(), &mut io::stdout());
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    fn remove(text: &str) -> String {
        return format!("{}{}{}", REMOVE, text, NORMAL);
    }

    fn add(text: &str) -> String {
        return format!("{}{}{}", ADD, text, NORMAL);
    }

    #[test]
    fn test_remove_trailing_newline() {
        let mut input = "-hej\n\
            +hej\n\
            \\ No newline at end of file\n\
            "
        .as_bytes();

        let expected = format!(
            "{}\n{}\n{}\n",
            remove(&format!("-hej{}⏎", INVERSE_VIDEO)),
            add("+hej"),
            format!(
                "{}\\ No newline at end of file{}",
                NO_EOF_NEWLINE_COLOR, NORMAL
            )
        );

        let mut output: Vec<u8> = Vec::new();
        highlight_diff(&mut input, &mut output);
        assert_eq!(std::str::from_utf8(&output).unwrap(), expected);
    }

    #[test]
    fn test_trailing_newline_context() {
        let mut input = "+bepa\n apa\n\\ No newline at end of file\n".as_bytes();

        let expected = format!(
            "{}\n{}\n{}\n",
            add("+bepa"),
            " apa",
            format!(
                "{}\\ No newline at end of file{}",
                NO_EOF_NEWLINE_COLOR, NORMAL
            )
        );

        let mut output: Vec<u8> = Vec::new();
        highlight_diff(&mut input, &mut output);
        assert_eq!(std::str::from_utf8(&output).unwrap(), expected);
    }

    #[test]
    fn test_testdata_examples() {
        // Example value: `/Users/johan/src/riff/target/debug/deps/riff-7a8916c06b0d3d6c`
        let exe_path = std::env::current_exe().unwrap();

        // Example value: `/Users/johan/src/riff`
        let project_path = exe_path
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap();

        // Example value: `/Users/johan/src/riff/testdata`
        let testdata_path = &project_path.join("testdata");
        assert!(testdata_path.is_dir());

        // Iterate all files in there
        for diff in fs::read_dir(testdata_path).unwrap() {
            let diff = diff.unwrap();
            let diff = diff.path();
            let diff = diff.as_path();
            if !diff.is_file() {
                continue;
            }

            if diff.extension().unwrap() != "diff" {
                continue;
            }

            println!("Evaluating example file <{}>...", diff.to_str().unwrap());

            // Run highlighting on the file into a memory buffer
            let mut actual_result: Vec<u8> = Vec::new();
            highlight_diff(&mut fs::File::open(diff).unwrap(), &mut actual_result);
            let actual_result = str::from_utf8(&actual_result).unwrap();

            // Load the corresponding .riff-output file into a string
            let basename = diff.file_stem().unwrap().to_str().unwrap();
            let expected_path = format!(
                "{}/{}.riff-output",
                testdata_path.to_str().unwrap(),
                basename
            );
            let expected_result = fs::read_to_string(expected_path).unwrap();

            // Assert that the highlighting output matches the contents of .riff-output
            assert_eq!(actual_result, expected_result);
        }
    }
}
<commit_msg>Fix some more warnings<commit_after>// Clippy settings, full list here:
// <https://rust-lang.github.io/rust-clippy/master/index.html>
#![allow(clippy::clippy::clippy::needless_return)]
//
// Fail build on Clippy warnings
#![deny(warnings)]

#[macro_use]
extern crate lazy_static;

use backtrace::Backtrace;
use constants::*;
use git_version::git_version;
use isatty::{stdin_isatty, stdout_isatty};
use refiner::Refiner;
use regex::Regex;
use std::env;
use std::fs;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::panic;
use std::process::exit;
use std::process::{Command, Stdio};
use std::str;

mod constants;
mod refiner;
mod tokenizer;

const HELP_TEXT: &str = r#"
Usage: diff ... | riff

Colors diff and highlights what parts of changed lines have changed.

Git integration:
    git config --global pager.diff riff
    git config --global pager.show riff
    git config --global interactive.filter riff

Options:
    --help:    Print this text
    --version: Print version number
"#;

const HELP_TEXT_FOOTER: &str = r#"
Report issues at <https://github.com/walles/riff>.
"#;

const CRASH_FOOTER: &str = r#"
Please copy all of the above up to the --- RIFF CRASHED --- marker and report it at one of:
* <https://github.com/walles/riff/issues> (preferred)
* <johan.walles@gmail.com>
"#;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan
const PAGER_FORKBOMB_STOP: &str = "_RIFF_IGNORE_PAGER";

const GIT_VERSION: &str = git_version!();

lazy_static! {
    static ref STATIC_HEADERS: Vec<(Regex, &'static str)> = vec![
        (Regex::new("^diff ").unwrap(), BOLD),
        (Regex::new("^index ").unwrap(), BOLD),
        (Regex::new("^--- ").unwrap(), BOLD),
        (Regex::new("^\\+\\+\\+ ").unwrap(), BOLD),
        (Regex::new("^@@ ").unwrap(), HUNK_HEADER),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

enum LastLineKind {
    Initial,
    Add,
    Remove,
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header in STATIC_HEADERS.iter() {
        let re = &static_header.0;
        if re.is_match(line) {
            return static_header.1;
        }
    }

    return "";
}

fn print(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    stream.write_all(text.as_bytes()).unwrap();
}

fn println(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    print(stream, &text);
    print(stream, "\n");
}

fn highlight_diff(input: &mut dyn io::Read, output: &mut dyn io::Write) {
    let mut adds = String::new();
    let mut removes = String::new();
    let input = BufReader::new(input);
    let output = &mut BufWriter::new(output);
    let mut last_line_kind = LastLineKind::Initial;
    for line in input.lines() {
        let line = line.unwrap();

        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            // Drain outstanding adds / removes
            for line in Refiner::create(&adds, &removes).format() {
                println(output, &line);
            }
            adds.clear();
            removes.clear();

            print(output, fixed_highlight);
            print(output, &line);
            println(output, NORMAL);
            continue;
        }

        // Collect adds / removes
        if !line.is_empty() && line.starts_with('+') {
            adds.push_str(&line[1..]);
            adds.push('\n');
            last_line_kind = LastLineKind::Add;
            continue;
        } else if !line.is_empty() && line.starts_with('-') {
            removes.push_str(&line[1..]);
            removes.push('\n');
            last_line_kind = LastLineKind::Remove;
            continue;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            match last_line_kind {
                LastLineKind::Add => {
                    assert!(adds.pop().unwrap() == '\n');
                    continue;
                }
                LastLineKind::Remove => {
                    assert!(removes.pop().unwrap() == '\n');
                    continue;
                }
                LastLineKind::Initial => {
                    // This block intentionally left blank
                }
            }
        }

        last_line_kind = LastLineKind::Initial;

        // Drain outstanding adds / removes
        for line in Refiner::create(&adds, &removes).format() {
            println(output, &line);
        }
        adds.clear();
        removes.clear();

        // Print current line
        if line == NO_EOF_NEWLINE_MARKER {
            print(output, NO_EOF_NEWLINE_COLOR);
            print(output, &line);
            println(output, NORMAL);
        } else {
            println(output, &line);
        }
    }
    for line in Refiner::create(&adds, &removes).format() {
        println(output, &line);
    }
}

/// Try paging using the named pager (`$PATH` will be searched).
///
/// Returns `true` if the pager was found, `false` otherwise.
#[must_use]
fn try_pager(pager_name: &str) -> bool {
    let mut command = Command::new(pager_name);

    if env::var(PAGER_FORKBOMB_STOP).is_ok() {
        // Try preventing fork bombing if $PAGER is set to riff
        return false;
    }
    command.env(PAGER_FORKBOMB_STOP, "1");

    if env::var("LESS").is_err() {
        // Set by git when paging
        command.env("LESS", "FRX");
    }

    if env::var("LV").is_err() {
        // Set by git when paging
        command.env("LV", "-c");
    }

    command.stdin(Stdio::piped());

    match command.spawn() {
        Ok(mut pager) => {
            let pager_stdin = pager.stdin.as_mut().unwrap();
            highlight_diff(&mut io::stdin().lock(), pager_stdin);

            // FIXME: Report pager exit status if non-zero, together with
            // contents of pager stderr as well if possible.
            pager.wait().expect("Waiting for pager failed");

            return true;
        }
        Err(_) => {
            return false;
        }
    }
}

/// If `option` is found in `argv`, all instances of `option` will be removed
/// from `argv`.
///
/// Returns `true` if `option` was found and consumed, false otherwise.
#[must_use]
fn consume(option: &str, argv: &mut Vec<String>) -> bool {
    if !argv.contains(&option.to_string()) {
        // Not found
        return false;
    }

    argv.retain(|x| x != option);
    return true;
}

fn print_help(output: &mut dyn io::Write) {
    output.write_all(HELP_TEXT.trim().as_bytes()).unwrap();
    output.write_all(b"\n").unwrap();
    output.write_all(b"\n").unwrap();

    let self_path = env::args().into_iter().next().unwrap();
    let self_path = fs::canonicalize(self_path).unwrap();
    let self_path = self_path.as_path().to_str().unwrap();

    // FIXME: Do this only if we aren't already in the $PATH
    output
        .write_all(b"Installing riff in the $PATH:\n")
        .unwrap();
    output
        .write_all(&format!("  * sudo cp {} /usr/local/bin\n", self_path).as_bytes())
        .unwrap();
    output.write_all(b"\n").unwrap();

    output
        .write_all(HELP_TEXT_FOOTER.trim().as_bytes())
        .unwrap();
    output.write_all(b"\n").unwrap();
}

fn panic_handler(panic_info: &panic::PanicInfo) {
    let stderr: &mut dyn Write = &mut io::stderr();
    let stderr = &mut BufWriter::new(stderr);
    println(stderr, "\n\n------------ RIFF CRASHED -------------------");

    // Panic message
    if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
        println(stderr, &format!("Panic message: <{:?}>", s));
        println(stderr, "");
    }

    // Backtrace
    // FIXME: Ditch the Backtrace-internal frames from this backtrace
    // FIXME: Ditch the panic internal frames at the end of the backtrace
    println(stderr, &format!("{:?}", Backtrace::new()));

    println(stderr, &format!("Riff version: {}", GIT_VERSION));

    println(stderr, CRASH_FOOTER);
}

fn main() {
    panic::set_hook(Box::new(|panic_info: &panic::PanicInfo| {
        panic_handler(panic_info);
    }));

    let mut args: Vec<String> = env::args().collect();
    if consume("--help", &mut args) || consume("-h", &mut args) {
        print_help(&mut io::stdout());
        return;
    }

    if consume("--version", &mut args) {
        println!("riff {}", GIT_VERSION);
        println!();
        println!("Source code available at <https://github.com/walles/riff>.");
        return;
    }

    if stdin_isatty() {
        eprintln!("ERROR: Expected input from a pipe");
        eprintln!("");
        print_help(&mut io::stderr());
        exit(1);
    }

    if !stdout_isatty() {
        // We're being piped, just do stdin -> stdout
        highlight_diff(&mut io::stdin().lock(), &mut io::stdout());
        return;
    }

    let pager_env_var = env::var("PAGER");
    if pager_env_var.is_ok() {
        let pager_value = pager_env_var.unwrap();
        if try_pager(&pager_value) {
            return;
        }

        // FIXME: Print warning at the end if $PAGER was set to something that
        // doesn't exist.
    }

    if try_pager("moar") {
        return;
    }

    if try_pager("less") {
        return;
    }

    // No pager found, wth?
    highlight_diff(&mut io::stdin().lock(), &mut io::stdout());
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    fn remove(text: &str) -> String {
        return format!("{}{}{}", REMOVE, text, NORMAL);
    }

    fn add(text: &str) -> String {
        return format!("{}{}{}", ADD, text, NORMAL);
    }

    #[test]
    fn test_remove_trailing_newline() {
        let mut input = "-hej\n\
            +hej\n\
            \\ No newline at end of file\n\
            "
        .as_bytes();

        let expected = format!(
            "{}\n{}\n{}\n",
            remove(&format!("-hej{}⏎", INVERSE_VIDEO)),
            add("+hej"),
            format!(
                "{}\\ No newline at end of file{}",
                NO_EOF_NEWLINE_COLOR, NORMAL
            )
        );

        let mut output: Vec<u8> = Vec::new();
        highlight_diff(&mut input, &mut output);
        assert_eq!(std::str::from_utf8(&output).unwrap(), expected);
    }

    #[test]
    fn test_trailing_newline_context() {
        let mut input = "+bepa\n apa\n\\ No newline at end of file\n".as_bytes();

        let expected = format!(
            "{}\n{}\n{}\n",
            add("+bepa"),
            " apa",
            format!(
                "{}\\ No newline at end of file{}",
                NO_EOF_NEWLINE_COLOR, NORMAL
            )
        );

        let mut output: Vec<u8> = Vec::new();
        highlight_diff(&mut input, &mut output);
        assert_eq!(std::str::from_utf8(&output).unwrap(), expected);
    }

    #[test]
    fn test_testdata_examples() {
        // Example value: `/Users/johan/src/riff/target/debug/deps/riff-7a8916c06b0d3d6c`
        let exe_path = std::env::current_exe().unwrap();

        // Example value: `/Users/johan/src/riff`
        let project_path = exe_path
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap();

        // Example value: `/Users/johan/src/riff/testdata`
        let testdata_path = &project_path.join("testdata");
        assert!(testdata_path.is_dir());

        // Iterate all files in there
        for diff in fs::read_dir(testdata_path).unwrap() {
            let diff = diff.unwrap();
            let diff = diff.path();
            let diff = diff.as_path();
            if !diff.is_file() {
                continue;
            }

            if diff.extension().unwrap() != "diff" {
                continue;
            }

            println!("Evaluating example file <{}>...", diff.to_str().unwrap());

            // Run highlighting on the file into a memory buffer
            let mut actual_result: Vec<u8> = Vec::new();
            highlight_diff(&mut fs::File::open(diff).unwrap(), &mut actual_result);
            let actual_result = str::from_utf8(&actual_result).unwrap();

            // Load the corresponding .riff-output file into a string
            let basename = diff.file_stem().unwrap().to_str().unwrap();
            let expected_path = format!(
                "{}/{}.riff-output",
                testdata_path.to_str().unwrap(),
                basename
            );
            let expected_result = fs::read_to_string(expected_path).unwrap();

            // Assert that the highlighting output matches the contents of .riff-output
            assert_eq!(actual_result, expected_result);
        }
    }
}
<|endoftext|>


<commit_before>extern crate dotenv;
extern crate deploy;
extern crate pencil;
#[macro_use] extern crate lazy_static;

use dotenv::dotenv;
use std::env;
use pencil::{Pencil, Response, Request, PencilResult};
use deploy::*;

lazy_static! {
  pub static ref SECRET: String = env::var("TENJAVA_DEPLOY_SECRET").expect("no deploy secret set");
}

fn deploy_webhook(r: &mut Request) -> PencilResult {
  let (signature, event) = {
    let headers = r.headers();
    let signature: &XHubSignature = headers.get().unwrap();
    let event: &XGitHubEvent = headers.get().unwrap();
    (signature.clone(), event.clone())
  };
  if *event != "push" {
    return Ok("not a push event, but thanks anyway".into());
  }
  if !deploy::check_signature(r, &signature, &SECRET) {
    let mut res = Response::new("invalid signature");
    res.status_code = 401;
    return Ok(res);
  }
  Ok("okay".into())
}

fn main() {
  dotenv().ok();
  let mut app = Pencil::new("/static");
  app.get("/deploy", "deploy", deploy_webhook);
  app.run("0.0.0.0:32260");
}
<commit_msg>fix: listen for post events<commit_after>extern crate dotenv;
extern crate deploy;
extern crate pencil;
#[macro_use] extern crate lazy_static;

use dotenv::dotenv;
use std::env;
use pencil::{Pencil, Response, Request, PencilResult};
use deploy::*;

lazy_static! {
  pub static ref SECRET: String = env::var("TENJAVA_DEPLOY_SECRET").expect("no deploy secret set");
}

fn deploy_webhook(r: &mut Request) -> PencilResult {
  let (signature, event) = {
    let headers = r.headers();
    let signature: &XHubSignature = headers.get().unwrap();
    let event: &XGitHubEvent = headers.get().unwrap();
    (signature.clone(), event.clone())
  };
  if *event != "push" {
    return Ok("not a push event, but thanks anyway".into());
  }
  if !deploy::check_signature(r, &signature, &SECRET) {
    let mut res = Response::new("invalid signature");
    res.status_code = 401;
    return Ok(res);
  }
  Ok("okay".into())
}

fn main() {
  dotenv().ok();
  let mut app = Pencil::new("/static");
  app.post("/deploy", "deploy", deploy_webhook);
  app.run("0.0.0.0:32260");
}
<|endoftext|>


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

struct Disk {
    weight : usize,
}

impl Disk {
    pub fn new(weight: usize) -> Disk {
        Disk { weight : weight }
    }

    pub fn weight(&self) -> usize {
        self.weight
    }
}

impl Display for Disk {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("[{0}]", iter::repeat("#").take(self.weight()).collect::<String>()))
    }
}

struct Rod {
    stack : Vec<Disk>,
}

impl Rod {
    pub fn new(sizes : &[usize]) -> Rod {
        Rod { stack : sizes.iter().map(|x| Disk::new(*x) ).collect::<Vec<_>>() }
    }

    fn can_move_disk(&self, disk : &Disk) -> bool {
        match self.stack.last() {
            None => true,
            Some(t) => t.weight() > disk.weight(),
        }
    }

    pub fn can_move(&self, other: &Rod) -> bool {
        false // self.can_take_disk(&other.stack.last())
    }

    pub fn swap(& mut self, other: &mut Rod) -> &mut Self {
        self
    }

}

struct Desk {
    rods : Vec<Rod>,
}

impl Desk {
    pub fn new(rods: &[&[usize]]) -> Desk {
        Desk { rods : rods.iter().map(|x| Rod::new(*x) ).collect::<Vec<_>>() }
    }
}

impl Display for Desk {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        let max_weight : usize =
            self.rods.iter()
                .map(|r| r.stack.iter().map(|s| s.weight()).max().unwrap_or(0))
                .max().unwrap_or(0);
        let height = max_weight + 1;

        let dup = |s: &str, n: usize| iter::repeat(s).take(n).collect::<String>();
        let mut display : Vec<String> = Vec::new();

        for i in 0..height {
            let mut s : String = "  ".to_string();

            for rod in &self.rods {
                let tmp = match rod.stack.get(i) {
                    None => format!("{0}|{0}", dup(" ", max_weight + 1)),
                    Some(disk) => format!("{1}[{0}|{0}]{1}", dup("#", disk.weight()), dup(" ", max_weight - disk.weight())),
                };
                s.push_str(" ");
                s.push_str(&tmp);
            }

            s.push_str("  ");
            s.push_str("\n");
            display.push(s);
        }

        display.reverse();
        f.write_fmt(format_args!("{0}", display.connect("")))
    }
}

fn main() {
    let desk1 = Desk::new(&[
        &[4, 3],
        &[2, 1]
    ]);
    println!("{0}", desk1);

}
<commit_msg>Initial skeleton<commit_after>use std::fmt;
use std::fmt::Display;
use std::iter;
use std::io;

struct Disk {
    weight : usize,
}

impl Disk {
    pub fn new(weight: usize) -> Disk {
        Disk { weight : weight }
    }

    pub fn weight(&self) -> usize {
        self.weight
    }
}

impl Display for Disk {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("[{0}]", iter::repeat("#").take(self.weight()).collect::<String>()))
    }
}

struct Rod {
    stack : Vec<Disk>,
}

impl Rod {
    pub fn new(sizes : &[usize]) -> Rod {
        Rod { stack : sizes.iter().map(|x| Disk::new(*x) ).collect::<Vec<_>>() }
    }

    fn can_move_disk(&self, disk : &Disk) -> bool {
        match self.stack.last() {
            None => true,
            Some(t) => t.weight() > disk.weight(),
        }
    }

    pub fn can_move(&self, other: &Rod) -> bool {
        match other.stack.last() {
            None => false,
            Some(ref disk) => self.can_move_disk(disk)
        }
    }

    pub fn take_from(& mut self, other: &mut Rod) -> bool {
        if !self.can_move(other) {
            self.stack.push(other.stack.pop().expect("can_move returned true"));
            true
        } else {
            false
        }
    }

}

struct Desk {
    rods : Vec<Rod>,
}

impl Desk {
    pub fn new(rods: &[&[usize]]) -> Desk {
        Desk { rods : rods.iter().map(|x| Rod::new(*x) ).collect::<Vec<_>>() }
    }

    pub fn is_done(&self) -> bool {
        self.rods.iter().take(self.rods.len() -1).all(|r| r.stack.is_empty())
    }

    fn _take_give(&mut self, from: usize, to: usize) -> bool {
        assert!(from < to);
        let (x, y) = self.rods.split_at_mut(to);

        let from_rod = x.get_mut(from);
        let to_rod = y.get_mut(0);

        match (to_rod, from_rod) {
            (Some(a), Some(b)) => a.take_from(b),
            _ => false,
        }
    }

    pub fn move_disk(&mut self, from: usize, to: usize) -> bool {
        if from == to {
            false
        } else if from < to {
            self._take_give(from, to)
        } else {
            self._take_give(to, from)
        }
    }
}

impl Display for Desk {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        let max_weight : usize =
            self.rods.iter()
                .map(|r| r.stack.iter().map(|s| s.weight()).max().unwrap_or(0))
                .max().unwrap_or(0);
        let height = max_weight + 2;

        let dup = |s: &str, n: usize| iter::repeat(s).take(n).collect::<String>();
        let mut display : Vec<String> = Vec::new();

        for i in 0..height {
            let mut s : String = "  ".to_string();

            for rod_index in (0..self.rods.len()) {
                let rod = &self.rods[rod_index];
                let tmp = match rod.stack.get(i) {
                    None => format!("{0}{1}{0}", dup(" ", max_weight + 1), if i == height -1 {(rod_index+1).to_string()} else {"|".to_string()}),
                    Some(disk) => format!("{1}[{0}|{0}]{1}", dup("#", disk.weight()), dup(" ", max_weight - disk.weight())),
                };
                s.push_str(" ");
                s.push_str(&tmp);
            }

            s.push_str("  ");
            s.push_str("\n");
            display.push(s);
        }

        display.reverse();
        display.push(dup("-", 2 + 2 + (self.rods.len() +1) * max_weight * 2) + "\n");
        f.write_fmt(format_args!("{0}", display.connect("")))
    }
}

fn read_move() ->(usize, usize) {
    let buffer = &mut String::with_capacity(32);
    let _ = io::stdin().read_line(buffer)
        .ok()
        .expect("Failed to read line");

    let splits = buffer.trim().split(' ').collect::<Vec<&str>>();
    let from = splits[0].trim().parse::<usize>().unwrap_or(1);
    let to = splits[1].trim().parse::<usize>().unwrap_or(1);

    (from, to)
}

fn main() {
    let desk = &mut Desk::new(&[
        &[10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
        &[],
        &[]
    ]);

    while !desk.is_done() {
        println!("{0}", desk);

        println!("Your move: [from] [to]");
        let (from, to) = read_move();
        println!("Moving from {0} -> {1}", from, to);
        desk.move_disk(from -1, to -1);
    }

    println!("Game over, you win");
}
<|endoftext|>


<commit_before>use actix_web::{web, HttpRequest, HttpResponse};
#[cfg(not(feature = "lambda"))]
use actix_web::{App, HttpServer};
#[cfg(not(feature = "lambda"))]
use log::info;
#[cfg(not(feature = "lambda"))]
use std::env;

mod arrivals;
mod common;
mod favourite;
mod id;
mod nearby;
mod search;

async fn root_handler(request: HttpRequest) -> HttpResponse {
    let data = common::mustache_favourites(&request);
    common::render_to_response("resources/templates/root.mustache", &data)
}

fn config(cfg: &mut web::ServiceConfig) {
    cfg.route("/", web::get().to(root_handler))
        .route("/search", web::get().to(search::search_handler))
        .route("/id/{id}", web::get().to(id::id_handler))
        .route("/nearby", web::get().to(nearby::nearby_handler))
        .route("/favourites", web::get().to(favourite::list_favourites))
        .route("/favourites", web::post().to(favourite::add_favourite))
        .route("/favourite-remove", web::post().to(favourite::remove_favourite))
        .route("/arrivals/{stopid}", web::get().to(arrivals::arrivals_handler));
}

#[cfg(not(feature = "lambda"))]
#[actix_rt::main]
async fn main() {
    log4rs::init_file("log.yaml", Default::default()).unwrap();
    let port = env::var("PORT")
        .unwrap_or("8000".to_string())
        .parse::<u16>()
        .unwrap();
    let mut server = HttpServer::new(|| App::new().configure(config));
    for iface in get_if_addrs::get_if_addrs().unwrap() {
        let ip = iface.ip();
        info!("Listening on {}:{} for {}", ip, port, iface.name);
        server = server.bind((ip, port)).unwrap();
    }
    server.run().await.unwrap();
}

#[cfg(feature = "lambda")]
fn main() {
    env_logger::try_init().unwrap_or_default();
    actix_lambda::run(config);
}

#[cfg(test)]
mod tests {
    use std::fs::{File, create_dir};
    use std::path::PathBuf;
    use std::thread;

    #[cfg(feature = "lambda")]
    use super::main;
    use super::{common, config};
    #[cfg(feature = "lambda")]
    use actix_lambda;
    use actix_web::{test, App};
    use serde::{Deserialize, Serialize};
    use wiremock::matchers::any;
    use wiremock::{Mock, MockServer, Request, ResponseTemplate};

    #[cfg(feature = "lambda")]
    #[test]
    fn lambda_test() {
        actix_lambda::test::lambda_test(main);
    }

    #[derive(Serialize, Deserialize, Debug)]
    struct StoredResponse {
        response_code: u16,
        content: String,
    }

    #[tokio::test]
    async fn simple_search() {
        env_logger::try_init().unwrap_or_default();
        let app = test::init_service(App::new().configure(config)).await;
        let mock_server = MockServer::start().await;
        Mock::given(any())
            .respond_with(|req: &Request| {
                let mut data_path = PathBuf::new();
                data_path.push("tests");
                if !data_path.exists() {
                    create_dir(&data_path).unwrap();
                }
                data_path.push(
                    &format!(
                        "{}-query-{}.json",
                        req.url.path(),
                        req.url.query().unwrap_or("None")
                    )
                    .replace("/", "_")[1..],
                );
                if !data_path.exists() {
                    let url = format!(
                        "https://api.tfl.gov.uk{}?{}",
                        req.url.path(),
                        req.url.query().unwrap_or("")
                    );
                    let local_data_path = data_path.to_string_lossy().to_string();
                    thread::spawn(move || {
                        let real_data = reqwest::blocking::get(url).unwrap();
                        let sr = StoredResponse {
                            response_code: real_data.status().as_u16(),
                            content: real_data.text().unwrap(),
                        };
                        serde_json::to_writer(File::create(local_data_path).unwrap(), &sr).unwrap();
                    })
                    .join()
                    .unwrap();
                }
                let sr: StoredResponse = serde_json::from_reader(File::open(&data_path).unwrap()).unwrap();
                ResponseTemplate::new(sr.response_code).set_body_string(sr.content)
            })
            .mount(&mock_server)
            .await;
        common::set_client(&mock_server.uri());
        let request = test::TestRequest::with_uri("/search?query=foo").to_request();
        let response = test::call_service(&app, request).await;
        assert!(response.status().is_success(), "{}", response.status());
        let body = String::from_utf8(test::read_body(response).await.to_vec()).unwrap();
        assert!(body.find("<title>Search: foo</title>").is_some(), "{}", body);
    }
}
<commit_msg>Fix format<commit_after>use actix_web::{web, HttpRequest, HttpResponse};
#[cfg(not(feature = "lambda"))]
use actix_web::{App, HttpServer};
#[cfg(not(feature = "lambda"))]
use log::info;
#[cfg(not(feature = "lambda"))]
use std::env;

mod arrivals;
mod common;
mod favourite;
mod id;
mod nearby;
mod search;

async fn root_handler(request: HttpRequest) -> HttpResponse {
    let data = common::mustache_favourites(&request);
    common::render_to_response("resources/templates/root.mustache", &data)
}

fn config(cfg: &mut web::ServiceConfig) {
    cfg.route("/", web::get().to(root_handler))
        .route("/search", web::get().to(search::search_handler))
        .route("/id/{id}", web::get().to(id::id_handler))
        .route("/nearby", web::get().to(nearby::nearby_handler))
        .route("/favourites", web::get().to(favourite::list_favourites))
        .route("/favourites", web::post().to(favourite::add_favourite))
        .route("/favourite-remove", web::post().to(favourite::remove_favourite))
        .route("/arrivals/{stopid}", web::get().to(arrivals::arrivals_handler));
}

#[cfg(not(feature = "lambda"))]
#[actix_rt::main]
async fn main() {
    log4rs::init_file("log.yaml", Default::default()).unwrap();
    let port = env::var("PORT")
        .unwrap_or("8000".to_string())
        .parse::<u16>()
        .unwrap();
    let mut server = HttpServer::new(|| App::new().configure(config));
    for iface in get_if_addrs::get_if_addrs().unwrap() {
        let ip = iface.ip();
        info!("Listening on {}:{} for {}", ip, port, iface.name);
        server = server.bind((ip, port)).unwrap();
    }
    server.run().await.unwrap();
}

#[cfg(feature = "lambda")]
fn main() {
    env_logger::try_init().unwrap_or_default();
    actix_lambda::run(config);
}

#[cfg(test)]
mod tests {
    use std::fs::{create_dir, File};
    use std::path::PathBuf;
    use std::thread;

    #[cfg(feature = "lambda")]
    use super::main;
    use super::{common, config};
    #[cfg(feature = "lambda")]
    use actix_lambda;
    use actix_web::{test, App};
    use serde::{Deserialize, Serialize};
    use wiremock::matchers::any;
    use wiremock::{Mock, MockServer, Request, ResponseTemplate};

    #[cfg(feature = "lambda")]
    #[test]
    fn lambda_test() {
        actix_lambda::test::lambda_test(main);
    }

    #[derive(Serialize, Deserialize, Debug)]
    struct StoredResponse {
        response_code: u16,
        content: String,
    }

    #[tokio::test]
    async fn simple_search() {
        env_logger::try_init().unwrap_or_default();
        let app = test::init_service(App::new().configure(config)).await;
        let mock_server = MockServer::start().await;
        Mock::given(any())
            .respond_with(|req: &Request| {
                let mut data_path = PathBuf::new();
                data_path.push("tests");
                if !data_path.exists() {
                    create_dir(&data_path).unwrap();
                }
                data_path.push(
                    &format!(
                        "{}-query-{}.json",
                        req.url.path(),
                        req.url.query().unwrap_or("None")
                    )
                    .replace("/", "_")[1..],
                );
                if !data_path.exists() {
                    let url = format!(
                        "https://api.tfl.gov.uk{}?{}",
                        req.url.path(),
                        req.url.query().unwrap_or("")
                    );
                    let local_data_path = data_path.to_string_lossy().to_string();
                    thread::spawn(move || {
                        let real_data = reqwest::blocking::get(url).unwrap();
                        let sr = StoredResponse {
                            response_code: real_data.status().as_u16(),
                            content: real_data.text().unwrap(),
                        };
                        serde_json::to_writer(File::create(local_data_path).unwrap(), &sr).unwrap();
                    })
                    .join()
                    .unwrap();
                }
                let sr: StoredResponse = serde_json::from_reader(File::open(&data_path).unwrap()).unwrap();
                ResponseTemplate::new(sr.response_code).set_body_string(sr.content)
            })
            .mount(&mock_server)
            .await;
        common::set_client(&mock_server.uri());
        let request = test::TestRequest::with_uri("/search?query=foo").to_request();
        let response = test::call_service(&app, request).await;
        assert!(response.status().is_success(), "{}", response.status());
        let body = String::from_utf8(test::read_body(response).await.to_vec()).unwrap();
        assert!(body.find("<title>Search: foo</title>").is_some(), "{}", body);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate staticfile;
extern crate docopt;
extern crate serde;

use serde::Deserialize;
use iron::Iron;
use staticfile::Static;
use docopt::Docopt;

const DEFAULT_PORT: u16 = 8080;
const USAGE: &'static str = "
Serve files in the current directory via HTTP.

Usage:
    serve [<port>]
    serve (-h | --help)

Options:
    -h, --help  Show this screen
";

#[derive(Deserialize)]
struct Args {
    arg_port: Option<u16>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|dopt| dopt.deserialize())
                            .unwrap_or_else(|e| e.exit());

    let port = args.arg_port.unwrap_or(DEFAULT_PORT);

    let addr = format!("localhost:{}", port);

    match Iron::new(Static::new(".")).http(&*addr) {
        Ok(_) => {
            println!("Listening on port {}", port);
        },
        Err(_) => {
            println!("Could not start server on port {}. \
                      Make sure that you have the required permissions \
                      and that the port is not already in use.", port);
        },
    }
}
<commit_msg>apply rustfmt<commit_after>extern crate docopt;
extern crate iron;
extern crate serde;
extern crate staticfile;

use docopt::Docopt;
use iron::Iron;
use serde::Deserialize;
use staticfile::Static;

const DEFAULT_PORT: u16 = 8080;
const USAGE: &'static str = "
Serve files in the current directory via HTTP.

Usage:
    serve [<port>]
    serve (-h | --help)

Options:
    -h, --help  Show this screen
";

#[derive(Deserialize)]
struct Args {
    arg_port: Option<u16>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|dopt| dopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let port = args.arg_port.unwrap_or(DEFAULT_PORT);

    let addr = format!("localhost:{}", port);

    match Iron::new(Static::new(".")).http(&*addr) {
        Ok(_) => {
            println!("Listening on port {}", port);
        }
        Err(_) => {
            println!(
                "Could not start server on port {}. \
                      Make sure that you have the required permissions \
                      and that the port is not already in use.",
                port
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::{DefaultHasher};
use std::collections::HashMap;
use std::fs::{File, read_dir};
use std::io::Result;
use std::env;

fn get_file_content(path: String) -> Result<String> {
    let mut f = File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

fn get_file_hash(text: String) -> u64 {
    let mut hasher = DefaultHasher::new();

    text.into_bytes().hash(&mut hasher);

    hasher.finish()
}

fn get_file_paths(dir: String) -> Result<Vec<std::path::PathBuf>> {
    let dir_list = read_dir(dir)?;
    let mut files_paths = vec![];

    for item in dir_list {
        let i = item?.path();

        if *&i.is_file() {
            files_paths.push(i);
        }
    }

    Ok(files_paths)
}

fn print_duplicats(duplicates: Vec<String>) {
    if duplicates.len() == 0 {
        println!("Duplicates not founded");
        return ();
    }

    println!("Duplicates ({}): ", duplicates.len());

    for path in duplicates {
        println!("{}", path);
    }
}

fn main() {
    let dir_path = env::args().nth(1).unwrap().to_string();
    let files = get_file_paths(dir_path).unwrap();
    let mut store = HashMap::new();
    let mut duplicates: Vec<String> = vec![];

    for file in &files {
        let file_path = file.to_str().unwrap();
        let file_content = get_file_content(file_path.to_string()).unwrap();
        let hash = get_file_hash(file_content);

        if !store.contains_key(&hash) {
            store.insert(hash, file_path);
        } else {
            duplicates.push(file_path.to_string());
        }
    }

    print_duplicats(duplicates);
}
<commit_msg>moved finding duplicates functionality in a single function<commit_after>use std::io::prelude::*;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::{DefaultHasher};
use std::collections::HashMap;
use std::fs::{File, read_dir};
use std::io::Result;
use std::env;
use std::path::PathBuf;

fn get_file_content(path: String) -> Result<String> {
    let mut f = File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

fn get_file_hash(text: String) -> u64 {
    let mut hasher = DefaultHasher::new();

    text.into_bytes().hash(&mut hasher);

    hasher.finish()
}

fn get_file_paths(dir: String) -> Result<Vec<PathBuf>> {
    let dir_list = read_dir(dir)?;
    let mut files_paths = vec![];

    for item in dir_list {
        let i = item?.path();

        if *&i.is_file() {
            files_paths.push(i);
        }
    }

    Ok(files_paths)
}

fn print_duplicats(duplicates: Vec<String>) {
    if duplicates.len() == 0 {
        println!("Duplicates not founded");
        return ();
    }

    println!("Duplicates ({}): ", duplicates.len());

    for path in duplicates {
        println!("{}", path);
    }
}

fn find_duplicates(files: Vec<PathBuf>) -> Vec<String> {
    let mut store = HashMap::new();
    let mut duplicates: Vec<String> = vec![];

    for file in &files {
        let file_path = file.to_str().unwrap();
        let file_content = get_file_content(file_path.to_string()).unwrap();
        let hash = get_file_hash(file_content);

        if !store.contains_key(&hash) {
            store.insert(hash, file_path);
        } else {
            duplicates.push(file_path.to_string());
        }
    }

    duplicates
}

fn main() {
    let dir_path = env::args().nth(1).unwrap().to_string();
    let files = get_file_paths(dir_path).unwrap();
    let duplicates = find_duplicates(files);

    print_duplicats(duplicates);
}
<|endoftext|>


<commit_before>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

fn main() {
    println!("Hello, world!");
}
<commit_msg>Accepting Connections<commit_after>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate rusqlite;
extern crate time;

use std::net::{SocketAddr, UdpSocket};
use std::rand;
use std::rand::Rng;
use std::sync::Arc;
use std::thread::Thread;

use rusqlite::SqliteConnection;

#[repr(C)]
struct PacketHeader {
    connection_id:  u64,
    action:         u32,
    transaction_id: u32,
}

fn gen_uuid() -> u64 {
    let mut rng = rand::thread_rng();
    let mut uuid = time::precise_time_ns();
    uuid <<= 32;
    uuid | (rng.gen::<u32>() as u64)
}

fn parse_header(packet: &[u8]) -> PacketHeader {
    let p_con_id            = &packet[0..7];
    let p_action            = &packet[8..11];
    let p_tran_id           = &packet[12..15];

    let mut connection_id:  u64 = 0;
    let mut action:         u32 = 0;
    let mut transaction_id: u32 = 0;

    for i in p_con_id.iter() {
        connection_id <<= 8;
        connection_id |= (*i as u64);
    }

    for i in p_action.iter() {
        action <<= 8;
        action |= (*i as u32);
    }

    for i in p_tran_id.iter() {
        transaction_id <<= 8;
        transaction_id |= (*i as u32);
    }

    PacketHeader {connection_id: connection_id, action: action, transaction_id: transaction_id}
}

fn init_db(path: &'static str) -> SqliteConnection {
    let conn = SqliteConnection::open(path).unwrap();
    conn.execute_batch(
        "BEGIN;
        CREATE TABLE IF NOT EXISTS users (
            uuid          INTEGER PRIMARY KEY,
            last_active   INTEGER
        );
        CREATE TABLE IF NOT EXISTS torrent (
            info_hash   TEXT,
            uuid        INTEGER,
            downloaded  INTEGER,
            uploaded    INTEGER,
            remaining   INTEGER,
            PRIMARY KEY (info_hash, uuid)
            FOREIGN KEY(uuid) REFERENCES users(uuid)
        );
        COMMIT;"
    ).unwrap();
    conn
}

fn create_connection(conn: &SqliteConnection) {
    // Cool Story, we got a new connection.
    // We need to generate an unique id for this client.
    // 32bits of the current time in nanoseconds combined with 32bits of
    // random numbers
    let uuid = gen_uuid() as i64;
    conn.execute(
        "INSERT OR REPLACE INTO users (uuid, last_active) VALUES ($1, strftime('%s', 'now'))",
        &[&uuid]
    ).unwrap();
}

fn handle_packet(src: &SocketAddr, amt: usize, packet: [u8; 2048], conn: &SqliteConnection) {
    let header = parse_header(&packet[0..15]);

    if header.connection_id == 17568305177 {
        create_connection(conn);
        return
    }
}

fn main() {
    let DATABASE_PATH = "file::memory:?cache=shared";

    // Let's first initialize the database.
    let conn = init_db(DATABASE_PATH);
    let mut sock = UdpSocket::bind("127.0.0.1:6969").unwrap();

    loop {
        let mut buf = [0; 2048];
        let (amt, src) = sock.recv_from(&mut buf).unwrap();
        Thread::spawn(move|| {
            let conn = SqliteConnection::open(DATABASE_PATH).unwrap();
            handle_packet(&src, amt, buf, &conn);
            conn.close();
        });
    }
    conn.close();
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate image;
extern crate serde_json;
extern crate vegas_lattice;

use std::error::Error;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;

use docopt::{ArgvMap, Docopt};
use vegas_lattice::{Axis, Lattice, Mask};

const USAGE: &'static str = "
Vegas lattice.

Usage:
    vegas-lattice check [<input>]
    vegas-lattice compress [<input>]
    vegas-lattice drop [-x -y -z] [<input>]
    vegas-lattice expand [--x=<x> --y=<y> --z=<z>] [<input>]
    vegas-lattice mask [--ppu=<ppu>] <mask> [<input>]
    vegas-lattice into xyz [<input>]
    vegas-lattice (-h | --help)
    vegas-lattice --version

Options:
    -p=<ppu> --ppu=<ppu>        Pixels per unit [default: 10].
    -h --help       Show this message.
    --version       Show version and exit.
";

fn read(input: &str) -> Result<Lattice, Box<Error>> {
    let mut data = String::new();
    if !input.is_empty() {
        let mut file = File::open(input)?;
        file.read_to_string(&mut data)?;
    } else {
        io::stdin().read_to_string(&mut data)?;
    };
    let lattice: Lattice = data.parse()?;
    Ok(lattice)
}

fn write_compressed(lattice: Lattice) {
    println!("{}", serde_json::to_string(&lattice).unwrap());
}

fn write(lattice: Lattice) {
    println!("{}", serde_json::to_string_pretty(&lattice).unwrap());
}

fn check_error(res: Result<(), Box<Error>>) {
    match res {
        Err(e) => {
            eprintln!("Error: {}", e.description());
            match e.cause() {
                Some(cause) => eprintln!("Cause: {}", cause),
                _ => ()
            };
            std::process::exit(1);
        },
        _ => {},
    }
}

// Commands over here

fn check(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write(lattice);
    Ok(())
}

fn compress(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write_compressed(lattice);
    Ok(())
}

fn drop(args: ArgvMap) -> Result<(), Box<Error>> {
    let mut lattice = read(args.get_str("<input>"))?;
    for (key, axis) in Axis::map(Some("-".to_string())) {
        if args.get_bool(&key) {
            lattice = lattice.drop(axis);
        }
    }
    write(lattice);
    Ok(())
}

fn expand(args: ArgvMap) -> Result<(), Box<Error>> {
    let map = Axis::map(Some("--".to_string()));
    let mut lattice = read(args.get_str("<input>"))?;
    for (flag, axis) in map.into_iter() {
        let string_value = args.get_str(&flag);
        if !string_value.is_empty() {
            let size: usize = string_value.parse()?;
            lattice = lattice.expand_along(axis, size);
        }
    }
    write(lattice);
    Ok(())
}

fn mask(args: ArgvMap) -> Result<(), Box<Error>> {
    let path = args.get_str("<mask>");
    let ppu: f64 = args.get_str("--ppu").parse()?;
    let mask = Mask::new(&Path::new(path), ppu)?;
    let mut lattice = read(args.get_str("<input>"))?;
    lattice = lattice.apply_mask(mask);
    write(lattice);
    Ok(())
}

fn into(args: ArgvMap) -> Result<(), Box<Error>> {
    if args.get_bool("xyz") {
        let lattice = read(args.get_str("<input>"))?;
        for site in lattice.sites().iter() {
            let (x, y, z) = site.position;
            println!("{} {} {} {}", x, y, z, site.kind)
        }
    }
    Ok(())
}

fn main() {
    let args = Docopt::new(USAGE)
        .and_then(|doc| doc.version(Some("0.0.1".to_string())).parse())
        .unwrap_or_else(|e| e.exit());

    if args.get_bool("check") {
        check_error(check(args));
    } else if args.get_bool("compress") {
        check_error(compress(args));
    } else if args.get_bool("drop") {
        check_error(drop(args));
    } else if args.get_bool("expand") {
        check_error(expand(args));
    } else if args.get_bool("mask") {
        check_error(mask(args));
    } else if args.get_bool("into") {
        check_error(into(args));
    } else {
        println!("{:?}", args);
    }
}<commit_msg>Chean up docopt<commit_after>extern crate docopt;
extern crate image;
extern crate serde_json;
extern crate vegas_lattice;

use std::error::Error;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;

use docopt::{ArgvMap, Docopt};
use vegas_lattice::{Axis, Lattice, Mask};

const USAGE: &'static str = "
Vegas lattice.

Usage:
    vegas-lattice check [<input>]
    vegas-lattice compress [<input>]
    vegas-lattice drop [-x -y -z] [<input>]
    vegas-lattice expand [--x=<x> --y=<y> --z=<z>] [<input>]
    vegas-lattice mask [--ppu=<ppu>] <mask> [<input>]
    vegas-lattice into xyz [<input>]
    vegas-lattice (-h | --help)
    vegas-lattice --version

Options:
    --ppu=<ppu>     Pixels per unit [default: 10].
    -h --help       Show this message.
    --version       Show version and exit.
";

fn read(input: &str) -> Result<Lattice, Box<Error>> {
    let mut data = String::new();
    if !input.is_empty() {
        let mut file = File::open(input)?;
        file.read_to_string(&mut data)?;
    } else {
        io::stdin().read_to_string(&mut data)?;
    };
    let lattice: Lattice = data.parse()?;
    Ok(lattice)
}

fn write_compressed(lattice: Lattice) {
    println!("{}", serde_json::to_string(&lattice).unwrap());
}

fn write(lattice: Lattice) {
    println!("{}", serde_json::to_string_pretty(&lattice).unwrap());
}

fn check_error(res: Result<(), Box<Error>>) {
    match res {
        Err(e) => {
            eprintln!("Error: {}", e.description());
            match e.cause() {
                Some(cause) => eprintln!("Cause: {}", cause),
                _ => ()
            };
            std::process::exit(1);
        },
        _ => {},
    }
}

// Commands over here

fn check(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write(lattice);
    Ok(())
}

fn compress(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write_compressed(lattice);
    Ok(())
}

fn drop(args: ArgvMap) -> Result<(), Box<Error>> {
    let mut lattice = read(args.get_str("<input>"))?;
    for (key, axis) in Axis::map(Some("-".to_string())) {
        if args.get_bool(&key) {
            lattice = lattice.drop(axis);
        }
    }
    write(lattice);
    Ok(())
}

fn expand(args: ArgvMap) -> Result<(), Box<Error>> {
    let map = Axis::map(Some("--".to_string()));
    let mut lattice = read(args.get_str("<input>"))?;
    for (flag, axis) in map.into_iter() {
        let string_value = args.get_str(&flag);
        if !string_value.is_empty() {
            let size: usize = string_value.parse()?;
            lattice = lattice.expand_along(axis, size);
        }
    }
    write(lattice);
    Ok(())
}

fn mask(args: ArgvMap) -> Result<(), Box<Error>> {
    let path = args.get_str("<mask>");
    let ppu: f64 = args.get_str("--ppu").parse()?;
    let mask = Mask::new(&Path::new(path), ppu)?;
    let mut lattice = read(args.get_str("<input>"))?;
    lattice = lattice.apply_mask(mask);
    write(lattice);
    Ok(())
}

fn into(args: ArgvMap) -> Result<(), Box<Error>> {
    if args.get_bool("xyz") {
        let lattice = read(args.get_str("<input>"))?;
        for site in lattice.sites().iter() {
            let (x, y, z) = site.position;
            println!("{} {} {} {}", x, y, z, site.kind)
        }
    }
    Ok(())
}

fn main() {
    let args = Docopt::new(USAGE)
        .and_then(|doc| doc.version(Some("0.0.1".to_string())).parse())
        .unwrap_or_else(|e| e.exit());

    if args.get_bool("check") {
        check_error(check(args));
    } else if args.get_bool("compress") {
        check_error(compress(args));
    } else if args.get_bool("drop") {
        check_error(drop(args));
    } else if args.get_bool("expand") {
        check_error(expand(args));
    } else if args.get_bool("mask") {
        check_error(mask(args));
    } else if args.get_bool("into") {
        check_error(into(args));
    } else {
        println!("{:?}", args);
    }
}<|endoftext|>