<commit_before>extern crate iron;
extern crate router;
extern crate urlencoded;
extern crate redis;
extern crate image;
extern crate num;
extern crate time;

use std::io;
use time::precise_time_ns;
use iron::prelude::*;
use iron::{
    BeforeMiddleware,
    AfterMiddleware,
    typemap
};
use iron::mime::Mime;
use iron::status;
use iron::modifier::Modifier;
use iron::response;
use urlencoded::UrlEncodedQuery;
use router::Router;
use redis::Commands;
use image::{
    ImageBuffer,
};
use num::complex::Complex;

fn fetch_an_integer(key: &str, inc: bool) -> redis::RedisResult<i64> {
    // connect to redis
    let client = try!(redis::Client::open("redis://127.0.0.1/"));
    let con = try!(client.get_connection());
    if inc {
        let cur = con.get(key).unwrap_or(0i64);
        let _ : () = try!(con.set(key, cur+1));
    }
    con.get(key)
}

// from: https://github.com/iron/iron/blob/master/examples/time.rs
struct ResponseTime;

impl typemap::Key for ResponseTime { type Value = u64; }

impl BeforeMiddleware for ResponseTime {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<ResponseTime>(precise_time_ns());
        Ok(())
    }
}

impl AfterMiddleware for ResponseTime {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        let delta = precise_time_ns() - *req.extensions.get::<ResponseTime>().unwrap();
        println!("Request took: {} ms", (delta as f64) / 1000000.0);
        Ok(res)
    }
}

// ImgWriter writes a generated image out to the request
struct ImgWriter {
    img: ImageBuffer<image::Luma<u8>, Vec<u8>>
}

impl Modifier<Response> for ImgWriter {
    fn modify(self, res: &mut Response) {
        res.body = Some(Box::new(self));
    }
}

impl response::WriteBody for ImgWriter {
    fn write_body(&mut self, res: &mut response::ResponseBody) -> io::Result<()> {
        image::ImageLuma8(self.img.clone()).save(res, image::PNG)
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

fn main() {
	fn handler(_: &mut Request) -> IronResult<Response> {
        let content = "Peekaboo server";
        let content_type = "text/html".parse::<Mime>().unwrap();
		Ok(Response::with((content_type, status::Ok, content)))
	}

    fn peek_handler(r: &mut Request) -> IronResult<Response> {
        {
            let id = r.extensions.get::<Router>().unwrap().find("id").unwrap();
            let _ = fetch_an_integer(id, true).unwrap_or(0i64);
        }

        let mut img = ImageBuffer::new(512, 512);
        let content_type = "image/png".parse::<Mime>().unwrap();

        match r.get_ref::<UrlEncodedQuery>() {
            Ok(ref hashmap) => {
                match hashmap.get("t").map(|t| &t[0]) {
                    Some(t) => {
                        if t == "mandelbrot" {
                            apply_mandelbrot(&mut img, 500);
                        } else if t == "julia" {
                            apply_julia(&mut img, 500);
                        }
                    },
                    None => {
                        return Ok(Response::with((status::NotFound, "type not found")))
                    },
                }
            },
            Err(urlencoded::UrlDecodingError::EmptyQuery) => {
                // turn the image white
                let mut img_sm = ImageBuffer::new(1, 1);
                apply_color(&mut img_sm, 255);
                return Ok(Response::with((content_type, status::Ok, ImgWriter{img: img_sm})))
            },
            Err(ref e) => {
                return Ok(Response::with((status::BadRequest, format!("invalid query: {}", e))))
            }
        }

        Ok(Response::with((content_type, status::Ok, ImgWriter{img: img})))
    }

    fn peek_info_handler(r: &mut Request) -> IronResult<Response> {
        let id = r.extensions.get::<Router>().unwrap().find("id").unwrap();
        let val = fetch_an_integer(id, false).unwrap_or(0i64);

        Ok(Response::with((status::Ok, format!("'{}' has had {} visitors!", id, val))))
    }

    let mut peek_chain = Chain::new(peek_handler);
    peek_chain.link_before(ResponseTime);
    peek_chain.link_after(ResponseTime);

    let mut router = Router::new();
    router.get("/", handler);
    router.get("/peek/:id", peek_chain);
    router.get("/peek/:id/info", peek_info_handler);

	Iron::new(router).http("localhost:2829").unwrap();
}

fn apply_color(img: &mut ImageBuffer<image::Luma<u8>, Vec<u8>>, value: u8) {
    for (_, _, pixel) in img.enumerate_pixels_mut() {
        *pixel = image::Luma([value]);
    }
}

fn apply_mandelbrot(img: &mut ImageBuffer<image::Luma<u8>, Vec<u8>>, max_iters: i64) {

    // from: https://en.wikipedia.org/wiki/Mandelbrot_set#Escape_time_algorithm

    let scalex = 3.5 / img.width() as f32;
    let scaley = 2.0 / img.height() as f32;

    for (x, y, pixel) in img.enumerate_pixels_mut() {

        let x0 = x as f32 * scalex - 2.5;
        let y0 = y as f32 * scaley - 1.0;

        let mut z = Complex::new(x0, y0);
        // let c = z.clone();

        let mut iters = 0;
        for _ in 0..max_iters {
            if z.norm() > 2.0 {
                break
            }
            let xt = z.re * z.re - z.im * z.im + x0;
            z.im = 2.0*z.re*z.im + y0;
            z.re = xt;

            // for some reason this is about 2x slower
            // z = z * z + c;

            iters += 1;
        }

        *pixel = image::Luma([iters as u8]);
    }
}

fn apply_julia(img: &mut ImageBuffer<image::Luma<u8>, Vec<u8>>, max_iters: i64) {

    // from: https://github.com/PistonDevelopers/image#62-generating-fractals

    let scalex = 4.0 / img.width() as f32;
    let scaley = 4.0 / img.height() as f32;

    for (x, y, pixel) in img.enumerate_pixels_mut() {

        let cy = y as f32 * scaley - 2.0;
        let cx = x as f32 * scalex - 2.0;

        let mut z = Complex::new(cx, cy);
        let c = Complex::new(-0.4, 0.6);

        let mut i = 0;

        for t in 0..max_iters {
            if z.norm() > 2.0 {
                break
            }
            z = z * z + c;
            i = t;
        }

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([i as u8]);
    }
}
<commit_msg>cleanup imports<commit_after>extern crate iron;
extern crate router;
extern crate urlencoded;
extern crate redis;
extern crate image;
extern crate num;
extern crate time;

use std::io;
use time::precise_time_ns;
use iron::prelude::*;
use iron::{
    BeforeMiddleware,
    AfterMiddleware,
    typemap,
    status,
    response,
};
use iron::mime::Mime;
use iron::modifier::Modifier;
use urlencoded::UrlEncodedQuery;
use router::Router;
use redis::Commands;
use image::ImageBuffer;
use num::complex::Complex;

fn fetch_an_integer(key: &str, inc: bool) -> redis::RedisResult<i64> {
    // connect to redis
    let client = try!(redis::Client::open("redis://127.0.0.1/"));
    let con = try!(client.get_connection());
    if inc {
        let cur = con.get(key).unwrap_or(0i64);
        let _ : () = try!(con.set(key, cur+1));
    }
    con.get(key)
}

// from: https://github.com/iron/iron/blob/master/examples/time.rs
struct ResponseTime;

impl typemap::Key for ResponseTime { type Value = u64; }

impl BeforeMiddleware for ResponseTime {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<ResponseTime>(precise_time_ns());
        Ok(())
    }
}

impl AfterMiddleware for ResponseTime {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        let delta = precise_time_ns() - *req.extensions.get::<ResponseTime>().unwrap();
        println!("Request took: {} ms", (delta as f64) / 1000000.0);
        Ok(res)
    }
}

// ImgWriter writes a generated image out to the request
struct ImgWriter {
    img: ImageBuffer<image::Luma<u8>, Vec<u8>>
}

impl Modifier<Response> for ImgWriter {
    fn modify(self, res: &mut Response) {
        res.body = Some(Box::new(self));
    }
}

impl response::WriteBody for ImgWriter {
    fn write_body(&mut self, res: &mut response::ResponseBody) -> io::Result<()> {
        image::ImageLuma8(self.img.clone()).save(res, image::PNG)
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

fn main() {
	fn handler(_: &mut Request) -> IronResult<Response> {
        let content = "Peekaboo server";
        let content_type = "text/html".parse::<Mime>().unwrap();
		Ok(Response::with((content_type, status::Ok, content)))
	}

    fn peek_handler(r: &mut Request) -> IronResult<Response> {
        {
            let id = r.extensions.get::<Router>().unwrap().find("id").unwrap();
            let _ = fetch_an_integer(id, true).unwrap_or(0i64);
        }

        let mut img = ImageBuffer::new(512, 512);
        let content_type = "image/png".parse::<Mime>().unwrap();

        match r.get_ref::<UrlEncodedQuery>() {
            Ok(ref hashmap) => {
                match hashmap.get("t").map(|t| &t[0]) {
                    Some(t) => {
                        if t == "mandelbrot" {
                            apply_mandelbrot(&mut img, 500);
                        } else if t == "julia" {
                            apply_julia(&mut img, 500);
                        }
                    },
                    None => {
                        return Ok(Response::with((status::NotFound, "type not found")))
                    },
                }
            },
            Err(urlencoded::UrlDecodingError::EmptyQuery) => {
                // turn the image white
                let mut img_sm = ImageBuffer::new(1, 1);
                apply_color(&mut img_sm, 255);
                return Ok(Response::with((content_type, status::Ok, ImgWriter{img: img_sm})))
            },
            Err(ref e) => {
                return Ok(Response::with((status::BadRequest, format!("invalid query: {}", e))))
            }
        }

        Ok(Response::with((content_type, status::Ok, ImgWriter{img: img})))
    }

    fn peek_info_handler(r: &mut Request) -> IronResult<Response> {
        let id = r.extensions.get::<Router>().unwrap().find("id").unwrap();
        let val = fetch_an_integer(id, false).unwrap_or(0i64);

        Ok(Response::with((status::Ok, format!("'{}' has had {} visitors!", id, val))))
    }

    let mut peek_chain = Chain::new(peek_handler);
    peek_chain.link_before(ResponseTime);
    peek_chain.link_after(ResponseTime);

    let mut router = Router::new();
    router.get("/", handler);
    router.get("/peek/:id", peek_chain);
    router.get("/peek/:id/info", peek_info_handler);

	Iron::new(router).http("localhost:2829").unwrap();
}

fn apply_color(img: &mut ImageBuffer<image::Luma<u8>, Vec<u8>>, value: u8) {
    for (_, _, pixel) in img.enumerate_pixels_mut() {
        *pixel = image::Luma([value]);
    }
}

fn apply_mandelbrot(img: &mut ImageBuffer<image::Luma<u8>, Vec<u8>>, max_iters: i64) {

    // from: https://en.wikipedia.org/wiki/Mandelbrot_set#Escape_time_algorithm

    let scalex = 3.5 / img.width() as f32;
    let scaley = 2.0 / img.height() as f32;

    for (x, y, pixel) in img.enumerate_pixels_mut() {

        let x0 = x as f32 * scalex - 2.5;
        let y0 = y as f32 * scaley - 1.0;

        let mut z = Complex::new(x0, y0);
        // let c = z.clone();

        let mut iters = 0;
        for _ in 0..max_iters {
            if z.norm() > 2.0 {
                break
            }
            let xt = z.re * z.re - z.im * z.im + x0;
            z.im = 2.0*z.re*z.im + y0;
            z.re = xt;

            // for some reason this is about 2x slower
            // z = z * z + c;

            iters += 1;
        }

        *pixel = image::Luma([iters as u8]);
    }
}

fn apply_julia(img: &mut ImageBuffer<image::Luma<u8>, Vec<u8>>, max_iters: i64) {

    // from: https://github.com/PistonDevelopers/image#62-generating-fractals

    let scalex = 4.0 / img.width() as f32;
    let scaley = 4.0 / img.height() as f32;

    for (x, y, pixel) in img.enumerate_pixels_mut() {

        let cy = y as f32 * scaley - 2.0;
        let cx = x as f32 * scalex - 2.0;

        let mut z = Complex::new(cx, cy);
        let c = Complex::new(-0.4, 0.6);

        let mut i = 0;

        for t in 0..max_iters {
            if z.norm() > 2.0 {
                break
            }
            z = z * z + c;
            i = t;
        }

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([i as u8]);
    }
}
<|endoftext|>


<commit_before>extern crate clap;

extern crate serde_json;

extern crate integrity_checker;

use std::ffi::OsString;
use std::io::{self, Write};
use std::path::PathBuf;

use integrity_checker::database::{Database, DiffSummary};
use integrity_checker::error;

enum Action {
    Build { db_path: OsString, dir_path: OsString, threads: usize },
    Check { db_path: OsString, dir_path: OsString, threads: usize },
    Diff { old_path: OsString, new_path: OsString },
}

#[derive(Debug)]
enum ActionSummary {
    Built,
    Diff(DiffSummary),
}

fn validate_usize(s: String) -> Result<(), String> {
    s.parse::<usize>().map(|_| ()).map_err(|e| e.to_string())
}

fn parse_args() -> Action {
    let matches = clap::App::new("Integrity Checker")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(clap::SubCommand::with_name("build")
                    .about("Creates an integrity database from a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to create")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .arg(clap::Arg::with_name("threads")
                         .help("Number of threads to use")
                         .short("j").long("threads")
                         .takes_value(true)
                         .validator(validate_usize)))
        .subcommand(clap::SubCommand::with_name("check")
                    .about("Check an integrity database against a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to read")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .arg(clap::Arg::with_name("threads")
                         .help("Number of threads to use")
                         .short("j").long("threads")
                         .takes_value(true)
                         .validator(validate_usize)))
        .subcommand(clap::SubCommand::with_name("diff")
                    .about("Compare two integrity databases")
                    .arg(clap::Arg::with_name("old")
                         .help("Path of old integrity database")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("new")
                         .help("Path of new integrity database")
                         .required(true)
                         .index(2)))
        .after_help("RETURN CODE: \
                    \n    0       Success \
                    \n    1       Changes \
                    \n    2       Suspicious changes \
                    \n   -1       Error")
        .get_matches();
    match matches.subcommand() {
        ("build", Some(submatches)) => Action::Build {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            threads: match submatches.value_of("threads") {
                None => 1, // FIXME: Pick a reasonable number of threads
                Some(threads) => threads.parse().unwrap(),
            },
        },
        ("check", Some(submatches)) => Action::Check {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            threads: match submatches.value_of("threads") {
                None => 1, // FIXME: Pick a reasonable number of threads
                Some(threads) => threads.parse().unwrap(),
            },
        },
        ("diff", Some(submatches)) => Action::Diff {
            old_path: submatches.value_of_os("old").unwrap().to_owned(),
            new_path: submatches.value_of_os("new").unwrap().to_owned(),
        },
        _ => unreachable!(),
    }
}

fn driver() -> Result<ActionSummary, error::Error> {
    let action = parse_args();
    match action {
        Action::Build { db_path, dir_path, threads } => {
            let database = Database::build(&dir_path, true, threads)?;

            {
                let mut json_path = PathBuf::from(&db_path);
                json_path.set_extension("json.gz");
                database.dump_json(json_path)?;
            }

            Ok(ActionSummary::Built)
        }
        Action::Check { db_path, dir_path, threads } => {
            let mut json_path = PathBuf::from(&db_path);
            json_path.set_extension("json.gz");
            let database = Database::load_json(&json_path)?;
            Ok(ActionSummary::Diff(database.check(&dir_path, threads)?))
        }
        Action::Diff { old_path, new_path } => {
            let mut json_old_path = PathBuf::from(&old_path);
            json_old_path.set_extension("json.gz");
            let mut json_new_path = PathBuf::from(&new_path);
            json_new_path.set_extension("json.gz");
            let old = Database::load_json(&json_old_path)?;
            let new = Database::load_json(&json_new_path)?;
            Ok(ActionSummary::Diff(old.show_diff(&new)))
        }
    }
}

fn main() {
    ::std::process::exit(match driver() {
       Ok(action_summary) => match action_summary {
           ActionSummary::Built => 0,
           ActionSummary::Diff(DiffSummary::NoChanges) => 0,
           ActionSummary::Diff(DiffSummary::Changes) => 1,
           ActionSummary::Diff(DiffSummary::Suspicious) => 2,
       },
       Err(err) => {
           writeln!(io::stderr(), "error: {:?}", err).unwrap();
           -1
       },
    });
}
<commit_msg>Add a selfcheck command to test the internal consistency of a database.<commit_after>extern crate clap;

extern crate serde_json;

extern crate integrity_checker;

use std::ffi::OsString;
use std::io::{self, Write};
use std::path::PathBuf;

use integrity_checker::database::{Database, DiffSummary};
use integrity_checker::error;

enum Action {
    Build { db_path: OsString, dir_path: OsString, threads: usize },
    Check { db_path: OsString, dir_path: OsString, threads: usize },
    Diff { old_path: OsString, new_path: OsString },
    SelfCheck { db_path: OsString },
}

#[derive(Debug)]
enum ActionSummary {
    Built,
    Diff(DiffSummary),
}

fn validate_usize(s: String) -> Result<(), String> {
    s.parse::<usize>().map(|_| ()).map_err(|e| e.to_string())
}

fn parse_args() -> Action {
    let matches = clap::App::new("Integrity Checker")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(clap::SubCommand::with_name("build")
                    .about("Creates an integrity database from a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to create")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .arg(clap::Arg::with_name("threads")
                         .help("Number of threads to use")
                         .short("j").long("threads")
                         .takes_value(true)
                         .validator(validate_usize)))
        .subcommand(clap::SubCommand::with_name("check")
                    .about("Check an integrity database against a directory")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to read")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("path")
                         .help("Path of file or directory to scan")
                         .required(true)
                         .index(2))
                    .arg(clap::Arg::with_name("threads")
                         .help("Number of threads to use")
                         .short("j").long("threads")
                         .takes_value(true)
                         .validator(validate_usize)))
        .subcommand(clap::SubCommand::with_name("diff")
                    .about("Compare two integrity databases")
                    .arg(clap::Arg::with_name("old")
                         .help("Path of old integrity database")
                         .required(true)
                         .index(1))
                    .arg(clap::Arg::with_name("new")
                         .help("Path of new integrity database")
                         .required(true)
                         .index(2)))
        .subcommand(clap::SubCommand::with_name("selfcheck")
                    .about("Check the internal consistency of an integrity database")
                    .arg(clap::Arg::with_name("database")
                         .help("Path of integrity database to create")
                         .required(true)
                         .index(1)))
        .after_help("RETURN CODE: \
                    \n    0       Success \
                    \n    1       Changes \
                    \n    2       Suspicious changes \
                    \n   -1       Error")
        .get_matches();
    match matches.subcommand() {
        ("build", Some(submatches)) => Action::Build {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            threads: match submatches.value_of("threads") {
                None => 1, // FIXME: Pick a reasonable number of threads
                Some(threads) => threads.parse().unwrap(),
            },
        },
        ("check", Some(submatches)) => Action::Check {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
            dir_path: submatches.value_of_os("path").unwrap().to_owned(),
            threads: match submatches.value_of("threads") {
                None => 1, // FIXME: Pick a reasonable number of threads
                Some(threads) => threads.parse().unwrap(),
            },
        },
        ("diff", Some(submatches)) => Action::Diff {
            old_path: submatches.value_of_os("old").unwrap().to_owned(),
            new_path: submatches.value_of_os("new").unwrap().to_owned(),
        },
        ("selfcheck", Some(submatches)) => Action::SelfCheck {
            db_path: submatches.value_of_os("database").unwrap().to_owned(),
        },
        _ => unreachable!(),
    }
}

fn driver() -> Result<ActionSummary, error::Error> {
    let action = parse_args();
    match action {
        Action::Build { db_path, dir_path, threads } => {
            let database = Database::build(&dir_path, true, threads)?;

            {
                let mut json_path = PathBuf::from(&db_path);
                json_path.set_extension("json.gz");
                database.dump_json(json_path)?;
            }

            Ok(ActionSummary::Built)
        }
        Action::Check { db_path, dir_path, threads } => {
            let mut json_path = PathBuf::from(&db_path);
            json_path.set_extension("json.gz");
            let database = Database::load_json(&json_path)?;
            Ok(ActionSummary::Diff(database.check(&dir_path, threads)?))
        }
        Action::Diff { old_path, new_path } => {
            let mut json_old_path = PathBuf::from(&old_path);
            json_old_path.set_extension("json.gz");
            let mut json_new_path = PathBuf::from(&new_path);
            json_new_path.set_extension("json.gz");
            let old = Database::load_json(&json_old_path)?;
            let new = Database::load_json(&json_new_path)?;
            Ok(ActionSummary::Diff(old.show_diff(&new)))
        }
        Action::SelfCheck { db_path } => {
            let mut json_path = PathBuf::from(&db_path);
            json_path.set_extension("json.gz");
            Database::load_json(&json_path)?;
            Ok(ActionSummary::Diff(DiffSummary::NoChanges))
        }
    }
}

fn main() {
    ::std::process::exit(match driver() {
       Ok(action_summary) => match action_summary {
           ActionSummary::Built => 0,
           ActionSummary::Diff(DiffSummary::NoChanges) => 0,
           ActionSummary::Diff(DiffSummary::Changes) => 1,
           ActionSummary::Diff(DiffSummary::Suspicious) => 2,
       },
       Err(err) => {
           writeln!(io::stderr(), "error: {:?}", err).unwrap();
           -1
       },
    });
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::path;
use std::str;

use anyhow::Result;
use cargo::core::dependency::DepKind;
use cargo::core::package::PackageSet;
use cargo::core::{Package, Resolve, Workspace};
use cargo::ops;
use cargo::util::Config;
use cargo::CargoResult;
use structopt::StructOpt;
use tabled::Tabled;

#[derive(StructOpt)]
#[structopt(bin_name = "cargo")]
enum Opts {
    #[structopt(name = "bom")]
    /// Display a Bill-of-Materials for Rust project
    Bom(Args),
}

#[derive(StructOpt)]
struct Args {
    /// List all dependencies instead of only top level ones
    #[structopt(long = "all", short = "a")]
    all: bool,
    /// Directory for all generated artifacts
    #[structopt(long = "target-dir", value_name = "DIRECTORY", parse(from_os_str))]
    target_dir: Option<path::PathBuf>,
    #[structopt(long = "manifest-path", value_name = "PATH", parse(from_os_str))]
    /// Path to Cargo.toml
    manifest_path: Option<path::PathBuf>,
    #[structopt(long = "verbose", short = "v", parse(from_occurrences))]
    /// Use verbose output (-vv very verbose/build.rs output)
    verbose: u32,
    #[structopt(long = "quiet", short = "q")]
    /// No output printed to stdout other than the tree
    quiet: bool,
    #[structopt(long = "color", value_name = "WHEN")]
    /// Coloring: auto, always, never
    color: Option<String>,
    #[structopt(long = "frozen")]
    /// Require Cargo.lock and cache are up to date
    frozen: bool,
    #[structopt(long = "locked")]
    /// Require Cargo.lock is up to date
    locked: bool,
    #[structopt(long = "offline")]
    /// Run without accessing the network
    offline: bool,
    #[structopt(short = "Z", value_name = "FLAG")]
    /// Unstable (nightly-only) flags to Cargo
    unstable_flags: Vec<String>,
}

#[derive(Debug, Tabled, PartialEq, Eq, PartialOrd, Ord)]
struct DepTable {
    #[header("Name")]
    name: String,
    #[header("Version")]
    version: String,
    #[header("Licenses")]
    licenses: String,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct LicenseTable {
    name: String,
    version: String,
    license_files: BTreeSet<path::PathBuf>,
}

fn main() -> Result<()> {
    let mut config = Config::default()?;
    let Opts::Bom(args) = Opts::from_args();
    real_main(&mut config, args)
}

fn real_main(config: &mut Config, args: Args) -> Result<()> {
    config.configure(
        args.verbose,
        args.quiet,
        args.color.as_deref(),
        args.frozen,
        args.locked,
        args.offline,
        &args.target_dir,
        &args.unstable_flags,
        &[],
    )?;

    let manifest = args
        .manifest_path
        .unwrap_or_else(|| config.cwd().join("Cargo.toml"));
    let ws = Workspace::new(&manifest, &config)?;
    let members: Vec<Package> = ws.members().cloned().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws)?;

    let dependencies = if args.all {
        all_dependencies(&members, package_ids, resolve)?
    } else {
        top_level_dependencies(&members, package_ids)?
    };

    let mut depencies_list = BTreeSet::new();
    let mut licenses_list = BTreeSet::new();

    for package in &dependencies {
        let name = package.name().to_string();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package)?;
        depencies_list.insert(DepTable {
            name: name.clone(),
            version: version.clone(),
            licenses,
        });
        licenses_list.insert(LicenseTable {
            name,
            version,
            license_files,
        });
    }

    let table = tabled::table!(depencies_list, tabled::Style::PseudoClean,);

    let stdout = io::stdout();
    let mut out = stdout.lock();

    out.write_all(table.as_bytes())?;
    out.flush()?;

    for LicenseTable {
        name,
        version,
        license_files,
    } in licenses_list
    {
        if license_files.is_empty() {
            continue;
        }

        writeln!(out, "\n-----BEGIN {} {} LICENSES-----", name, version)?;

        let mut licenses_to_print = license_files.len();
        for file in license_files {
            let buf = std::fs::read(file)?;
            out.write_all(&buf)?;
            if licenses_to_print > 1 {
                out.write_all(b"\n-----NEXT LICENSE-----\n")?;
                licenses_to_print -= 1;
            }
        }

        writeln!(out, "\n-----END {} {} LICENSES-----", name, version)?;
        out.flush()?;
    }

    Ok(())
}

fn top_level_dependencies(
    members: &[Package],
    package_ids: PackageSet<'_>,
) -> CargoResult<BTreeSet<Package>> {
    let mut dependencies = BTreeSet::new();

    for member in members {
        for dependency in member.dependencies() {
            // Filter out Build and Development dependencies
            match dependency.kind() {
                DepKind::Normal => (),
                DepKind::Build | DepKind::Development => continue,
            }
            if let Some(dep) = package_ids
                .package_ids()
                .find(|id| dependency.matches_id(*id))
            {
                let package = package_ids.get_one(dep)?;
                dependencies.insert(package.to_owned());
            }
        }
    }

    // Filter out our own workspace crates from dependency list
    for member in members {
        dependencies.remove(member);
    }

    Ok(dependencies)
}

fn all_dependencies(
    members: &[Package],
    package_ids: PackageSet<'_>,
    resolve: Resolve,
) -> CargoResult<BTreeSet<Package>> {
    let mut dependencies = BTreeSet::new();

    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id)?;
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        dependencies.insert(package.to_owned());
    }

    Ok(dependencies)
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split("OR")
            .map(|s| s.split("AND"))
            .flatten()
            .map(|s| s.split('/'))
            .flatten()
            .map(str::trim)
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

static LICENCE_FILE_NAMES: &[&str] = &["LICENSE", "UNLICENSE"];

fn package_license_files(package: &Package) -> io::Result<BTreeSet<path::PathBuf>> {
    let mut result = BTreeSet::new();

    let path = package
        .manifest_path()
        .parent()
        .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Package manifest path missing"))?;

    for entry in path.read_dir()?.flatten() {
        if let Ok(name) = entry.file_name().into_string() {
            for license_name in LICENCE_FILE_NAMES {
                if name.starts_with(license_name) {
                    result.insert(entry.path());
                }
            }
        }
    }

    Ok(result)
}

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}
<commit_msg>Check if license-file is specified in package manifest<commit_after>use std::collections::BTreeSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::path;
use std::str;

use anyhow::Result;
use cargo::core::dependency::DepKind;
use cargo::core::package::PackageSet;
use cargo::core::{Package, Resolve, Workspace};
use cargo::ops;
use cargo::util::Config;
use cargo::CargoResult;
use structopt::StructOpt;
use tabled::Tabled;

#[derive(StructOpt)]
#[structopt(bin_name = "cargo")]
enum Opts {
    #[structopt(name = "bom")]
    /// Display a Bill-of-Materials for Rust project
    Bom(Args),
}

#[derive(StructOpt)]
struct Args {
    /// List all dependencies instead of only top level ones
    #[structopt(long = "all", short = "a")]
    all: bool,
    /// Directory for all generated artifacts
    #[structopt(long = "target-dir", value_name = "DIRECTORY", parse(from_os_str))]
    target_dir: Option<path::PathBuf>,
    #[structopt(long = "manifest-path", value_name = "PATH", parse(from_os_str))]
    /// Path to Cargo.toml
    manifest_path: Option<path::PathBuf>,
    #[structopt(long = "verbose", short = "v", parse(from_occurrences))]
    /// Use verbose output (-vv very verbose/build.rs output)
    verbose: u32,
    #[structopt(long = "quiet", short = "q")]
    /// No output printed to stdout other than the tree
    quiet: bool,
    #[structopt(long = "color", value_name = "WHEN")]
    /// Coloring: auto, always, never
    color: Option<String>,
    #[structopt(long = "frozen")]
    /// Require Cargo.lock and cache are up to date
    frozen: bool,
    #[structopt(long = "locked")]
    /// Require Cargo.lock is up to date
    locked: bool,
    #[structopt(long = "offline")]
    /// Run without accessing the network
    offline: bool,
    #[structopt(short = "Z", value_name = "FLAG")]
    /// Unstable (nightly-only) flags to Cargo
    unstable_flags: Vec<String>,
}

#[derive(Debug, Tabled, PartialEq, Eq, PartialOrd, Ord)]
struct DepTable {
    #[header("Name")]
    name: String,
    #[header("Version")]
    version: String,
    #[header("Licenses")]
    licenses: String,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct LicenseTable {
    name: String,
    version: String,
    license_files: BTreeSet<path::PathBuf>,
}

fn main() -> Result<()> {
    let mut config = Config::default()?;
    let Opts::Bom(args) = Opts::from_args();
    real_main(&mut config, args)
}

fn real_main(config: &mut Config, args: Args) -> Result<()> {
    config.configure(
        args.verbose,
        args.quiet,
        args.color.as_deref(),
        args.frozen,
        args.locked,
        args.offline,
        &args.target_dir,
        &args.unstable_flags,
        &[],
    )?;

    let manifest = args
        .manifest_path
        .unwrap_or_else(|| config.cwd().join("Cargo.toml"));
    let ws = Workspace::new(&manifest, &config)?;
    let members: Vec<Package> = ws.members().cloned().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws)?;

    let dependencies = if args.all {
        all_dependencies(&members, package_ids, resolve)?
    } else {
        top_level_dependencies(&members, package_ids)?
    };

    let mut depencies_list = BTreeSet::new();
    let mut licenses_list = BTreeSet::new();

    for package in &dependencies {
        let name = package.name().to_string();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package)?;
        depencies_list.insert(DepTable {
            name: name.clone(),
            version: version.clone(),
            licenses,
        });
        licenses_list.insert(LicenseTable {
            name,
            version,
            license_files,
        });
    }

    let table = tabled::table!(depencies_list, tabled::Style::PseudoClean,);

    let stdout = io::stdout();
    let mut out = stdout.lock();

    out.write_all(table.as_bytes())?;
    out.flush()?;

    for LicenseTable {
        name,
        version,
        license_files,
    } in licenses_list
    {
        if license_files.is_empty() {
            continue;
        }

        writeln!(out, "\n-----BEGIN {} {} LICENSES-----", name, version)?;

        let mut licenses_to_print = license_files.len();
        for file in license_files {
            let buf = std::fs::read(file)?;
            out.write_all(&buf)?;
            if licenses_to_print > 1 {
                out.write_all(b"\n-----NEXT LICENSE-----\n")?;
                licenses_to_print -= 1;
            }
        }

        writeln!(out, "\n-----END {} {} LICENSES-----", name, version)?;
        out.flush()?;
    }

    Ok(())
}

fn top_level_dependencies(
    members: &[Package],
    package_ids: PackageSet<'_>,
) -> CargoResult<BTreeSet<Package>> {
    let mut dependencies = BTreeSet::new();

    for member in members {
        for dependency in member.dependencies() {
            // Filter out Build and Development dependencies
            match dependency.kind() {
                DepKind::Normal => (),
                DepKind::Build | DepKind::Development => continue,
            }
            if let Some(dep) = package_ids
                .package_ids()
                .find(|id| dependency.matches_id(*id))
            {
                let package = package_ids.get_one(dep)?;
                dependencies.insert(package.to_owned());
            }
        }
    }

    // Filter out our own workspace crates from dependency list
    for member in members {
        dependencies.remove(member);
    }

    Ok(dependencies)
}

fn all_dependencies(
    members: &[Package],
    package_ids: PackageSet<'_>,
    resolve: Resolve,
) -> CargoResult<BTreeSet<Package>> {
    let mut dependencies = BTreeSet::new();

    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id)?;
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        dependencies.insert(package.to_owned());
    }

    Ok(dependencies)
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split("OR")
            .map(|s| s.split("AND"))
            .flatten()
            .map(|s| s.split('/'))
            .flatten()
            .map(str::trim)
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

static LICENCE_FILE_NAMES: &[&str] = &["LICENSE", "UNLICENSE"];

fn package_license_files(package: &Package) -> io::Result<BTreeSet<path::PathBuf>> {
    let mut result = BTreeSet::new();

    let path = package
        .manifest_path()
        .parent()
        .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Package manifest path missing"))?;

    let metadata = package.manifest().metadata();
    if let Some(ref license_file) = metadata.license_file {
        let file = path.join(license_file);
        if file.exists() {
            result.insert(file);
        }
    }

    for entry in path.read_dir()?.flatten() {
        if let Ok(name) = entry.file_name().into_string() {
            for license_name in LICENCE_FILE_NAMES {
                if name.starts_with(license_name) {
                    result.insert(entry.path());
                }
            }
        }
    }

    Ok(result)
}

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}
<|endoftext|>


<commit_before>// #![allow(dead_code)]
// #![allow(unused_imports)]
extern crate labyrinth as library;
extern crate num_cpus;
extern crate threadpool;

use std::env;
use threadpool::ThreadPool;
#[allow(unused_imports)]
use std::sync::mpsc::{channel, sync_channel};

use library::{Int, Uint, Wall};

fn main() {
    let mut args = env::args();
    args.next();
    let cols = if let Some(arg) = args.next() { arg.parse::<Int>() }   else { Ok(10) };
    let rows = if let Some(arg) = args.next() { arg.parse::<Int>() }   else { Ok(10) };
    let deep = if let Some(arg) = args.next() { arg.parse::<Uint>() }  else { Ok(1u32) };
    let concurrency = if let Some(arg) = args.next() { arg.parse::<usize>() } else { Ok(num_cpus::get()) };

    match (rows, cols, deep, concurrency) {
        (Ok(rows), Ok(cols), Ok(deep), Ok(concurrency)) => {
            if rows > 0 && cols > 0 {

                if concurrency <= 1 {
                    /* Linear implementation */
                    for _ in 0..deep {
                        let mut wall = Wall::new(cols, rows);
                        wall.carve();
                        wall.print();
                    }
                } else {
                    /* Parallel implementation */
                    parallel(cols, rows, deep, concurrency);
                }

            } else {
                println!("Hey, give me numbers bigger than 0");
            }
        }
        _ => println!("Hey, give me a number.")
    }
}

fn parallel(cols: Int, rows: Int, deep: Uint, concurrency: usize) {
    let pool = ThreadPool::new(concurrency);
    let port = {
        let (chan, port) = channel(); // sync_channel((deep as usize + concurrency - 1) / concurrency);
        for _ in 0..deep {
            let chan = chan.clone();
            pool.execute(move || {
                let mut wall = Wall::new(cols, rows);
                wall.carve();
                chan.send(wall).unwrap();
            });
        }
        port
    };
    for _ in 0..deep {
        let wall = port.recv().unwrap();
        wall.print();
    }
}
<commit_msg>fix default arguments<commit_after>// #![allow(dead_code)]
// #![allow(unused_imports)]
extern crate labyrinth as library;
extern crate num_cpus;
extern crate threadpool;

use std::env;
use threadpool::ThreadPool;
#[allow(unused_imports)]
use std::sync::mpsc::{channel, sync_channel};

use library::{Int, Uint, Wall};

fn main() {
    let mut args = env::args();
    args.next();
    let cols = if let Some(arg) = args.next() { arg.parse::<Int>() }   else { Ok(10) };
    let rows = if let Some(arg) = args.next() { arg.parse::<Int>() }   else { cols.clone() };
    let deep = if let Some(arg) = args.next() { arg.parse::<Uint>() }  else { Ok(1u32) };
    let cpus = if let Some(arg) = args.next() { arg.parse::<usize>() } else { Ok(num_cpus::get()) };

    match (rows, cols, deep, cpus) {
        (Ok(rows), Ok(cols), Ok(deep), Ok(cpus)) => {
            if rows > 0 && cols > 0 {

                let concurrency = if cpus > deep as usize { deep as usize } else { cpus };

                if concurrency <= 1 {
                    /* Linear implementation */
                    for _ in 0..deep {
                        let mut wall = Wall::new(cols, rows);
                        wall.carve();
                        wall.print();
                    }
                } else {
                    /* Parallel implementation */
                    parallel(cols, rows, deep, concurrency);
                }

            } else {
                println!("Hey, give me numbers bigger than 0");
            }
        }
        _ => println!("Hey, give me a number.")
    }
}

fn parallel(cols: Int, rows: Int, deep: Uint, concurrency: usize) {
    let pool = ThreadPool::new(concurrency);
    let port = {
        let (chan, port) = channel(); // sync_channel((deep as usize + concurrency - 1) / concurrency);
        for _ in 0..deep {
            let chan = chan.clone();
            pool.execute(move || {
                let mut wall = Wall::new(cols, rows);
                wall.carve();
                chan.send(wall).unwrap();
            });
        }
        port
    };
    for _ in 0..deep {
        let wall = port.recv().unwrap();
        wall.print();
    }
}
<|endoftext|>


<commit_before>extern crate chan_signal;
#[macro_use]
extern crate clap;
extern crate daemonize;
extern crate env_logger;
extern crate fuse;
extern crate libc;
#[macro_use]
extern crate log;
extern crate syslog;
extern crate time;

use std::env;
use std::error::Error;
use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::path::Path;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;

use chan_signal::Signal;
use clap::{App, Arg};
use daemonize::{Daemonize};
use env_logger::LogBuilder;
use log::LogRecord;
use syslog::{Facility,Severity};

mod pcatfs;
mod catfs;
mod flags;
mod evicter;

use catfs::error;
use catfs::flags::{DiskSpace, FlagStorage};
use catfs::rlibc;

fn main() {
    if let Err(e) = main_internal() {
        error!("Cannot mount: {}", e);
        std::process::exit(1);
    }
}

static mut SYSLOG: bool = false;
static mut SYSLOGGER: Option<Box<syslog::Logger>> = None;

fn main_internal() -> error::Result<()> {
    let format = |record: &LogRecord| {
        let t = time::now();
        let syslog: bool;
        unsafe {
            syslog = SYSLOG;
        }
        if !syslog {
            format!(
                "{} {:5} - {}",
                time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
                record.level(),
                record.args()
            )
        } else {
            unsafe {
                if let Some(ref logger) = SYSLOGGER {
                    // ignore error if we can't log, not much we can do anyway
                    let _ = logger.send_3164(match record.level() {
                        log::LogLevel::Trace => Severity::LOG_DEBUG,
                        log::LogLevel::Debug => Severity::LOG_DEBUG,
                        log::LogLevel::Info => Severity::LOG_INFO,
                        log::LogLevel::Warn => Severity::LOG_WARNING,
                        log::LogLevel::Error => Severity::LOG_ERR,
                    }, record.args());
                }
            }
            format!("\u{08}")
        }
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    } else {
        // default to info
        builder.parse("info");
    }

    builder.init().unwrap();

    let mut flags: FlagStorage = Default::default();
    let mut test = false;

    flags.mount_options.push(OsString::from("-o"));
    flags.mount_options.push(OsString::from("atomic_o_trunc"));
    flags.mount_options.push(OsString::from("-o"));
    flags.mount_options.push(
        OsString::from("default_permissions"),
    );

    let app = App::new("catfs")
        .about("Cache Anything FileSystem")
        .version(crate_version!());

    {
        fn diskspace_validator(s: String) -> Result<(), String> {
            DiskSpace::from_str(&s).map(|_| ()).map_err(
                |e| e.to_str().to_owned(),
            )
        }

        fn path_validator(s: String) -> Result<(), String> {
            Path::new(&s)
                .canonicalize()
                .map_err(|e| e.description().to_owned())
                .and_then(|p| if p.is_dir() {
                    Ok(())
                } else {
                    Err("is not a directory".to_owned())
                })
        }

        let mut args = [
            flags::Flag {
                arg: Arg::with_name("space")
                    .long("free")
                    .takes_value(true)
                    .help(
                        "Ensure filesystem has at least this much free space. (ex: 9.5%, 10G)",
                    )
                    .validator(diskspace_validator),
                value: &mut flags.free_space,
            },
            flags::Flag {
                arg: Arg::with_name("foreground").short("f").help(
                    "Run catfs in foreground.",
                ),
                value: &mut flags.foreground,
            },
            flags::Flag{
                arg: Arg::with_name("uid")
                    .long("uid")
                    .takes_value(true)
                    .help("Run as this uid"),
                value: &mut flags.uid,
            },
            flags::Flag{
                arg: Arg::with_name("gid")
                    .long("gid")
                    .takes_value(true)
                    .help("Run as this gid"),
                value: &mut flags.gid,
            },
            flags::Flag {
                arg: Arg::with_name("option")
                    .short("o")
                    .takes_value(true)
                    .multiple(true)
                    .help("Additional system-specific mount options. Be careful!"),
                value: &mut flags.mount_options,
            },
            flags::Flag {
                arg: Arg::with_name("test").long("test").help(
                    "Exit after parsing arguments",
                ),
                value: &mut test,
            },
            flags::Flag {
                arg: Arg::with_name("from")
                    .index(1)
                    .required(true)
                    .help("Cache files from this directory.")
                    .validator(path_validator),
                value: &mut flags.cat_from,
            },
            flags::Flag {
                arg: Arg::with_name("to")
                    .index(2)
                    .required(true)
                    .help("Cache files to this directory.")
                    .validator(path_validator),
                value: &mut flags.cat_to,
            },
            flags::Flag {
                arg: Arg::with_name("mountpoint")
                    .index(3)
                    .required(true)
                    .help("Expose the mount point at this directory.")
                    .validator(path_validator),
                value: &mut flags.mount_point,
            },
        ];

        flags::parse_options(app, &mut args);
    }

    if test {
        return Ok(());
    }

    if flags.gid != 0 {
        rlibc::setgid(flags.gid)?;
    }
    if flags.uid != 0 {
        rlibc::setuid(flags.uid)?;
    }

    if !flags.foreground {
        let daemonize = Daemonize::new()
            .working_directory(env::current_dir()?.as_path())
            ;

        match daemonize.start() {
            Ok(_) => {
                if let Ok(mut logger) = syslog::unix(Facility::LOG_USER) {
                    unsafe {
                        logger.set_process_name("catfs".to_string());
                        logger.set_process_id(libc::getpid());
                        SYSLOGGER = Some(logger);
                        SYSLOG = true;
                    }
                }
            },
            Err(e) => error!("unable to daemonize: {}", e),
        }
    }

    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    let path_from = Path::new(&flags.cat_from).canonicalize()?;
    let path_to = Path::new(&flags.cat_to).canonicalize()?;
    let fs = catfs::CatFS::new(&path_from, &path_to)?;
    let fs = pcatfs::PCatFS::new(fs);
    let cache_dir = fs.get_cache_dir()?;
    let mut options: Vec<&OsStr> = Vec::new();
    for i in 0..flags.mount_options.len() {
        options.push(&flags.mount_options[i]);
    }

    debug!("options are {:?}", flags.mount_options);

    {
        let mut session = fuse::Session::new(fs, Path::new(&flags.mount_point), &options)?;
        let need_unmount = Arc::new(Mutex::new(true));
        let need_unmount2 = need_unmount.clone();
        thread::spawn(move || {
            if let Err(e) = session.run() {
                error!("session.run() = {}", e);
            }
            info!("{:?} unmounted", session.mountpoint());
            let mut need_unmount = need_unmount2.lock().unwrap();
            *need_unmount = false;
            unsafe { libc::kill(libc::getpid(), libc::SIGTERM) };
        });

        let mut ev = evicter::Evicter::new(cache_dir, &flags.free_space);
        ev.run();
        // unmount after we get signaled becausep session will go out of scope
        let s = signal.recv().unwrap();
        info!(
            "Received {:?}, attempting to unmount {:?}",
            s,
            flags.mount_point
        );
        let need_unmount = need_unmount.lock().unwrap();
        if *need_unmount {
            unmount(Path::new(&flags.mount_point))?;
        }
    }
    rlibc::close(cache_dir)?;
    return Ok(());
}

use libc::{c_char, c_int};
use std::ffi::{CString, CStr};
/// Unmount an arbitrary mount point
pub fn unmount(mountpoint: &Path) -> io::Result<()> {
    // fuse_unmount_compat22 unfortunately doesn't return a status. Additionally,
    // it attempts to call realpath, which in turn calls into the filesystem. So
    // if the filesystem returns an error, the unmount does not take place, with
    // no indication of the error available to the caller. So we call unmount
    // directly, which is what osxfuse does anyway, since we already converted
    // to the real path when we first mounted.

    #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly",
                target_os = "openbsd", target_os = "bitrig", target_os = "netbsd"))]
    #[inline]
    fn libc_umount(mnt: &CStr) -> c_int {
        unsafe { libc::unmount(mnt.as_ptr(), 0) }
    }

    #[cfg(not(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly",
                      target_os = "openbsd", target_os = "bitrig", target_os = "netbsd")))]
    #[inline]
    fn libc_umount(mnt: &CStr) -> c_int {
        use std::io::ErrorKind::PermissionDenied;

        let rc = unsafe { libc::umount(mnt.as_ptr()) };
        if rc < 0 && io::Error::last_os_error().kind() == PermissionDenied {
            // Linux always returns EPERM for non-root users.  We have to let the
            // library go through the setuid-root "fusermount -u" to unmount.
            unsafe {
                fuse_unmount_compat22(mnt.as_ptr());
            }
            0
        } else {
            rc
        }
    }

    let mnt = CString::new(mountpoint.as_os_str().as_bytes())?;
    let rc = libc_umount(&mnt);
    if rc < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

extern "system" {
    pub fn fuse_unmount_compat22(mountpoint: *const c_char);
}
<commit_msg>split backtrace to syslog<commit_after>extern crate chan_signal;
#[macro_use]
extern crate clap;
extern crate daemonize;
extern crate env_logger;
extern crate fuse;
extern crate libc;
#[macro_use]
extern crate log;
extern crate syslog;
extern crate time;

use std::env;
use std::error::Error;
use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::path::Path;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;

use chan_signal::Signal;
use clap::{App, Arg};
use daemonize::{Daemonize};
use env_logger::LogBuilder;
use log::LogRecord;
use syslog::{Facility,Severity};

mod pcatfs;
mod catfs;
mod flags;
mod evicter;

use catfs::error;
use catfs::flags::{DiskSpace, FlagStorage};
use catfs::rlibc;

fn main() {
    if let Err(e) = main_internal() {
        error!("Cannot mount: {}", e);
        std::process::exit(1);
    }
}

static mut SYSLOG: bool = false;
static mut SYSLOGGER: Option<Box<syslog::Logger>> = None;

fn main_internal() -> error::Result<()> {
    let format = |record: &LogRecord| {
        let t = time::now();
        let syslog: bool;
        unsafe {
            syslog = SYSLOG;
        }
        if !syslog {
            format!(
                "{} {:5} - {}",
                time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
                record.level(),
                record.args()
            )
        } else {
            unsafe {
                if let Some(ref logger) = SYSLOGGER {
                    let level = match record.level() {
                        log::LogLevel::Trace => Severity::LOG_DEBUG,
                        log::LogLevel::Debug => Severity::LOG_DEBUG,
                        log::LogLevel::Info => Severity::LOG_INFO,
                        log::LogLevel::Warn => Severity::LOG_WARNING,
                        log::LogLevel::Error => Severity::LOG_ERR,
                    };
                    let msg = format!("{}", record.args());
                    for line in msg.split('\n') {
                        // ignore error if we can't log, not much we can do anyway
                        let _ = logger.send_3164(level, line);
                    }
                }
            }
            format!("\u{08}")
        }
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    } else {
        // default to info
        builder.parse("info");
    }

    builder.init().unwrap();

    let mut flags: FlagStorage = Default::default();
    let mut test = false;

    flags.mount_options.push(OsString::from("-o"));
    flags.mount_options.push(OsString::from("atomic_o_trunc"));
    flags.mount_options.push(OsString::from("-o"));
    flags.mount_options.push(
        OsString::from("default_permissions"),
    );

    let app = App::new("catfs")
        .about("Cache Anything FileSystem")
        .version(crate_version!());

    {
        fn diskspace_validator(s: String) -> Result<(), String> {
            DiskSpace::from_str(&s).map(|_| ()).map_err(
                |e| e.to_str().to_owned(),
            )
        }

        fn path_validator(s: String) -> Result<(), String> {
            Path::new(&s)
                .canonicalize()
                .map_err(|e| e.description().to_owned())
                .and_then(|p| if p.is_dir() {
                    Ok(())
                } else {
                    Err("is not a directory".to_owned())
                })
        }

        let mut args = [
            flags::Flag {
                arg: Arg::with_name("space")
                    .long("free")
                    .takes_value(true)
                    .help(
                        "Ensure filesystem has at least this much free space. (ex: 9.5%, 10G)",
                    )
                    .validator(diskspace_validator),
                value: &mut flags.free_space,
            },
            flags::Flag {
                arg: Arg::with_name("foreground").short("f").help(
                    "Run catfs in foreground.",
                ),
                value: &mut flags.foreground,
            },
            flags::Flag{
                arg: Arg::with_name("uid")
                    .long("uid")
                    .takes_value(true)
                    .help("Run as this uid"),
                value: &mut flags.uid,
            },
            flags::Flag{
                arg: Arg::with_name("gid")
                    .long("gid")
                    .takes_value(true)
                    .help("Run as this gid"),
                value: &mut flags.gid,
            },
            flags::Flag {
                arg: Arg::with_name("option")
                    .short("o")
                    .takes_value(true)
                    .multiple(true)
                    .help("Additional system-specific mount options. Be careful!"),
                value: &mut flags.mount_options,
            },
            flags::Flag {
                arg: Arg::with_name("test").long("test").help(
                    "Exit after parsing arguments",
                ),
                value: &mut test,
            },
            flags::Flag {
                arg: Arg::with_name("from")
                    .index(1)
                    .required(true)
                    .help("Cache files from this directory.")
                    .validator(path_validator),
                value: &mut flags.cat_from,
            },
            flags::Flag {
                arg: Arg::with_name("to")
                    .index(2)
                    .required(true)
                    .help("Cache files to this directory.")
                    .validator(path_validator),
                value: &mut flags.cat_to,
            },
            flags::Flag {
                arg: Arg::with_name("mountpoint")
                    .index(3)
                    .required(true)
                    .help("Expose the mount point at this directory.")
                    .validator(path_validator),
                value: &mut flags.mount_point,
            },
        ];

        flags::parse_options(app, &mut args);
    }

    if test {
        return Ok(());
    }

    if flags.gid != 0 {
        rlibc::setgid(flags.gid)?;
    }
    if flags.uid != 0 {
        rlibc::setuid(flags.uid)?;
    }

    if !flags.foreground {
        let daemonize = Daemonize::new()
            .working_directory(env::current_dir()?.as_path())
            ;

        match daemonize.start() {
            Ok(_) => {
                if let Ok(mut logger) = syslog::unix(Facility::LOG_USER) {
                    unsafe {
                        logger.set_process_name("catfs".to_string());
                        logger.set_process_id(libc::getpid());
                        SYSLOGGER = Some(logger);
                        SYSLOG = true;
                    }
                }
            },
            Err(e) => error!("unable to daemonize: {}", e),
        }
    }

    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    let path_from = Path::new(&flags.cat_from).canonicalize()?;
    let path_to = Path::new(&flags.cat_to).canonicalize()?;
    let fs = catfs::CatFS::new(&path_from, &path_to)?;
    let fs = pcatfs::PCatFS::new(fs);
    let cache_dir = fs.get_cache_dir()?;
    let mut options: Vec<&OsStr> = Vec::new();
    for i in 0..flags.mount_options.len() {
        options.push(&flags.mount_options[i]);
    }

    debug!("options are {:?}", flags.mount_options);

    {
        let mut session = fuse::Session::new(fs, Path::new(&flags.mount_point), &options)?;
        let need_unmount = Arc::new(Mutex::new(true));
        let need_unmount2 = need_unmount.clone();
        thread::spawn(move || {
            if let Err(e) = session.run() {
                error!("session.run() = {}", e);
            }
            info!("{:?} unmounted", session.mountpoint());
            let mut need_unmount = need_unmount2.lock().unwrap();
            *need_unmount = false;
            unsafe { libc::kill(libc::getpid(), libc::SIGTERM) };
        });

        let mut ev = evicter::Evicter::new(cache_dir, &flags.free_space);
        ev.run();
        // unmount after we get signaled becausep session will go out of scope
        let s = signal.recv().unwrap();
        info!(
            "Received {:?}, attempting to unmount {:?}",
            s,
            flags.mount_point
        );
        let need_unmount = need_unmount.lock().unwrap();
        if *need_unmount {
            unmount(Path::new(&flags.mount_point))?;
        }
    }
    rlibc::close(cache_dir)?;
    return Ok(());
}

use libc::{c_char, c_int};
use std::ffi::{CString, CStr};
/// Unmount an arbitrary mount point
pub fn unmount(mountpoint: &Path) -> io::Result<()> {
    // fuse_unmount_compat22 unfortunately doesn't return a status. Additionally,
    // it attempts to call realpath, which in turn calls into the filesystem. So
    // if the filesystem returns an error, the unmount does not take place, with
    // no indication of the error available to the caller. So we call unmount
    // directly, which is what osxfuse does anyway, since we already converted
    // to the real path when we first mounted.

    #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly",
                target_os = "openbsd", target_os = "bitrig", target_os = "netbsd"))]
    #[inline]
    fn libc_umount(mnt: &CStr) -> c_int {
        unsafe { libc::unmount(mnt.as_ptr(), 0) }
    }

    #[cfg(not(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly",
                      target_os = "openbsd", target_os = "bitrig", target_os = "netbsd")))]
    #[inline]
    fn libc_umount(mnt: &CStr) -> c_int {
        use std::io::ErrorKind::PermissionDenied;

        let rc = unsafe { libc::umount(mnt.as_ptr()) };
        if rc < 0 && io::Error::last_os_error().kind() == PermissionDenied {
            // Linux always returns EPERM for non-root users.  We have to let the
            // library go through the setuid-root "fusermount -u" to unmount.
            unsafe {
                fuse_unmount_compat22(mnt.as_ptr());
            }
            0
        } else {
            rc
        }
    }

    let mnt = CString::new(mountpoint.as_os_str().as_bytes())?;
    let rc = libc_umount(&mnt);
    if rc < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

extern "system" {
    pub fn fuse_unmount_compat22(mountpoint: *const c_char);
}
<|endoftext|>


<commit_before>#![feature(globs)]
extern crate libc;

use xlib::{XOpenDisplay, XDisplayName, XQueryExtension, XInitExtension, XSynchronize, XKeysymToString, XKeycodeToKeysym};
use libc::{c_int};
use std::ptr;
use xtst::{XRecordCreateContext, XRecordAllClients, XRecordAllocRange, XRecordRange, XRecordQueryVersion, XRecordEnableContext, XRecordEnableContextAsync,XRecordInterceptData, XRecordProcessReplies, XRecordFreeData};
use std::mem;
use std::c_str::CString;
mod xtst;
mod xlib;
mod xlibint;
mod xutil;

struct XRecordDatum {
  xtype: ::libc::c_uchar,
  event: ::xlib::XEvent,
  req:   ::xlibint::xResourceReq,
  reply: ::xlibint::xGenericReply,
  error: ::xlibint::xError,
  setup: ::xlibint::xConnSetupPrefix,
}

// let mut display_control: *mut xlib::Display  = std::mem::transmute(0);
// let mut display_data: *mut xlib::Display  = std::mem::transmute(0);
static mut display_control: *mut xlib::Display = 0 as *mut xlib::Struct__XDisplay;
static mut display_data: *mut xlib::Display = 0 as *mut xlib::Struct__XDisplay;
static mut event_count:u32 = 0;
fn main() {
	unsafe {
		let mut a:  i8 = 0;
		display_control = XOpenDisplay(&a);
		display_data = XOpenDisplay(&a);

		if display_data.is_null() || display_control.is_null() {
			fail!("XOpenDisplay() failed!");
		}

		XSynchronize(display_control, 1);

		let display_name = unsafe {XDisplayName(&a)};
		let ext_name = "RECORD";
		// Check presence of Record extension
		let arg2:*mut c_int = &mut 1;
		let arg3:*mut c_int = &mut 1;
		let arg4:*mut c_int = &mut 1;
		let has_record = XQueryExtension(display_control, ext_name.to_c_str().as_ptr() as *const i8,arg2,arg3,arg4);
		let extension = XInitExtension(display_control, ext_name.to_c_str().as_ptr() as *const i8);
		if extension.is_null() {
			fail!("XInitExtension() failed!");
		}

		// Get version
		let mut versionMajor: c_int = 0;
		let mut versionMinor: c_int = 0;
		XRecordQueryVersion(display_control, &mut versionMajor, &mut versionMinor);
		println!("RECORD extension version {}.{}", versionMajor, versionMinor);

		// Prepare record range
		let mut recordRange: XRecordRange = *XRecordAllocRange();
		let mut recordRangePtr: *mut *mut XRecordRange = std::mem::transmute(&mut &mut recordRange);
		recordRange.device_events.first = 2; // KeyPress
		recordRange.device_events.last = 6; // MotionNotify

		// Create context
		let context = XRecordCreateContext(
			display_control,
			0,
			&mut XRecordAllClients,
			1,
			recordRangePtr,
			1
		);
		if context == 0 {
			fail!("Fail create Record context\n");
		}

		// Run
		let res = XRecordEnableContextAsync(display_data, context, Some(recordCallback), &mut 0);
		if res == 0 {
			fail!("Cound not enable the Record context!\n");
		}
		xtst::XRecordFreeContext(display_data, context);
		loop {
			XRecordProcessReplies(display_data);
		}
	}
}

extern "C" fn recordCallback(pointer:*mut i8, raw_data: *mut XRecordInterceptData) {

	unsafe {

		let data = &*raw_data;
		// println!("Category {}", data.category);
		if data.category != xtst::XRecordFromServer {
			return;
		}
		println!("Event count: {}", event_count);
		event_count += 1;
		println!("Time {}", data.server_time);
		println!("Datalen {}", data.data_len);
		let mut xdatum_ptr: *mut XRecordDatum = data.data as *mut XRecordDatum;
		let mut xdatum = &*xdatum_ptr;

		let mut event = xdatum.event;
		println!("Type {}", xdatum.xtype);

		// Catch key event
		if xdatum.xtype == xtst::KeyPress || xdatum.xtype == xtst::KeyRelease {
			// extract key code
			let raw_bytes: &mut [u8,..4] = std::mem::transmute(data.data);
			let c_char  = XKeysymToString(XKeycodeToKeysym(display_control, raw_bytes[1], 0));
			let c_string = CString::new(std::mem::transmute(c_char), false);
			let char: &str = c_string.as_str().unwrap();
			println!("Keycode: {}, Character {}", raw_bytes[1], char);

			// println!("nitems {}", (&*wm_name).nitems);
		}
		// get current focus window
		let current_window: *mut xlib::Window = &mut 0;
		let revert_to_return: *mut i32 = &mut 0;
		xlib::XGetInputFocus(display_control, current_window, revert_to_return);
		println!("revertToReturn {}", *revert_to_return);
		let mut j = 0u;
		let mut wm_name: *mut xutil::XTextProperty = std::mem::transmute(&mut j);
		let mut wm_name_true: &str = "";
		let mut tmp =0i8;
		let mut c_wm_name: CString = CString::new(&tmp,false);
		let mut res = 0;
		// res = xutil::XGetWMName(display_control, *current_window, wm_name);
		let mut i = 0u;
		while res == 0 && i < 2 {
			print!(".");
			println!("current_window {}", *current_window);
			res = xutil::XGetWMName(display_control, *current_window, wm_name);

			if res == 0 {
				println!("Move to parent");
				let mut root: xlib::Window = 0;
				let mut parent: xlib::Window = 0;
				let mut childrens: *mut xlib::Window = &mut 0u64;
				let mut nchildren: u32 = 0;
				let r2 = xlib::XQueryTree(display_control, *current_window, &mut root, &mut parent, &mut childrens, &mut nchildren);
				if r2 == 0 {
					print!("*");
				} else {
					println!("parent {}", parent);
					*current_window = parent;
				}
			}
			// get parent window
			i += 1;
		}
		println!("---");
		if res == 0 {
			println!("no wmname");
		} else {
			// extract name from XTextProperty
			println!("wmname found!");
			println!("format: {}", (*wm_name).format);
			if (*wm_name).format != 8 {
				fail!("");
			}
			println!("encoding: {}", (*wm_name).encoding);
			let encoding_name = xlib::XGetAtomName(display_control, (*wm_name).encoding);
			let encoding_name_string = CString::new(std::mem::transmute(encoding_name), false);
			println!("encoding name: {}", encoding_name_string.as_str().unwrap());
			let mut tmp2 = 0i8;
			let mut list: *mut *mut ::libc::c_char = std::mem::transmute(&mut &mut tmp2);
			let mut list_count: i32 = 0;
			let res3 = xutil::XmbTextPropertyToTextList(display_control, std::mem::transmute(wm_name), &mut list, &mut list_count);
			println!("convert result: {}", res3);
			if res3 == 0 {
				println!("list count {}", list_count);
				c_wm_name = CString::new(std::mem::transmute(*list), false);
				wm_name_true = c_wm_name.as_str().unwrap();
				println!("wm_name: {}", wm_name_true);
				xlib::XFreeStringList(list);
			} else {
				c_wm_name = CString::new(std::mem::transmute((*wm_name).value), false);
				// wm_name_true = c_wm_name.as_str().unwrap();
				println!("wm_name bytes: {}", c_wm_name.as_bytes());
				// ая -      27 45 76 208 239 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// бв -      27 45 76 209 210 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// zx -      122 120 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// длодлод - 27 45 76 212 219 222 212 219 222 212 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// zx • - Sublime Text (UNREGISTERED)

				println!("wm_name: {}", c_wm_name);
				println!("wm_name len w/o null: {}", c_wm_name.len());
			}

		}

		XRecordFreeData(raw_data);
	}
	println!("\n");
}

// fn string_convert(string: *mut libc::c_char) -> &'static str{
// 	let temp = unsafe{CString::new(std::mem::transmute(string), true)};
// 	let a: &str = temp.as_str().unwrap();
// }<commit_msg>begin wrappers<commit_after>#![feature(globs)]
extern crate libc;

use xlib::{XOpenDisplay, XDisplayName, XQueryExtension, XInitExtension, XSynchronize, XKeysymToString, XKeycodeToKeysym};
use libc::{c_int};
use std::ptr;
use xtst::{XRecordCreateContext, XRecordAllClients, XRecordAllocRange, XRecordRange, XRecordQueryVersion, XRecordEnableContext, XRecordEnableContextAsync,XRecordInterceptData, XRecordProcessReplies, XRecordFreeData};
use std::mem;
use std::c_str::CString;
mod xtst;
mod xlib;
mod xlibint;
mod xutil;

struct XRecordDatum {
  xtype: ::libc::c_uchar,
  event: ::xlib::XEvent,
  req:   ::xlibint::xResourceReq,
  reply: ::xlibint::xGenericReply,
  error: ::xlibint::xError,
  setup: ::xlibint::xConnSetupPrefix,
}

// let mut display_control: *mut xlib::Display  = std::mem::transmute(0);
// let mut display_data: *mut xlib::Display  = std::mem::transmute(0);
static mut display_control: *mut xlib::Display = 0 as *mut xlib::Struct__XDisplay;
static mut display_data: *mut xlib::Display = 0 as *mut xlib::Struct__XDisplay;
static mut event_count:u32 = 0;
fn main() {
	unsafe {
		let mut a:  i8 = 0;
		display_control = XOpenDisplay(&a);
		display_data = XOpenDisplay(&a);

		if display_data.is_null() || display_control.is_null() {
			fail!("XOpenDisplay() failed!");
		}

		XSynchronize(display_control, 1);

		let display_name = unsafe {XDisplayName(&a)};
		let ext_name = "RECORD";
		// Check presence of Record extension
		let arg2:*mut c_int = &mut 1;
		let arg3:*mut c_int = &mut 1;
		let arg4:*mut c_int = &mut 1;
		let has_record = XQueryExtension(display_control, ext_name.to_c_str().as_ptr() as *const i8,arg2,arg3,arg4);
		let extension = XInitExtension(display_control, ext_name.to_c_str().as_ptr() as *const i8);
		if extension.is_null() {
			fail!("XInitExtension() failed!");
		}

		// Get version
		let mut versionMajor: c_int = 0;
		let mut versionMinor: c_int = 0;
		XRecordQueryVersion(display_control, &mut versionMajor, &mut versionMinor);
		println!("RECORD extension version {}.{}", versionMajor, versionMinor);

		// Prepare record range
		let mut recordRange: XRecordRange = *XRecordAllocRange();
		let mut recordRangePtr: *mut *mut XRecordRange = std::mem::transmute(&mut &mut recordRange);
		recordRange.device_events.first = 2; // KeyPress
		recordRange.device_events.last = 6; // MotionNotify

		// Create context
		let context = XRecordCreateContext(
			display_control,
			0,
			&mut XRecordAllClients,
			1,
			recordRangePtr,
			1
		);
		if context == 0 {
			fail!("Fail create Record context\n");
		}

		// Run
		let res = XRecordEnableContextAsync(display_data, context, Some(recordCallback), &mut 0);
		if res == 0 {
			fail!("Cound not enable the Record context!\n");
		}
		xtst::XRecordFreeContext(display_data, context);
		loop {
			XRecordProcessReplies(display_data);
		}
	}
}

extern "C" fn recordCallback(pointer:*mut i8, raw_data: *mut XRecordInterceptData) {

	unsafe {

		let data = &*raw_data;
		// println!("Category {}", data.category);
		if data.category != xtst::XRecordFromServer {
			return;
		}
		println!("Event count: {}", event_count);
		event_count += 1;
		println!("Time {}", data.server_time);
		println!("Datalen {}", data.data_len);
		let mut xdatum_ptr: *mut XRecordDatum = data.data as *mut XRecordDatum;
		let mut xdatum = &*xdatum_ptr;

		let mut event = xdatum.event;
		println!("Type {}", xdatum.xtype);

		// Catch key event
		if xdatum.xtype == xtst::KeyPress || xdatum.xtype == xtst::KeyRelease {
			// extract key code
			let raw_bytes: &mut [u8,..4] = std::mem::transmute(data.data);
			let c_char  = XKeysymToString(XKeycodeToKeysym(display_control, raw_bytes[1], 0));
			let c_string = CString::new(std::mem::transmute(c_char), false);
			let char: &str = c_string.as_str().unwrap();
			println!("Keycode: {}, Character {}", raw_bytes[1], char);

			// println!("nitems {}", (&*wm_name).nitems);
		}
		// get current focus window
		let current_window: *mut xlib::Window = &mut 0;
		let revert_to_return: *mut i32 = &mut 0;
		xlib::XGetInputFocus(display_control, current_window, revert_to_return);
		println!("revertToReturn {}", *revert_to_return);
		let mut j = 0u;
		let mut wm_name: *mut xutil::XTextProperty = std::mem::transmute(&mut j);
		let mut wm_name_true: &str = "";
		let mut tmp =0i8;
		let mut c_wm_name: CString = CString::new(&tmp,false);
		let mut res = 0;
		// res = xutil::XGetWMName(display_control, *current_window, wm_name);
		let mut i = 0u;
		while res == 0 && i < 2 {
			print!(".");
			println!("current_window {}", *current_window);
			if *current_window == 0 {
				break;
			}
			res = xutil::XGetWMName(display_control, *current_window, wm_name);

			if res == 0 {
				println!("Move to parent");
				let mut root: xlib::Window = 0;
				let mut parent: xlib::Window = 0;
				let mut childrens: *mut xlib::Window = &mut 0u64;
				let mut nchildren: u32 = 0;
				let r2 = xlib::XQueryTree(display_control, *current_window, &mut root, &mut parent, &mut childrens, &mut nchildren);
				if r2 == 0 {
					print!("*");
				} else {
					println!("parent {}", parent);
					*current_window = parent;
				}
			}
			// get parent window
			i += 1;
		}
		println!("---");
		if res == 0 {
			println!("no wmname");
		} else {
			// extract name from XTextProperty
			println!("wmname found!");
			println!("format: {}", (*wm_name).format);
			if (*wm_name).format != 8 {
				fail!("");
			}
			println!("encoding: {}", (*wm_name).encoding);
			let encoding_name = xlib::XGetAtomName(display_control, (*wm_name).encoding);
			let encoding_name_string = CString::new(std::mem::transmute(encoding_name), false);
			println!("encoding name: {}", encoding_name_string.as_str().unwrap());
			let mut tmp2 = 0i8;
			let mut list: *mut *mut ::libc::c_char = std::mem::transmute(&mut &mut tmp2);
			let mut list_count: i32 = 0;
			let res3 = xutil::XmbTextPropertyToTextList(display_control, std::mem::transmute(wm_name), &mut list, &mut list_count);
			println!("convert result: {}", res3);
			if res3 == 0 {
				println!("list count {}", list_count);
				c_wm_name = CString::new(std::mem::transmute(*list), false);
				wm_name_true = c_wm_name.as_str().unwrap();
				println!("wm_name: {}", wm_name_true);
				xlib::XFreeStringList(list);
			} else {
				c_wm_name = CString::new(std::mem::transmute((*wm_name).value), false);
				// wm_name_true = c_wm_name.as_str().unwrap();
				println!("wm_name bytes: {}", c_wm_name.as_bytes());
				// ая -      27 45 76 208 239 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// бв -      27 45 76 209 210 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// zx -      122 120 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// длодлод - 27 45 76 212 219 222 212 219 222 212 32 27 37 71 226 128 162 27 37 64 32 45 32 83 117 98 108 105 109 101 32 84 101 120 116 32 40 85 78 82 69 71 73 83 84 69 82 69 68 41 0
				// zx • - Sublime Text (UNREGISTERED)

				println!("wm_name: {}", c_wm_name);
				println!("wm_name len w/o null: {}", c_wm_name.len());
			}

		}

		XRecordFreeData(raw_data);
	}
	println!("\n");
}

// fn string_convert(string: *mut libc::c_char) -> &'static str{
// 	let temp = unsafe{CString::new(std::mem::transmute(string), true)};
// 	let a: &str = temp.as_str().unwrap();
// }
struct Display {
    display: *mut xlib::Display,
}

impl Display {
	fn get_input_focus(&self) {
		let current_window: *mut xlib::Window = &mut 0;
		let revert_to_return: *mut i32 = &mut 0;
		xlib::XGetInputFocus(self.display, current_window, revert_to_return);
		Window {display: &self}
	}
}

struct Window {
    id: u64, // XID
    display: &Display
}

impl Window {
	fn get_wm_name(&self) {
		let prop: xutil::XTextProperty;
		let res = xutil::XGetWMName(self.display.display, self.id, prop);
	}
}<|endoftext|>


<commit_before>
extern crate mio;
extern crate http_muncher;
extern crate sha1;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use std::fmt;
use std::net::SocketAddr;

use mio::*;
use mio::tcp::*;
use http_muncher::{Parser, ParserHandler};
use rustc_serialize::base64::{ToBase64, STANDARD};

fn gen_key(key: &String) -> String {
    let mut m = sha1::Sha1::new();
    let mut buf = [0u8; 20];

    m.update(key.as_bytes());
    m.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11".as_bytes());

    m.output(&mut buf);

    return buf.to_base64(STANDARD);
}

struct HttpParser {
    current_key: Option<String>,
    headers: Rc<RefCell<HashMap<String, String>>>
}

impl ParserHandler for HttpParser {
    fn on_header_field(&mut self, s: &[u8]) -> bool {
        self.current_key = Some(std::str::from_utf8(s).unwrap().to_string());
        true
    }

    fn on_header_value(&mut self, s: &[u8]) -> bool {
        self.headers.borrow_mut()
            .insert(self.current_key.clone().unwrap(),
                    std::str::from_utf8(s).unwrap().to_string());
        true
    }

    fn on_headers_complete(&mut self) -> bool {
        false
    }
}

#[derive(PartialEq)]
enum ClientState {
    AwaitingHandshake,
    HandshakeResponse,
    Connected
}

struct WebSocketClient {
    socket: TcpStream,
    headers: Rc<RefCell<HashMap<String, String>>>,
    http_parser: Parser<HttpParser>,
    interest: EventSet,
    state: ClientState
}

impl WebSocketClient {
    fn new(socket: TcpStream) -> WebSocketClient {
        let headers = Rc::new(RefCell::new(HashMap::new()));

        WebSocketClient {
            socket: socket,
            headers: headers.clone(),
            http_parser: Parser::request(HttpParser {
                current_key: None,
                headers: headers.clone()
            }),
            interest: EventSet::readable(),
            state: ClientState::AwaitingHandshake
        }
    }

    fn write(&mut self) {
        let headers = self.headers.borrow();
        let response_key = gen_key(&headers.get("Sec-WebSocket-Key").unwrap());
        let response = fmt::format(format_args!("HTTP/1.1 101 Switching Protocols\r\n\
                                                 Connection: Upgrade\r\n\
                                                 Sec-WebSocket-Accept: {}\r\n\
                                                 Upgrade: websocket\r\n\r\n", response_key));
        self.socket.try_write(response.as_bytes()).unwrap();

        // Change the state
        self.state = ClientState::Connected;

        self.interest.remove(EventSet::writable());
        self.interest.insert(EventSet::readable());
    }

    fn read(&mut self) {
        loop {
            let mut buf = [0; 2048];
            match self.socket.try_read(&mut buf) {
                Err(e) => {
                    println!("Error while reading socket: {:?}", e);
                    return
                },
                Ok(None) =>
                    // Socket buffer has got no more bytes.
                    break,
                Ok(Some(len)) => {
                    self.http_parser.parse(&buf);
                    if self.http_parser.is_upgrade() {
                        // Change the current state
                        self.state = ClientState::HandshakeResponse;

                        // Change current interest to `Writable`
                        self.interest.remove(EventSet::readable());
                        self.interest.insert(EventSet::writable());
                        break;
                    }
                }
            }
        }
    }
}

struct WebSocketServer {
    socket: TcpListener,
    clients: HashMap<Token, WebSocketClient>,
    token_counter: usize
}

const SERVER_TOKEN: Token = Token(0);

impl Handler for WebSocketServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<WebSocketServer>, token: Token, events: EventSet) {
        if events.is_readable() {
            match token {
                SERVER_TOKEN => {
                    let client_socket = match self.socket.accept() {
                        Ok(Some((sock, addr))) => sock,
                        Ok(None) => unreachable!(),
                        Err(e) => {
                            println!("Accept error: {}", e);
                            return;
                        }
                    };

                    let new_token = Token(self.token_counter);
                    self.clients.insert(new_token, WebSocketClient::new(client_socket));
                    self.token_counter += 1;

                    event_loop.register(&self.clients[&new_token].socket, new_token, EventSet::readable(),
                                        PollOpt::edge() | PollOpt::oneshot()).unwrap();
                },
	        token => {
                    let mut client = self.clients.get_mut(&token).unwrap();
                    client.read();
                    event_loop.reregister(&client.socket, token, client.interest,
                                          PollOpt::edge() | PollOpt::oneshot()).unwrap();
                }
            }
        }

        if events.is_writable() {
            let mut client = self.clients.get_mut(&token).unwrap();
            client.write();
            event_loop.reregister(&client.socket, token, client.interest,
                                  PollOpt::edge() | PollOpt::oneshot()).unwrap();
        }
    }
}

fn main() {
    let address = "0.0.0.0:10000".parse::<SocketAddr>().unwrap();
    let server_socket = TcpListener::bind(&address).unwrap();

    let mut event_loop = EventLoop::new().unwrap();

    let mut server = WebSocketServer {
        token_counter: 1,
        clients: HashMap::new(),
        socket: server_socket
    };

    event_loop.register(&server.socket,
                        SERVER_TOKEN,
                        EventSet::readable(),
                        PollOpt::edge()).unwrap();
    event_loop.run(&mut server).unwrap();
}
<commit_msg>Refactor HTTP parser state containment<commit_after>
extern crate mio;
extern crate http_muncher;
extern crate sha1;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use std::fmt;
use std::net::SocketAddr;

use mio::*;
use mio::tcp::*;
use http_muncher::{Parser, ParserHandler};
use rustc_serialize::base64::{ToBase64, STANDARD};

fn gen_key(key: &String) -> String {
    let mut m = sha1::Sha1::new();
    let mut buf = [0u8; 20];

    m.update(key.as_bytes());
    m.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11".as_bytes());

    m.output(&mut buf);

    return buf.to_base64(STANDARD);
}

struct HttpParser {
    current_key: Option<String>,
    headers: Rc<RefCell<HashMap<String, String>>>
}

impl ParserHandler for HttpParser {
    fn on_header_field(&mut self, s: &[u8]) -> bool {
        self.current_key = Some(std::str::from_utf8(s).unwrap().to_string());
        true
    }

    fn on_header_value(&mut self, s: &[u8]) -> bool {
        self.headers.borrow_mut()
            .insert(self.current_key.clone().unwrap(),
                    std::str::from_utf8(s).unwrap().to_string());
        true
    }

    fn on_headers_complete(&mut self) -> bool {
        false
    }
}

enum ClientState {
    AwaitingHandshake(RefCell<Parser<HttpParser>>),
    HandshakeResponse,
    Connected
}

struct WebSocketClient {
    socket: TcpStream,
    headers: Rc<RefCell<HashMap<String, String>>>,
    interest: EventSet,
    state: ClientState
}

impl WebSocketClient {
    fn new(socket: TcpStream) -> WebSocketClient {
        let headers = Rc::new(RefCell::new(HashMap::new()));

        WebSocketClient {
            socket: socket,
            headers: headers.clone(),
            interest: EventSet::readable(),
            state: ClientState::AwaitingHandshake(RefCell::new(Parser::request(HttpParser {
                current_key: None,
                headers: headers.clone()
            })))
        }
    }

    fn write(&mut self) {
        let headers = self.headers.borrow();
        let response_key = gen_key(&headers.get("Sec-WebSocket-Key").unwrap());
        let response = fmt::format(format_args!("HTTP/1.1 101 Switching Protocols\r\n\
                                                 Connection: Upgrade\r\n\
                                                 Sec-WebSocket-Accept: {}\r\n\
                                                 Upgrade: websocket\r\n\r\n", response_key));
        self.socket.try_write(response.as_bytes()).unwrap();

        // Change the state
        self.state = ClientState::Connected;

        self.interest.remove(EventSet::writable());
        self.interest.insert(EventSet::readable());
    }

    fn read(&mut self) {
        match self.state {
            ClientState::AwaitingHandshake(_) => {
                self.read_handshake();
            },
            _ => {}
        }
    }

    fn read_handshake(&mut self) {
        loop {
            let mut buf = [0; 2048];
            match self.socket.try_read(&mut buf) {
                Err(e) => {
                    println!("Error while reading socket: {:?}", e);
                    return
                },
                Ok(None) =>
                    // Socket buffer has got no more bytes.
                    break,
                Ok(Some(len)) => {
                    let is_upgrade = if let ClientState::AwaitingHandshake(ref parser_state) = self.state {
                        let mut parser = parser_state.borrow_mut();
                        parser.parse(&buf);
                        parser.is_upgrade()
                    } else { false };

                    if is_upgrade {
                        // Change the current state
                        self.state = ClientState::HandshakeResponse;

                        // Change current interest to `Writable`
                        self.interest.remove(EventSet::readable());
                        self.interest.insert(EventSet::writable());
                        break;
                    }
                }
            }
        }
    }
}

struct WebSocketServer {
    socket: TcpListener,
    clients: HashMap<Token, WebSocketClient>,
    token_counter: usize
}

const SERVER_TOKEN: Token = Token(0);

impl Handler for WebSocketServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<WebSocketServer>, token: Token, events: EventSet) {
        if events.is_readable() {
            match token {
                SERVER_TOKEN => {
                    let client_socket = match self.socket.accept() {
                        Ok(Some((sock, addr))) => sock,
                        Ok(None) => unreachable!(),
                        Err(e) => {
                            println!("Accept error: {}", e);
                            return;
                        }
                    };

                    let new_token = Token(self.token_counter);
                    self.clients.insert(new_token, WebSocketClient::new(client_socket));
                    self.token_counter += 1;

                    event_loop.register(&self.clients[&new_token].socket, new_token, EventSet::readable(),
                                        PollOpt::edge() | PollOpt::oneshot()).unwrap();
                },
	        token => {
                    let mut client = self.clients.get_mut(&token).unwrap();
                    client.read();
                    event_loop.reregister(&client.socket, token, client.interest,
                                          PollOpt::edge() | PollOpt::oneshot()).unwrap();
                }
            }
        }

        if events.is_writable() {
            let mut client = self.clients.get_mut(&token).unwrap();
            client.write();
            event_loop.reregister(&client.socket, token, client.interest,
                                  PollOpt::edge() | PollOpt::oneshot()).unwrap();
        }
    }
}

fn main() {
    let address = "0.0.0.0:10000".parse::<SocketAddr>().unwrap();
    let server_socket = TcpListener::bind(&address).unwrap();

    let mut event_loop = EventLoop::new().unwrap();

    let mut server = WebSocketServer {
        token_counter: 1,
        clients: HashMap::new(),
        socket: server_socket
    };

    event_loop.register(&server.socket,
                        SERVER_TOKEN,
                        EventSet::readable(),
                        PollOpt::edge()).unwrap();
    event_loop.run(&mut server).unwrap();
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{Arg, App, AppSettings};
use std::ffi::OsStr;
use std::fs::File;
use std::io;

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author("Scott Olson <scott@solson.me>")
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .setting(AppSettings::ArgRequiredElseHelp)
        .arg(Arg::with_name("FILE")
             .multiple(true)
             .required(true)
             .help("The file(s) to display"))
        .get_matches();

    let files: Vec<&OsStr> = matches.values_of_os("FILE").unwrap().collect();

    for (i, &filename) in files.iter().enumerate() {
        if i != 0 {
            println!("");
        }

        if files.len() > 1 {
            println!("# {}", filename.to_string_lossy());
        }

        io::copy(&mut File::open(filename).unwrap(), &mut io::stdout()).unwrap();
    }
}
<commit_msg>Remove author line.<commit_after>extern crate clap;

use clap::{Arg, App, AppSettings};
use std::ffi::OsStr;
use std::fs::File;
use std::io;

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .setting(AppSettings::ArgRequiredElseHelp)
        .arg(Arg::with_name("FILE")
             .multiple(true)
             .required(true)
             .help("The file(s) to display"))
        .get_matches();

    let files: Vec<&OsStr> = matches.values_of_os("FILE").unwrap().collect();

    for (i, &filename) in files.iter().enumerate() {
        if i != 0 {
            println!("");
        }

        if files.len() > 1 {
            println!("# {}", filename.to_string_lossy());
        }

        io::copy(&mut File::open(filename).unwrap(), &mut io::stdout()).unwrap();
    }
}
<|endoftext|>