<commit_before>#[macro_use(crate_version, crate_authors)]
extern crate clap;

extern crate api_server;
extern crate devices;
extern crate sys_util;
extern crate vmm;

use clap::{App, Arg, SubCommand};
use std::fs::File;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;

use api_server::{ApiRequest, ApiServer};
use sys_util::{syslog, EventFd, GuestAddress};
use vmm::{CMDLINE_MAX_SIZE, CMDLINE_OFFSET, KERNEL_START_OFFSET};
use vmm::{kernel_cmdline, KernelConfig};
use vmm::machine::{MachineCfg, DEFAULT_SUBNET_MASK};
use vmm::device_config::BlockDeviceConfig;

fn main() {
    if let Err(e) = syslog::init() {
        println!("failed to initialize syslog: {:?}", e);
        return;
    }

    let cmd_arguments = App::new("firecracker")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Launch a microvm.")
        .arg(
            Arg::with_name("api_sock")
                .long("api-sock")
                .help("Path to unix domain socket used by the API")
                .default_value("/tmp/firecracker.socket")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("vmm-no-api")
                .about("Start vmm without an API thread")
                .arg(
                    Arg::with_name("kernel_path")
                        .short("k")
                        .long("kernel-path")
                        .help("The kernel's file path (vmlinux.bin)")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("kernel_cmdline")
                        .long("kernel-cmdline")
                        .help("The kernel's command line")
                        .default_value("console=ttyS0 noapic reboot=k panic=1 pci=off nomodules")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("mem_size")
                        .long("mem-size")
                        .default_value("128")
                        .help("Virtual Machine Memory Size in MiB")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("vcpu_count")
                        .long("vcpu-count")
                        .default_value("1")
                        .help("Number of VCPUs")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("root_blk_file")
                        .short("r")
                        .long("root-blk")
                        .help("File to serve as root block device")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("tap_dev_name")
                        .long("tap-dev-name")
                        .help("Name of existing TAP interface to use for guest Virtio net device")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("subnet_mask")
                        .long("subnet-mask")
                        .default_value(DEFAULT_SUBNET_MASK)
                        .help("Subnet mask for the IP address of host interface")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("vsock_guest_cid")
                        .long("vsock-guest-cid")
                        .help("The guest CID for the virtio-vhost-vsock device")
                        .takes_value(true),
                ),
        )
        .get_matches();

    let (to_vmm, from_api) = channel();

    // TODO: vmm_no_api is for integration testing, need to find a more pretty solution
    match cmd_arguments.subcommand {
        Some(_) => {
            vmm_no_api_handler(
                cmd_arguments.subcommand_matches("vmm-no-api").unwrap(),
                from_api,
            );
        }
        None => {
            // safe to unwrap since api_sock has a default value
            let bind_path = cmd_arguments
                .value_of("api_sock")
                .map(|s| PathBuf::from(s))
                .unwrap();

            let server = ApiServer::new(to_vmm, 100).unwrap();
            let api_event_fd = server
                .get_event_fd_clone()
                .expect("cannot clone API eventFD");
            // vmm thread should not need a MachineCfg, will give the default for the moment
            // and remove it later on
            let _vmm_thread_handle =
                vmm::start_vmm_thread(MachineCfg::default(), api_event_fd, from_api);
            server.bind_and_run(bind_path).unwrap();
        }
    }
}

fn vmm_no_api_handler(cmd_arguments: &clap::ArgMatches, from_api: Receiver<Box<ApiRequest>>) {
    let cfg = parse_args(&cmd_arguments);

    let mut vmm = vmm::Vmm::new(
        cfg,
        EventFd::new().expect("cannot create eventFD"),
        from_api,
    ).expect("cannot create VMM");

    // configure virtual machine from command line
    if cmd_arguments.is_present("vcpu_count") {
        match cmd_arguments
            .value_of("vcpu_count")
            .unwrap()
            .to_string()
            .parse::<u8>()
        {
            Ok(vcpu_count) => {
                vmm.put_virtual_machine_configuration(Some(vcpu_count), None)
                    .expect("Invalid value for vcpu_count");
            }
            Err(error) => {
                panic!("Invalid value for vcpu_count! {:?}", error);
            }
        };
    }
    if cmd_arguments.is_present("mem_size") {
        match cmd_arguments
            .value_of("mem_size")
            .unwrap()
            .to_string()
            .parse::<usize>()
        {
            Ok(mem_size_mib) => {
                vmm.put_virtual_machine_configuration(None, Some(mem_size_mib))
                    .expect("Invalid value for mem_size!");
            }
            Err(error) => {
                panic!("Invalid value for mem_size! {:?}", error);
            }
        }
    }

    // This is a temporary fix. Block devices should be added via http requests.
    // With the command line, we can only add one device, with default to root block device.
    if cmd_arguments.is_present("root_blk_file") {
        let root_block_device = BlockDeviceConfig {
            path_on_host: PathBuf::from(cmd_arguments.value_of("root_blk_file").unwrap()),
            is_root_device: true,
            drive_id: String::from("1"),
        };
        vmm.put_block_device(root_block_device)
            .expect("cannot add root block device.");
    }

    if let Some(value) = cmd_arguments.value_of("tap_dev_name") {
        let host_dev_name = String::from(value);

        use api_server::request::sync::DeviceState;
        use api_server::request::sync::NetworkInterfaceBody;

        let body = NetworkInterfaceBody {
            iface_id: String::from("0"),
            state: DeviceState::Attached,
            host_dev_name,
            guest_mac: None,
        };

        vmm.put_net_device(body).expect("failed adding net device.");
    }

    // configure kernel from command line
    //we're using unwrap here because the kernel_path is mandatory for now
    let kernel_file = File::open(cmd_arguments.value_of("kernel_path").unwrap_or_default())
        .expect("Cannot open kernel file");

    let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE);
    cmdline
        .insert_str(cmd_arguments.value_of("kernel_cmdline").unwrap())
        .expect("could not use the specified kernel cmdline");
    let kernel_config = KernelConfig {
        cmdline,
        kernel_file,
        kernel_start_addr: GuestAddress(KERNEL_START_OFFSET),
        cmdline_addr: GuestAddress(CMDLINE_OFFSET),
    };
    vmm.configure_kernel(kernel_config);
    vmm.boot_kernel().expect("cannot boot kernel");
    vmm.run_control().expect("VMM loop error!");
}

fn parse_args(cmd_arguments: &clap::ArgMatches) -> MachineCfg {
    let root_blk_file = cmd_arguments
        .value_of("root_blk_file")
        .map(|s| PathBuf::from(s));

    let vsock_guest_cid = match cmd_arguments.value_of("vsock_guest_cid") {
        Some(cid) => match cid.parse::<u64>() {
            Ok(value) => Some(value),
            Err(error) => {
                panic!(
                    "Invalid parameter value for the vsock's guest CID! {:?}",
                    error
                );
            }
        },
        None => None,
    };

    // host_ip; no longer used; remove when refactoring MachineCfg
    let host_ip: Option<Ipv4Addr> = Some("1.2.3.4".parse().unwrap());
    // subnet_mask; no longer used; remove when refactoring MachineCfg
    let subnet_mask: Ipv4Addr = "255.255.255.0".parse().unwrap();

    MachineCfg::new(root_blk_file, host_ip, subnet_mask, vsock_guest_cid)
}
<commit_msg>src/main.rs: vsock with vmm-no-api<commit_after>#[macro_use(crate_version, crate_authors)]
extern crate clap;

extern crate api_server;
extern crate devices;
extern crate sys_util;
extern crate vmm;

use clap::{App, Arg, SubCommand};
use std::fs::File;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;

use api_server::{ApiRequest, ApiServer};
use api_server::request::sync::{DeviceState, NetworkInterfaceBody, VsockJsonBody};
use sys_util::{syslog, EventFd, GuestAddress};
use vmm::{CMDLINE_MAX_SIZE, CMDLINE_OFFSET, KERNEL_START_OFFSET};
use vmm::{kernel_cmdline, KernelConfig};
use vmm::machine::{MachineCfg, DEFAULT_SUBNET_MASK};
use vmm::device_config::BlockDeviceConfig;

fn main() {
    if let Err(e) = syslog::init() {
        println!("failed to initialize syslog: {:?}", e);
        return;
    }

    let cmd_arguments = App::new("firecracker")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Launch a microvm.")
        .arg(
            Arg::with_name("api_sock")
                .long("api-sock")
                .help("Path to unix domain socket used by the API")
                .default_value("/tmp/firecracker.socket")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("vmm-no-api")
                .about("Start vmm without an API thread")
                .arg(
                    Arg::with_name("kernel_path")
                        .short("k")
                        .long("kernel-path")
                        .help("The kernel's file path (vmlinux.bin)")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("kernel_cmdline")
                        .long("kernel-cmdline")
                        .help("The kernel's command line")
                        .default_value("console=ttyS0 noapic reboot=k panic=1 pci=off nomodules")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("mem_size")
                        .long("mem-size")
                        .default_value("128")
                        .help("Virtual Machine Memory Size in MiB")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("vcpu_count")
                        .long("vcpu-count")
                        .default_value("1")
                        .help("Number of VCPUs")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("root_blk_file")
                        .short("r")
                        .long("root-blk")
                        .help("File to serve as root block device")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("tap_dev_name")
                        .long("tap-dev-name")
                        .help("Name of existing TAP interface to use for guest Virtio net device")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("subnet_mask")
                        .long("subnet-mask")
                        .default_value(DEFAULT_SUBNET_MASK)
                        .help("Subnet mask for the IP address of host interface")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("vsock_guest_cid")
                        .long("vsock-guest-cid")
                        .help("The guest CID for the virtio-vhost-vsock device")
                        .takes_value(true),
                ),
        )
        .get_matches();

    let (to_vmm, from_api) = channel();

    // TODO: vmm_no_api is for integration testing, need to find a more pretty solution
    match cmd_arguments.subcommand {
        Some(_) => {
            vmm_no_api_handler(
                cmd_arguments.subcommand_matches("vmm-no-api").unwrap(),
                from_api,
            );
        }
        None => {
            // safe to unwrap since api_sock has a default value
            let bind_path = cmd_arguments
                .value_of("api_sock")
                .map(|s| PathBuf::from(s))
                .unwrap();

            let server = ApiServer::new(to_vmm, 100).unwrap();
            let api_event_fd = server
                .get_event_fd_clone()
                .expect("cannot clone API eventFD");
            // vmm thread should not need a MachineCfg, will give the default for the moment
            // and remove it later on
            let _vmm_thread_handle =
                vmm::start_vmm_thread(MachineCfg::default(), api_event_fd, from_api);
            server.bind_and_run(bind_path).unwrap();
        }
    }
}

fn vmm_no_api_handler(cmd_arguments: &clap::ArgMatches, from_api: Receiver<Box<ApiRequest>>) {
    let cfg = parse_args(&cmd_arguments);

    let mut vmm = vmm::Vmm::new(
        cfg,
        EventFd::new().expect("cannot create eventFD"),
        from_api,
    ).expect("cannot create VMM");

    // configure virtual machine from command line
    if cmd_arguments.is_present("vcpu_count") {
        match cmd_arguments
            .value_of("vcpu_count")
            .unwrap()
            .to_string()
            .parse::<u8>()
        {
            Ok(vcpu_count) => {
                vmm.put_virtual_machine_configuration(Some(vcpu_count), None)
                    .expect("Invalid value for vcpu_count");
            }
            Err(error) => {
                panic!("Invalid value for vcpu_count! {:?}", error);
            }
        };
    }
    if cmd_arguments.is_present("mem_size") {
        match cmd_arguments
            .value_of("mem_size")
            .unwrap()
            .to_string()
            .parse::<usize>()
        {
            Ok(mem_size_mib) => {
                vmm.put_virtual_machine_configuration(None, Some(mem_size_mib))
                    .expect("Invalid value for mem_size!");
            }
            Err(error) => {
                panic!("Invalid value for mem_size! {:?}", error);
            }
        }
    }

    // This is a temporary fix. Block devices should be added via http requests.
    // With the command line, we can only add one device, with default to root block device.
    if cmd_arguments.is_present("root_blk_file") {
        let root_block_device = BlockDeviceConfig {
            path_on_host: PathBuf::from(cmd_arguments.value_of("root_blk_file").unwrap()),
            is_root_device: true,
            drive_id: String::from("1"),
        };
        vmm.put_block_device(root_block_device)
            .expect("cannot add root block device.");
    }

    if let Some(value) = cmd_arguments.value_of("tap_dev_name") {
        let host_dev_name = String::from(value);

        let body = NetworkInterfaceBody {
            iface_id: String::from("0"),
            state: DeviceState::Attached,
            host_dev_name,
            guest_mac: None,
        };

        vmm.put_net_device(body).expect("failed adding net device.");
    }

    if let Some(cid) = cmd_arguments.value_of("vsock_guest_cid") {
        let cid = cid.parse::<u32>().expect("unable to parse cid value.");
        let body = VsockJsonBody {
            vsock_id: String::from("1"),
            guest_cid: cid,
            state: DeviceState::Attached,
        };

        vmm.put_vsock_device(body)
            .expect("cannot add vsock device.");
    }

    // configure kernel from command line
    //we're using unwrap here because the kernel_path is mandatory for now
    let kernel_file = File::open(cmd_arguments.value_of("kernel_path").unwrap_or_default())
        .expect("Cannot open kernel file");

    let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE);
    cmdline
        .insert_str(cmd_arguments.value_of("kernel_cmdline").unwrap())
        .expect("could not use the specified kernel cmdline");
    let kernel_config = KernelConfig {
        cmdline,
        kernel_file,
        kernel_start_addr: GuestAddress(KERNEL_START_OFFSET),
        cmdline_addr: GuestAddress(CMDLINE_OFFSET),
    };
    vmm.configure_kernel(kernel_config);
    vmm.boot_kernel().expect("cannot boot kernel");
    vmm.run_control().expect("VMM loop error!");
}

fn parse_args(cmd_arguments: &clap::ArgMatches) -> MachineCfg {
    // TODO: this is also no longer necesssary, right?
    let root_blk_file = cmd_arguments
        .value_of("root_blk_file")
        .map(|s| PathBuf::from(s));

    // no longer used; remove when refactoring MachineCfg
    let host_ip: Option<Ipv4Addr> = Some("1.2.3.4".parse().unwrap());
    // no longer used; remove when refactoring MachineCfg
    let subnet_mask: Ipv4Addr = "255.255.255.0".parse().unwrap();
    // no longer used; remove when refactoring MachineCfg
    let vsock_guest_cid = None;

    MachineCfg::new(root_blk_file, host_ip, subnet_mask, vsock_guest_cid)
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use std::fmt;
use std::io;
use std::io::Write;
use std::sync::Mutex;

extern crate syn;
use syn::*;

mod rust_lib;

#[derive(Debug)]
struct ConvertedType {
    /// The type converted to C (e.g. `uint32_t`)
    prefix: String,
    /// Stuff that might need to go after the identifier (e.g. `[3]` for an array).
    postfix: String,
}

impl ConvertedType {
    fn new<T: Into<String>>(pre: T, post: String) -> Self {
        ConvertedType {
            prefix: pre.into(),
            postfix: post
        }
    }

    fn format_with_ident(&self, ident: &Ident) -> String {
        format!("{} {}{}", &self.prefix, &ident.to_string(), &self.postfix)
    }
}

impl Into<String> for ConvertedType {
    fn into(self) -> String {
        let mut str = String::from(self.prefix);
        str.push_str(&self.postfix);
        str
    }
}

impl From<String> for ConvertedType {
    fn from(str: String) -> ConvertedType {
        ConvertedType {
            prefix: str,
            postfix: String::new()
        }
    }
}

impl fmt::Display for ConvertedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", &self.prefix, &self.postfix)
    }
}

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_repr_u32(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> ConvertedType {
    let l = p.segments[0].ident.to_string();
    let mut c = match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "u64" => "uint64_t".to_string(),
        "i8" => "int8_t".to_string(),
        "i32" => "int32_t".to_string(),
        "i64" => "int64_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    };
    if let PathParameters::AngleBracketed(ref d) = p.segments[0].parameters {
        let template_args = d.types
            .iter()
            .map(|ty| map_ty(ty).into())
            .collect::<Vec<String>>()
            .join(", ");
        if !template_args.is_empty() {
            c.push('<');
            c.push_str(&template_args);
            c.push('>');
        }
    }
    ConvertedType::from(c)
}

fn map_mut_ty(mut_ty: &MutTy) -> ConvertedType {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> ConvertedType {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => ConvertedType::from(format!("{}*", map_ty(&p.ty))),
        &Ty::Rptr(_, ref mut_ty) => ConvertedType::from(format!("{}*", map_mut_ty(mut_ty))),
        &Ty::Array(ref p, ConstExpr::Lit(Lit::Int(sz, _))) => ConvertedType::new(map_ty(&p), format!("[{}]", sz)),
        _ => ConvertedType::from(format!("unknown {:?}", ty)),
    }
}

fn map_return_type(ret: &FunctionRetTy) -> ConvertedType {
    match ret {
        &FunctionRetTy::Default => ConvertedType::from("void".to_string()),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => map_ty(ty).format_with_ident(ident),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    let converted = map_ty(&f.ty);
    ret.push_str(&converted.format_with_ident(f.ident.as_ref().expect("Struct fields must have idents")));
    ret.push_str(";\n");
    ret
}

fn map_generic_param(t: &TyParam) -> String {
    let mut ret = String::from("typename ");
    ret.push_str(&t.ident.to_string());
    ret
}

fn fold_enum_variants(accum: (String, i32), v: &Variant) -> (String, i32) {
    // `accum` contains the combined string of converted enum variants so far, to which
    // we will append the converted version of `v`. The other thing in `accum` is the
    // value of the previous variant. If `v` has an explicit value we keep that, otherwise
    // we increment the value of the previous variant to get the new one. This is all
    // so that we properly support enums with explicitly-specified and discontinuous
    // values.
    let mut ret = accum.0;
    ret.push_str("  ");
    ret.push_str(&v.ident.to_string());
    ret.push_str(" = ");
    let new_value = match &v.discriminant {
        &None => accum.1 + 1,
        &Some(ConstExpr::Lit(Lit::Int(ref specified_value, _))) => *specified_value as i32,
        &Some(_) => {
            // we don't handle this yet, so just put in something that will fail C compilation
            writeln!(io::stderr(), "warning, unsupported enum discriminant").unwrap();
            ret.push_str("???");
            accum.1 + 1
        }
    };
    ret.push_str(&new_value.to_string());
    ret.push_str(",\n");
    (ret, new_value)
}

/// A structure to store all the results of converting Rust stuff to C
/// stuff, so that we can pick and choose what we output.
struct ConversionResults {
    /// This holds the C function signatures of no_mangle rust functions,
    /// in the order that they were encountered in Rust.
    funcs: Vec<String>,
    /// This holds the C conversions of repr(C) structs and repr(u32) enums
    /// from Rust. The 'ds' in the name stands for 'data structures'. The
    /// key of the map is the name of the type, and the value is the C code.
    c_ds: HashMap<String, String>,
    /// This holds the dependency tree. If a struct contains another struct
    /// or an enum it will be in this map. The key is the dependent type,
    /// the list of values are all the things it depends on.
    _dep_tree: HashMap<String, Vec<String>>,
}

fn main() {
    let p = env::args().nth(1).unwrap();

    let results = Mutex::new(ConversionResults {
        funcs: Vec::new(),
        c_ds: HashMap::new(),
        _dep_tree: HashMap::new(),
    });

    rust_lib::parse(p, &|mod_name, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    writeln!(io::stderr(), "processing function {}::{}", mod_name, &item.ident).unwrap();
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        results.lock().unwrap().funcs.push(
                            format!("WR_INLINE {}\n{}({})\n{};\n",
                                    map_return_type(&decl.output),
                                    item.ident,
                                    decl.inputs
                                        .iter()
                                        .map(map_arg)
                                        .collect::<Vec<_>>()
                                        .join(", "),
                                    wr_func_body(&item.attrs)));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref generics) => {
                    writeln!(io::stderr(), "processing struct {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            let mut c_struct = String::new();
                            if !generics.ty_params.is_empty() {
                                c_struct.push_str(&(
                                    format!("template<{}>",
                                            generics.ty_params
                                                    .iter()
                                                    .map(map_generic_param)
                                                    .collect::<Vec<_>>()
                                                    .join(", "))));
                            }
                            c_struct.push_str(&(
                                format!("struct {} {{\n{}}};\n",
                                        item.ident,
                                        fields.iter()
                                              .map(map_field)
                                              .collect::<String>())));
                            results.lock().unwrap().c_ds.insert(
                                item.ident.to_string(),
                                c_struct);
                        }
                    }
                }
                ItemKind::Enum(ref variants, ref _generics) => {
                    writeln!(io::stderr(), "processing enum {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_u32(&item.attrs) {
                        let c_enum = format!("enum class {}: uint32_t {{\n{}\n  Sentinel /* this must be last for serialization purposes. */\n}};\n",
                                             item.ident,
                                             variants.iter()
                                                     .fold((String::new(), -1), fold_enum_variants)
                                                     .0);
                        results.lock().unwrap().c_ds.insert(
                            item.ident.to_string(),
                            c_enum);
                    }
                }
                _ => {}
            }
        }
    });
    for (_, c_stuff) in &results.lock().unwrap().c_ds {
        println!("{}", c_stuff);
    }
    for func in &results.lock().unwrap().funcs {
        println!("{}", func);
    }
}
<commit_msg>Use BTreeMap for more deterministic output, since it keeps stuff sorted<commit_after>use std::collections::BTreeMap;
use std::env;
use std::fmt;
use std::io;
use std::io::Write;
use std::sync::Mutex;

extern crate syn;
use syn::*;

mod rust_lib;

#[derive(Debug)]
struct ConvertedType {
    /// The type converted to C (e.g. `uint32_t`)
    prefix: String,
    /// Stuff that might need to go after the identifier (e.g. `[3]` for an array).
    postfix: String,
}

impl ConvertedType {
    fn new<T: Into<String>>(pre: T, post: String) -> Self {
        ConvertedType {
            prefix: pre.into(),
            postfix: post
        }
    }

    fn format_with_ident(&self, ident: &Ident) -> String {
        format!("{} {}{}", &self.prefix, &ident.to_string(), &self.postfix)
    }
}

impl Into<String> for ConvertedType {
    fn into(self) -> String {
        let mut str = String::from(self.prefix);
        str.push_str(&self.postfix);
        str
    }
}

impl From<String> for ConvertedType {
    fn from(str: String) -> ConvertedType {
        ConvertedType {
            prefix: str,
            postfix: String::new()
        }
    }
}

impl fmt::Display for ConvertedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", &self.prefix, &self.postfix)
    }
}

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_repr_u32(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> ConvertedType {
    let l = p.segments[0].ident.to_string();
    let mut c = match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "u64" => "uint64_t".to_string(),
        "i8" => "int8_t".to_string(),
        "i32" => "int32_t".to_string(),
        "i64" => "int64_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    };
    if let PathParameters::AngleBracketed(ref d) = p.segments[0].parameters {
        let template_args = d.types
            .iter()
            .map(|ty| map_ty(ty).into())
            .collect::<Vec<String>>()
            .join(", ");
        if !template_args.is_empty() {
            c.push('<');
            c.push_str(&template_args);
            c.push('>');
        }
    }
    ConvertedType::from(c)
}

fn map_mut_ty(mut_ty: &MutTy) -> ConvertedType {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> ConvertedType {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => ConvertedType::from(format!("{}*", map_ty(&p.ty))),
        &Ty::Rptr(_, ref mut_ty) => ConvertedType::from(format!("{}*", map_mut_ty(mut_ty))),
        &Ty::Array(ref p, ConstExpr::Lit(Lit::Int(sz, _))) => ConvertedType::new(map_ty(&p), format!("[{}]", sz)),
        _ => ConvertedType::from(format!("unknown {:?}", ty)),
    }
}

fn map_return_type(ret: &FunctionRetTy) -> ConvertedType {
    match ret {
        &FunctionRetTy::Default => ConvertedType::from("void".to_string()),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => map_ty(ty).format_with_ident(ident),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    let converted = map_ty(&f.ty);
    ret.push_str(&converted.format_with_ident(f.ident.as_ref().expect("Struct fields must have idents")));
    ret.push_str(";\n");
    ret
}

fn map_generic_param(t: &TyParam) -> String {
    let mut ret = String::from("typename ");
    ret.push_str(&t.ident.to_string());
    ret
}

fn fold_enum_variants(accum: (String, i32), v: &Variant) -> (String, i32) {
    // `accum` contains the combined string of converted enum variants so far, to which
    // we will append the converted version of `v`. The other thing in `accum` is the
    // value of the previous variant. If `v` has an explicit value we keep that, otherwise
    // we increment the value of the previous variant to get the new one. This is all
    // so that we properly support enums with explicitly-specified and discontinuous
    // values.
    let mut ret = accum.0;
    ret.push_str("  ");
    ret.push_str(&v.ident.to_string());
    ret.push_str(" = ");
    let new_value = match &v.discriminant {
        &None => accum.1 + 1,
        &Some(ConstExpr::Lit(Lit::Int(ref specified_value, _))) => *specified_value as i32,
        &Some(_) => {
            // we don't handle this yet, so just put in something that will fail C compilation
            writeln!(io::stderr(), "warning, unsupported enum discriminant").unwrap();
            ret.push_str("???");
            accum.1 + 1
        }
    };
    ret.push_str(&new_value.to_string());
    ret.push_str(",\n");
    (ret, new_value)
}

/// A structure to store all the results of converting Rust stuff to C
/// stuff, so that we can pick and choose what we output.
struct ConversionResults {
    /// This holds the C function signatures of no_mangle rust functions,
    /// in the order that they were encountered in Rust.
    funcs: Vec<String>,
    /// This holds the C conversions of repr(C) structs and repr(u32) enums
    /// from Rust. The 'ds' in the name stands for 'data structures'. The
    /// key of the map is the name of the type, and the value is the C code.
    c_ds: BTreeMap<String, String>,
    /// This holds the dependency tree. If a struct contains another struct
    /// or an enum it will be in this map. The key is the dependent type,
    /// the list of values are all the things it depends on.
    _dep_tree: BTreeMap<String, Vec<String>>,
}

fn main() {
    let p = env::args().nth(1).unwrap();

    let results = Mutex::new(ConversionResults {
        funcs: Vec::new(),
        c_ds: BTreeMap::new(),
        _dep_tree: BTreeMap::new(),
    });

    rust_lib::parse(p, &|mod_name, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    writeln!(io::stderr(), "processing function {}::{}", mod_name, &item.ident).unwrap();
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        results.lock().unwrap().funcs.push(
                            format!("WR_INLINE {}\n{}({})\n{};\n",
                                    map_return_type(&decl.output),
                                    item.ident,
                                    decl.inputs
                                        .iter()
                                        .map(map_arg)
                                        .collect::<Vec<_>>()
                                        .join(", "),
                                    wr_func_body(&item.attrs)));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref generics) => {
                    writeln!(io::stderr(), "processing struct {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            let mut c_struct = String::new();
                            if !generics.ty_params.is_empty() {
                                c_struct.push_str(&(
                                    format!("template<{}>",
                                            generics.ty_params
                                                    .iter()
                                                    .map(map_generic_param)
                                                    .collect::<Vec<_>>()
                                                    .join(", "))));
                            }
                            c_struct.push_str(&(
                                format!("struct {} {{\n{}}};\n",
                                        item.ident,
                                        fields.iter()
                                              .map(map_field)
                                              .collect::<String>())));
                            results.lock().unwrap().c_ds.insert(
                                item.ident.to_string(),
                                c_struct);
                        }
                    }
                }
                ItemKind::Enum(ref variants, ref _generics) => {
                    writeln!(io::stderr(), "processing enum {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_u32(&item.attrs) {
                        let c_enum = format!("enum class {}: uint32_t {{\n{}\n  Sentinel /* this must be last for serialization purposes. */\n}};\n",
                                             item.ident,
                                             variants.iter()
                                                     .fold((String::new(), -1), fold_enum_variants)
                                                     .0);
                        results.lock().unwrap().c_ds.insert(
                            item.ident.to_string(),
                            c_enum);
                    }
                }
                _ => {}
            }
        }
    });
    for (_, c_stuff) in &results.lock().unwrap().c_ds {
        println!("{}", c_stuff);
    }
    for func in &results.lock().unwrap().funcs {
        println!("{}", func);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use iron::prelude::*;
use iron::status;
use router::Router;

use std::io::Read;
fn main() {
    let router = router!(telegram: post "/telegram" => telegram);

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

    fn telegram(req: &mut Request) -> IronResult<Response> {
        let mut body = Vec::new();
        req
            .body
            .read_to_end(&mut body)
            .map_err(|e| IronError::new(e, (status::InternalServerError, "Error reading request")))?;
        let body = String::from_utf8(body).unwrap();
        println!("{}", body);
        Ok(Response::with((status::Ok, "ok")))
    }
}

#[derive(Serialize, Deserialize)]
struct Update {
    update_id: i32,
    message: Option<Message>,
    edited_message: Option<Message>,
    channel_post: Option<Message>,
    edited_channel_post: Option<Message>,
    inline_query: Option<InlineQuery>,
    chosen_inline_result: Option<ChosenInlineResult>,
    callback_query: Option<CallbackQuery>,
    shipping_query: Option<ShippingQuery>,
    pre_checkout_query: Option<PreCheckoutQuery>,
}

#[derive(Serialize, Deserialize)]
struct Message {
    message_id: i32,
    from: Option<User>,
    date: i32,
    chat: Chat,
    forward_from: Option<User>,
    forward_from_chat: Option<Chat>,
    forward_from_message_id: Option<i32>,
    forward_date: Option<i32>,
    reply_to_message: Box<Option<Message>>,
    edit_date: Option<i32>,
    text: Option<String>,
    entities: Option<Vec<MessageEntity>>,
    audio: Option<Audio>,
    document: Option<Document>,
    game: Option<Game>,
    photo: Option<Vec<PhotoSize>>,
    sticker: Option<Sticker>,
    video: Option<Video>,
    voice: Option<Voice>,
    video_note: Option<VideoNote>,
    new_chat_members: Option<Vec<User>>,
    caption: Option<String>,
    contact: Option<Contact>,
    location: Option<Location>,
    venue: Option<Venue>,
    new_chat_member: Option<User>,
    left_chat_member: Option<User>,
    new_chat_title: Option<String>,
    new_chat_photo: Option<Vec<PhotoSize>>,
    delete_chat_photo: Option<bool>,
}

#[derive(Serialize, Deserialize)]
struct InlineQuery {
    update_id: i32,
    from: User,
    location: Option<Location>,
    query: String,
    offset: String,
}

#[derive(Serialize, Deserialize)]
struct ChosenInlineResult {
    update_id: i32,
    from: User,
    location: Option<Location>,
    inline_message_id: Option<String>,
    query: String,
}

#[derive(Serialize, Deserialize)]
struct CallbackQuery {
    result: i32,
    from: User,
    message: Option<String>,
    inline_message_id: Option<String>,
    chat_instance: String,
    data: Option<String>,
    game_short_name: Option<String>
}

#[derive(Serialize, Deserialize)]
struct ShippingQuery {
    shipping_query_id: String,
    ok: bool,
    shipping_options: Option<Vec<ShippingOption>>,
    error_message: Option<String>,
}

#[derive(Serialize, Deserialize)]
struct ShippingOption {
    id:String,
    from: User,
    invoice_payload: String,
    shipping_address: ShippingAddress,
}

#[derive(Serialize, Deserialize)]
struct ShippingAddress {
   country_code: String,
   state: String,
   city: String,
   street_line1: String,
   street_line2: String,
   post_code: String,
}

#[derive(Serialize, Deserialize)]
struct PreCheckoutQuery {
id:String,
from: User,
currency: String,
total_amount: i32,
invoice_payload: String,
shipping_option_id: Option<String>,
order_info: Option<OrderInfo>,
}

#[derive(Serialize, Deserialize)]
struct User {
    id: i32,
    first_name: Option<String>,
    last_name: Option<String>,
    username: Option<String>,
    language_code: Option<String>,
}

#[derive(Serialize, Deserialize)]
struct Chat {
    id: i32,
    type: String,
    title: Option<String>,
    username: Option<String>,
    first_name: Option<String>,
    last_name: Option<String>,
    all_members_are_administrators: Option<bool>,
}

#[derive(Serialize, Deserialize)]
struct Location {
longitude: f64,
latitude: f64,
}

#[derive(Serialize, Deserialize)]
struct OrderInfo {
name: Option<String>,
phone_number: Option<String>,
email: Option<String>,
shipping_address: Option<String>,
}
<commit_msg>Run rustfmt<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use iron::prelude::*;
use iron::status;
use router::Router;

use std::io::Read;
fn main() {
    let router = router!(telegram: post "/telegram" => telegram);

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

    fn telegram(req: &mut Request) -> IronResult<Response> {
        let mut body = Vec::new();
        req
            .body
            .read_to_end(&mut body)
            .map_err(|e|
                IronError::new(e,
                    (status::InternalServerError, "Error reading request")
                )
            )?;
        let body = String::from_utf8(body).unwrap();
        println!("{}", body);
        Ok(Response::with((status::Ok, "ok")))
    }
}

#[derive(Serialize, Deserialize)]
struct Update {
    update_id: i32,
    message: Option<Message>,
    edited_message: Option<Message>,
    channel_post: Option<Message>,
    edited_channel_post: Option<Message>,
    inline_query: Option<InlineQuery>,
    chosen_inline_result: Option<ChosenInlineResult>,
    callback_query: Option<CallbackQuery>,
    shipping_query: Option<ShippingQuery>,
    pre_checkout_query: Option<PreCheckoutQuery>,
}

#[derive(Serialize, Deserialize)]
struct Message {
    message_id: i32,
    from: Option<User>,
    date: i32,
    chat: Chat,
    forward_from: Option<User>,
    forward_from_chat: Option<Chat>,
    forward_from_message_id: Option<i32>,
    forward_date: Option<i32>,
    reply_to_message: Box<Option<Message>>,
    edit_date: Option<i32>,
    text: Option<String>,
    entities: Option<Vec<MessageEntity>>,
    audio: Option<Audio>,
    document: Option<Document>,
    game: Option<Game>,
    photo: Option<Vec<PhotoSize>>,
    sticker: Option<Sticker>,
    video: Option<Video>,
    voice: Option<Voice>,
    video_note: Option<VideoNote>,
    new_chat_members: Option<Vec<User>>,
    caption: Option<String>,
    contact: Option<Contact>,
    location: Option<Location>,
    venue: Option<Venue>,
    new_chat_member: Option<User>,
    left_chat_member: Option<User>,
    new_chat_title: Option<String>,
    new_chat_photo: Option<Vec<PhotoSize>>,
    delete_chat_photo: Option<bool>,
}

#[derive(Serialize, Deserialize)]
struct InlineQuery {
    update_id: i32,
    from: User,
    location: Option<Location>,
    query: String,
    offset: String,
}

#[derive(Serialize, Deserialize)]
struct ChosenInlineResult {
    update_id: i32,
    from: User,
    location: Option<Location>,
    inline_message_id: Option<String>,
    query: String,
}

#[derive(Serialize, Deserialize)]
struct CallbackQuery {
    result: i32,
    from: User,
    message: Option<String>,
    inline_message_id: Option<String>,
    chat_instance: String,
    data: Option<String>,
    game_short_name: Option<String>,
}

#[derive(Serialize, Deserialize)]
struct ShippingQuery {
    shipping_query_id: String,
    ok: bool,
    shipping_options: Option<Vec<ShippingOption>>,
    error_message: Option<String>,
}

#[derive(Serialize, Deserialize)]
struct ShippingOption {
    id: String,
    from: User,
    invoice_payload: String,
    shipping_address: ShippingAddress,
}

#[derive(Serialize, Deserialize)]
struct ShippingAddress {
    country_code: String,
    state: String,
    city: String,
    street_line1: String,
    street_line2: String,
    post_code: String,
}

#[derive(Serialize, Deserialize)]
struct PreCheckoutQuery {
    id: String,
    from: User,
    currency: String,
    total_amount: i32,
    invoice_payload: String,
    shipping_option_id: Option<String>,
    order_info: Option<OrderInfo>,
}

#[derive(Serialize, Deserialize)]
struct User {
    id: i32,
    first_name: Option<String>,
    last_name: Option<String>,
    username: Option<String>,
    language_code: Option<String>,
}

#[derive(Serialize, Deserialize)]
#[serde(chat_type = "type")]
struct Chat {
    id: i32,
    chat_type: String,
    title: Option<String>,
    username: Option<String>,
    first_name: Option<String>,
    last_name: Option<String>,
    all_members_are_administrators: Option<bool>,
}

#[derive(Serialize, Deserialize)]
struct Location {
    longitude: f64,
    latitude: f64,
}

#[derive(Serialize, Deserialize)]
struct OrderInfo {
    name: Option<String>,
    phone_number: Option<String>,
    email: Option<String>,
    shipping_address: Option<String>,
}
<|endoftext|>


<commit_before>//! A Rust port of sbt-extras.
//! Author: Dale Wijnand <dale.wijnand@gmail.com>

extern crate curl;
#[macro_use] extern crate duct;
extern crate jsonrpc_lite;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde_json;
extern crate void;

use std::fs::File;

mod launcher;
mod client;

fn main() {
    match File::open("project/target/active.json") {
        Ok(port_file) => client::talk_to_client(port_file),
        Err(_)        => launcher::Launcher::new().run(),
    }
}
<commit_msg>Fix edition idioms<commit_after>//! A Rust port of sbt-extras.
//! Author: Dale Wijnand <dale.wijnand@gmail.com>

use curl;
#[macro_use] extern crate duct;
use jsonrpc_lite;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde_json;
use void;

use std::fs::File;

mod launcher;
mod client;

fn main() {
    match File::open("project/target/active.json") {
        Ok(port_file) => client::talk_to_client(port_file),
        Err(_)        => launcher::Launcher::new().run(),
    }
}
<|endoftext|>


<commit_before>extern crate bytes;
extern crate env_logger;
extern crate mio;
#[macro_use]
extern crate log;
#[macro_use]
extern crate clap;
extern crate failure;
extern crate slab;

use clap::{App, Arg};
use failure::Error;
use failure::ResultExt;
use mio::net::{TcpListener, TcpStream};
use slab::Slab;
use std::collections::VecDeque;
use std::io::{Read, Write};
use std::ops;

#[derive(Debug)]
enum MiChatCommand {
    Broadcast(String),
    NewConnection(TcpStream),
}

struct MiChat {
    connections: Slab<EventHandler>,
}

trait RuleHandler {
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready);
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token);
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error>;
    fn is_closed(&self) -> bool;
}

impl MiChat {
    fn new() -> MiChat {
        MiChat {
            connections: Slab::new(),
        }
    }

    fn listen(&mut self, event_loop: &mut mio::Poll, listener: TcpListener) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Listener(Listener::new(listener, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn process_action(&mut self, msg: MiChatCommand, event_loop: &mut mio::Poll) {
        trace!("{:p}; got {:?}", self, msg);
        match msg {
            MiChatCommand::Broadcast(s) => self.process_broadcast(s),
            MiChatCommand::NewConnection(socket) => self.process_new_connection(event_loop, socket),
        }
    }

    fn process_broadcast(&mut self, s: String) {
        for c in self.client_connections_mut() {
            c.enqueue(&s);
        }
    }

    fn process_new_connection(&mut self, event_loop: &mut mio::Poll, socket: mio::tcp::TcpStream) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Conn(Connection::new(socket, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn client_connections_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Connection> + 'a {
        self.connections.iter_mut().filter_map(|(_, it)| match it {
            &mut EventHandler::Conn(ref mut c) => Some(c),
            _ => None,
        })
    }
}

#[derive(Debug)]
struct Connection {
    socket: TcpStream,
    sock_status: mio::Ready,
    token: mio::Token,
    read_buf: Vec<u8>,
    read_eof: bool,
    failed: bool,
    write_buf: Vec<u8>,
}

impl RuleHandler for Connection {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .register(
                &self.socket,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("event loop register");
    }

    // Event updates arrive here
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        self.sock_status.insert(events);
        info!(
            "Connection::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.socket.peer_addr(),
            events,
            self.sock_status
        );
    }

    // actions are processed here on down.

    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            self.sock_status.remove(mio::Ready::readable());
            self.read()?;
        }

        self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.sock_status.remove(mio::Ready::writable());
            self.write()?;
        }

        if !self.is_closed() {
            self.reregister(event_loop)?;
        }

        Ok(())
    }

    fn is_closed(&self) -> bool {
        self.failed || (self.read_eof && self.write_buf.is_empty())
    }
}

impl Connection {
    fn new(socket: TcpStream, token: mio::Token) -> Connection {
        Connection {
            socket: socket,
            sock_status: mio::Ready::empty(),
            token: token,
            read_buf: Vec::with_capacity(1024),
            write_buf: Vec::new(),
            read_eof: false,
            failed: false,
        }
    }
    fn process_buffer(&mut self, to_parent: &mut FnMut(MiChatCommand)) {
        let mut prev = 0;
        info!(
            "{:?}: Read buffer: {:?}",
            self.socket.peer_addr(),
            self.read_buf
        );
        for n in self.read_buf.iter().enumerate().filter_map(|(i, e)| {
            if *e == '\n' as u8 {
                Some(i)
            } else {
                None
            }
        }) {
            info!(
                "{:?}: Pos: {:?}; chunk: {:?}",
                self.socket.peer_addr(),
                n,
                &self.read_buf[prev..n]
            );
            let s = String::from_utf8_lossy(&self.read_buf[prev..n]).to_string();
            let cmd = MiChatCommand::Broadcast(s);
            info!("Send! {:?}", cmd);
            to_parent(cmd);
            prev = n + 1;
        }
        let remainder = self.read_buf[prev..].to_vec();
        info!(
            "{:?}: read Remainder: {}",
            self.socket.peer_addr(),
            remainder.len()
        );
        self.read_buf = remainder;
    }

    fn read(&mut self) -> Result<(), Error> {
        let mut abuf = vec![0; 1024];
        match self.socket.read(&mut abuf).context("Reading socket")? {
            0 => {
                info!("{:?}: EOF!", self.socket.peer_addr());
                self.read_eof = true;
                Ok(())
            }
            n => {
                info!("{:?}: Read {}bytes", self.socket.peer_addr(), n);
                self.read_buf.extend(&abuf[0..n]);
                Ok(())
            }
        }
    }

    fn write(&mut self) -> Result<(), Error> {
        let n = self
            .socket
            .write(&mut self.write_buf)
            .context("writing buffer")?;
        info!(
            "{:?}: Wrote {} of {} in buffer",
            self.socket.peer_addr(),
            n,
            self.write_buf.len()
        );
        self.write_buf = self.write_buf[n..].to_vec();
        info!(
            "{:?}: Now {:?}b",
            self.socket.peer_addr(),
            self.write_buf.len()
        );
        Ok(())
    }

    fn reregister(&mut self, event_loop: &mut mio::Poll) -> Result<(), Error> {
        let mut flags = mio::Ready::readable();
        if !self.write_buf.is_empty() {
            flags.insert(mio::Ready::writable());
        }
        info!("Registering {:?} with {:?}", self, flags);

        event_loop
            .reregister(&self.socket, self.token, flags, mio::PollOpt::oneshot())
            .context("EventLoop#reregister")?;

        Ok(())
    }

    fn enqueue(&mut self, s: &str) {
        self.write_buf.extend(s.as_bytes());
        self.write_buf.push('\n' as u8);
    }
}

#[derive(Debug)]
struct Listener {
    listener: TcpListener,
    sock_status: mio::Ready,
    token: mio::Token,
}

impl Listener {
    fn new(listener: TcpListener, token: mio::Token) -> Listener {
        Listener {
            listener: listener,
            sock_status: mio::Ready::empty(),
            token: token,
        }
    }
    fn reregister(&self, event_loop: &mut mio::Poll, token: mio::Token) -> Result<(), Error> {
        event_loop
            .reregister(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).context("Register listener")?;
            Ok(())
    }
}

impl RuleHandler for Listener {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .register(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("Register listener");
    }

    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        assert!(events.is_readable());
        self.sock_status.insert(events);
        info!(
            "Listener::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.listener.local_addr(),
            events,
            self.sock_status
        );
    }
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            info!("the listener socket is ready to accept a connection");
            self.sock_status.remove(mio::Ready::readable());
            match self.listener.accept().context("Accept listening socket")? {
                (socket, _client) => {
                    let cmd = MiChatCommand::NewConnection(socket);
                    to_parent(cmd);
                }
            }

            self.reregister(event_loop, self.token)?;
        }
        Ok(())
    }

    fn is_closed(&self) -> bool {
        false
    }
}

#[derive(Debug)]
enum EventHandler {
    Listener(Listener),
    Conn(Connection),
}

impl ops::Deref for EventHandler {
    type Target = RuleHandler;
    fn deref(&self) -> &Self::Target {
        match self {
            &EventHandler::Conn(ref conn) => conn,
            &EventHandler::Listener(ref listener) => listener,
        }
    }
}
impl ops::DerefMut for EventHandler {
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            &mut EventHandler::Conn(ref mut conn) => conn,
            &mut EventHandler::Listener(ref mut listener) => listener,
        }
    }
}

impl MiChat {
    fn ready(&mut self, event_loop: &mut mio::Poll, token: mio::Token, events: mio::Ready) {
        info!("{:?}: {:?}", token, events);
        self.connections[token.into()].handle_event(event_loop, events);
        if self.connections[token.into()].is_closed() {
            info!("Removing; {:?}", token);
            self.connections.remove(token.into());
        }

        let mut parent_actions = VecDeque::new();
        let mut failed = Vec::new();
        loop {
            for (idx, conn) in self.connections.iter_mut() {
                if let Err(e) =
                    conn.process_rules(event_loop, &mut |action| parent_actions.push_back(action))
                {
                    failed.push(idx);
                    error!("Error on connection {:?}; Dropping: {:?}", idx, e);
                }
            }
            for idx in failed.drain(..) {
                self.connections.remove(idx);
            }
            // Anything left to process?
            if parent_actions.is_empty() {
                break;
            }

            for action in parent_actions.drain(..) {
                self.process_action(action, event_loop);
            }
        }
    }

    fn run(&mut self, event_loop: &mut mio::Poll) {
        loop {
            self.run_once(event_loop);
        }
    }
    fn run_once(&mut self, event_loop: &mut mio::Poll) {
        let mut events = mio::Events::with_capacity(1024);
        event_loop.poll(&mut events, None).expect("Poll");
        for ev in &events {
            self.ready(event_loop, ev.token(), ev.readiness())
        }
    }
}

fn main() {
    env_logger::init();
    let matches = App::new("michat")
        .arg(
            Arg::with_name("bind")
                .short("l")
                .takes_value(true)
                .required(true),
        ).get_matches();

    let address = value_t_or_exit!(matches.value_of("bind"), std::net::SocketAddr);
    let listener = TcpListener::bind(&address).expect("bind");

    let mut event_loop = mio::Poll::new().expect("Create event loop");
    let mut service = MiChat::new();

    service.listen(&mut event_loop, listener);
    info!("running michat listener at: {:?}", address);
    service.run(&mut event_loop);
}
<commit_msg>Errors on listen/register.<commit_after>extern crate bytes;
extern crate env_logger;
extern crate mio;
#[macro_use]
extern crate log;
#[macro_use]
extern crate clap;
extern crate failure;
extern crate slab;

use clap::{App, Arg};
use failure::Error;
use failure::ResultExt;
use mio::net::{TcpListener, TcpStream};
use slab::Slab;
use std::collections::VecDeque;
use std::io::{Read, Write};
use std::ops;

#[derive(Debug)]
enum MiChatCommand {
    Broadcast(String),
    NewConnection(TcpStream),
}

struct MiChat {
    connections: Slab<EventHandler>,
}

trait RuleHandler {
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready);
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) -> Result<(), Error>;
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error>;
    fn is_closed(&self) -> bool;
}

impl MiChat {
    fn new() -> MiChat {
        MiChat {
            connections: Slab::new(),
        }
    }

    fn listen(&mut self, event_loop: &mut mio::Poll, listener: TcpListener) -> Result<(), Error> {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Listener(Listener::new(listener, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token)?;
        Ok(())
    }

    fn process_action(&mut self, msg: MiChatCommand, event_loop: &mut mio::Poll) {
        trace!("{:p}; got {:?}", self, msg);
        match msg {
            MiChatCommand::Broadcast(s) => self.process_broadcast(s),
            MiChatCommand::NewConnection(socket) => self.process_new_connection(event_loop, socket),
        }
    }

    fn process_broadcast(&mut self, s: String) {
        for c in self.client_connections_mut() {
            c.enqueue(&s);
        }
    }

    fn process_new_connection(&mut self, event_loop: &mut mio::Poll, socket: mio::tcp::TcpStream) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Conn(Connection::new(socket, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn client_connections_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Connection> + 'a {
        self.connections.iter_mut().filter_map(|(_, it)| match it {
            &mut EventHandler::Conn(ref mut c) => Some(c),
            _ => None,
        })
    }
}

#[derive(Debug)]
struct Connection {
    socket: TcpStream,
    sock_status: mio::Ready,
    token: mio::Token,
    read_buf: Vec<u8>,
    read_eof: bool,
    failed: bool,
    write_buf: Vec<u8>,
}

impl RuleHandler for Connection {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) -> Result<(), Error> {
        event_loop
            .register(
                &self.socket,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).context("event loop register")?;
            Ok(())
    }

    // Event updates arrive here
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        self.sock_status.insert(events);
        info!(
            "Connection::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.socket.peer_addr(),
            events,
            self.sock_status
        );
    }

    // actions are processed here on down.

    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            self.sock_status.remove(mio::Ready::readable());
            self.read()?;
        }

        self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.sock_status.remove(mio::Ready::writable());
            self.write()?;
        }

        if !self.is_closed() {
            self.reregister(event_loop)?;
        }

        Ok(())
    }

    fn is_closed(&self) -> bool {
        self.failed || (self.read_eof && self.write_buf.is_empty())
    }
}

impl Connection {
    fn new(socket: TcpStream, token: mio::Token) -> Connection {
        Connection {
            socket: socket,
            sock_status: mio::Ready::empty(),
            token: token,
            read_buf: Vec::with_capacity(1024),
            write_buf: Vec::new(),
            read_eof: false,
            failed: false,
        }
    }
    fn process_buffer(&mut self, to_parent: &mut FnMut(MiChatCommand)) {
        let mut prev = 0;
        info!(
            "{:?}: Read buffer: {:?}",
            self.socket.peer_addr(),
            self.read_buf
        );
        for n in self.read_buf.iter().enumerate().filter_map(|(i, e)| {
            if *e == '\n' as u8 {
                Some(i)
            } else {
                None
            }
        }) {
            info!(
                "{:?}: Pos: {:?}; chunk: {:?}",
                self.socket.peer_addr(),
                n,
                &self.read_buf[prev..n]
            );
            let s = String::from_utf8_lossy(&self.read_buf[prev..n]).to_string();
            let cmd = MiChatCommand::Broadcast(s);
            info!("Send! {:?}", cmd);
            to_parent(cmd);
            prev = n + 1;
        }
        let remainder = self.read_buf[prev..].to_vec();
        info!(
            "{:?}: read Remainder: {}",
            self.socket.peer_addr(),
            remainder.len()
        );
        self.read_buf = remainder;
    }

    fn read(&mut self) -> Result<(), Error> {
        let mut abuf = vec![0; 1024];
        match self.socket.read(&mut abuf).context("Reading socket")? {
            0 => {
                info!("{:?}: EOF!", self.socket.peer_addr());
                self.read_eof = true;
                Ok(())
            }
            n => {
                info!("{:?}: Read {}bytes", self.socket.peer_addr(), n);
                self.read_buf.extend(&abuf[0..n]);
                Ok(())
            }
        }
    }

    fn write(&mut self) -> Result<(), Error> {
        let n = self
            .socket
            .write(&mut self.write_buf)
            .context("writing buffer")?;
        info!(
            "{:?}: Wrote {} of {} in buffer",
            self.socket.peer_addr(),
            n,
            self.write_buf.len()
        );
        self.write_buf = self.write_buf[n..].to_vec();
        info!(
            "{:?}: Now {:?}b",
            self.socket.peer_addr(),
            self.write_buf.len()
        );
        Ok(())
    }

    fn reregister(&mut self, event_loop: &mut mio::Poll) -> Result<(), Error> {
        let mut flags = mio::Ready::readable();
        if !self.write_buf.is_empty() {
            flags.insert(mio::Ready::writable());
        }
        info!("Registering {:?} with {:?}", self, flags);

        event_loop
            .reregister(&self.socket, self.token, flags, mio::PollOpt::oneshot())
            .context("EventLoop#reregister")?;

        Ok(())
    }

    fn enqueue(&mut self, s: &str) {
        self.write_buf.extend(s.as_bytes());
        self.write_buf.push('\n' as u8);
    }
}

#[derive(Debug)]
struct Listener {
    listener: TcpListener,
    sock_status: mio::Ready,
    token: mio::Token,
}

impl Listener {
    fn new(listener: TcpListener, token: mio::Token) -> Listener {
        Listener {
            listener: listener,
            sock_status: mio::Ready::empty(),
            token: token,
        }
    }
    fn reregister(&self, event_loop: &mut mio::Poll, token: mio::Token) -> Result<(), Error> {
        event_loop
            .reregister(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).context("Register listener")?;
            Ok(())
    }
}

impl RuleHandler for Listener {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) -> Result<(), Error> {
        event_loop
            .register(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).context("Register listener")?;
            Ok(())
    }

    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        assert!(events.is_readable());
        self.sock_status.insert(events);
        info!(
            "Listener::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.listener.local_addr(),
            events,
            self.sock_status
        );
    }
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            info!("the listener socket is ready to accept a connection");
            self.sock_status.remove(mio::Ready::readable());
            match self.listener.accept().context("Accept listening socket")? {
                (socket, _client) => {
                    let cmd = MiChatCommand::NewConnection(socket);
                    to_parent(cmd);
                }
            }

            self.reregister(event_loop, self.token)?;
        }
        Ok(())
    }

    fn is_closed(&self) -> bool {
        false
    }
}

#[derive(Debug)]
enum EventHandler {
    Listener(Listener),
    Conn(Connection),
}

impl ops::Deref for EventHandler {
    type Target = RuleHandler;
    fn deref(&self) -> &Self::Target {
        match self {
            &EventHandler::Conn(ref conn) => conn,
            &EventHandler::Listener(ref listener) => listener,
        }
    }
}
impl ops::DerefMut for EventHandler {
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            &mut EventHandler::Conn(ref mut conn) => conn,
            &mut EventHandler::Listener(ref mut listener) => listener,
        }
    }
}

impl MiChat {
    fn ready(&mut self, event_loop: &mut mio::Poll, token: mio::Token, events: mio::Ready) {
        info!("{:?}: {:?}", token, events);
        self.connections[token.into()].handle_event(event_loop, events);
        if self.connections[token.into()].is_closed() {
            info!("Removing; {:?}", token);
            self.connections.remove(token.into());
        }

        let mut parent_actions = VecDeque::new();
        let mut failed = Vec::new();
        loop {
            for (idx, conn) in self.connections.iter_mut() {
                if let Err(e) =
                    conn.process_rules(event_loop, &mut |action| parent_actions.push_back(action))
                {
                    failed.push(idx);
                    error!("Error on connection {:?}; Dropping: {:?}", idx, e);
                }
            }
            for idx in failed.drain(..) {
                self.connections.remove(idx);
            }
            // Anything left to process?
            if parent_actions.is_empty() {
                break;
            }

            for action in parent_actions.drain(..) {
                self.process_action(action, event_loop);
            }
        }
    }

    fn run(&mut self, event_loop: &mut mio::Poll) {
        loop {
            self.run_once(event_loop);
        }
    }
    fn run_once(&mut self, event_loop: &mut mio::Poll) {
        let mut events = mio::Events::with_capacity(1024);
        event_loop.poll(&mut events, None).expect("Poll");
        for ev in &events {
            self.ready(event_loop, ev.token(), ev.readiness())
        }
    }
}

fn main() {
    env_logger::init();
    let matches = App::new("michat")
        .arg(
            Arg::with_name("bind")
                .short("l")
                .takes_value(true)
                .required(true),
        ).get_matches();

    let address = value_t_or_exit!(matches.value_of("bind"), std::net::SocketAddr);
    let listener = TcpListener::bind(&address).expect("bind");

    let mut event_loop = mio::Poll::new().expect("Create event loop");
    let mut service = MiChat::new();

    service.listen(&mut event_loop, listener).expect("Starting listener");
    info!("running michat listener at: {:?}", address);
    service.run(&mut event_loop);
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Downloading nginx.<commit_after>#![feature(core)]
#![feature(path)]

use std::process::Command;
use std::env;

const NGINX_VERSION: &'static str = "1.7.10";

fn download_nginx() {
   println!("Downloading nginx v{}...", NGINX_VERSION);

   let http_location = format!("http://nginx.org/download/nginx-{}.tar.gz", NGINX_VERSION);

   let exe_path = env::current_exe().unwrap_or_else(|_| {
      panic!("Cannot retrieve current executable location")
   });

   let download_dir = exe_path.parent().unwrap();

   let args = ["-s", "-L", "-O", http_location.as_slice()];

   Command::new("curl").args(&args).current_dir(download_dir).output().unwrap_or_else(|e| {
      panic!("Downloading nginx: {}", e)
   });
}

fn main() {
   download_nginx();

   println!("Done.");
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::BTreeSet;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
struct FileEntry {
    size : u64,
    hash : u64,
    files : Vec<String>,
}

fn collect_files(dir: &String, files: &mut HashMap<u64, Vec<String>>,
                 inodes: &mut BTreeSet<(u64, u64)>) {

    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            warn!("{}: invalid directory", dir);
            return
        },
    };

    for path in  entries.filter( |x| x.is_ok() )
                        .map( |x| x.unwrap().path() )
                        .collect::<Vec<PathBuf>>() {
        if let (Some(path_str), Ok(metadata)) =
                (path.to_str(), path.symlink_metadata()) {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                let inode = metadata.ino();
                let device = metadata.dev();
                if inodes.contains(&(inode, device)) {
                    continue;
                }
                inodes.insert((inode, device));
                match metadata.len() {
                    0 => continue, //Ignore empty files.
                    i => files.entry(i).or_insert_with(Vec::new)
                          .push(String::from(path_str)),
                };
            } else if ft.is_dir() {
                collect_files(&(String::from(path_str)), files, inodes);
            }
        } else {
            warn!("Failed to retrieve metadata for {}", path.to_str().unwrap());
        }
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<String>>,
                   vec: &Vec<String>, thorough: bool ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut hash: u64 = 0;
            let mut hasher = DefaultHasher::new();
            if thorough {
                let mut contents: Vec<u8> = Vec::new();
                if let Ok(_) = file.read_to_end(&mut contents) {
                    hasher.write(&contents[..]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {}", file_entry);
                }
            } else {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    hasher.write(&buf[..nbytes as usize]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {} chunk", file_entry);
                }
            }
            if hash != 0 {
                duplicates.entry(hash).or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            }
        } else {
            warn!("Failed to open file {}", file_entry);
        }
    }
}

fn print_duplicates(vec: &Vec<String>, cluster: i32, key: u64, hash: u64,
                    json_list: &mut Vec<FileEntry>, json_output: bool) {
    if json_output {
        json_list.push( FileEntry {
            size  : key,
            hash  : hash,
            files : vec.to_vec(),
        });
    } else {
        println!("{} files in cluster {} (size: {}, digest: {})",
                 vec.len(), cluster, key, hash);
        // for_each becomes stable v1.22.0 onwards. Should uncomment then.
        //vec.iter().for_each(|f| println!("{}", f.path));
        for file_entry in vec {
            println!("{}", file_entry);
        }
    }
}

fn exhaustive_search(emap: &mut HashMap<Vec<u8>, Vec<String>>,
                     vec: &Vec<String>) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut contents: Vec<u8> = Vec::new();
            if let Ok(_) = file.read_to_end(&mut contents) {
                emap.entry(contents).or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            } else {
                warn!("Failed to read {}", file_entry);
            }
        } else {
            warn!("Failed to open {}", file_entry);
        }
    }
}

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

    let mut args: Vec<String> = env::args().collect();

    let binary_name = args.remove(0);

    let mut hmap: HashMap<u64, Vec<String> > = HashMap::new();
    let mut bset: BTreeSet<(u64, u64)> = BTreeSet::new();

    let mut thorough = false;
    let mut exhaustive = false;
    let mut json_output = false;
    let mut print_usage = true;

    for dir in &args[..] {
        match dir.as_ref() {
            "-t" => {
                thorough = true;
                continue;
            },
            "-e" => {
                thorough = false;
                exhaustive = false;
                continue;
            },
            "-j" => {
                json_output = true;
                continue;
            },
            _ => {
                print_usage = false;
                collect_files(dir, &mut hmap, &mut bset);
            },
        }
    }

    if print_usage {
        println!("Usage: {} [-t] [-e] [-j] <dir1> [dir2 [dir3 ...]]",
                 binary_name);
        ::std::process::exit(0);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    let mut json_list : Vec<FileEntry> = Vec::new();
    for (key, val) in hmap {
        let mut duplicates: HashMap<u64, Vec<String> > = HashMap::new();
        find_duplicates(&mut duplicates, &val, thorough);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                if exhaustive {
                    let mut emap: HashMap<Vec<u8>, Vec<String>> = HashMap::new();
                    exhaustive_search(&mut emap, &vec);
                    for (_, v) in emap {
                        if v.len() >= 2 {
                            print_duplicates(&v, cluster, key, hash,
                                             &mut json_list, json_output);
                            cluster += 1;
                        }
                    }
                } else {
                    print_duplicates(&vec, cluster, key, hash, &mut json_list,
                                     json_output);
                    cluster += 1;
                }
            }
        }
    }
    if json_output {
        println!("{}", serde_json::to_string_pretty(&json_list).unwrap());
    }
}
<commit_msg>Whitespace changes<commit_after>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::BTreeSet;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
struct FileEntry {
    size : u64,
    hash : u64,
    files : Vec<String>,
}

fn collect_files(dir: &String, files: &mut HashMap<u64, Vec<String>>,
                 inodes: &mut BTreeSet<(u64, u64)>) {

    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            warn!("{}: invalid directory", dir);
            return
        },
    };

    for path in  entries.filter( |x| x.is_ok() )
                        .map( |x| x.unwrap().path() )
                        .collect::<Vec<PathBuf>>() {
        if let (Some(path_str), Ok(metadata)) =
                (path.to_str(), path.symlink_metadata()) {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                let inode = metadata.ino();
                let device = metadata.dev();
                if inodes.contains(&(inode, device)) {
                    continue;
                }
                inodes.insert((inode, device));
                match metadata.len() {
                    0 => continue, //Ignore empty files.
                    i => files.entry(i).or_insert_with(Vec::new)
                          .push(String::from(path_str)),
                };
            } else if ft.is_dir() {
                collect_files(&(String::from(path_str)), files, inodes);
            }
        } else {
            warn!("Failed to retrieve metadata for {}", path.to_str().unwrap());
        }
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<String>>,
                   vec: &Vec<String>, thorough: bool ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut hash: u64 = 0;
            let mut hasher = DefaultHasher::new();
            if thorough {
                let mut contents: Vec<u8> = Vec::new();
                if let Ok(_) = file.read_to_end(&mut contents) {
                    hasher.write(&contents[..]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {}", file_entry);
                }
            } else {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    hasher.write(&buf[..nbytes as usize]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {} chunk", file_entry);
                }
            }
            if hash != 0 {
                duplicates.entry(hash).or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            }
        } else {
            warn!("Failed to open file {}", file_entry);
        }
    }
}

fn print_duplicates(vec: &Vec<String>, cluster: i32, key: u64, hash: u64,
                    json_list: &mut Vec<FileEntry>, json_output: bool) {
    if json_output {
        json_list.push( FileEntry {
            size  : key,
            hash  : hash,
            files : vec.to_vec(),
        });
    } else {
        println!("{} files in cluster {} (size: {}, digest: {})",
                 vec.len(), cluster, key, hash);
        // for_each becomes stable v1.22.0 onwards. Should uncomment then.
        //vec.iter().for_each(|f| println!("{}", f.path));
        for file_entry in vec {
            println!("{}", file_entry);
        }
    }
}

fn exhaustive_search(emap: &mut HashMap<Vec<u8>, Vec<String>>,
                     vec: &Vec<String>) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut contents: Vec<u8> = Vec::new();
            if let Ok(_) = file.read_to_end(&mut contents) {
                emap.entry(contents).or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            } else {
                warn!("Failed to read {}", file_entry);
            }
        } else {
            warn!("Failed to open {}", file_entry);
        }
    }
}

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

    let mut args: Vec<String> = env::args().collect();

    let binary_name = args.remove(0);

    let mut hmap: HashMap<u64, Vec<String> > = HashMap::new();
    let mut bset: BTreeSet<(u64, u64)> = BTreeSet::new();

    let mut thorough = false;
    let mut exhaustive = false;
    let mut json_output = false;
    let mut print_usage = true;

    for dir in &args[..] {
        match dir.as_ref() {
            "-t" => {
                thorough = true;
                continue;
            },
            "-e" => {
                thorough = false;
                exhaustive = false;
                continue;
            },
            "-j" => {
                json_output = true;
                continue;
            },
            _ => {
                print_usage = false;
                collect_files(dir, &mut hmap, &mut bset);
            },
        }
    }

    if print_usage {
        println!("Usage: {} [-t] [-e] [-j] <dir1> [dir2 [dir3 ...]]",
                 binary_name);
        ::std::process::exit(0);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    let mut json_list : Vec<FileEntry> = Vec::new();
    for (key, val) in hmap {
        let mut duplicates: HashMap<u64, Vec<String> > = HashMap::new();
        find_duplicates(&mut duplicates, &val, thorough);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                if exhaustive {
                    let mut emap: HashMap<Vec<u8>, Vec<String>> = HashMap::new();
                    exhaustive_search(&mut emap, &vec);
                    for (_, v) in emap {
                        if v.len() >= 2 {
                            print_duplicates(&v, cluster, key, hash,
                                             &mut json_list, json_output);
                            cluster += 1;
                        }
                    }
                } else {
                    print_duplicates(&vec, cluster, key, hash, &mut json_list,
                                     json_output);
                    cluster += 1;
                }
            }
        }
    }
    if json_output {
        println!("{}", serde_json::to_string_pretty(&json_list).unwrap());
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;

use std::env;
use std::process::{self, Command};
use std::str;

use serde_json::Value;

#[derive(Debug)]
struct Target {
    name: String,
    kind: String,
}

fn parse_targets(metadata: &str) -> Vec<Target> {
    let metadata: Value = serde_json::from_str(&metadata).unwrap();

    let targets = metadata.find("packages").unwrap().as_array().unwrap()[0]
        .find("targets")
        .unwrap()
        .as_array()
        .unwrap();

    targets.into_iter()
        .map(|t| {
            let t = t.as_object().unwrap();

            Target {
                name: t["name"].as_str().unwrap().to_owned(),
                kind: t["kind"]
                        .as_array()
                        .unwrap()[0]
                    .as_str()
                    .unwrap()
                    .to_owned(),
            }
        })
        .collect()
}

fn main() {
    let targets = {
        let output = Command::new("cargo").arg("metadata").arg("--no-deps").output().unwrap();
        parse_targets(str::from_utf8(&output.stdout).unwrap())
    };

    for target in &targets {
        let mut args = vec!["rustc".to_owned()];

        match &target.kind[..] {
            "lib" => args.push("--lib".to_owned()),
            "bin" => {
                args.push("--bin".to_owned());
                args.push(target.name.to_owned())
            }
            _ => (),
        };

        args.extend(env::args().skip(2).take_while(|arg| arg != "--"));
        args.push("--".to_owned());
        args.extend(env::args().skip(2).skip_while(|arg| arg != "--").skip(1));
        args.push("-Zno-trans".to_owned());

        let status = Command::new("cargo").args(&args).status().unwrap();

        // If the command didn't execute successfully, exit this process with
        // the same code, defaulting to an arbitrary error exit code (1) if
        // `status.code()` returns None.
        if !status.success() {
            process::exit(status.code().unwrap_or(1));
        }
    }
}
<commit_msg>Add '--version' flag and exit cleanly on 'cargo metadata' errors<commit_after>extern crate serde_json;

use std::env;
use std::process::{self, Command};
use std::str;

use serde_json::Value;

#[derive(Debug)]
struct Target {
    name: String,
    kind: String,
}

fn parse_targets(metadata: &str) -> Vec<Target> {
    let metadata: Value = serde_json::from_str(&metadata).unwrap();

    let targets = metadata.find("packages").unwrap().as_array().unwrap()[0]
        .find("targets")
        .unwrap()
        .as_array()
        .unwrap();

    targets.into_iter()
        .map(|t| {
            let t = t.as_object().unwrap();

            Target {
                name: t["name"].as_str().unwrap().to_owned(),
                kind: t["kind"]
                        .as_array()
                        .unwrap()[0]
                    .as_str()
                    .unwrap()
                    .to_owned(),
            }
        })
        .collect()
}

fn main() {
    let env_args: Vec<_> = env::args().collect();
    for arg in &env_args {
        if arg == "--version" {
            return println!("{}", env!("CARGO_PKG_VERSION"));
        }
    }
    let targets = {
        let output = match Command::new("cargo").arg("metadata").arg("--no-deps").output() {
            Ok(output) => output,
            Err(_) => {
                println!("Failed to run 'cargo metadata'");
                process::exit(1);
            }
        };
        if ! output.status.success() {
            print!("{}", String::from_utf8_lossy(&output.stderr));
            if let Some(code) = output.status.code() {
                process::exit(code);
            } else {
                process::exit(1);
            }
        }
        parse_targets(str::from_utf8(&output.stdout).unwrap())
    };

    for target in &targets {
        let mut args = vec!["rustc".to_owned()];

        match &target.kind[..] {
            "lib" => args.push("--lib".to_owned()),
            "bin" => {
                args.push("--bin".to_owned());
                args.push(target.name.to_owned())
            }
            _ => (),
        };

        args.extend(env::args().skip(2).take_while(|arg| arg != "--"));
        args.push("--".to_owned());
        args.extend(env::args().skip(2).skip_while(|arg| arg != "--").skip(1));
        args.push("-Zno-trans".to_owned());

        let status = Command::new("cargo").args(&args).status().unwrap();

        // If the command didn't execute successfully, exit this process with
        // the same code, defaulting to an arbitrary error exit code (1) if
        // `status.code()` returns None.
        if !status.success() {
            process::exit(status.code().unwrap_or(1));
        }
    }
}
<|endoftext|>