<commit_before>#[feature(globs)];
#[feature(struct_variant)];
#[feature(macro_rules)];
extern mod std;
extern mod extra;
use extra::getopts;
use basics::*;
use policies::TimingPolicy;
use std::rt::io::File;

mod basics;
mod policies;
mod raft;
mod sim;

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("logs"),
        getopts::optopt("samples"),
        getopts::optopt("servers"),
        getopts::optopt("tasks"),
        getopts::optopt("timing"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println!("-h, --help       Print this help message");
        println!("--logs=POLICY    Log length policy (default same)");
        println!("--samples=N      Number of simulations (default 10,000)");
        println!("--servers=N      Simulate cluster with N servers");
        println!("--tasks=N        Number of parallel jobs (default {})",
                 std::rt::default_sched_threads() - 1);
        println!("--timing=POLICY  Network timing policy (default LAN)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let log_length : ~str = match matches.opt_str("logs") {
        Some(s) => { s },
        None => { ~"same" },
    };
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 10000 },
    };
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { std::rt::default_sched_threads() - 1 },
    };
    let timing : ~str = match matches.opt_str("timing") {
        Some(s) => { s },
        None => { ~"LAN" },
    };

    let mut meta : ~[(~str, ~str)] = ~[];
    meta.push((~"log_length", log_length.clone()));
    meta.push((~"servers",    format!("{}", num_servers)));
    meta.push((~"tasks",      format!("{}", num_tasks)));
    meta.push((~"trials",     format!("{}", num_samples)));
    meta.push((~"timing",     timing.clone()));

    println!("Log length: {}", log_length)
    println!("Servers:    {}", num_servers)
    println!("Tasks:      {}", num_tasks)
    println!("Trials:     {}", num_samples)
    println!("Timing:     {}", timing)

    let start_ns = extra::time::precise_time_ns();

    let samples = if num_tasks <= 1 {
        run_task(num_samples, num_servers, timing, log_length)
    } else {
        let (port, chan): (Port<~[Time]>, Chan<~[Time]>) = stream();
        let chan = std::comm::SharedChan::new(chan);
        for tid in range(0, num_tasks) {
            let child_chan = chan.clone();
            let child_log_length = log_length.clone();
            let child_timing = timing.clone();
            do spawn || {
                let n = if tid == 0 {
                    // get the odd one left over
                    num_samples - (num_samples / num_tasks) * (num_tasks - 1)
                } else {
                    num_samples / num_tasks
                };
                child_chan.send(run_task(n, num_servers, child_timing, child_log_length));
            }
        }

        let mut samples = ~[];
        samples.reserve(num_samples);
        do num_tasks.times {
            samples.push_all(port.recv());
        }
        extra::sort::tim_sort(samples);
        samples
    };

    let end_ns = extra::time::precise_time_ns();
    let elapsed_ns = end_ns - start_ns;
    meta.push((~"wall",  format!("{}", elapsed_ns as f64 / 1e9)));

    println!("Min:     {} ticks", samples[0]);
    println!("Median:  {} ticks", samples[samples.len()/2]);
    println!("Max:     {} ticks", samples[samples.len()-1]);
    println!("Wall:    {:.2f} s",     elapsed_ns as f64 / 1e9);

    let metaf = &mut File::create(&Path::new("meta.csv")).unwrap() as &mut Writer;
    for &(ref k, ref _v) in meta.iter() {
        write!(metaf, "{}, ", *k);
    }
    write!(metaf, "\n");
    for &(ref _k, ref v) in meta.iter() {
        write!(metaf, "{}, ", *v);
    }
    write!(metaf, "\n");

    let runf = &mut File::create(&Path::new("samples.csv")).unwrap() as &mut Writer;
    writeln!(runf, "election_time");
    for sample in samples.iter() {
        writeln!(runf, "{}", *sample);
    }
}

fn run_task(n: uint, num_servers: uint, timing: &str, log_length: &str) -> ~[Time] {
    let mut samples = ~[];
    samples.reserve(n);
    do n.times {
        // TODO: may be better to reuse these timing policies.
        let p = policies::make(timing);
        let sample = sim::simulate(num_servers, p, log_length);
        samples.push(sample);
    }
    extra::sort::tim_sort(samples);
    return samples;
}
<commit_msg>Found some way to make select work<commit_after>#[feature(globs)];
#[feature(struct_variant)];
#[feature(macro_rules)];
extern mod std;
extern mod extra;
use extra::getopts;
use basics::*;
use policies::TimingPolicy;
use std::io::File;
use std::rt::shouldnt_be_public::SelectInner;
use std::select::Select;

mod basics;
mod policies;
mod raft;
mod sim;

struct SelectBox<'self> {
    inner: &'self mut std::select::Select,
}

impl<'self> SelectInner for SelectBox<'self> {
    fn optimistic_check(&mut self) -> bool {
        self.inner.optimistic_check()
    }
    // Returns true if data was available. If so, shall also wake() the task.
    fn block_on(&mut self, sched: &mut std::rt::sched::Scheduler, task: std::rt::BlockedTask) -> bool {
        self.inner.block_on(sched, task)
    }
    // Returns true if data was available.
    fn unblock_from(&mut self) -> bool {
        self.inner.unblock_from()
    }
}

impl<'self> std::select::Select for SelectBox<'self> {
}

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("logs"),
        getopts::optopt("samples"),
        getopts::optopt("servers"),
        getopts::optopt("tasks"),
        getopts::optopt("timing"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println!("-h, --help       Print this help message");
        println!("--logs=POLICY    Log length policy (default same)");
        println!("--samples=N      Number of simulations (default 10,000)");
        println!("--servers=N      Simulate cluster with N servers");
        println!("--tasks=N        Number of parallel jobs (default {})",
                 std::rt::default_sched_threads() - 1);
        println!("--timing=POLICY  Network timing policy (default LAN)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let log_length : ~str = match matches.opt_str("logs") {
        Some(s) => { s },
        None => { ~"same" },
    };
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 10000 },
    };
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { std::rt::default_sched_threads() - 1 },
    };
    let timing : ~str = match matches.opt_str("timing") {
        Some(s) => { s },
        None => { ~"LAN" },
    };

    let mut meta : ~[(~str, ~str)] = ~[];
    meta.push((~"log_length", log_length.clone()));
    meta.push((~"servers",    format!("{}", num_servers)));
    meta.push((~"tasks",      format!("{}", num_tasks)));
    meta.push((~"trials",     format!("{}", num_samples)));
    meta.push((~"timing",     timing.clone()));

    println!("Log length: {}", log_length)
    println!("Servers:    {}", num_servers)
    println!("Tasks:      {}", num_tasks)
    println!("Trials:     {}", num_samples)
    println!("Timing:     {}", timing)

    let start_ns = extra::time::precise_time_ns();

    let mut signals = std::io::signal::Listener::new();
    signals.register(std::io::signal::Interrupt);

    let samples = if num_tasks <= 1 {
        run_task(num_samples, num_servers, timing, log_length)
        // TODO: ctrl-c?
    } else {
        let (mut port, chan): (std::comm::Port<~[Time]>, std::comm::Chan<~[Time]>) = stream();
        let chan = std::comm::SharedChan::new(chan);
        for tid in range(0, num_tasks) {
            let child_chan = chan.clone();
            let child_log_length = log_length.clone();
            let child_timing = timing.clone();
            do spawn || {
                let n = if tid == 0 {
                    // get the odd one left over
                    num_samples - (num_samples / num_tasks) * (num_tasks - 1)
                } else {
                    num_samples / num_tasks
                };
                child_chan.send(run_task(n, num_servers, child_timing, child_log_length));
            }
        }

        let mut samples = ~[];
        samples.reserve(num_samples);
        let mut tasks_outstanding = num_tasks;
        while tasks_outstanding > 0 {
            //let (p1, c1): (std::rt::comm::Port<std::rt::io::signal::Signum>, std::rt::comm::Chan<std::rt::io::signal::Signum>) = std::rt::comm::stream();
            //let (p2, c2): (std::rt::comm::Port<~[uint]>, std::rt::comm::Chan<~[uint]>) = std::rt::comm::stream();
            //match std::select::select([p1 as &Select, p2 as &Select]) {
            match std::select::select([SelectBox{ inner: &mut signals.port.x as &mut std::select::Select }, SelectBox{ inner: &mut port.x as &mut std::select::Select }]) {
                0 => match signals.port.recv() {
                    std::io::signal::Interrupt => {
                        println!("Should exit now");
                    },
                    _ => fail!("Unexpected signal"),
                },
                1 => {
                    println!("Task completed");
                    tasks_outstanding -= 1;
                    samples.push_all(port.recv());
                },
                _ => fail!("Unexpected return value from select")
            }
        }

        //do num_tasks.times {
        //    samples.push_all(port.recv());
        //}
        extra::sort::tim_sort(samples);
        samples
    };

    let end_ns = extra::time::precise_time_ns();
    let elapsed_ns = end_ns - start_ns;
    meta.push((~"wall",  format!("{}", elapsed_ns as f64 / 1e9)));

    println!("Min:     {} ticks", samples[0]);
    println!("Median:  {} ticks", samples[samples.len()/2]);
    println!("Max:     {} ticks", samples[samples.len()-1]);
    println!("Wall:    {:.2f} s",     elapsed_ns as f64 / 1e9);

    let metaf = &mut File::create(&Path::new("meta.csv")).unwrap() as &mut Writer;
    for &(ref k, ref _v) in meta.iter() {
        write!(metaf, "{}, ", *k);
    }
    write!(metaf, "\n");
    for &(ref _k, ref v) in meta.iter() {
        write!(metaf, "{}, ", *v);
    }
    write!(metaf, "\n");

    let runf = &mut File::create(&Path::new("samples.csv")).unwrap() as &mut Writer;
    writeln!(runf, "election_time");
    for sample in samples.iter() {
        writeln!(runf, "{}", *sample);
    }
}

fn run_task(n: uint, num_servers: uint, timing: &str, log_length: &str) -> ~[Time] {
    let mut samples = ~[];
    samples.reserve(n);
    do n.times {
        // TODO: may be better to reuse these timing policies.
        let p = policies::make(timing);
        let sample = sim::simulate(num_servers, p, log_length);
        samples.push(sample);
    }
    extra::sort::tim_sort(samples);
    return samples;
}
<|endoftext|>


<commit_before>// Copyright 2016 Phillip Oppermann, Calvin Lee and JJ Garzella.
// See the README.md file at the top-level directory of this
// distribution.
//
// Licensed under the MIT license <LICENSE or
// http://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed
// except according to those terms.

use bit_field::BitField;

/// The type of an interrupt service routine
pub type HandlerFunc = unsafe extern "C" fn();

/// The Interrupt Descriptor table
///
/// # Safety
/// The `IDT` must be CPU-local.
pub struct Idt([Entry; 40]);

impl Idt {
    /// Creates a new Idt, each entry is unused
    pub const fn new() -> Idt {
        Idt([Entry::missing(); 40])
    }

    /// Sets a certain entry as present and initializes it with a certain handler
    pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions {
        use x86_64::instructions::segmentation;

        self.0[entry as usize] = Entry::new(segmentation::cs().0, handler);
        &mut self.0[entry as usize].options
    }

    /// Loads the given IDT into the CPU
    ///
    /// # Safety
    /// The IDT must be valid, if it is not undefined behaviour will most likely
    /// occur. `self` must live for the duration of the kernel, however, as
    /// long as it is only mutated while interrupts are disabled, access is safe.
    /// For this reason we do not currently use 'static, as it would disallow any
    /// mutable references.
    // XXX There are two ways to do this. Either make the mutable functions
    // take a &self and disable interrupts with them, or make them take a
    // &mut self, and remove static on this function. Both will work, but I
    // took the latter approach this time as this function is marked unsafe
    pub unsafe fn load(&self) {
        use x86_64::instructions::tables::{lidt, DescriptorTablePointer};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self as *const _ as u64,
            limit: (size_of::<Self>() - 1) as u16,
        };
        lidt(&ptr)
    }

    pub fn get_handler(&self, entry: u8) -> Entry {
        self.0[entry as usize]
    }
}

/// An Interrupt Descriptor Table entry type
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Entry {
    /// The lowest 16 bits of the isr pointer
    pointer_low: u16,
    gdt_selector: u16,
    /// A bitfield of options for the entry
    options: EntryOptions,
    /// The middle 16 bits of the isr pointer
    pointer_middle: u16,
    /// The high 32 bits of the isr pointer
    pointer_high: u32,
    /// Must be zero
    reserved: u32,
}

impl Entry {
    /// Creates a new Entry given a `HandlerFunc`
    fn new(gdt_selector_index: u16, handler: HandlerFunc) -> Self {
        let pointer = handler as usize;
        Entry {
            gdt_selector: gdt_selector_index,
            pointer_low: pointer as u16,
            pointer_middle: (pointer >> 16) as u16,
            pointer_high: (pointer >> 32) as u32,
            options: EntryOptions::new(),
            reserved: 0,
        }
    }

    /// Returns an uninitialized Entry
    const fn missing() -> Self {
        Entry {
            gdt_selector: 0,
            pointer_low: 0,
            pointer_middle: 0,
            pointer_high: 0,
            options: EntryOptions::minimal(),
            reserved: 0,
        }
    }

    pub fn func(self) -> HandlerFunc {
        use core::mem;
        let pointer = ((self.pointer_high as usize) << 32)
            | ((self.pointer_middle as usize) << 16)
            | (self.pointer_low as usize);
        // XXX only `transmute` usage in the kernel so far, replace with
        // something better if possible
        unsafe { mem::transmute::<usize, HandlerFunc>(pointer) }
    }
}

/// A representation of the `Options` field of an `Entry`
#[derive(Debug, Clone, Copy)]
pub struct EntryOptions(u16);

impl EntryOptions {
    /// Returns options with 'must be one' bits set
    const fn minimal() -> Self {
        EntryOptions(0b111 << 9) // 'must be one' bits
    }

    /// Returns a option with `present` and `disable_interrupts` set
    fn new() -> Self {
        let mut options = Self::minimal();
        options.set_present(true);
        options.disable_interrupts(true);
        options
    }

    /// Sets or resets the `present` bit
    pub fn set_present(&mut self, present: bool) -> &mut Self {
        self.0.set_bit(15, present);
        self
    }

    /// Let the CPU disable hardware interrupts when the handler is invoked.
    /// By default, interrupts are disabled.
    pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
        self.0.set_bit(8, !disable);
        self
    }

    /// Sets the required privilege level(DPL) for invoking the handler. If
    /// CPL > DPL, a #GP occurs.
    ///
    /// # Panics
    /// Panic if DPL > 3
    pub fn set_privilege_level(&mut self, dpl: u16) -> &mut Self {
        self.0.set_bits(13..15, dpl);
        self
    }

    /// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU
    /// will then always switch to the specified stack before the handler is
    /// invoked. This allows kernels to recover from corrupt stack pointers
    /// (e.g., on kernel stack overflow).
    ///
    /// An IST stack is specified by an IST index between 0 and 6 (inclusive).
    /// Using the same stack for multiple interrupts can be dangerous when
    /// nested interrupts are possible.
    ///
    /// This function panics if the index is not in the range 0..7.
    ///
    /// ## Safety
    /// This function is unsafe because the caller must ensure that the passed
    /// stack index is valid and not used by other interrupts. Otherwise, memory
    /// safety violations are possible.
    pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self {
        self.0.set_bits(0..3, index);
        self
    }
}
<commit_msg>Fix #36<commit_after>// Copyright 2016 Phillip Oppermann, Calvin Lee and JJ Garzella.
// See the README.md file at the top-level directory of this
// distribution.
//
// Licensed under the MIT license <LICENSE or
// http://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed
// except according to those terms.

use bit_field::BitField;

/// The type of an interrupt service routine
pub type HandlerFunc = unsafe extern "C" fn();

/// The Interrupt Descriptor table
///
/// # Safety
/// The `IDT` must be CPU-local.
pub struct Idt([Entry; 40]);

impl Idt {
    /// Creates a new Idt, each entry is unused
    pub const fn new() -> Idt {
        Idt([Entry::missing(); 40])
    }

    /// Sets a certain entry as present and initializes it with a certain handler
    pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions {
        use x86_64::instructions::segmentation;

        self.0[entry as usize] = Entry::new(segmentation::cs().0, handler);
        &mut self.0[entry as usize].options
    }

    /// Loads the given IDT into the CPU
    ///
    /// # Safety
    /// The IDT must be valid, if it is not undefined behaviour will most likely
    /// occur. `self` must live for the duration of the kernel, however, as
    /// long as it is only mutated while interrupts are disabled, access is safe.
    /// For this reason we do not currently use 'static, as it would disallow any
    /// mutable references.
    // XXX There are two ways to do this. Either make the mutable functions
    // take a &self and disable interrupts with them, or make them take a
    // &mut self, and remove static on this function. Both will work, but I
    // took the latter approach this time as this function is marked unsafe
    pub unsafe fn load(&self) {
        use x86_64::instructions::tables::{lidt, DescriptorTablePointer};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self as *const _ as u64,
            limit: (size_of::<Self>() - 1) as u16,
        };
        lidt(&ptr)
    }

    pub fn get_handler(&self, entry: u8) -> Entry {
        self.0[entry as usize]
    }
}

/// An Interrupt Descriptor Table entry type
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Entry {
    /// The lowest 16 bits of the isr pointer
    pointer_low: u16,
    gdt_selector: u16,
    /// A bitfield of options for the entry
    options: EntryOptions,
    /// The middle 16 bits of the isr pointer
    pointer_middle: u16,
    /// The high 32 bits of the isr pointer
    pointer_high: u32,
    /// Must be zero
    reserved: u32,
}

impl Entry {
    /// Creates a new Entry given a `HandlerFunc`
    fn new(gdt_selector_index: u16, handler: HandlerFunc) -> Self {
        let pointer = handler as usize;
        Entry {
            gdt_selector: gdt_selector_index,
            pointer_low: pointer as u16,
            pointer_middle: (pointer >> 16) as u16,
            pointer_high: (pointer >> 32) as u32,
            options: EntryOptions::new(),
            reserved: 0,
        }
    }

    /// Returns an uninitialized Entry
    const fn missing() -> Self {
        Entry {
            gdt_selector: 0,
            pointer_low: 0,
            pointer_middle: 0,
            pointer_high: 0,
            options: EntryOptions::minimal(),
            reserved: 0,
        }
    }

    pub fn func(self) -> HandlerFunc {
        use core::mem;
        let pointer = ((self.pointer_high as usize) << 32)
            | ((self.pointer_middle as usize) << 16)
            | (self.pointer_low as usize);
        // XXX only `transmute` usage in the kernel so far, replace with
        // something better if possible
        unsafe { mem::transmute::<usize, HandlerFunc>(pointer) }
    }
}

/// A representation of the `Options` field of an `Entry`
#[derive(Debug, Clone, Copy)]
pub struct EntryOptions(u16);

impl EntryOptions {
    /// Returns options with 'must be one' bits set
    const fn minimal() -> Self {
        EntryOptions(0b111 << 9) // 'must be one' bits
    }

    /// Returns a option with `present` and `disable_interrupts` set
    fn new() -> Self {
        let mut options = Self::minimal();
        options.set_present(true);
        options.disable_interrupts(true);
        options
    }

    /// Sets or resets the `present` bit
    pub fn set_present(&mut self, present: bool) -> &mut Self {
        self.0.set_bit(15, present);
        self
    }

    /// Let the CPU disable hardware interrupts when the handler is invoked.
    /// By default, interrupts are disabled.
    pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
        self.0.set_bit(8, !disable);
        self
    }

    /// Sets the required privilege level(DPL) for invoking the handler. If
    /// CPL > DPL, a #GP occurs.
    ///
    /// # Panics
    /// Panic if DPL > 3
    pub fn set_privilege_level(&mut self, dpl: u16) -> &mut Self {
        self.0.set_bits(13..15, dpl);
        self
    }

    /// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU
    /// will then always switch to the specified stack before the handler is
    /// invoked. This allows kernels to recover from corrupt stack pointers
    /// (e.g., on kernel stack overflow).
    ///
    /// An IST stack is specified by an IST index between 0 and 6 (inclusive).
    /// Using the same stack for multiple interrupts can be dangerous when
    /// nested interrupts are possible.
    ///
    /// This function panics if the index is not in the range 0..7.
    ///
    /// ## Safety
    /// This function is unsafe because the caller must ensure that the passed
    /// stack index is valid and not used by other interrupts. Otherwise, memory
    /// safety violations are possible.
    pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self {
        // The hardware IST index starts at 1, but our software IST index
        // starts at 0. Therefore we need to add 1 here.
        self.0.set_bits(0..3, index + 1);
        self
    }
}
<|endoftext|>


<commit_before>///! Handle `cargo add` arguments

use std::collections::BTreeMap;
use std::error::Error;
use toml;
use semver;
use cargo_edit::Dependency;

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name
    pub arg_crate: String,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_ver: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build depenency from arguments
    pub fn parse_dependency(&self) -> Result<Dependency, Box<Error>> {
        if crate_name_has_version(&self.arg_crate) {
            return parse_crate_name_with_version(&self.arg_crate);
        }

        let version = if let Some(ref version) = self.flag_ver {
            parse_semver(&version)
        } else if let Some(ref repo) = self.flag_git {
            parse_git(&repo)
        } else if let Some(ref path) = self.flag_path {
            parse_path(&path)
        } else {
            Ok(toml::Value::String(String::from("*")))
        };

        version.map(|data| (self.arg_crate.clone(), data))
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            flag_dev: false,
            flag_build: false,
            flag_ver: None,
            flag_git: None,
            flag_path: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
        }
    }
}

macro_rules! toml_table {
    ($key:expr => $value:expr) => {
        {
            let mut dep = BTreeMap::new();
            dep.insert(String::from($key), toml::Value::String($value.clone()));
            toml::Value::Table(dep)
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains("@")
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    // if !crate_name_has_version(name) {
    //     return Err("fuu");
    // }

    let xs: Vec<&str> = name.splitn(2, "@").collect();
    let (name, version) = (xs[0], xs[1]);
    let version = try!(parse_semver(&version.to_owned()));

    Ok((String::from(name), version))
}

/// Parse (and validate) a version requirement to the correct TOML data.
fn parse_semver(version: &String) -> Result<toml::Value, Box<Error>> {
    try!(semver::VersionReq::parse(version));
    Ok(toml::Value::String(version.clone()))
}

/// Parse a git source to the correct TOML data.
fn parse_git(repo: &String) -> Result<toml::Value, Box<Error>> {
    Ok(toml_table!("git" => repo))
}

/// Parse a path to the correct TOML data.
fn parse_path(path: &String) -> Result<toml::Value, Box<Error>> {
    Ok(toml_table!("path" => path))
}

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

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_v: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependency().unwrap(),
                   ("demo".to_owned(), toml::Value::String("0.4.2".to_owned())));
    }
}
<commit_msg>Fix Add Tests<commit_after>///! Handle `cargo add` arguments

use std::collections::BTreeMap;
use std::error::Error;
use toml;
use semver;
use cargo_edit::Dependency;

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name
    pub arg_crate: String,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_ver: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build depenency from arguments
    pub fn parse_dependency(&self) -> Result<Dependency, Box<Error>> {
        if crate_name_has_version(&self.arg_crate) {
            return parse_crate_name_with_version(&self.arg_crate);
        }

        let version = if let Some(ref version) = self.flag_ver {
            parse_semver(&version)
        } else if let Some(ref repo) = self.flag_git {
            parse_git(&repo)
        } else if let Some(ref path) = self.flag_path {
            parse_path(&path)
        } else {
            Ok(toml::Value::String(String::from("*")))
        };

        version.map(|data| (self.arg_crate.clone(), data))
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            flag_dev: false,
            flag_build: false,
            flag_ver: None,
            flag_git: None,
            flag_path: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
        }
    }
}

macro_rules! toml_table {
    ($key:expr => $value:expr) => {
        {
            let mut dep = BTreeMap::new();
            dep.insert(String::from($key), toml::Value::String($value.clone()));
            toml::Value::Table(dep)
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains("@")
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    // if !crate_name_has_version(name) {
    //     return Err("fuu");
    // }

    let xs: Vec<&str> = name.splitn(2, "@").collect();
    let (name, version) = (xs[0], xs[1]);
    let version = try!(parse_semver(&version.to_owned()));

    Ok((String::from(name), version))
}

/// Parse (and validate) a version requirement to the correct TOML data.
fn parse_semver(version: &String) -> Result<toml::Value, Box<Error>> {
    try!(semver::VersionReq::parse(version));
    Ok(toml::Value::String(version.clone()))
}

/// Parse a git source to the correct TOML data.
fn parse_git(repo: &String) -> Result<toml::Value, Box<Error>> {
    Ok(toml_table!("git" => repo))
}

/// Parse a path to the correct TOML data.
fn parse_path(path: &String) -> Result<toml::Value, Box<Error>> {
    Ok(toml_table!("path" => path))
}

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

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_ver: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependency().unwrap(),
                   ("demo".to_owned(), toml::Value::String("0.4.2".to_owned())));
    }
}
<|endoftext|>


<commit_before>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    get_features_from_registry, get_manifest_from_path, get_manifest_from_url, registry_url,
    workspace_members, Dependency, LocalManifest,
};
use cargo_edit::{get_latest_dependency, CrateSpec};
use cargo_metadata::Package;
use clap::Parser;
use std::path::Path;
use std::path::PathBuf;

use crate::errors::*;

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub enum Command {
    /// Add dependencies to a Cargo.toml manifest file.
    #[clap(name = "add")]
    #[clap(after_help = "\
Examples:
  $ cargo add regex
  $ cargo add regex@0.1.41 --build
  $ cargo add trycmd --dev
  $ cargo add ./crate/parser/
")]
    Add(Args),
}

#[derive(Debug, Parser)]
#[clap(about, version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct Args {
    /// Reference to a package to add as a dependency
    ///
    /// You can reference a packages by:{n}
    /// - `<name>`, like `cargo add serde` (latest version will be used){n}
    /// - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`{n}
    /// - `<path>`, like `cargo add ./crates/parser/`
    #[clap(value_name = "DEP_ID", required = true)]
    pub crates: Vec<String>,

    /// Disable the default features
    #[clap(long)]
    no_default_features: bool,
    /// Re-enable the default features
    #[clap(long, overrides_with = "no-default-features")]
    default_features: bool,

    /// Space-separated list of features to add
    #[clap(long)]
    pub features: Option<Vec<String>>,

    /// Mark the dependency as optional
    ///
    /// The package name will be exposed as feature of your crate.
    #[clap(long, conflicts_with = "dev")]
    pub optional: bool,

    /// Mark the dependency as required
    ///
    /// The package will be removed from your features.
    #[clap(long, conflicts_with = "dev", overrides_with = "optional")]
    pub no_optional: bool,

    /// Rename the dependency
    ///
    /// Example uses:{n}
    /// - Depending on multiple versions of a crate{n}
    /// - Depend on crates with the same name from different registries
    #[clap(long, short)]
    pub rename: Option<String>,

    /// Package registry for this dependency
    #[clap(long, conflicts_with = "git")]
    pub registry: Option<String>,

    /// Add as development dependency
    ///
    /// Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
    ///
    /// These dependencies are not propagated to other packages which depend on this package.
    #[clap(short = 'D', long, help_heading = "SECTION", group = "section")]
    pub dev: bool,

    /// Add as build dependency
    ///
    /// Build-dependencies are the only dependencies available for use by build scripts (`build.rs`
    /// files).
    #[clap(short = 'B', long, help_heading = "SECTION", group = "section")]
    pub build: bool,

    /// Add as dependency to the given target platform.
    #[clap(
        long,
        forbid_empty_values = true,
        help_heading = "SECTION",
        group = "section"
    )]
    pub target: Option<String>,

    /// Path to `Cargo.toml`
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to modify
    #[clap(short = 'p', long = "package", value_name = "PKGID")]
    pub pkgid: Option<String>,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Do not print any output in case of success.
    #[clap(long)]
    pub quiet: bool,

    /// Unstable (nightly-only) flags
    #[clap(
        short = 'Z',
        value_name = "FLAG",
        help_heading = "UNSTABLE",
        global = true,
        arg_enum
    )]
    pub unstable_features: Vec<UnstableOptions>,

    /// Git repository location
    ///
    /// Without any other information, cargo will use latest commit on the main branch.
    #[clap(long, value_name = "URI", help_heading = "UNSTABLE")]
    pub git: Option<String>,

    /// Git branch to download the crate from.
    #[clap(
        long,
        value_name = "BRANCH",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub branch: Option<String>,

    /// Git tag to download the crate from.
    #[clap(
        long,
        value_name = "TAG",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub tag: Option<String>,

    /// Git reference to download the crate from
    ///
    /// This is the catch all, handling hashes to named references in remote repositories.
    #[clap(
        long,
        value_name = "REV",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub rev: Option<String>,
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    pub fn default_features(&self) -> Option<bool> {
        resolve_bool_arg(self.default_features, self.no_default_features)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self, manifest: &LocalManifest) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1 && self.git.is_some() {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_spec| {
                self.parse_single_dependency(manifest, crate_spec, &workspace_members)
            })
            .collect()
    }

    fn parse_single_dependency(
        &self,
        manifest: &LocalManifest,
        crate_spec: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_spec = CrateSpec::resolve(crate_spec)?;
        let manifest_path = manifest.path.as_path();

        let mut dependency = match &crate_spec {
            CrateSpec::PkgId {
                name: _,
                version_req: Some(_),
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);
                // crate specifier includes a version (e.g. `docopt@0.8`)
                if let Some(ref url) = self.git {
                    let url = url.clone();
                    let version = dependency.version().unwrap().to_string();
                    return Err(ErrorKind::GitUrlWithVersion(url, version).into());
                }

                dependency
            }
            CrateSpec::PkgId {
                name,
                version_req: None,
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                if let Some(repo) = &self.git {
                    assert!(self.registry.is_none());
                    dependency = dependency.set_git(
                        repo,
                        self.branch.clone(),
                        self.tag.clone(),
                        self.rev.clone(),
                    );
                } else if let Some(version) =
                    manifest.get_dep_version(&self.get_section(), dependency.toml_key())
                {
                    dependency = dependency.set_version(&version);
                } else if let Some(package) = workspace_members.iter().find(|p| p.name == *name) {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    dependency = dependency.set_path(
                        package
                            .manifest_path
                            .parent()
                            .expect("at least parent dir")
                            .as_std_path()
                            .to_owned(),
                    );
                    // dev-dependencies do not need the version populated
                    if !self.dev {
                        let op = "";
                        let v = format!("{op}{version}", op = op, version = package.version);
                        dependency = dependency.set_version(&v);
                    }
                } else {
                    let registry_url = registry_url(&manifest_path, self.registry.as_deref())?;
                    let latest =
                        get_latest_dependency(name, false, &manifest_path, Some(&registry_url))?;
                    let op = "";
                    let v = format!(
                        "{op}{version}",
                        op = op,
                        // If version is unavailable `get_latest_dependency` must have
                        // returned `Err(FetchVersionError::GetVersion)`
                        version = latest.version().unwrap_or_else(|| unreachable!())
                    );
                    dependency = dependency
                        .set_version(&v)
                        .set_available_features(latest.available_features);
                }

                dependency
            }
            CrateSpec::Path(_) => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                // dev-dependencies do not need the version populated
                if !self.dev {
                    let dep_path = dependency.path().map(ToOwned::to_owned);
                    if let Some(dep_path) = dep_path {
                        if let Some(package) = workspace_members.iter().find(|p| {
                            p.manifest_path.parent().map(|p| p.as_std_path())
                                == Some(dep_path.as_path())
                        }) {
                            let op = "";
                            let v = format!("{op}{version}", op = op, version = package.version);

                            dependency = dependency.set_version(&v);
                        }
                    }
                }
                dependency
            }
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }
        dependency = self.populate_available_features(dependency, manifest_path)?;

        Ok(dependency)
    }

    fn populate_dependency(&self, mut dependency: Dependency) -> Dependency {
        let requested_features: Option<Vec<_>> = self.features.as_ref().map(|v| {
            v.iter()
                .flat_map(|s| s.split(' '))
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(|f| f.to_owned())
                .collect()
        });

        dependency = dependency
            .set_optional(self.optional())
            .set_default_features(self.default_features())
            .set_features(requested_features);

        if let Some(ref rename) = self.rename {
            dependency = dependency.set_rename(rename);
        }

        dependency
    }

    /// Lookup available features
    pub fn populate_available_features(
        &self,
        dependency: Dependency,
        manifest_path: &Path,
    ) -> Result<Dependency> {
        if !dependency.available_features.is_empty() {
            return Ok(dependency);
        }

        let available_features = if let Some(path) = dependency.path() {
            let manifest = get_manifest_from_path(path)?;
            manifest.features()?
        } else if let Some(repo) = dependency.git() {
            get_manifest_from_url(repo)?
                .map(|m| m.features())
                .transpose()?
                .unwrap_or_else(Vec::new)
        } else if let Some(version) = dependency.version() {
            let registry_url = registry_url(&manifest_path, self.registry.as_deref())?;
            get_features_from_registry(&dependency.name, version, &registry_url)?
        } else {
            vec![]
        };

        let dependency = dependency.set_available_features(available_features);
        Ok(dependency)
    }
}

impl Args {
    pub fn optional(&self) -> Option<bool> {
        resolve_bool_arg(self.optional, self.no_optional)
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            git: None,
            branch: None,
            tag: None,
            rev: None,
            target: None,
            optional: false,
            no_optional: false,
            manifest_path: None,
            pkgid: None,
            features: None,
            no_default_features: false,
            default_features: false,
            quiet: false,
            offline: true,
            registry: None,
            unstable_features: vec![],
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
pub enum UnstableOptions {
    Git,
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
    match (yes, no) {
        (true, false) => Some(true),
        (false, true) => Some(false),
        (false, false) => None,
        (_, _) => unreachable!("clap should make this impossible"),
    }
}

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

    #[test]
    fn verify_app() {
        use clap::IntoApp;
        Command::into_app().debug_assert()
    }
}
<commit_msg>style: Make clippy happy<commit_after>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    get_features_from_registry, get_manifest_from_path, get_manifest_from_url, registry_url,
    workspace_members, Dependency, LocalManifest,
};
use cargo_edit::{get_latest_dependency, CrateSpec};
use cargo_metadata::Package;
use clap::Parser;
use std::path::Path;
use std::path::PathBuf;

use crate::errors::*;

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub enum Command {
    /// Add dependencies to a Cargo.toml manifest file.
    #[clap(name = "add")]
    #[clap(after_help = "\
Examples:
  $ cargo add regex
  $ cargo add regex@0.1.41 --build
  $ cargo add trycmd --dev
  $ cargo add ./crate/parser/
")]
    Add(Args),
}

#[derive(Debug, Parser)]
#[clap(about, version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct Args {
    /// Reference to a package to add as a dependency
    ///
    /// You can reference a packages by:{n}
    /// - `<name>`, like `cargo add serde` (latest version will be used){n}
    /// - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`{n}
    /// - `<path>`, like `cargo add ./crates/parser/`
    #[clap(value_name = "DEP_ID", required = true)]
    pub crates: Vec<String>,

    /// Disable the default features
    #[clap(long)]
    no_default_features: bool,
    /// Re-enable the default features
    #[clap(long, overrides_with = "no-default-features")]
    default_features: bool,

    /// Space-separated list of features to add
    #[clap(long)]
    pub features: Option<Vec<String>>,

    /// Mark the dependency as optional
    ///
    /// The package name will be exposed as feature of your crate.
    #[clap(long, conflicts_with = "dev")]
    pub optional: bool,

    /// Mark the dependency as required
    ///
    /// The package will be removed from your features.
    #[clap(long, conflicts_with = "dev", overrides_with = "optional")]
    pub no_optional: bool,

    /// Rename the dependency
    ///
    /// Example uses:{n}
    /// - Depending on multiple versions of a crate{n}
    /// - Depend on crates with the same name from different registries
    #[clap(long, short)]
    pub rename: Option<String>,

    /// Package registry for this dependency
    #[clap(long, conflicts_with = "git")]
    pub registry: Option<String>,

    /// Add as development dependency
    ///
    /// Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
    ///
    /// These dependencies are not propagated to other packages which depend on this package.
    #[clap(short = 'D', long, help_heading = "SECTION", group = "section")]
    pub dev: bool,

    /// Add as build dependency
    ///
    /// Build-dependencies are the only dependencies available for use by build scripts (`build.rs`
    /// files).
    #[clap(short = 'B', long, help_heading = "SECTION", group = "section")]
    pub build: bool,

    /// Add as dependency to the given target platform.
    #[clap(
        long,
        forbid_empty_values = true,
        help_heading = "SECTION",
        group = "section"
    )]
    pub target: Option<String>,

    /// Path to `Cargo.toml`
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to modify
    #[clap(short = 'p', long = "package", value_name = "PKGID")]
    pub pkgid: Option<String>,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Do not print any output in case of success.
    #[clap(long)]
    pub quiet: bool,

    /// Unstable (nightly-only) flags
    #[clap(
        short = 'Z',
        value_name = "FLAG",
        help_heading = "UNSTABLE",
        global = true,
        arg_enum
    )]
    pub unstable_features: Vec<UnstableOptions>,

    /// Git repository location
    ///
    /// Without any other information, cargo will use latest commit on the main branch.
    #[clap(long, value_name = "URI", help_heading = "UNSTABLE")]
    pub git: Option<String>,

    /// Git branch to download the crate from.
    #[clap(
        long,
        value_name = "BRANCH",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub branch: Option<String>,

    /// Git tag to download the crate from.
    #[clap(
        long,
        value_name = "TAG",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub tag: Option<String>,

    /// Git reference to download the crate from
    ///
    /// This is the catch all, handling hashes to named references in remote repositories.
    #[clap(
        long,
        value_name = "REV",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub rev: Option<String>,
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    pub fn default_features(&self) -> Option<bool> {
        resolve_bool_arg(self.default_features, self.no_default_features)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self, manifest: &LocalManifest) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1 && self.git.is_some() {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_spec| {
                self.parse_single_dependency(manifest, crate_spec, &workspace_members)
            })
            .collect()
    }

    fn parse_single_dependency(
        &self,
        manifest: &LocalManifest,
        crate_spec: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_spec = CrateSpec::resolve(crate_spec)?;
        let manifest_path = manifest.path.as_path();

        let mut dependency = match &crate_spec {
            CrateSpec::PkgId {
                name: _,
                version_req: Some(_),
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);
                // crate specifier includes a version (e.g. `docopt@0.8`)
                if let Some(ref url) = self.git {
                    let url = url.clone();
                    let version = dependency.version().unwrap().to_string();
                    return Err(ErrorKind::GitUrlWithVersion(url, version).into());
                }

                dependency
            }
            CrateSpec::PkgId {
                name,
                version_req: None,
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                if let Some(repo) = &self.git {
                    assert!(self.registry.is_none());
                    dependency = dependency.set_git(
                        repo,
                        self.branch.clone(),
                        self.tag.clone(),
                        self.rev.clone(),
                    );
                } else if let Some(version) =
                    manifest.get_dep_version(&self.get_section(), dependency.toml_key())
                {
                    dependency = dependency.set_version(&version);
                } else if let Some(package) = workspace_members.iter().find(|p| p.name == *name) {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    dependency = dependency.set_path(
                        package
                            .manifest_path
                            .parent()
                            .expect("at least parent dir")
                            .as_std_path()
                            .to_owned(),
                    );
                    // dev-dependencies do not need the version populated
                    if !self.dev {
                        let op = "";
                        let v = format!("{op}{version}", op = op, version = package.version);
                        dependency = dependency.set_version(&v);
                    }
                } else {
                    let registry_url = registry_url(manifest_path, self.registry.as_deref())?;
                    let latest =
                        get_latest_dependency(name, false, manifest_path, Some(&registry_url))?;
                    let op = "";
                    let v = format!(
                        "{op}{version}",
                        op = op,
                        // If version is unavailable `get_latest_dependency` must have
                        // returned `Err(FetchVersionError::GetVersion)`
                        version = latest.version().unwrap_or_else(|| unreachable!())
                    );
                    dependency = dependency
                        .set_version(&v)
                        .set_available_features(latest.available_features);
                }

                dependency
            }
            CrateSpec::Path(_) => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                // dev-dependencies do not need the version populated
                if !self.dev {
                    let dep_path = dependency.path().map(ToOwned::to_owned);
                    if let Some(dep_path) = dep_path {
                        if let Some(package) = workspace_members.iter().find(|p| {
                            p.manifest_path.parent().map(|p| p.as_std_path())
                                == Some(dep_path.as_path())
                        }) {
                            let op = "";
                            let v = format!("{op}{version}", op = op, version = package.version);

                            dependency = dependency.set_version(&v);
                        }
                    }
                }
                dependency
            }
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }
        dependency = self.populate_available_features(dependency, manifest_path)?;

        Ok(dependency)
    }

    fn populate_dependency(&self, mut dependency: Dependency) -> Dependency {
        let requested_features: Option<Vec<_>> = self.features.as_ref().map(|v| {
            v.iter()
                .flat_map(|s| s.split(' '))
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(|f| f.to_owned())
                .collect()
        });

        dependency = dependency
            .set_optional(self.optional())
            .set_default_features(self.default_features())
            .set_features(requested_features);

        if let Some(ref rename) = self.rename {
            dependency = dependency.set_rename(rename);
        }

        dependency
    }

    /// Lookup available features
    pub fn populate_available_features(
        &self,
        dependency: Dependency,
        manifest_path: &Path,
    ) -> Result<Dependency> {
        if !dependency.available_features.is_empty() {
            return Ok(dependency);
        }

        let available_features = if let Some(path) = dependency.path() {
            let manifest = get_manifest_from_path(path)?;
            manifest.features()?
        } else if let Some(repo) = dependency.git() {
            get_manifest_from_url(repo)?
                .map(|m| m.features())
                .transpose()?
                .unwrap_or_else(Vec::new)
        } else if let Some(version) = dependency.version() {
            let registry_url = registry_url(manifest_path, self.registry.as_deref())?;
            get_features_from_registry(&dependency.name, version, &registry_url)?
        } else {
            vec![]
        };

        let dependency = dependency.set_available_features(available_features);
        Ok(dependency)
    }
}

impl Args {
    pub fn optional(&self) -> Option<bool> {
        resolve_bool_arg(self.optional, self.no_optional)
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            git: None,
            branch: None,
            tag: None,
            rev: None,
            target: None,
            optional: false,
            no_optional: false,
            manifest_path: None,
            pkgid: None,
            features: None,
            no_default_features: false,
            default_features: false,
            quiet: false,
            offline: true,
            registry: None,
            unstable_features: vec![],
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
pub enum UnstableOptions {
    Git,
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
    match (yes, no) {
        (true, false) => Some(true),
        (false, true) => Some(false),
        (false, false) => None,
        (_, _) => unreachable!("clap should make this impossible"),
    }
}

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

    #[test]
    fn verify_app() {
        use clap::IntoApp;
        Command::into_app().debug_assert()
    }
}
<|endoftext|>


<commit_before>//! `cargo add`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::args::{Args, ArgsWrap};
use cargo_edit::{Dependency, Manifest};
use std::io::Write;
use std::process;
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

mod args;

mod errors {
    error_chain! {
        errors {
            /// Specified a dependency with both a git URL and a version.
            GitUrlWithVersion(git: String, version: String) {
                description("Specified git URL with version")
                display("Cannot specify a git URL (`{}`) with a version (`{}`).", git, version)
            }
            /// Specified a dependency with both a git URL and a path.
            GitUrlWithPath(git: String, path: String) {
                description("Specified git URL with path")
                display("Cannot specify a git URL (`{}`) with a path (`{}`).", git, path)
            }
            MutiCrateWithGitOrPath{
                description("Specified multiple crates with path or git")
                display("Cannot specify multiple crates with path or git")
            }
        }
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            Io(::std::io::Error);
        }
    }
}
use crate::errors::*;

fn print_msg(dep: &Dependency, section: &[String], optional: bool) -> Result<()> {
    let colorchoice = if atty::is(atty::Stream::Stdout) {
        ColorChoice::Auto
    } else {
        ColorChoice::Never
    };
    let mut output = StandardStream::stdout(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))?;
    write!(output, "{:>12}", "Adding")?;
    output.reset()?;
    write!(output, " {}", dep.name)?;
    if let Some(version) = dep.version() {
        write!(output, " v{}", version)?;
    } else {
        write!(output, " (unknown version)")?;
    }
    write!(output, " to")?;
    if optional {
        write!(output, " optional")?;
    }
    let section = if section.len() == 1 {
        section[0].clone()
    } else {
        format!("{} for target `{}`", &section[2], &section[1])
    };
    writeln!(output, " {}", section)?;
    Ok(())
}

fn handle_add(args: &Args) -> Result<()> {
    let manifest_path = &args.manifest_path;
    let mut manifest = Manifest::open(manifest_path)?;
    let deps = &args.parse_dependencies()?;

    deps.iter()
        .map(|dep| {
            if !args.quiet {
                print_msg(dep, &args.get_section(), args.optional)?;
            }
            manifest
                .insert_into_table(&args.get_section(), dep)
                .map_err(Into::into)
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    let mut file = Manifest::find_file(manifest_path)?;
    manifest.write_to_file(&mut file)?;

    Ok(())
}

fn main() {
    let args: ArgsWrap = ArgsWrap::from_args();
    let ArgsWrap::Add(args) = args;

    if let Err(err) = handle_add(&args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>remove unused error kind<commit_after>//! `cargo add`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::args::{Args, ArgsWrap};
use cargo_edit::{Dependency, Manifest};
use std::io::Write;
use std::process;
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

mod args;

mod errors {
    error_chain! {
        errors {
            /// Specified a dependency with both a git URL and a version.
            GitUrlWithVersion(git: String, version: String) {
                description("Specified git URL with version")
                display("Cannot specify a git URL (`{}`) with a version (`{}`).", git, version)
            }
            /// Specified multiple crates with path or git
            MutiCrateWithGitOrPath{
                description("Specified multiple crates with path or git")
                display("Cannot specify multiple crates with path or git")
            }
        }
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            Io(::std::io::Error);
        }
    }
}
use crate::errors::*;

fn print_msg(dep: &Dependency, section: &[String], optional: bool) -> Result<()> {
    let colorchoice = if atty::is(atty::Stream::Stdout) {
        ColorChoice::Auto
    } else {
        ColorChoice::Never
    };
    let mut output = StandardStream::stdout(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))?;
    write!(output, "{:>12}", "Adding")?;
    output.reset()?;
    write!(output, " {}", dep.name)?;
    if let Some(version) = dep.version() {
        write!(output, " v{}", version)?;
    } else {
        write!(output, " (unknown version)")?;
    }
    write!(output, " to")?;
    if optional {
        write!(output, " optional")?;
    }
    let section = if section.len() == 1 {
        section[0].clone()
    } else {
        format!("{} for target `{}`", &section[2], &section[1])
    };
    writeln!(output, " {}", section)?;
    Ok(())
}

fn handle_add(args: &Args) -> Result<()> {
    let manifest_path = &args.manifest_path;
    let mut manifest = Manifest::open(manifest_path)?;
    let deps = &args.parse_dependencies()?;

    deps.iter()
        .map(|dep| {
            if !args.quiet {
                print_msg(dep, &args.get_section(), args.optional)?;
            }
            manifest
                .insert_into_table(&args.get_section(), dep)
                .map_err(Into::into)
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    let mut file = Manifest::find_file(manifest_path)?;
    manifest.write_to_file(&mut file)?;

    Ok(())
}

fn main() {
    let args: ArgsWrap = ArgsWrap::from_args();
    let ArgsWrap::Add(args) = args;

    if let Err(err) = handle_add(&args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

pub type BitCount0 = uint; // `BitCount` clashes with a standard trait
pub type BitCount8 = u8;
pub type BitCount16 = u16;
pub type BitCount32 = u32;
pub type BitCount64 = u64;

pub type ByteCount = uint;
pub type ByteCount8 = u8;
pub type ByteCount16 = u16;
pub type ByteCount32 = u32;
pub type ByteCount64 = u64;

pub type WordCount = uint;
pub type WordCount8 = u8;
pub type WordCount16 = u16;
pub type WordCount32 = u32;
pub type WordCount64 = u64;

pub type ElementCount = uint;
pub type ElementCount8 = u8;
pub type ElementCount16 = u16;
pub type ElementCount32 = u32;
pub type ElementCount64 = u64;

pub type WirePointerCount = uint;
pub type WirePointerCount8 = u8;
pub type WirePointerCount16 = u16;
pub type WirePointerCount32 = u32;
pub type WirePointerCount64 = u64;

#[deriving(Copy)]
pub struct Word {_x : u64}

pub const BITS_PER_BYTE : BitCount0 = 8;
pub const BITS_PER_WORD : BitCount0 = 64;
pub const BYTES_PER_WORD : ByteCount = 8;

pub const BITS_PER_POINTER : BitCount0 = 64;
pub const BYTES_PER_POINTER : ByteCount = 8;
pub const WORDS_PER_POINTER : WordCount = 1;

pub const POINTER_SIZE_IN_WORDS : WordCount = 1;

pub fn bytes_per_element<T>() -> ByteCount {
    ::std::mem::size_of::<T>()
}

pub fn bits_per_element<T>() -> BitCount0 {
    8 * ::std::mem::size_of::<T>()
}

#[inline]
pub fn allocate_zeroed_words(size : WordCount) -> ::std::vec::Vec<Word> {

//    Do this, but faster:
//    return ::std::vec::Vec::from_elem(size, 0);

    let mut result : ::std::vec::Vec<Word> = ::std::vec::Vec::with_capacity(size);
    unsafe {
        result.set_len(size);
        let p : *mut u8 = ::std::mem::transmute(result.as_mut_slice().as_mut_ptr());
        ::std::ptr::set_memory(p, 0, size * BYTES_PER_WORD);
    }
    return result;
}

#[deriving(Copy)]
pub struct MessageSize {
    //# Size of a message. Every struct type has a method `.total_size()` that returns this.
    pub word_count : u64,
    pub cap_count : u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

#[inline]
pub fn ptr_sub<T, U: ::std::ptr::PtrExt<T>, V: ::std::ptr::PtrExt<T>>(p1 : U, p2 : V) -> uint {
    return (p1.to_uint() - p2.to_uint()) / ::std::mem::size_of::<T>();
}
<commit_msg>kill to_uint() warnings<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

pub type BitCount0 = uint; // `BitCount` clashes with a standard trait
pub type BitCount8 = u8;
pub type BitCount16 = u16;
pub type BitCount32 = u32;
pub type BitCount64 = u64;

pub type ByteCount = uint;
pub type ByteCount8 = u8;
pub type ByteCount16 = u16;
pub type ByteCount32 = u32;
pub type ByteCount64 = u64;

pub type WordCount = uint;
pub type WordCount8 = u8;
pub type WordCount16 = u16;
pub type WordCount32 = u32;
pub type WordCount64 = u64;

pub type ElementCount = uint;
pub type ElementCount8 = u8;
pub type ElementCount16 = u16;
pub type ElementCount32 = u32;
pub type ElementCount64 = u64;

pub type WirePointerCount = uint;
pub type WirePointerCount8 = u8;
pub type WirePointerCount16 = u16;
pub type WirePointerCount32 = u32;
pub type WirePointerCount64 = u64;

#[deriving(Copy)]
pub struct Word {_x : u64}

pub const BITS_PER_BYTE : BitCount0 = 8;
pub const BITS_PER_WORD : BitCount0 = 64;
pub const BYTES_PER_WORD : ByteCount = 8;

pub const BITS_PER_POINTER : BitCount0 = 64;
pub const BYTES_PER_POINTER : ByteCount = 8;
pub const WORDS_PER_POINTER : WordCount = 1;

pub const POINTER_SIZE_IN_WORDS : WordCount = 1;

pub fn bytes_per_element<T>() -> ByteCount {
    ::std::mem::size_of::<T>()
}

pub fn bits_per_element<T>() -> BitCount0 {
    8 * ::std::mem::size_of::<T>()
}

#[inline]
pub fn allocate_zeroed_words(size : WordCount) -> ::std::vec::Vec<Word> {

//    Do this, but faster:
//    return ::std::vec::Vec::from_elem(size, 0);

    let mut result : ::std::vec::Vec<Word> = ::std::vec::Vec::with_capacity(size);
    unsafe {
        result.set_len(size);
        let p : *mut u8 = ::std::mem::transmute(result.as_mut_slice().as_mut_ptr());
        ::std::ptr::set_memory(p, 0, size * BYTES_PER_WORD);
    }
    return result;
}

#[deriving(Copy)]
pub struct MessageSize {
    //# Size of a message. Every struct type has a method `.total_size()` that returns this.
    pub word_count : u64,
    pub cap_count : u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

pub trait PtrUint<T> {
    fn as_uint(self) -> uint;
}

impl <T> PtrUint<T> for *const T {
    fn as_uint(self) -> uint {
        self as uint
    }
}

impl <T> PtrUint<T> for *mut T {
    fn as_uint(self) -> uint {
        self as uint
    }
}

#[inline]
pub fn ptr_sub<T, U: PtrUint<T>, V: PtrUint<T>>(p1 : U, p2 : V) -> uint {
    return (p1.as_uint() - p2.as_uint()) / ::std::mem::size_of::<T>();
}
<|endoftext|>