<commit_before>//! Common traits for input backends to receive input from.

use backend::{SeatInternal, TouchSlotInternal};

use std::error::Error;

/// A seat describes a group of input devices and at least one
/// graphics device belonging together.
///
/// By default only one seat exists for most systems and smithay backends
/// however multiseat configurations are possible and should be treated as
/// separated users, all with their own focus, input and cursor available.
///
/// Seats can be checked for equality and hashed for differentiation.
// FIXME: Impl PartialEq, Eq and Hash only dependant on `id`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Seat {
    id: u64,
    capabilities: SeatCapabilities,
}

impl SeatInternal for Seat {
    fn new(id: u64, capabilities: SeatCapabilities) -> Seat {
        Seat {
            id: id,
            capabilities: capabilities,
        }
    }

    fn capabilities_mut(&mut self) -> &mut SeatCapabilities {
        &mut self.capabilities
    }
}

impl Seat {
    /// Get the currently capabilities of this `Seat`
    pub fn capabilities(&self) -> &SeatCapabilities {
        &self.capabilities
    }
}

/// Describes capabilities a `Seat` has.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SeatCapabilities {
    /// `Seat` has a pointer
    pub pointer: bool,
    /// `Seat` has a keyboard
    pub keyboard: bool,
    /// `Seat` has a touchscreen
    pub touch: bool,
}

/// State of key on a keyboard. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum KeyState {
    /// Key is released
    Released,
    /// Key is pressed
    Pressed,
}

/// A particular mouse button
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    /// Left mouse button
    Left,
    /// Middle mouse button
    Middle,
    /// Right mouse button
    Right,
    /// Other mouse button with index
    Other(u8),
}

/// State of a button on a mouse. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButtonState {
    /// Button is released
    Released,
    /// Button is pressed
    Pressed,
}

/// Axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Axis {
    /// Vertical axis
    Vertical,
    /// Horizonal axis
    Horizontal,
}

/// Source of an axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum AxisSource {
    /// Finger. Mostly used for trackpads.
    ///
    /// Guarantees that a scroll sequence is terminated with a scroll value of 0.
    /// A caller may use this information to decide on whether kinetic scrolling should
    /// be triggered on this scroll sequence.
    ///
    /// The coordinate system is identical to the
    /// cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Finger,
    /// Continous scrolling device. Almost identical to `Finger`
    ///
    /// No terminating event is guaranteed (though it may happen).
    ///
    /// The coordinate system is identical to
    /// the cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Continuous,
    /// Scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    Wheel,
    /// Scrolling through tilting the scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    WheelTilt,
}

/// Slot of a different touch event.
///
/// Touch events are groubed by slots, usually to identify different
/// fingers on a multi-touch enabled input device. Events should only
/// be interpreted in the context of other events on the same slot.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TouchSlot {
    id: u32,
}

impl TouchSlotInternal for TouchSlot {
    fn new(id: u32) -> Self {
        TouchSlot { id: id }
    }
}

/// Touch event
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TouchEvent {
    /// The start of an event at a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Down {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the touch position.
        x: f64,
        /// Absolute y-coordinate of the touch position.
        y: f64,
    },
    /// Movement of a touch on the device surface to a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Motion {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the final touch position after the motion.
        x: f64,
        /// Absolute y-coordinate of the final touch position after the motion.
        y: f64,
    },
    /// Stop of an event chain.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Up {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Cancel of an event chain. All previous events in the chain should be ignored.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Cancel {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Signals the end of a set of touchpoints at one device sample time.
    Frame,
}

/// Trait that describes objects providing a source of input events. All input backends
/// need to implemenent this and provide the same base gurantees about the presicion of
/// given events.
pub trait InputBackend: Sized {
    /// Type of input device associated with the backend
    type InputConfig: ?Sized;

    /// Type representing errors that may be returned when processing events
    type EventError: Error;

    /// Sets a new handler for this `InputBackend`
    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, handler: H);
    /// Get a reference to the currently set handler, if any
    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>>;
    /// Clears the currently handler, if one is set
    fn clear_handler(&mut self);

    /// Get current `InputConfig`
    fn input_config(&mut self) -> &mut Self::InputConfig;

    /// Processes new events of the underlying backend and drives the `InputHandler`.
    fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>;

    /// Sets the cursor position, useful for e.g. pointer wrapping.
    ///
    /// Not guaranteed to be supported on every backend. The result usually
    /// depends on the capability of the backend, but may also fail for certain
    /// specific actions. See the backends documentation.
    fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()>;
}

/// Implement to receive input events from any `InputBackend`.
pub trait InputHandler<B: InputBackend> {
    /// Called when a new `Seat` has been created
    fn on_seat_created(&mut self, seat: &Seat);
    /// Called when an existing `Seat` has been destroyed.
    fn on_seat_destroyed(&mut self, seat: &Seat);
    /// Called when a `Seat`'s properties have changed.
    fn on_seat_changed(&mut self, seat: &Seat);

    /// Called when a new keyboard event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `key_code` - Code of the pressed key. See linux/input-event-codes.h
    /// - `state` - `KeyState` of the event
    /// - `count` - Total number of keys pressed on all devices on the associated `Seat`
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32);
    /// Called when a new pointer movement event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `to` - Absolute screen coordinates of the pointer moved to.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32));
    /// Called when a new pointer button event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `button` - Which button was pressed..
    /// - `state` - `MouseButtonState` of the event
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState);
    /// Called when a new pointer scroll event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `axis` - `Axis` this event was generated for.
    /// - `source` - Source of the scroll event. Important for interpretation of `amount`.
    /// - `amount` - Amount of scrolling on the given `Axis`. See `source` for interpretation.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64);
    /// Called when a new touch event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `event` - Touch event recieved. See `TouchEvent`.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent);

    /// Called when the `InputConfig` was changed through an external event.
    ///
    /// What kind of events can trigger this call is completely backend dependent.
    /// E.g. an input devices was attached/detached or changed it's own configuration.
    fn on_input_config_changed(&mut self, config: &mut B::InputConfig);
}

impl<B: InputBackend> InputHandler<B> for Box<InputHandler<B>> {
    fn on_seat_created(&mut self, seat: &Seat) {
        (**self).on_seat_created(seat)
    }

    fn on_seat_destroyed(&mut self, seat: &Seat) {
        (**self).on_seat_destroyed(seat)
    }

    fn on_seat_changed(&mut self, seat: &Seat) {
        (**self).on_seat_changed(seat)
    }

    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32) {
        (**self).on_keyboard_key(seat, time, key_code, state, count)
    }

    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)) {
        (**self).on_pointer_move(seat, time, to)
    }

    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState) {
        (**self).on_pointer_button(seat, time, button, state)
    }

    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64) {
        (**self).on_pointer_scroll(seat, time, axis, source, amount)
    }

    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent) {
        (**self).on_touch(seat, time, event)
    }

    fn on_input_config_changed(&mut self, config: &mut B::InputConfig) {
        (**self).on_input_config_changed(config)
    }
}
<commit_msg>Fixup seat implementation<commit_after>//! Common traits for input backends to receive input from.

use backend::{SeatInternal, TouchSlotInternal};

use std::error::Error;

/// A seat describes a group of input devices and at least one
/// graphics device belonging together.
///
/// By default only one seat exists for most systems and smithay backends
/// however multiseat configurations are possible and should be treated as
/// separated users, all with their own focus, input and cursor available.
///
/// Seats can be checked for equality and hashed for differentiation.
#[derive(Debug, Clone, Copy, Eq)]
pub struct Seat {
    id: u64,
    capabilities: SeatCapabilities,
}

impl SeatInternal for Seat {
    fn new(id: u64, capabilities: SeatCapabilities) -> Seat {
        Seat {
            id: id,
            capabilities: capabilities,
        }
    }

    fn capabilities_mut(&mut self) -> &mut SeatCapabilities {
        &mut self.capabilities
    }
}

impl Seat {
    /// Get the currently capabilities of this `Seat`
    pub fn capabilities(&self) -> &SeatCapabilities {
        &self.capabilities
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        self.id == other.id
    }
}

impl ::std::hash::Hash for Seat {
    fn hash<H>(&self, state: &mut H) where H: ::std::hash::Hasher {
        self.id.hash(state);
    }
}

/// Describes capabilities a `Seat` has.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SeatCapabilities {
    /// `Seat` has a pointer
    pub pointer: bool,
    /// `Seat` has a keyboard
    pub keyboard: bool,
    /// `Seat` has a touchscreen
    pub touch: bool,
}

/// State of key on a keyboard. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum KeyState {
    /// Key is released
    Released,
    /// Key is pressed
    Pressed,
}

/// A particular mouse button
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    /// Left mouse button
    Left,
    /// Middle mouse button
    Middle,
    /// Right mouse button
    Right,
    /// Other mouse button with index
    Other(u8),
}

/// State of a button on a mouse. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButtonState {
    /// Button is released
    Released,
    /// Button is pressed
    Pressed,
}

/// Axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Axis {
    /// Vertical axis
    Vertical,
    /// Horizonal axis
    Horizontal,
}

/// Source of an axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum AxisSource {
    /// Finger. Mostly used for trackpads.
    ///
    /// Guarantees that a scroll sequence is terminated with a scroll value of 0.
    /// A caller may use this information to decide on whether kinetic scrolling should
    /// be triggered on this scroll sequence.
    ///
    /// The coordinate system is identical to the
    /// cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Finger,
    /// Continous scrolling device. Almost identical to `Finger`
    ///
    /// No terminating event is guaranteed (though it may happen).
    ///
    /// The coordinate system is identical to
    /// the cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Continuous,
    /// Scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    Wheel,
    /// Scrolling through tilting the scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    WheelTilt,
}

/// Slot of a different touch event.
///
/// Touch events are groubed by slots, usually to identify different
/// fingers on a multi-touch enabled input device. Events should only
/// be interpreted in the context of other events on the same slot.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TouchSlot {
    id: u32,
}

impl TouchSlotInternal for TouchSlot {
    fn new(id: u32) -> Self {
        TouchSlot { id: id }
    }
}

/// Touch event
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TouchEvent {
    /// The start of an event at a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Down {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the touch position.
        x: f64,
        /// Absolute y-coordinate of the touch position.
        y: f64,
    },
    /// Movement of a touch on the device surface to a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Motion {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the final touch position after the motion.
        x: f64,
        /// Absolute y-coordinate of the final touch position after the motion.
        y: f64,
    },
    /// Stop of an event chain.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Up {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Cancel of an event chain. All previous events in the chain should be ignored.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Cancel {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Signals the end of a set of touchpoints at one device sample time.
    Frame,
}

/// Trait that describes objects providing a source of input events. All input backends
/// need to implemenent this and provide the same base gurantees about the presicion of
/// given events.
pub trait InputBackend: Sized {
    /// Type of input device associated with the backend
    type InputConfig: ?Sized;

    /// Type representing errors that may be returned when processing events
    type EventError: Error;

    /// Sets a new handler for this `InputBackend`
    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, handler: H);
    /// Get a reference to the currently set handler, if any
    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>>;
    /// Clears the currently handler, if one is set
    fn clear_handler(&mut self);

    /// Get current `InputConfig`
    fn input_config(&mut self) -> &mut Self::InputConfig;

    /// Processes new events of the underlying backend and drives the `InputHandler`.
    fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>;

    /// Sets the cursor position, useful for e.g. pointer wrapping.
    ///
    /// Not guaranteed to be supported on every backend. The result usually
    /// depends on the capability of the backend, but may also fail for certain
    /// specific actions. See the backends documentation.
    fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()>;
}

/// Implement to receive input events from any `InputBackend`.
pub trait InputHandler<B: InputBackend> {
    /// Called when a new `Seat` has been created
    fn on_seat_created(&mut self, seat: &Seat);
    /// Called when an existing `Seat` has been destroyed.
    fn on_seat_destroyed(&mut self, seat: &Seat);
    /// Called when a `Seat`'s properties have changed.
    fn on_seat_changed(&mut self, seat: &Seat);

    /// Called when a new keyboard event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `key_code` - Code of the pressed key. See linux/input-event-codes.h
    /// - `state` - `KeyState` of the event
    /// - `count` - Total number of keys pressed on all devices on the associated `Seat`
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32);
    /// Called when a new pointer movement event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `to` - Absolute screen coordinates of the pointer moved to.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32));
    /// Called when a new pointer button event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `button` - Which button was pressed..
    /// - `state` - `MouseButtonState` of the event
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState);
    /// Called when a new pointer scroll event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `axis` - `Axis` this event was generated for.
    /// - `source` - Source of the scroll event. Important for interpretation of `amount`.
    /// - `amount` - Amount of scrolling on the given `Axis`. See `source` for interpretation.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64);
    /// Called when a new touch event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `event` - Touch event recieved. See `TouchEvent`.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent);

    /// Called when the `InputConfig` was changed through an external event.
    ///
    /// What kind of events can trigger this call is completely backend dependent.
    /// E.g. an input devices was attached/detached or changed it's own configuration.
    fn on_input_config_changed(&mut self, config: &mut B::InputConfig);
}

impl<B: InputBackend> InputHandler<B> for Box<InputHandler<B>> {
    fn on_seat_created(&mut self, seat: &Seat) {
        (**self).on_seat_created(seat)
    }

    fn on_seat_destroyed(&mut self, seat: &Seat) {
        (**self).on_seat_destroyed(seat)
    }

    fn on_seat_changed(&mut self, seat: &Seat) {
        (**self).on_seat_changed(seat)
    }

    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32) {
        (**self).on_keyboard_key(seat, time, key_code, state, count)
    }

    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)) {
        (**self).on_pointer_move(seat, time, to)
    }

    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState) {
        (**self).on_pointer_button(seat, time, button, state)
    }

    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64) {
        (**self).on_pointer_scroll(seat, time, axis, source, amount)
    }

    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent) {
        (**self).on_touch(seat, time, event)
    }

    fn on_input_config_changed(&mut self, config: &mut B::InputConfig) {
        (**self).on_input_config_changed(config)
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate serialize;
extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::os;

use cargo::ops;
use cargo::{execute_main_without_stdin};
use cargo::core::{MultiShell};
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::find_project_manifest;

docopt!(Options, "
Build a package's documentation

Usage:
    cargo-doc [options]

Options:
    -h, --help              Print this message
    --no-deps               Don't build documentation for dependencies
    -j N, --jobs N          The number of jobs to run in parallel
    -u, --update-remotes    Deprecated option, use `cargo update` instead
    --manifest-path PATH    Path to the manifest to document
    -v, --verbose           Use verbose output

By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.
",  flag_jobs: Option<uint>,
    flag_manifest_path: Option<String>)

fn main() {
    execute_main_without_stdin(execute, false)
}

fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
    shell.set_verbose(options.flag_verbose);
    let root = match options.flag_manifest_path {
        Some(path) => Path::new(path),
        None => try!(find_project_manifest(&os::getcwd(), "Cargo.toml")
                    .map_err(|_| {
                        CliError::new("Could not find Cargo.toml in this \
                                       directory or any parent directory",
                                      102)
                    }))
    };

    let mut doc_opts = ops::DocOptions {
        all: !options.flag_no_deps,
        compile_opts: ops::CompileOptions {
            update: options.flag_update_remotes,
            env: if options.flag_no_deps {"doc"} else {"doc-all"},
            shell: shell,
            jobs: options.flag_jobs,
            target: None,
        },
    };

    try!(ops::doc(&root, &mut doc_opts).map_err(|err| {
        CliError::from_boxed(err, 101)
    }));

    Ok(None)
}

<commit_msg>auto merge of #317 : jdeseno/cargo/doc-manifest-path, r=alexcrichton<commit_after>#![feature(phase)]

extern crate serialize;
extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use cargo::ops;
use cargo::{execute_main_without_stdin};
use cargo::core::{MultiShell};
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};

docopt!(Options, "
Build a package's documentation

Usage:
    cargo-doc [options]

Options:
    -h, --help              Print this message
    --no-deps               Don't build documentation for dependencies
    -j N, --jobs N          The number of jobs to run in parallel
    -u, --update-remotes    Deprecated option, use `cargo update` instead
    --manifest-path PATH    Path to the manifest to document
    -v, --verbose           Use verbose output

By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.
",  flag_jobs: Option<uint>,
    flag_manifest_path: Option<String>)

fn main() {
    execute_main_without_stdin(execute, false)
}

fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
    shell.set_verbose(options.flag_verbose);

    let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));

    let mut doc_opts = ops::DocOptions {
        all: !options.flag_no_deps,
        compile_opts: ops::CompileOptions {
            update: options.flag_update_remotes,
            env: if options.flag_no_deps {"doc"} else {"doc-all"},
            shell: shell,
            jobs: options.flag_jobs,
            target: None,
        },
    };

    try!(ops::doc(&root, &mut doc_opts).map_err(|err| {
        CliError::from_boxed(err, 101)
    }));

    Ok(None)
}

<|endoftext|>


<commit_before>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use getopts::{Matches, Options};
use json::Value;

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

fn execute() -> i32 {
    let success = 0;
    let failure = 1;

    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    if let Some(arg) = env::args()
        .skip(2)
        .take_while(|a| a != "--")
        .find(|a| !a.starts_with('-'))
    {
        print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
        return failure;
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return failure;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return failure;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return success;
    }

    let workspace_hitlist = WorkspaceHitlist::from_matches(&matches);

    match format_crate(verbosity, &workspace_hitlist) {
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            failure
        }
        Ok(status) => if status.success() {
            success
        } else {
            status.code().unwrap_or(failure)
        },
    }
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => ({
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    })
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn format_crate(
    verbosity: Verbosity,
    workspace_hitlist: &WorkspaceHitlist,
) -> Result<ExitStatus, std::io::Error> {
    let targets = get_targets(workspace_hitlist)?;

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .filter(|t| t.kind.should_format())
        .inspect(|t| if verbosity == Verbosity::Verbose {
            println!("[{:?}] {:?}", t.kind, t.path)
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &get_fmt_args(), verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

#[derive(Debug)]
enum TargetKind {
    Lib,         // dylib, staticlib, lib
    Bin,         // bin
    Example,     // example file
    Test,        // test file
    Bench,       // bench file
    CustomBuild, // build script
    ProcMacro,   // a proc macro implementation
    Other,       // plugin,...
}

impl TargetKind {
    fn should_format(&self) -> bool {
        match *self {
            TargetKind::Lib |
            TargetKind::Bin |
            TargetKind::Example |
            TargetKind::Test |
            TargetKind::Bench |
            TargetKind::CustomBuild |
            TargetKind::ProcMacro => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct Target {
    path: PathBuf,
    kind: TargetKind,
}

impl Target {
    pub fn from_json(json_val: &Value) -> Option<Self> {
        let jtarget = json_val.as_object()?;
        let path = PathBuf::from(jtarget.get("src_path")?.as_str()?);
        let kinds = jtarget.get("kind")?.as_array()?;
        let kind = match kinds[0].as_str()? {
            "bin" => TargetKind::Bin,
            "lib" | "dylib" | "staticlib" | "cdylib" | "rlib" => TargetKind::Lib,
            "test" => TargetKind::Test,
            "example" => TargetKind::Example,
            "bench" => TargetKind::Bench,
            "custom-build" => TargetKind::CustomBuild,
            "proc-macro" => TargetKind::ProcMacro,
            _ => TargetKind::Other,
        };

        Some(Target {
            path: path,
            kind: kind,
        })
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WorkspaceHitlist {
    All,
    Some(Vec<String>),
    None,
}

impl WorkspaceHitlist {
    pub fn get_some(&self) -> Option<&[String]> {
        if let WorkspaceHitlist::Some(ref hitlist) = *self {
            Some(hitlist)
        } else {
            None
        }
    }

    pub fn from_matches(matches: &Matches) -> WorkspaceHitlist {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => WorkspaceHitlist::None,
            (true, _) => WorkspaceHitlist::All,
            (false, true) => WorkspaceHitlist::Some(matches.opt_strs("p")),
        }
    }
}

fn get_cargo_metadata_from_utf8(v: &[u8]) -> Option<Value> {
    json::from_str(str::from_utf8(v).ok()?).ok()
}

fn get_json_array_with<'a>(v: &'a Value, key: &str) -> Option<&'a Vec<Value>> {
    v.as_object()?.get(key)?.as_array()
}

// `cargo metadata --no-deps | jq '.["packages"]'`
fn get_packages(v: &[u8]) -> Result<Vec<Value>, io::Error> {
    let e = io::Error::new(
        io::ErrorKind::NotFound,
        String::from("`cargo metadata` returned json without a 'packages' key"),
    );
    match get_cargo_metadata_from_utf8(v) {
        Some(ref json_obj) => get_json_array_with(json_obj, "packages").cloned().ok_or(e),
        None => Err(e),
    }
}

fn extract_target_from_package(package: &Value) -> Option<Vec<Target>> {
    let jtargets = get_json_array_with(package, "targets")?;
    let mut targets: Vec<Target> = vec![];
    for jtarget in jtargets {
        targets.push(Target::from_json(&jtarget)?);
    }
    Some(targets)
}

fn filter_packages_with_hitlist<'a>(
    packages: Vec<Value>,
    workspace_hitlist: &'a WorkspaceHitlist,
) -> Result<Vec<Value>, &'a String> {
    if *workspace_hitlist == WorkspaceHitlist::All {
        return Ok(packages);
    }
    let mut hitlist: HashSet<&String> = workspace_hitlist
        .get_some()
        .map_or(HashSet::new(), HashSet::from_iter);
    let members: Vec<Value> = packages
        .into_iter()
        .filter(|member| {
            member
                .as_object()
                .and_then(|member_obj| {
                    member_obj
                        .get("name")
                        .and_then(Value::as_str)
                        .map(|member_name| {
                            hitlist.take(&member_name.to_string()).is_some()
                        })
                })
                .unwrap_or(false)
        })
        .collect();
    if hitlist.is_empty() {
        Ok(members)
    } else {
        Err(hitlist.into_iter().next().unwrap())
    }
}

fn get_dependencies_from_package(package: &Value) -> Option<Vec<PathBuf>> {
    let jdependencies = get_json_array_with(package, "dependencies")?;
    let root_path = env::current_dir().ok()?;
    let mut dependencies: Vec<PathBuf> = vec![];
    for jdep in jdependencies {
        let jdependency = jdep.as_object()?;
        if !jdependency.get("source")?.is_null() {
            continue;
        }
        let name = jdependency.get("name")?.as_str()?;
        let mut path = root_path.clone();
        path.push(&name);
        dependencies.push(path);
    }
    Some(dependencies)
}

// Returns a vector of local dependencies under this crate
fn get_path_to_local_dependencies(packages: &[Value]) -> Vec<PathBuf> {
    let mut local_dependencies: Vec<PathBuf> = vec![];
    for package in packages {
        if let Some(mut d) = get_dependencies_from_package(package) {
            local_dependencies.append(&mut d);
        }
    }
    local_dependencies
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: &WorkspaceHitlist) -> Result<Vec<Target>, io::Error> {
    let output = Command::new("cargo")
        .args(&["metadata", "--no-deps", "--format-version=1"])
        .output()?;
    if output.status.success() {
        let cur_dir = env::current_dir()?;
        let mut targets: Vec<Target> = vec![];
        let packages = get_packages(&output.stdout)?;

        // If we can find any local dependencies, we will try to get targets from those as well.
        for path in get_path_to_local_dependencies(&packages) {
            env::set_current_dir(path)?;
            targets.append(&mut get_targets(workspace_hitlist)?);
        }

        env::set_current_dir(cur_dir)?;
        match filter_packages_with_hitlist(packages, workspace_hitlist) {
            Ok(packages) => {
                for package in packages {
                    if let Some(mut target) = extract_target_from_package(&package) {
                        targets.append(&mut target);
                    }
                }
                Ok(targets)
            }
            Err(package) => {
                // Mimick cargo of only outputting one <package> spec.
                Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("package `{}` is not a member of the workspace", package),
                ))
            }
        }
    } else {
        Err(io::Error::new(
            io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ))
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, std::io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };
    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args.iter() {
            print!(" {}", a);
        }
        for f in files.iter() {
            print!(" {}", f.display());
        }
        println!("");
    }
    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            std::io::ErrorKind::NotFound => std::io::Error::new(
                std::io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    command.wait()
}
<commit_msg>%s/std::io/io/g<commit_after>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use getopts::{Matches, Options};
use json::Value;

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

fn execute() -> i32 {
    let success = 0;
    let failure = 1;

    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    if let Some(arg) = env::args()
        .skip(2)
        .take_while(|a| a != "--")
        .find(|a| !a.starts_with('-'))
    {
        print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
        return failure;
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return failure;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return failure;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return success;
    }

    let workspace_hitlist = WorkspaceHitlist::from_matches(&matches);

    match format_crate(verbosity, &workspace_hitlist) {
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            failure
        }
        Ok(status) => if status.success() {
            success
        } else {
            status.code().unwrap_or(failure)
        },
    }
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => ({
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    })
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn format_crate(
    verbosity: Verbosity,
    workspace_hitlist: &WorkspaceHitlist,
) -> Result<ExitStatus, io::Error> {
    let targets = get_targets(workspace_hitlist)?;

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .filter(|t| t.kind.should_format())
        .inspect(|t| if verbosity == Verbosity::Verbose {
            println!("[{:?}] {:?}", t.kind, t.path)
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &get_fmt_args(), verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

#[derive(Debug)]
enum TargetKind {
    Lib,         // dylib, staticlib, lib
    Bin,         // bin
    Example,     // example file
    Test,        // test file
    Bench,       // bench file
    CustomBuild, // build script
    ProcMacro,   // a proc macro implementation
    Other,       // plugin,...
}

impl TargetKind {
    fn should_format(&self) -> bool {
        match *self {
            TargetKind::Lib |
            TargetKind::Bin |
            TargetKind::Example |
            TargetKind::Test |
            TargetKind::Bench |
            TargetKind::CustomBuild |
            TargetKind::ProcMacro => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct Target {
    path: PathBuf,
    kind: TargetKind,
}

impl Target {
    pub fn from_json(json_val: &Value) -> Option<Self> {
        let jtarget = json_val.as_object()?;
        let path = PathBuf::from(jtarget.get("src_path")?.as_str()?);
        let kinds = jtarget.get("kind")?.as_array()?;
        let kind = match kinds[0].as_str()? {
            "bin" => TargetKind::Bin,
            "lib" | "dylib" | "staticlib" | "cdylib" | "rlib" => TargetKind::Lib,
            "test" => TargetKind::Test,
            "example" => TargetKind::Example,
            "bench" => TargetKind::Bench,
            "custom-build" => TargetKind::CustomBuild,
            "proc-macro" => TargetKind::ProcMacro,
            _ => TargetKind::Other,
        };

        Some(Target {
            path: path,
            kind: kind,
        })
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WorkspaceHitlist {
    All,
    Some(Vec<String>),
    None,
}

impl WorkspaceHitlist {
    pub fn get_some(&self) -> Option<&[String]> {
        if let WorkspaceHitlist::Some(ref hitlist) = *self {
            Some(hitlist)
        } else {
            None
        }
    }

    pub fn from_matches(matches: &Matches) -> WorkspaceHitlist {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => WorkspaceHitlist::None,
            (true, _) => WorkspaceHitlist::All,
            (false, true) => WorkspaceHitlist::Some(matches.opt_strs("p")),
        }
    }
}

fn get_cargo_metadata_from_utf8(v: &[u8]) -> Option<Value> {
    json::from_str(str::from_utf8(v).ok()?).ok()
}

fn get_json_array_with<'a>(v: &'a Value, key: &str) -> Option<&'a Vec<Value>> {
    v.as_object()?.get(key)?.as_array()
}

// `cargo metadata --no-deps | jq '.["packages"]'`
fn get_packages(v: &[u8]) -> Result<Vec<Value>, io::Error> {
    let e = io::Error::new(
        io::ErrorKind::NotFound,
        String::from("`cargo metadata` returned json without a 'packages' key"),
    );
    match get_cargo_metadata_from_utf8(v) {
        Some(ref json_obj) => get_json_array_with(json_obj, "packages").cloned().ok_or(e),
        None => Err(e),
    }
}

fn extract_target_from_package(package: &Value) -> Option<Vec<Target>> {
    let jtargets = get_json_array_with(package, "targets")?;
    let mut targets: Vec<Target> = vec![];
    for jtarget in jtargets {
        targets.push(Target::from_json(&jtarget)?);
    }
    Some(targets)
}

fn filter_packages_with_hitlist<'a>(
    packages: Vec<Value>,
    workspace_hitlist: &'a WorkspaceHitlist,
) -> Result<Vec<Value>, &'a String> {
    if *workspace_hitlist == WorkspaceHitlist::All {
        return Ok(packages);
    }
    let mut hitlist: HashSet<&String> = workspace_hitlist
        .get_some()
        .map_or(HashSet::new(), HashSet::from_iter);
    let members: Vec<Value> = packages
        .into_iter()
        .filter(|member| {
            member
                .as_object()
                .and_then(|member_obj| {
                    member_obj
                        .get("name")
                        .and_then(Value::as_str)
                        .map(|member_name| {
                            hitlist.take(&member_name.to_string()).is_some()
                        })
                })
                .unwrap_or(false)
        })
        .collect();
    if hitlist.is_empty() {
        Ok(members)
    } else {
        Err(hitlist.into_iter().next().unwrap())
    }
}

fn get_dependencies_from_package(package: &Value) -> Option<Vec<PathBuf>> {
    let jdependencies = get_json_array_with(package, "dependencies")?;
    let root_path = env::current_dir().ok()?;
    let mut dependencies: Vec<PathBuf> = vec![];
    for jdep in jdependencies {
        let jdependency = jdep.as_object()?;
        if !jdependency.get("source")?.is_null() {
            continue;
        }
        let name = jdependency.get("name")?.as_str()?;
        let mut path = root_path.clone();
        path.push(&name);
        dependencies.push(path);
    }
    Some(dependencies)
}

// Returns a vector of local dependencies under this crate
fn get_path_to_local_dependencies(packages: &[Value]) -> Vec<PathBuf> {
    let mut local_dependencies: Vec<PathBuf> = vec![];
    for package in packages {
        if let Some(mut d) = get_dependencies_from_package(package) {
            local_dependencies.append(&mut d);
        }
    }
    local_dependencies
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: &WorkspaceHitlist) -> Result<Vec<Target>, io::Error> {
    let output = Command::new("cargo")
        .args(&["metadata", "--no-deps", "--format-version=1"])
        .output()?;
    if output.status.success() {
        let cur_dir = env::current_dir()?;
        let mut targets: Vec<Target> = vec![];
        let packages = get_packages(&output.stdout)?;

        // If we can find any local dependencies, we will try to get targets from those as well.
        for path in get_path_to_local_dependencies(&packages) {
            env::set_current_dir(path)?;
            targets.append(&mut get_targets(workspace_hitlist)?);
        }

        env::set_current_dir(cur_dir)?;
        match filter_packages_with_hitlist(packages, workspace_hitlist) {
            Ok(packages) => {
                for package in packages {
                    if let Some(mut target) = extract_target_from_package(&package) {
                        targets.append(&mut target);
                    }
                }
                Ok(targets)
            }
            Err(package) => {
                // Mimick cargo of only outputting one <package> spec.
                Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("package `{}` is not a member of the workspace", package),
                ))
            }
        }
    } else {
        Err(io::Error::new(
            io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ))
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };
    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args.iter() {
            print!(" {}", a);
        }
        for f in files.iter() {
            print!(" {}", f.display());
        }
        println!("");
    }
    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    command.wait()
}
<|endoftext|>


<commit_before>

extern crate cratesfyi;
extern crate clap;
extern crate log;
extern crate env_logger;
extern crate time;
extern crate rustwide;

use std::env;
use std::path::{Path, PathBuf};

use clap::{Arg, App, AppSettings, SubCommand};
use cratesfyi::{DocBuilder, RustwideBuilder, DocBuilderOptions, db};
use cratesfyi::utils::add_crate_to_queue;
use cratesfyi::start_web_server;
use cratesfyi::db::{add_path_into_database, connect_db};

pub fn main() {
    logger_init();

    let matches = App::new("cratesfyi")
        .version(cratesfyi::BUILD_VERSION)
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(SubCommand::with_name("build")
            .about("Builds documentation in a chroot environment")
            .setting(AppSettings::ArgRequiredElseHelp)
            .arg(Arg::with_name("PREFIX")
                .short("P")
                .long("prefix")
                .takes_value(true))
            .arg(Arg::with_name("CRATES_IO_INDEX_PATH")
                .long("crates-io-index-path")
                .help("Sets crates.io-index path")
                .takes_value(true))
            .arg(Arg::with_name("SKIP_IF_EXISTS")
                .short("s")
                .long("skip")
                .help("Skips building documentation if documentation exists"))
            .arg(Arg::with_name("SKIP_IF_LOG_EXISTS")
                .long("skip-if-log-exists")
                .help("Skips building documentation if build log exists"))
            .arg(Arg::with_name("KEEP_BUILD_DIRECTORY")
                .short("-k")
                .long("keep-build-directory")
                .help("Keeps build directory after build."))
            .subcommand(SubCommand::with_name("world")
                .about("Builds documentation of every crate"))
            .subcommand(SubCommand::with_name("crate")
                .about("Builds documentation for a crate")
                .arg(Arg::with_name("CRATE_NAME")
                    .index(1)
                    .required_unless("LOCAL")
                    .requires("CRATE_VERSION")
                    .help("Crate name"))
                .arg(Arg::with_name("CRATE_VERSION")
                    .index(2)
                    .help("Version of crate"))
                .arg(Arg::with_name("LOCAL")
                    .short("-l")
                    .long("--local")
                    .takes_value(true)
                    .conflicts_with_all(&["CRATE_NAME", "CRATE_VERSION"])
                    .help("Build a crate at a specific path")))
            .subcommand(SubCommand::with_name("update-toolchain")
                .about("update the curretntly installed rustup toolchain")
                .arg(Arg::with_name("ONLY_FIRST_TIME")
                     .long("only-first-time")
                     .help("update toolchain only if no toolchain is currently installed")))
            .subcommand(SubCommand::with_name("add-essential-files")
                .about("Adds essential files for the installed version of rustc"))
            .subcommand(SubCommand::with_name("lock")
                .about("Locks cratesfyi daemon to stop building new crates"))
            .subcommand(SubCommand::with_name("unlock")
                .about("Unlocks cratesfyi daemon to continue building new crates"))
            .subcommand(SubCommand::with_name("print-options")))
        .subcommand(SubCommand::with_name("start-web-server")
            .about("Starts web server")
            .arg(Arg::with_name("SOCKET_ADDR")
                .index(1)
                .required(false)
                .help("Socket address to listen to")))
        .subcommand(SubCommand::with_name("daemon")
            .about("Starts cratesfyi daemon")
            .arg(Arg::with_name("FOREGROUND")
                .short("-f")
                .long("foreground")
                .help("run the server in the foreground instead of detaching a child")))
        .subcommand(SubCommand::with_name("database")
            .about("Database operations")
            .setting(AppSettings::ArgRequiredElseHelp)
            .subcommand(SubCommand::with_name("move-to-s3"))
            .subcommand(SubCommand::with_name("migrate")
                .about("Run database migrations")
                .arg(Arg::with_name("VERSION")))
            .subcommand(SubCommand::with_name("update-github-fields")
                .about("Updates github stats for crates."))
            .subcommand(SubCommand::with_name("add-directory")
                .about("Adds a directory into database")
                .arg(Arg::with_name("DIRECTORY")
                    .index(1)
                    .required(true)
                    .help("Path of file or directory"))
                .arg(Arg::with_name("PREFIX")
                    .index(2)
                    .help("Prefix of files in database")))
            .subcommand(SubCommand::with_name("update-release-activity")
                .about("Updates monthly release activity chart"))
            .subcommand(SubCommand::with_name("update-search-index")
                .about("Updates search index"))
            .subcommand(SubCommand::with_name("delete-crate")
                .about("Removes a whole crate from the database")
                .arg(Arg::with_name("CRATE_NAME")
                    .takes_value(true)
                    .help("Name of the crate to delete"))))
        .subcommand(SubCommand::with_name("queue")
            .about("Interactions with the build queue")
            .setting(AppSettings::ArgRequiredElseHelp)
            .subcommand(SubCommand::with_name("add")
                .about("Add a crate to the build queue")
                .arg(Arg::with_name("CRATE_NAME")
                    .index(1)
                    .required(true)
                    .help("Name of crate to build"))
                .arg(Arg::with_name("CRATE_VERSION")
                    .index(2)
                    .required(true)
                    .help("Version of crate to build"))
                .arg(Arg::with_name("BUILD_PRIORITY")
                    .short("p")
                    .long("priority")
                    .help("Priority of build (default: 5) (new crate builds get priority 0)")
                    .takes_value(true))))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("build") {
        let docbuilder_opts = {
            let mut docbuilder_opts = if let Some(prefix) = matches.value_of("PREFIX") {
                DocBuilderOptions::from_prefix(PathBuf::from(prefix))
            } else if let Ok(prefix) = env::var("CRATESFYI_PREFIX") {
                DocBuilderOptions::from_prefix(PathBuf::from(prefix))
            } else {
                DocBuilderOptions::default()
            };

            if let Some(crates_io_index_path) = matches.value_of("CRATES_IO_INDEX_PATH") {
                docbuilder_opts.crates_io_index_path = PathBuf::from(crates_io_index_path);
            }

            docbuilder_opts.skip_if_exists = matches.is_present("SKIP_IF_EXISTS");
            docbuilder_opts.skip_if_log_exists = matches.is_present("SKIP_IF_LOG_EXISTS");
            docbuilder_opts.keep_build_directory = matches.is_present("KEEP_BUILD_DIRECTORY");

            docbuilder_opts.check_paths().unwrap();

            docbuilder_opts
        };

        let mut docbuilder = DocBuilder::new(docbuilder_opts);

        if let Some(_) = matches.subcommand_matches("world") {
            docbuilder.load_cache().expect("Failed to load cache");
            let mut builder = RustwideBuilder::init().unwrap();
            builder.build_world(&mut docbuilder).expect("Failed to build world");
            docbuilder.save_cache().expect("Failed to save cache");
        } else if let Some(matches) = matches.subcommand_matches("crate") {
            docbuilder.load_cache().expect("Failed to load cache");
            let mut builder = RustwideBuilder::init().expect("failed to initialize rustwide");
            match matches.value_of("LOCAL") {
                Some(path) => builder.build_local_package(&mut docbuilder, Path::new(path)),
                None => builder.build_package(&mut docbuilder,
                    matches.value_of("CRATE_NAME").unwrap(), matches.value_of("CRATE_VERSION").unwrap(), None),
            }.expect("Building documentation failed");
            docbuilder.save_cache().expect("Failed to save cache");
        } else if let Some(m) = matches.subcommand_matches("update-toolchain") {
            if m.is_present("ONLY_FIRST_TIME") {
                let conn = db::connect_db().unwrap();
                let res = conn.query("SELECT * FROM config WHERE name = 'rustc_version';", &[]).unwrap();
                if !res.is_empty() {
                    println!("update-toolchain was already called in the past, exiting");
                    return;
                }
            }
            let mut builder = RustwideBuilder::init().unwrap();
            builder.update_toolchain().expect("failed to update toolchain");
        } else if matches.subcommand_matches("add-essential-files").is_some() {
            let mut builder = RustwideBuilder::init().unwrap();
            builder.add_essential_files().expect("failed to add essential files");
        } else if let Some(_) = matches.subcommand_matches("lock") {
            docbuilder.lock().expect("Failed to lock");
        } else if let Some(_) = matches.subcommand_matches("unlock") {
            docbuilder.unlock().expect("Failed to unlock");
        } else if let Some(_) = matches.subcommand_matches("print-options") {
            println!("{:?}", docbuilder.options());
        }

    } else if let Some(matches) = matches.subcommand_matches("database") {
        if let Some(matches) = matches.subcommand_matches("migrate") {
            let version = matches.value_of("VERSION").map(|v| v.parse::<i64>()
                                                          .expect("Version should be an integer"));
            db::migrate(version, &connect_db().expect("failed to connect to the database"))
                .expect("Failed to run database migrations");
        } else if let Some(_) = matches.subcommand_matches("update-github-fields") {
            cratesfyi::utils::github_updater().expect("Failed to update github fields");
        } else if let Some(matches) = matches.subcommand_matches("add-directory") {
            add_path_into_database(&db::connect_db().unwrap(),
                                   matches.value_of("PREFIX").unwrap_or(""),
                                   matches.value_of("DIRECTORY").unwrap())
                .expect("Failed to add directory into database");
        } else if let Some(_) = matches.subcommand_matches("update-release-activity") {
            // FIXME: This is actually util command not database
            cratesfyi::utils::update_release_activity().expect("Failed to update release activity");
        } else if let Some(_) = matches.subcommand_matches("update-search-index") {
            let conn = db::connect_db().unwrap();
            db::update_search_index(&conn).expect("Failed to update search index");
        } else if let Some(_) = matches.subcommand_matches("move-to-s3") {
            let conn = db::connect_db().unwrap();
            let mut count = 1;
            let mut total = 0;
            while count != 0 {
                count = db::file::move_to_s3(&conn, 5_000).expect("Failed to upload batch to S3");
                total += count;
                eprintln!(
                    "moved {} rows to s3 in this batch, total moved so far: {}",
                    count, total
                );
            }
        } else if let Some(matches) = matches.subcommand_matches("delete-crate") {
            let name = matches.value_of("CRATE_NAME").expect("missing crate name");
            let conn = db::connect_db().expect("failed to connect to the database");
            db::delete_crate(&conn, &name).expect("failed to delete the crate");
        }

    } else if let Some(matches) = matches.subcommand_matches("start-web-server") {
        start_web_server(Some(matches.value_of("SOCKET_ADDR").unwrap_or("0.0.0.0:3000")));

    } else if let Some(_) = matches.subcommand_matches("daemon") {
        let foreground = matches.subcommand_matches("daemon")
            .map_or(false, |opts| opts.is_present("FOREGROUND"));
        cratesfyi::utils::start_daemon(!foreground);

    } else if let Some(matches) = matches.subcommand_matches("queue") {
        if let Some(matches) = matches.subcommand_matches("add") {
            let priority = matches.value_of("BUILD_PRIORITY").unwrap_or("5");
            let priority: i32 = priority.parse().expect("--priority was not a number");
            let conn = connect_db().expect("Could not connect to database");

            add_crate_to_queue(&conn,
                               matches.value_of("CRATE_NAME").unwrap(),
                               matches.value_of("CRATE_VERSION").unwrap(),
                               priority).expect("Could not add crate to queue");
        }
    }
}

fn logger_init() {
    use std::io::Write;

    let mut builder = env_logger::Builder::new();
    builder.format(|buf, record| {
        writeln!(buf, "{} [{}] {}: {}",
                time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(),
                record.level(),
                record.target(),
                record.args())
    });
    builder.parse(&env::var("RUST_LOG").unwrap_or("cratesfyi=info".to_owned()));

    rustwide::logging::init_with(builder.build());
}
<commit_msg>Make parameter of 'cratesfyi database delete-crate' required<commit_after>

extern crate cratesfyi;
extern crate clap;
extern crate log;
extern crate env_logger;
extern crate time;
extern crate rustwide;

use std::env;
use std::path::{Path, PathBuf};

use clap::{Arg, App, AppSettings, SubCommand};
use cratesfyi::{DocBuilder, RustwideBuilder, DocBuilderOptions, db};
use cratesfyi::utils::add_crate_to_queue;
use cratesfyi::start_web_server;
use cratesfyi::db::{add_path_into_database, connect_db};

pub fn main() {
    logger_init();

    let matches = App::new("cratesfyi")
        .version(cratesfyi::BUILD_VERSION)
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(SubCommand::with_name("build")
            .about("Builds documentation in a chroot environment")
            .setting(AppSettings::ArgRequiredElseHelp)
            .arg(Arg::with_name("PREFIX")
                .short("P")
                .long("prefix")
                .takes_value(true))
            .arg(Arg::with_name("CRATES_IO_INDEX_PATH")
                .long("crates-io-index-path")
                .help("Sets crates.io-index path")
                .takes_value(true))
            .arg(Arg::with_name("SKIP_IF_EXISTS")
                .short("s")
                .long("skip")
                .help("Skips building documentation if documentation exists"))
            .arg(Arg::with_name("SKIP_IF_LOG_EXISTS")
                .long("skip-if-log-exists")
                .help("Skips building documentation if build log exists"))
            .arg(Arg::with_name("KEEP_BUILD_DIRECTORY")
                .short("-k")
                .long("keep-build-directory")
                .help("Keeps build directory after build."))
            .subcommand(SubCommand::with_name("world")
                .about("Builds documentation of every crate"))
            .subcommand(SubCommand::with_name("crate")
                .about("Builds documentation for a crate")
                .arg(Arg::with_name("CRATE_NAME")
                    .index(1)
                    .required_unless("LOCAL")
                    .requires("CRATE_VERSION")
                    .help("Crate name"))
                .arg(Arg::with_name("CRATE_VERSION")
                    .index(2)
                    .help("Version of crate"))
                .arg(Arg::with_name("LOCAL")
                    .short("-l")
                    .long("--local")
                    .takes_value(true)
                    .conflicts_with_all(&["CRATE_NAME", "CRATE_VERSION"])
                    .help("Build a crate at a specific path")))
            .subcommand(SubCommand::with_name("update-toolchain")
                .about("update the curretntly installed rustup toolchain")
                .arg(Arg::with_name("ONLY_FIRST_TIME")
                     .long("only-first-time")
                     .help("update toolchain only if no toolchain is currently installed")))
            .subcommand(SubCommand::with_name("add-essential-files")
                .about("Adds essential files for the installed version of rustc"))
            .subcommand(SubCommand::with_name("lock")
                .about("Locks cratesfyi daemon to stop building new crates"))
            .subcommand(SubCommand::with_name("unlock")
                .about("Unlocks cratesfyi daemon to continue building new crates"))
            .subcommand(SubCommand::with_name("print-options")))
        .subcommand(SubCommand::with_name("start-web-server")
            .about("Starts web server")
            .arg(Arg::with_name("SOCKET_ADDR")
                .index(1)
                .required(false)
                .help("Socket address to listen to")))
        .subcommand(SubCommand::with_name("daemon")
            .about("Starts cratesfyi daemon")
            .arg(Arg::with_name("FOREGROUND")
                .short("-f")
                .long("foreground")
                .help("run the server in the foreground instead of detaching a child")))
        .subcommand(SubCommand::with_name("database")
            .about("Database operations")
            .setting(AppSettings::ArgRequiredElseHelp)
            .subcommand(SubCommand::with_name("move-to-s3"))
            .subcommand(SubCommand::with_name("migrate")
                .about("Run database migrations")
                .arg(Arg::with_name("VERSION")))
            .subcommand(SubCommand::with_name("update-github-fields")
                .about("Updates github stats for crates."))
            .subcommand(SubCommand::with_name("add-directory")
                .about("Adds a directory into database")
                .arg(Arg::with_name("DIRECTORY")
                    .index(1)
                    .required(true)
                    .help("Path of file or directory"))
                .arg(Arg::with_name("PREFIX")
                    .index(2)
                    .help("Prefix of files in database")))
            .subcommand(SubCommand::with_name("update-release-activity")
                .about("Updates monthly release activity chart"))
            .subcommand(SubCommand::with_name("update-search-index")
                .about("Updates search index"))
            .subcommand(SubCommand::with_name("delete-crate")
                .about("Removes a whole crate from the database")
                .arg(Arg::with_name("CRATE_NAME")
                    .takes_value(true)
                    .required(true)
                    .help("Name of the crate to delete"))))
        .subcommand(SubCommand::with_name("queue")
            .about("Interactions with the build queue")
            .setting(AppSettings::ArgRequiredElseHelp)
            .subcommand(SubCommand::with_name("add")
                .about("Add a crate to the build queue")
                .arg(Arg::with_name("CRATE_NAME")
                    .index(1)
                    .required(true)
                    .help("Name of crate to build"))
                .arg(Arg::with_name("CRATE_VERSION")
                    .index(2)
                    .required(true)
                    .help("Version of crate to build"))
                .arg(Arg::with_name("BUILD_PRIORITY")
                    .short("p")
                    .long("priority")
                    .help("Priority of build (default: 5) (new crate builds get priority 0)")
                    .takes_value(true))))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("build") {
        let docbuilder_opts = {
            let mut docbuilder_opts = if let Some(prefix) = matches.value_of("PREFIX") {
                DocBuilderOptions::from_prefix(PathBuf::from(prefix))
            } else if let Ok(prefix) = env::var("CRATESFYI_PREFIX") {
                DocBuilderOptions::from_prefix(PathBuf::from(prefix))
            } else {
                DocBuilderOptions::default()
            };

            if let Some(crates_io_index_path) = matches.value_of("CRATES_IO_INDEX_PATH") {
                docbuilder_opts.crates_io_index_path = PathBuf::from(crates_io_index_path);
            }

            docbuilder_opts.skip_if_exists = matches.is_present("SKIP_IF_EXISTS");
            docbuilder_opts.skip_if_log_exists = matches.is_present("SKIP_IF_LOG_EXISTS");
            docbuilder_opts.keep_build_directory = matches.is_present("KEEP_BUILD_DIRECTORY");

            docbuilder_opts.check_paths().unwrap();

            docbuilder_opts
        };

        let mut docbuilder = DocBuilder::new(docbuilder_opts);

        if let Some(_) = matches.subcommand_matches("world") {
            docbuilder.load_cache().expect("Failed to load cache");
            let mut builder = RustwideBuilder::init().unwrap();
            builder.build_world(&mut docbuilder).expect("Failed to build world");
            docbuilder.save_cache().expect("Failed to save cache");
        } else if let Some(matches) = matches.subcommand_matches("crate") {
            docbuilder.load_cache().expect("Failed to load cache");
            let mut builder = RustwideBuilder::init().expect("failed to initialize rustwide");
            match matches.value_of("LOCAL") {
                Some(path) => builder.build_local_package(&mut docbuilder, Path::new(path)),
                None => builder.build_package(&mut docbuilder,
                    matches.value_of("CRATE_NAME").unwrap(), matches.value_of("CRATE_VERSION").unwrap(), None),
            }.expect("Building documentation failed");
            docbuilder.save_cache().expect("Failed to save cache");
        } else if let Some(m) = matches.subcommand_matches("update-toolchain") {
            if m.is_present("ONLY_FIRST_TIME") {
                let conn = db::connect_db().unwrap();
                let res = conn.query("SELECT * FROM config WHERE name = 'rustc_version';", &[]).unwrap();
                if !res.is_empty() {
                    println!("update-toolchain was already called in the past, exiting");
                    return;
                }
            }
            let mut builder = RustwideBuilder::init().unwrap();
            builder.update_toolchain().expect("failed to update toolchain");
        } else if matches.subcommand_matches("add-essential-files").is_some() {
            let mut builder = RustwideBuilder::init().unwrap();
            builder.add_essential_files().expect("failed to add essential files");
        } else if let Some(_) = matches.subcommand_matches("lock") {
            docbuilder.lock().expect("Failed to lock");
        } else if let Some(_) = matches.subcommand_matches("unlock") {
            docbuilder.unlock().expect("Failed to unlock");
        } else if let Some(_) = matches.subcommand_matches("print-options") {
            println!("{:?}", docbuilder.options());
        }

    } else if let Some(matches) = matches.subcommand_matches("database") {
        if let Some(matches) = matches.subcommand_matches("migrate") {
            let version = matches.value_of("VERSION").map(|v| v.parse::<i64>()
                                                          .expect("Version should be an integer"));
            db::migrate(version, &connect_db().expect("failed to connect to the database"))
                .expect("Failed to run database migrations");
        } else if let Some(_) = matches.subcommand_matches("update-github-fields") {
            cratesfyi::utils::github_updater().expect("Failed to update github fields");
        } else if let Some(matches) = matches.subcommand_matches("add-directory") {
            add_path_into_database(&db::connect_db().unwrap(),
                                   matches.value_of("PREFIX").unwrap_or(""),
                                   matches.value_of("DIRECTORY").unwrap())
                .expect("Failed to add directory into database");
        } else if let Some(_) = matches.subcommand_matches("update-release-activity") {
            // FIXME: This is actually util command not database
            cratesfyi::utils::update_release_activity().expect("Failed to update release activity");
        } else if let Some(_) = matches.subcommand_matches("update-search-index") {
            let conn = db::connect_db().unwrap();
            db::update_search_index(&conn).expect("Failed to update search index");
        } else if let Some(_) = matches.subcommand_matches("move-to-s3") {
            let conn = db::connect_db().unwrap();
            let mut count = 1;
            let mut total = 0;
            while count != 0 {
                count = db::file::move_to_s3(&conn, 5_000).expect("Failed to upload batch to S3");
                total += count;
                eprintln!(
                    "moved {} rows to s3 in this batch, total moved so far: {}",
                    count, total
                );
            }
        } else if let Some(matches) = matches.subcommand_matches("delete-crate") {
            let name = matches.value_of("CRATE_NAME").expect("missing crate name");
            let conn = db::connect_db().expect("failed to connect to the database");
            db::delete_crate(&conn, &name).expect("failed to delete the crate");
        }

    } else if let Some(matches) = matches.subcommand_matches("start-web-server") {
        start_web_server(Some(matches.value_of("SOCKET_ADDR").unwrap_or("0.0.0.0:3000")));

    } else if let Some(_) = matches.subcommand_matches("daemon") {
        let foreground = matches.subcommand_matches("daemon")
            .map_or(false, |opts| opts.is_present("FOREGROUND"));
        cratesfyi::utils::start_daemon(!foreground);

    } else if let Some(matches) = matches.subcommand_matches("queue") {
        if let Some(matches) = matches.subcommand_matches("add") {
            let priority = matches.value_of("BUILD_PRIORITY").unwrap_or("5");
            let priority: i32 = priority.parse().expect("--priority was not a number");
            let conn = connect_db().expect("Could not connect to database");

            add_crate_to_queue(&conn,
                               matches.value_of("CRATE_NAME").unwrap(),
                               matches.value_of("CRATE_VERSION").unwrap(),
                               priority).expect("Could not add crate to queue");
        }
    }
}

fn logger_init() {
    use std::io::Write;

    let mut builder = env_logger::Builder::new();
    builder.format(|buf, record| {
        writeln!(buf, "{} [{}] {}: {}",
                time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(),
                record.level(),
                record.target(),
                record.args())
    });
    builder.parse(&env::var("RUST_LOG").unwrap_or("cratesfyi=info".to_owned()));

    rustwide::logging::init_with(builder.build());
}
<|endoftext|>