<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// We don't use `clap` to reduce executable size.

use std::process;
use std::path;

use gumdrop::Options as CliOptions;

use resvg::{
    usvg,
    FitTo,
    Options,
};

pub fn print_help() {
    print!("\
rendersvg is an SVG rendering application.

USAGE:
    rendersvg [OPTIONS] <in-svg> <out-png>

    rendersvg in.svg out.png
    rendersvg -z 4 in.svg out.png
    rendersvg --query-all in.svg

OPTIONS:
        --help                  Prints help information
    -V, --version               Prints version information

        --perf                  Prints performance stats
        --pretend               Does all the steps except rendering
        --quiet                 Disables warnings
        --dump-svg=<PATH>       Saves the preprocessed SVG to the selected file

        --query-all             Queries all valid SVG ids with bounding boxes
        --export-id=<ID>        Renders an object only with a specified ID

        --backend=<BACKEND>     Sets the rendering backend.
                                Has no effect if built with only one backend
                                [default: {}] [possible values: {}]

        --background=<COLOR>    Sets the background color.
                                Examples: red, #fff, #fff000
        --dpi=<DPI>             Sets the resolution
                                [default: 96] [possible values: 10..4000]
    -w, --width=<LENGTH>        Sets the width in pixels
    -h, --height=<LENGTH>       Sets the height in pixels
    -z, --zoom=<FACTOR>         Zooms the image by a factor

ARGS:
    <in-svg>                    Input file
    <out-png>                   Output file
", default_backend(),
   backends().join(", "));
}

#[derive(Debug, CliOptions)]
struct CliArgs {
    #[options(no_short)]
    help: bool,

    #[options(short = "V")]
    version: bool,

    #[options(no_short)]
    perf: bool,

    #[options(no_short)]
    pretend: bool,

    #[options(no_short)]
    quiet: bool,

    #[options(no_short, meta = "PATH")]
    dump_svg: Option<String>,

    #[options(no_short)]
    query_all: bool,

    #[options(no_short, meta = "ID")]
    export_id: Option<String>,

    #[options(no_short, meta = "BACKEND")]
    backend: Option<String>,

    #[options(no_short, meta = "COLOR", parse(try_from_str = "parse_color"))]
    background: Option<usvg::Color>,

    #[options(no_short, meta = "DPI", default = "96", parse(try_from_str = "parse_dpi"))]
    dpi: u32,

    #[options(short = "w", meta = "LENGTH", parse(try_from_str = "parse_length"))]
    width: Option<u32>,

    #[options(short = "h", meta = "LENGTH", parse(try_from_str = "parse_length"))]
    height: Option<u32>,

    #[options(short = "z", meta = "ZOOM", parse(try_from_str = "parse_zoom"))]
    zoom: Option<f32>,

    #[options(free)]
    free: Vec<String>,
}

fn parse_color(s: &str) -> Result<usvg::Color, &'static str> {
    s.parse().map_err(|_| "invalid zoom factor")
}

fn parse_dpi(s: &str) -> Result<u32, &'static str> {
    let n: u32 = s.parse().map_err(|_| "invalid number")?;

    if n >= 10 && n <= 4000 {
        Ok(n)
    } else {
        Err("DPI out of bounds")
    }
}

fn parse_length(s: &str) -> Result<u32, &'static str> {
    let n: u32 = s.parse().map_err(|_| "invalid length")?;

    if n > 0 {
        Ok(n)
    } else {
        Err("LENGTH cannot be zero")
    }
}

fn parse_zoom(s: &str) -> Result<f32, &'static str> {
    let n: f32 = s.parse().map_err(|_| "invalid zoom factor")?;

    if !(n > 0.0) {
        Ok(n)
    } else {
        Err("ZOOM should be positive")
    }
}

pub struct Args {
    pub in_svg: path::PathBuf,
    pub out_png: Option<path::PathBuf>,
    pub backend_name: String,
    pub query_all: bool,
    pub export_id: Option<String>,
    pub dump: Option<path::PathBuf>,
    pub pretend: bool,
    pub perf: bool,
    pub quiet: bool,
}

pub fn parse() -> Result<(Args, Options), String> {
    let args: Vec<String> = ::std::env::args().collect();
    let args = match CliArgs::parse_args_default(&args[1..]) {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if args.help {
        print_help();
        process::exit(0);
    }

    if args.version {
        println!("{}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    let positional_count = if args.query_all { 1 } else { 2 };

    if args.free.len() != positional_count {
        return Err(format!("<in-svg> and <out-png> must be set"));
    }

    let in_svg: path::PathBuf = args.free[0].to_string().into();

    let out_png = if !args.query_all {
        Some(args.free[1].to_string().into())
    } else {
        None
    };

    let backend_name = args.backend.unwrap_or(default_backend().to_string());
    let dump = args.dump_svg.map(|v| v.into());
    let export_id = args.export_id.map(|v| v.to_string());

    let app_args = Args {
        in_svg: in_svg.clone(),
        out_png,
        backend_name,
        query_all: args.query_all,
        export_id,
        dump,
        pretend: args.pretend,
        perf: args.perf,
        quiet: args.quiet,
    };

    // We don't have to keep named groups when we don't need them
    // because it will slow down rendering.
    let keep_named_groups = app_args.query_all || app_args.export_id.is_some();

    let mut fit_to = FitTo::Original;
    if let Some(w) = args.width {
        fit_to = FitTo::Width(w);
    } else if let Some(h) = args.height {
        fit_to = FitTo::Height(h);
    } else if let Some(z) = args.zoom {
        fit_to = FitTo::Zoom(z);
    }

    let opt = Options {
        usvg: usvg::Options {
            path: Some(in_svg.into()),
            dpi: args.dpi as f64,
            font_family: "Times New Roman".to_string(),
            font_size: 12.0,
            keep_named_groups,
        },
        fit_to,
        background: args.background,
    };

    Ok((app_args, opt))
}

#[allow(unreachable_code)]
fn default_backend() -> &'static str {
    #[cfg(feature = "cairo-backend")]
    { return "cairo" }

    #[cfg(feature = "qt-backend")]
    { return "qt" }

    unreachable!();
}

fn backends() -> Vec<&'static str> {
    let mut list = Vec::new();

    #[cfg(feature = "cairo-backend")]
    { list.push("cairo"); }

    #[cfg(feature = "qt-backend")]
    { list.push("qt"); }

    list
}
<commit_msg>Build fixed.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// We don't use `clap` to reduce executable size.

use std::process;
use std::path;

use gumdrop::Options as CliOptions;

use resvg::{
    usvg,
    FitTo,
    Options,
};

pub fn print_help() {
    print!("\
rendersvg is an SVG rendering application.

USAGE:
    rendersvg [OPTIONS] <in-svg> <out-png>

    rendersvg in.svg out.png
    rendersvg -z 4 in.svg out.png
    rendersvg --query-all in.svg

OPTIONS:
        --help                  Prints help information
    -V, --version               Prints version information

        --perf                  Prints performance stats
        --pretend               Does all the steps except rendering
        --quiet                 Disables warnings
        --dump-svg=<PATH>       Saves the preprocessed SVG to the selected file

        --query-all             Queries all valid SVG ids with bounding boxes
        --export-id=<ID>        Renders an object only with a specified ID

        --backend=<BACKEND>     Sets the rendering backend.
                                Has no effect if built with only one backend
                                [default: {}] [possible values: {}]

        --background=<COLOR>    Sets the background color.
                                Examples: red, #fff, #fff000
        --dpi=<DPI>             Sets the resolution
                                [default: 96] [possible values: 10..4000]
    -w, --width=<LENGTH>        Sets the width in pixels
    -h, --height=<LENGTH>       Sets the height in pixels
    -z, --zoom=<FACTOR>         Zooms the image by a factor

ARGS:
    <in-svg>                    Input file
    <out-png>                   Output file
", default_backend(),
   backends().join(", "));
}

#[derive(Debug, CliOptions)]
struct CliArgs {
    #[options(no_short)]
    help: bool,

    #[options(short = "V")]
    version: bool,

    #[options(no_short)]
    perf: bool,

    #[options(no_short)]
    pretend: bool,

    #[options(no_short)]
    quiet: bool,

    #[options(no_short, meta = "PATH")]
    dump_svg: Option<String>,

    #[options(no_short)]
    query_all: bool,

    #[options(no_short, meta = "ID")]
    export_id: Option<String>,

    #[options(no_short, meta = "BACKEND")]
    backend: Option<String>,

    #[options(no_short, meta = "COLOR", parse(try_from_str = "parse_color"))]
    background: Option<usvg::Color>,

    #[options(no_short, meta = "DPI", default = "96", parse(try_from_str = "parse_dpi"))]
    dpi: u32,

    #[options(short = "w", meta = "LENGTH", parse(try_from_str = "parse_length"))]
    width: Option<u32>,

    #[options(short = "h", meta = "LENGTH", parse(try_from_str = "parse_length"))]
    height: Option<u32>,

    #[options(short = "z", meta = "ZOOM", parse(try_from_str = "parse_zoom"))]
    zoom: Option<f32>,

    #[options(free)]
    free: Vec<String>,
}

fn parse_color(s: &str) -> Result<usvg::Color, &'static str> {
    s.parse().map_err(|_| "invalid zoom factor")
}

fn parse_dpi(s: &str) -> Result<u32, &'static str> {
    let n: u32 = s.parse().map_err(|_| "invalid number")?;

    if n >= 10 && n <= 4000 {
        Ok(n)
    } else {
        Err("DPI out of bounds")
    }
}

fn parse_length(s: &str) -> Result<u32, &'static str> {
    let n: u32 = s.parse().map_err(|_| "invalid length")?;

    if n > 0 {
        Ok(n)
    } else {
        Err("LENGTH cannot be zero")
    }
}

fn parse_zoom(s: &str) -> Result<f32, &'static str> {
    let n: f32 = s.parse().map_err(|_| "invalid zoom factor")?;

    if n > 0.0 {
        Ok(n)
    } else {
        Err("ZOOM should be positive")
    }
}

pub struct Args {
    pub in_svg: path::PathBuf,
    pub out_png: Option<path::PathBuf>,
    pub backend_name: String,
    pub query_all: bool,
    pub export_id: Option<String>,
    pub dump: Option<path::PathBuf>,
    pub pretend: bool,
    pub perf: bool,
    pub quiet: bool,
}

pub fn parse() -> Result<(Args, Options), String> {
    let args: Vec<String> = ::std::env::args().collect();
    let args = match CliArgs::parse_args_default(&args[1..]) {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if args.help {
        print_help();
        process::exit(0);
    }

    if args.version {
        println!("{}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    let positional_count = if args.query_all { 1 } else { 2 };

    if args.free.len() != positional_count {
        return Err(format!("<in-svg> and <out-png> must be set"));
    }

    let in_svg: path::PathBuf = args.free[0].to_string().into();

    let out_png = if !args.query_all {
        Some(args.free[1].to_string().into())
    } else {
        None
    };

    let backend_name = args.backend.unwrap_or(default_backend().to_string());
    let dump = args.dump_svg.map(|v| v.into());
    let export_id = args.export_id.map(|v| v.to_string());

    let app_args = Args {
        in_svg: in_svg.clone(),
        out_png,
        backend_name,
        query_all: args.query_all,
        export_id,
        dump,
        pretend: args.pretend,
        perf: args.perf,
        quiet: args.quiet,
    };

    // We don't have to keep named groups when we don't need them
    // because it will slow down rendering.
    let keep_named_groups = app_args.query_all || app_args.export_id.is_some();

    let mut fit_to = FitTo::Original;
    if let Some(w) = args.width {
        fit_to = FitTo::Width(w);
    } else if let Some(h) = args.height {
        fit_to = FitTo::Height(h);
    } else if let Some(z) = args.zoom {
        fit_to = FitTo::Zoom(z);
    }

    let opt = Options {
        usvg: usvg::Options {
            path: Some(in_svg.into()),
            dpi: args.dpi as f64,
            font_family: "Times New Roman".to_string(),
            font_size: 12.0,
            keep_named_groups,
        },
        fit_to,
        background: args.background,
    };

    Ok((app_args, opt))
}

#[allow(unreachable_code)]
fn default_backend() -> &'static str {
    #[cfg(feature = "cairo-backend")]
    { return "cairo" }

    #[cfg(feature = "qt-backend")]
    { return "qt" }

    unreachable!();
}

fn backends() -> Vec<&'static str> {
    let mut list = Vec::new();

    #[cfg(feature = "cairo-backend")]
    { list.push("cairo"); }

    #[cfg(feature = "qt-backend")]
    { list.push("qt"); }

    list
}
<|endoftext|>


<commit_before>//! Implementation of event enum and event content enum macros.

use std::fmt;

use proc_macro2::Span;
use quote::format_ident;
use syn::{
    bracketed,
    parse::{self, Parse, ParseStream},
    Attribute, Ident, LitStr, Token,
};

/// Custom keywords for the `event_enum!` macro
mod kw {
    syn::custom_keyword!(kind);
    syn::custom_keyword!(events);
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum EventKindVariation {
    Full,
    Sync,
    Stripped,
    Initial,
    Redacted,
    RedactedSync,
    RedactedStripped,
}

impl fmt::Display for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKindVariation::Full => write!(f, ""),
            EventKindVariation::Sync => write!(f, "Sync"),
            EventKindVariation::Stripped => write!(f, "Stripped"),
            EventKindVariation::Initial => write!(f, "Initial"),
            EventKindVariation::Redacted => write!(f, "Redacted"),
            EventKindVariation::RedactedSync => write!(f, "RedactedSync"),
            EventKindVariation::RedactedStripped => write!(f, "RedactedStripped"),
        }
    }
}

impl EventKindVariation {
    pub fn is_redacted(&self) -> bool {
        matches!(self, Self::Redacted | Self::RedactedSync | Self::RedactedStripped)
    }

    pub fn to_full_variation(&self) -> Self {
        match self {
            EventKindVariation::Redacted
            | EventKindVariation::RedactedSync
            | EventKindVariation::RedactedStripped => EventKindVariation::Redacted,
            EventKindVariation::Full
            | EventKindVariation::Sync
            | EventKindVariation::Stripped
            | EventKindVariation::Initial => EventKindVariation::Full,
        }
    }
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Debug, Eq, PartialEq)]
pub enum EventKind {
    Basic,
    Ephemeral,
    Message,
    State,
    ToDevice,
    Redaction,
    Presence,
}

impl fmt::Display for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKind::Basic => write!(f, "BasicEvent"),
            EventKind::Ephemeral => write!(f, "EphemeralRoomEvent"),
            EventKind::Message => write!(f, "MessageEvent"),
            EventKind::State => write!(f, "StateEvent"),
            EventKind::ToDevice => write!(f, "ToDeviceEvent"),
            EventKind::Redaction => write!(f, "RedactionEvent"),
            EventKind::Presence => write!(f, "PresenceEvent"),
        }
    }
}

impl EventKind {
    pub fn is_state(&self) -> bool {
        matches!(self, Self::State)
    }

    pub fn is_message(&self) -> bool {
        matches!(self, Self::Message)
    }

    pub fn to_event_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        use EventKindVariation as V;

        // this match is only used to validate the input
        match (self, var) {
            (_, V::Full)
            | (Self::Ephemeral, V::Sync)
            | (Self::Message, V::Sync)
            | (Self::State, V::Sync)
            | (Self::State, V::Stripped)
            | (Self::State, V::Initial)
            | (Self::Message, V::Redacted)
            | (Self::State, V::Redacted)
            | (Self::Message, V::RedactedSync)
            | (Self::State, V::RedactedSync)
            | (Self::State, V::RedactedStripped) => {
                Some(Ident::new(&format!("{}{}", var, self), Span::call_site()))
            }
            _ => None,
        }
    }

    pub fn to_event_enum_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        Some(format_ident!("Any{}", self.to_event_ident(var)?))
    }

    /// `Any[kind]EventContent`
    pub fn to_content_enum(&self) -> Ident {
        Ident::new(&format!("Any{}Content", self), Span::call_site())
    }
}

impl Parse for EventKind {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let ident: Ident = input.parse()?;
        Ok(match ident.to_string().as_str() {
            "Basic" => EventKind::Basic,
            "EphemeralRoom" => EventKind::Ephemeral,
            "Message" => EventKind::Message,
            "State" => EventKind::State,
            "ToDevice" => EventKind::ToDevice,
            id => {
                return Err(syn::Error::new(
                    input.span(),
                    format!(
                        "valid event kinds are Basic, EphemeralRoom, Message, State, ToDevice \
                         found `{}`",
                        id
                    ),
                ));
            }
        })
    }
}

// This function is only used in the `Event` derive macro expansion code.
/// Validates the given `ident` is a valid event struct name and returns a tuple of enums
/// representing the name.
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
    let ident_str = ident.to_string();
    match ident_str.as_str() {
        "BasicEvent" => Some((EventKind::Basic, EventKindVariation::Full)),
        "EphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Full)),
        "SyncEphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Sync)),
        "MessageEvent" => Some((EventKind::Message, EventKindVariation::Full)),
        "SyncMessageEvent" => Some((EventKind::Message, EventKindVariation::Sync)),
        "RedactedMessageEvent" => Some((EventKind::Message, EventKindVariation::Redacted)),
        "RedactedSyncMessageEvent" => Some((EventKind::Message, EventKindVariation::RedactedSync)),
        "StateEvent" => Some((EventKind::State, EventKindVariation::Full)),
        "SyncStateEvent" => Some((EventKind::State, EventKindVariation::Sync)),
        "StrippedStateEvent" => Some((EventKind::State, EventKindVariation::Stripped)),
        "InitialStateEvent" => Some((EventKind::State, EventKindVariation::Initial)),
        "RedactedStateEvent" => Some((EventKind::State, EventKindVariation::Redacted)),
        "RedactedSyncStateEvent" => Some((EventKind::State, EventKindVariation::RedactedSync)),
        "RedactedStrippedStateEvent" => {
            Some((EventKind::State, EventKindVariation::RedactedStripped))
        }
        "ToDeviceEvent" => Some((EventKind::ToDevice, EventKindVariation::Full)),
        "PresenceEvent" => Some((EventKind::Presence, EventKindVariation::Full)),
        "RedactionEvent" => Some((EventKind::Redaction, EventKindVariation::Full)),
        "SyncRedactionEvent" => Some((EventKind::Redaction, EventKindVariation::Sync)),
        _ => None,
    }
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the event.
    pub name: EventKind,

    /// An array of valid matrix event types.
    ///
    /// This will generate the variants of the event type "name". There needs to be a corresponding
    /// variant in `ruma_events::EventType` for this event (converted to a valid Rust-style type
    /// name by stripping `m.`, replacing the remaining dots by underscores and then converting
    /// from snake_case to CamelCase).
    pub events: Vec<EventEnumEntry>,
}

impl Parse for EventEnumInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;
        // "name" field
        let _: kw::kind = input.parse()?;
        let _: Token![:] = input.parse()?;

        // the name of our event enum
        let name: EventKind = input.parse()?;
        let _: Token![,] = input.parse()?;

        // "events" field
        let _: kw::events = input.parse()?;
        let _: Token![:] = input.parse()?;

        // an array of event names `["m.room.whatever", ...]`
        let content;
        bracketed!(content in input);
        let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
        let events = events.into_iter().collect();

        Ok(Self { attrs, name, events })
    }
}

pub struct EventEnumEntry {
    pub attrs: Vec<Attribute>,
    pub ev_type: LitStr,
}

impl Parse for EventEnumEntry {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
    }
}
<commit_msg>events-macros: Make methods on `Copy` type take self by value<commit_after>//! Implementation of event enum and event content enum macros.

use std::fmt;

use proc_macro2::Span;
use quote::format_ident;
use syn::{
    bracketed,
    parse::{self, Parse, ParseStream},
    Attribute, Ident, LitStr, Token,
};

/// Custom keywords for the `event_enum!` macro
mod kw {
    syn::custom_keyword!(kind);
    syn::custom_keyword!(events);
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum EventKindVariation {
    Full,
    Sync,
    Stripped,
    Initial,
    Redacted,
    RedactedSync,
    RedactedStripped,
}

impl fmt::Display for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKindVariation::Full => write!(f, ""),
            EventKindVariation::Sync => write!(f, "Sync"),
            EventKindVariation::Stripped => write!(f, "Stripped"),
            EventKindVariation::Initial => write!(f, "Initial"),
            EventKindVariation::Redacted => write!(f, "Redacted"),
            EventKindVariation::RedactedSync => write!(f, "RedactedSync"),
            EventKindVariation::RedactedStripped => write!(f, "RedactedStripped"),
        }
    }
}

impl EventKindVariation {
    pub fn is_redacted(self) -> bool {
        matches!(self, Self::Redacted | Self::RedactedSync | Self::RedactedStripped)
    }

    pub fn to_full_variation(self) -> Self {
        match self {
            EventKindVariation::Redacted
            | EventKindVariation::RedactedSync
            | EventKindVariation::RedactedStripped => EventKindVariation::Redacted,
            EventKindVariation::Full
            | EventKindVariation::Sync
            | EventKindVariation::Stripped
            | EventKindVariation::Initial => EventKindVariation::Full,
        }
    }
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Debug, Eq, PartialEq)]
pub enum EventKind {
    Basic,
    Ephemeral,
    Message,
    State,
    ToDevice,
    Redaction,
    Presence,
}

impl fmt::Display for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKind::Basic => write!(f, "BasicEvent"),
            EventKind::Ephemeral => write!(f, "EphemeralRoomEvent"),
            EventKind::Message => write!(f, "MessageEvent"),
            EventKind::State => write!(f, "StateEvent"),
            EventKind::ToDevice => write!(f, "ToDeviceEvent"),
            EventKind::Redaction => write!(f, "RedactionEvent"),
            EventKind::Presence => write!(f, "PresenceEvent"),
        }
    }
}

impl EventKind {
    pub fn is_state(&self) -> bool {
        matches!(self, Self::State)
    }

    pub fn is_message(&self) -> bool {
        matches!(self, Self::Message)
    }

    pub fn to_event_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        use EventKindVariation as V;

        // this match is only used to validate the input
        match (self, var) {
            (_, V::Full)
            | (Self::Ephemeral, V::Sync)
            | (Self::Message, V::Sync)
            | (Self::State, V::Sync)
            | (Self::State, V::Stripped)
            | (Self::State, V::Initial)
            | (Self::Message, V::Redacted)
            | (Self::State, V::Redacted)
            | (Self::Message, V::RedactedSync)
            | (Self::State, V::RedactedSync)
            | (Self::State, V::RedactedStripped) => {
                Some(Ident::new(&format!("{}{}", var, self), Span::call_site()))
            }
            _ => None,
        }
    }

    pub fn to_event_enum_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        Some(format_ident!("Any{}", self.to_event_ident(var)?))
    }

    /// `Any[kind]EventContent`
    pub fn to_content_enum(&self) -> Ident {
        Ident::new(&format!("Any{}Content", self), Span::call_site())
    }
}

impl Parse for EventKind {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let ident: Ident = input.parse()?;
        Ok(match ident.to_string().as_str() {
            "Basic" => EventKind::Basic,
            "EphemeralRoom" => EventKind::Ephemeral,
            "Message" => EventKind::Message,
            "State" => EventKind::State,
            "ToDevice" => EventKind::ToDevice,
            id => {
                return Err(syn::Error::new(
                    input.span(),
                    format!(
                        "valid event kinds are Basic, EphemeralRoom, Message, State, ToDevice \
                         found `{}`",
                        id
                    ),
                ));
            }
        })
    }
}

// This function is only used in the `Event` derive macro expansion code.
/// Validates the given `ident` is a valid event struct name and returns a tuple of enums
/// representing the name.
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
    let ident_str = ident.to_string();
    match ident_str.as_str() {
        "BasicEvent" => Some((EventKind::Basic, EventKindVariation::Full)),
        "EphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Full)),
        "SyncEphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Sync)),
        "MessageEvent" => Some((EventKind::Message, EventKindVariation::Full)),
        "SyncMessageEvent" => Some((EventKind::Message, EventKindVariation::Sync)),
        "RedactedMessageEvent" => Some((EventKind::Message, EventKindVariation::Redacted)),
        "RedactedSyncMessageEvent" => Some((EventKind::Message, EventKindVariation::RedactedSync)),
        "StateEvent" => Some((EventKind::State, EventKindVariation::Full)),
        "SyncStateEvent" => Some((EventKind::State, EventKindVariation::Sync)),
        "StrippedStateEvent" => Some((EventKind::State, EventKindVariation::Stripped)),
        "InitialStateEvent" => Some((EventKind::State, EventKindVariation::Initial)),
        "RedactedStateEvent" => Some((EventKind::State, EventKindVariation::Redacted)),
        "RedactedSyncStateEvent" => Some((EventKind::State, EventKindVariation::RedactedSync)),
        "RedactedStrippedStateEvent" => {
            Some((EventKind::State, EventKindVariation::RedactedStripped))
        }
        "ToDeviceEvent" => Some((EventKind::ToDevice, EventKindVariation::Full)),
        "PresenceEvent" => Some((EventKind::Presence, EventKindVariation::Full)),
        "RedactionEvent" => Some((EventKind::Redaction, EventKindVariation::Full)),
        "SyncRedactionEvent" => Some((EventKind::Redaction, EventKindVariation::Sync)),
        _ => None,
    }
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the event.
    pub name: EventKind,

    /// An array of valid matrix event types.
    ///
    /// This will generate the variants of the event type "name". There needs to be a corresponding
    /// variant in `ruma_events::EventType` for this event (converted to a valid Rust-style type
    /// name by stripping `m.`, replacing the remaining dots by underscores and then converting
    /// from snake_case to CamelCase).
    pub events: Vec<EventEnumEntry>,
}

impl Parse for EventEnumInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;
        // "name" field
        let _: kw::kind = input.parse()?;
        let _: Token![:] = input.parse()?;

        // the name of our event enum
        let name: EventKind = input.parse()?;
        let _: Token![,] = input.parse()?;

        // "events" field
        let _: kw::events = input.parse()?;
        let _: Token![:] = input.parse()?;

        // an array of event names `["m.room.whatever", ...]`
        let content;
        bracketed!(content in input);
        let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
        let events = events.into_iter().collect();

        Ok(Self { attrs, name, events })
    }
}

pub struct EventEnumEntry {
    pub attrs: Vec<Attribute>,
    pub ev_type: LitStr,
}

impl Parse for EventEnumEntry {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
    }
}
<|endoftext|>


<commit_before>use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::UnSupModel;

struct KMeansClassifier {
    iters: usize,
    k: usize,
    centroids: Option<Matrix<f64>>,
}

impl UnSupModel<Matrix<f64>, Vector<usize>> for KMeansClassifier {
    fn predict(&self, data: Matrix<f64>) -> Vector<usize> {
        Vector::new(vec![0])
    }

    fn train(&mut self, data: Matrix<f64>) {
    	self.init_centroids(data.cols);

    	for i in self.iters {
    		let idx = self.find_closest_centroids(&data);
    		self.compute_means(data, idx);
    	}
    }
}

impl KMeansClassifier {
	pub fn new(k: usize) -> KMeansClassifier {
		KMeansClassifier{ iters: 100, k:k, centroids: None}
	}

    fn init_centroids(&mut self, dim: usize) {
    	// These should not all be equal!
    	self.centroids = Some(Matrix::zeros(self.k, dim));
    }

    fn find_closest_centroids(&self, data: &Matrix<f64>) -> Vector<usize> {
    	let mut idx = Vector::zeros(data.rows);

    	for i in 0..data.rows {
    		for j in 0..self.k {
    			// idx[i] = argmin distance to centroid;
    		}
    	}
    	idx
    }

    fn compute_means(&mut self, data: Matrix<f64>, classes: Vector<usize>)
    {
    	for i in 0..self.k {
    		let mut vec_k = Vec::new();

    		for j in classes {
    			if j == k }
    			vec_k.push(j);
    		}

    		// index out these rows from data
    		// make a new matrix
    		// compute average of it's rows
    	}
    }
}
<commit_msg>Fixing some bugs.<commit_after>use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::UnSupModel;

struct KMeansClassifier {
    iters: usize,
    k: usize,
    centroids: Option<Matrix<f64>>,
}

impl UnSupModel<Matrix<f64>, Vector<usize>> for KMeansClassifier {
    fn predict(&self, data: Matrix<f64>) -> Vector<usize> {
        Vector::new(vec![0])
    }

    fn train(&mut self, data: Matrix<f64>) {
    	self.init_centroids(data.cols);

    	for i in 0..self.iters {
    		let idx = self.find_closest_centroids(&data);
    		self.compute_means(&data, idx);
    	}
    }
}

impl KMeansClassifier {
	pub fn new(k: usize) -> KMeansClassifier {
		KMeansClassifier{ iters: 100, k:k, centroids: None}
	}

    fn init_centroids(&mut self, dim: usize) {
    	// These should not all be equal!
    	self.centroids = Some(Matrix::zeros(self.k, dim));
    }

    fn find_closest_centroids(&self, data: &Matrix<f64>) -> Vector<usize> {
    	let mut idx = Vector::zeros(data.rows);

    	for i in 0..data.rows {
    		for j in 0..self.k {
    			// idx[i] = argmin distance to centroid;
    		}
    	}
    	idx
    }

    fn compute_means(&mut self, data: &Matrix<f64>, classes: Vector<usize>)
    {
    	for i in 0..self.k {
    		let mut vec_k = Vec::new();

    		for j in classes.data.iter() {
    			if *j == i {
    				vec_k.push(j);
    			}
    		}

    		// index out these rows from data
    		// make a new matrix
    		// compute average of it's rows
    	}
    }
}

<|endoftext|>


<commit_before>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "e708cbd91c9cae4426d69270248362b423324556";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/closing-args-token.rs",
    "src/test/ui/const-generics/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/include-single-expr-helper.rs",
    "src/test/ui/include-single-expr-helper-1.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/parser/auxiliary/issue-21146-inc.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
        return false;
    }

    if path.starts_with("src/test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Update test suite to nightly-2021-03-26<commit_after>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "52e3dffa50cfffdcfa145c0cc0ba48b49abc0c07";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // TODO
    "src/test/pretty/gat-bounds.rs",
    "src/test/ui/const-generics/defaults/auxiliary/const_defaulty.rs",
    "src/test/ui/const-generics/defaults/const-default.rs",
    "src/test/ui/const-generics/defaults/default-annotation.rs",
    "src/test/ui/const-generics/defaults/external.rs",
    "src/test/ui/const-generics/defaults/pretty-printing-ast.rs",
    "src/test/ui/const-generics/min_const_generics/type_and_const_defaults.rs",
    "src/test/ui/generic-associated-types/generic-associated-type-bounds.rs",
    "src/test/ui/generic-associated-types/issue-80433-reduced.rs",
    "src/test/ui/macros/pub-macro-rules.rs",
    "src/test/ui/or-patterns/or-patterns-syntactic-pass.rs",
    "src/test/ui/typeck/typeck_type_placeholder_item.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/closing-args-token.rs",
    "src/test/ui/const-generics/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/include-single-expr-helper.rs",
    "src/test/ui/include-single-expr-helper-1.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/parser/auxiliary/issue-21146-inc.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
        return false;
    }

    if path.starts_with("src/test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|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,
}

#[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")),
        }
    }
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: &WorkspaceHitlist) -> Result<Vec<Target>, std::io::Error> {
    let mut targets: Vec<Target> = vec![];
    if *workspace_hitlist == WorkspaceHitlist::None {
        let output = Command::new("cargo").arg("read-manifest").output()?;
        if output.status.success() {
            // None of the unwraps should fail if output of `cargo read-manifest` is correct
            let data = &String::from_utf8(output.stdout).unwrap();
            let json: Value = json::from_str(data).unwrap();
            let json_obj = json.as_object().unwrap();
            let jtargets = json_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }

            return Ok(targets);
        }
        return Err(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ));
    }
    // This happens when cargo-fmt is not used inside a crate or
    // is used inside a workspace.
    // To ensure backward compatability, we only use `cargo metadata` for workspaces.
    // TODO: Is it possible only use metadata or read-manifest
    let output = Command::new("cargo")
        .arg("metadata")
        .arg("--no-deps")
        .output()?;
    if output.status.success() {
        let data = &String::from_utf8(output.stdout).unwrap();
        let json: Value = json::from_str(data).unwrap();
        let json_obj = json.as_object().unwrap();
        let mut hitlist: HashSet<&String> = if *workspace_hitlist != WorkspaceHitlist::All {
            HashSet::from_iter(workspace_hitlist.get_some().unwrap())
        } else {
            HashSet::new() // Unused
        };
        let members: Vec<&Value> = json_obj
            .get("packages")
            .unwrap()
            .as_array()
            .unwrap()
            .into_iter()
            .filter(|member| if *workspace_hitlist == WorkspaceHitlist::All {
                true
            } else {
                let member_obj = member.as_object().unwrap();
                let member_name = member_obj.get("name").unwrap().as_str().unwrap();
                hitlist.take(&member_name.to_string()).is_some()
            })
            .collect();
        if !hitlist.is_empty() {
            // Mimick cargo of only outputting one <package> spec.
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!(
                    "package `{}` is not a member of the workspace",
                    hitlist.iter().next().unwrap()
                ),
            ));
        }
        for member in members {
            let member_obj = member.as_object().unwrap();
            let jtargets = member_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }
        }
        return Ok(targets);
    }
    Err(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        str::from_utf8(&output.stderr).unwrap(),
    ))
}

fn target_from_json(jtarget: &Value) -> Target {
    let jtarget = jtarget.as_object().unwrap();
    let path = PathBuf::from(jtarget.get("src_path").unwrap().as_str().unwrap());
    let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
    let kind = match kinds[0].as_str().unwrap() {
        "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,
    };

    Target {
        path: path,
        kind: kind,
    }
}

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>Do not use 'cargo manifest' anymore as it is deprecated<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::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,
}

#[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")),
        }
    }
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: &WorkspaceHitlist) -> Result<Vec<Target>, std::io::Error> {
    let mut targets: Vec<Target> = vec![];

        }
    }
    let output = Command::new("cargo")
        .arg("metadata")
        .arg("--no-deps")
        .output()?;
    if output.status.success() {
        let data = &String::from_utf8(output.stdout).unwrap();
        let json: Value = json::from_str(data).unwrap();
        let json_obj = json.as_object().unwrap();
        let mut hitlist: HashSet<&String> = if *workspace_hitlist != WorkspaceHitlist::All {
            HashSet::from_iter(workspace_hitlist.get_some().unwrap())
        } else {
            HashSet::new() // Unused
        };
        let members: Vec<&Value> = json_obj
            .get("packages")
            .unwrap()
            .as_array()
            .unwrap()
            .into_iter()
            .filter(|member| if *workspace_hitlist == WorkspaceHitlist::All {
                true
            } else {
                let member_obj = member.as_object().unwrap();
                let member_name = member_obj.get("name").unwrap().as_str().unwrap();
                hitlist.take(&member_name.to_string()).is_some()
            })
            .collect();
        if !hitlist.is_empty() {
            // Mimick cargo of only outputting one <package> spec.
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!(
                    "package `{}` is not a member of the workspace",
                    hitlist.iter().next().unwrap()
                ),
            ));
        }
        for member in members {
            let member_obj = member.as_object().unwrap();
            let jtargets = member_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }
        }
}

fn target_from_json(jtarget: &Value) -> Target {
    let jtarget = jtarget.as_object().unwrap();
    let path = PathBuf::from(jtarget.get("src_path").unwrap().as_str().unwrap());
    let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
    let kind = match kinds[0].as_str().unwrap() {
        "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,
    };

    Target {
        path: path,
        kind: kind,
    }
}

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()
}
<|endoftext|>


<commit_before>

extern crate cratesfyi;
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate time;

use std::env;
use std::path::PathBuf;

use clap::{Arg, App, SubCommand};
use cratesfyi::{DocBuilder, DocBuilderOptions, db};
use cratesfyi::utils::build_doc;
use cratesfyi::start_web_server;
use cratesfyi::db::add_path_into_database;

pub fn main() {
    logger_init();

    let matches = App::new("cratesfyi")
        .version(cratesfyi::BUILD_VERSION)
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .subcommand(SubCommand::with_name("doc")
            .about("Builds documentation of a crate")
            .arg(Arg::with_name("CRATE_NAME")
                .index(1)
                .required(true)
                .help("Crate name"))
            .arg(Arg::with_name("CRATE_VERSION")
                .index(2)
                .required(false)
                .help("Crate version"))
            .arg(Arg::with_name("TARGET")
                .index(3)
                .required(false)
                .help("The target platform to compile for")))
        .subcommand(SubCommand::with_name("build")
            .about("Builds documentation in a chroot environment")
            .arg(Arg::with_name("PREFIX")
                .short("P")
                .long("prefix")
                .takes_value(true))
            .arg(Arg::with_name("DESTINATION")
                .short("d")
                .long("destination")
                .help("Sets destination path")
                .takes_value(true))
            .arg(Arg::with_name("CHROOT_PATH")
                .short("c")
                .long("chroot")
                .help("Sets chroot path")
                .takes_value(true))
            .arg(Arg::with_name("CHROOT_USER")
                .short("u")
                .long("chroot-user")
                .help("Sets chroot user name")
                .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(true)
                    .help("Crate name"))
                .arg(Arg::with_name("CRATE_VERSION")
                    .index(2)
                    .required(true)
                    .help("Version of crate")))
            .subcommand(SubCommand::with_name("add-essential-files")
                .about("Adds essential files for 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("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"))
        .subcommand(SubCommand::with_name("database")
            .about("Database operations")
            .subcommand(SubCommand::with_name("init").about("Initialize database. Currently \
                                                              only creates tables in database."))
            .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 montly release activity \
                                                              chart")
            .subcommand(SubCommand::with_name("update-search-index"))
            .about("Updates search index"))
        .get_matches();

    // doc subcommand
    if let Some(matches) = matches.subcommand_matches("doc") {
        let name = matches.value_of("CRATE_NAME").unwrap();
        let version = matches.value_of("CRATE_VERSION");
        let target = matches.value_of("TARGET");
        if let Err(e) = build_doc(name, version, target) {
            panic!("{:#?}", e);
        }
    } else 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()
            };

            // set options
            if let Some(destination) = matches.value_of("DESTINATION") {
                docbuilder_opts.destination = PathBuf::from(destination);
            }

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

            if let Some(chroot_user) = matches.value_of("CHROOT_USER") {
                docbuilder_opts.chroot_user = chroot_user.to_string();
            }

            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");
            docbuilder.build_world().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");
            docbuilder.build_package(matches.value_of("CRATE_NAME").unwrap(),
                               matches.value_of("CRATE_VERSION").unwrap())
                .expect("Building documentation failed");
            docbuilder.save_cache().expect("Failed to save cache");
        } else if let Some(_) = matches.subcommand_matches("add-essential-files") {
            docbuilder.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) = matches.subcommand_matches("database") {
        if let Some(_) = matches.subcommand_matches("init") {
            let conn = db::connect_db().unwrap();
            db::create_tables(&conn).expect("Failed to initialize database");
        } 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) = 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") {
        cratesfyi::utils::start_daemon();
    } else {
        println!("{}", matches.usage());
    }
}

fn logger_init() {
    let format = |record: &log::LogRecord| {
        format!("{} [{}] {}: {}",
                time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(),
                record.level(),
                record.target(),
                record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format);
    builder.parse(&env::var("RUST_LOG").unwrap_or("cratesfyi=info".to_owned()));
    builder.init().unwrap();
}
<commit_msg>Remove unused #[macro_use]<commit_after>

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

use std::env;
use std::path::PathBuf;

use clap::{Arg, App, SubCommand};
use cratesfyi::{DocBuilder, DocBuilderOptions, db};
use cratesfyi::utils::build_doc;
use cratesfyi::start_web_server;
use cratesfyi::db::add_path_into_database;

pub fn main() {
    logger_init();

    let matches = App::new("cratesfyi")
        .version(cratesfyi::BUILD_VERSION)
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .subcommand(SubCommand::with_name("doc")
            .about("Builds documentation of a crate")
            .arg(Arg::with_name("CRATE_NAME")
                .index(1)
                .required(true)
                .help("Crate name"))
            .arg(Arg::with_name("CRATE_VERSION")
                .index(2)
                .required(false)
                .help("Crate version"))
            .arg(Arg::with_name("TARGET")
                .index(3)
                .required(false)
                .help("The target platform to compile for")))
        .subcommand(SubCommand::with_name("build")
            .about("Builds documentation in a chroot environment")
            .arg(Arg::with_name("PREFIX")
                .short("P")
                .long("prefix")
                .takes_value(true))
            .arg(Arg::with_name("DESTINATION")
                .short("d")
                .long("destination")
                .help("Sets destination path")
                .takes_value(true))
            .arg(Arg::with_name("CHROOT_PATH")
                .short("c")
                .long("chroot")
                .help("Sets chroot path")
                .takes_value(true))
            .arg(Arg::with_name("CHROOT_USER")
                .short("u")
                .long("chroot-user")
                .help("Sets chroot user name")
                .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(true)
                    .help("Crate name"))
                .arg(Arg::with_name("CRATE_VERSION")
                    .index(2)
                    .required(true)
                    .help("Version of crate")))
            .subcommand(SubCommand::with_name("add-essential-files")
                .about("Adds essential files for 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("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"))
        .subcommand(SubCommand::with_name("database")
            .about("Database operations")
            .subcommand(SubCommand::with_name("init").about("Initialize database. Currently \
                                                              only creates tables in database."))
            .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 montly release activity \
                                                              chart")
            .subcommand(SubCommand::with_name("update-search-index"))
            .about("Updates search index"))
        .get_matches();

    // doc subcommand
    if let Some(matches) = matches.subcommand_matches("doc") {
        let name = matches.value_of("CRATE_NAME").unwrap();
        let version = matches.value_of("CRATE_VERSION");
        let target = matches.value_of("TARGET");
        if let Err(e) = build_doc(name, version, target) {
            panic!("{:#?}", e);
        }
    } else 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()
            };

            // set options
            if let Some(destination) = matches.value_of("DESTINATION") {
                docbuilder_opts.destination = PathBuf::from(destination);
            }

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

            if let Some(chroot_user) = matches.value_of("CHROOT_USER") {
                docbuilder_opts.chroot_user = chroot_user.to_string();
            }

            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");
            docbuilder.build_world().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");
            docbuilder.build_package(matches.value_of("CRATE_NAME").unwrap(),
                               matches.value_of("CRATE_VERSION").unwrap())
                .expect("Building documentation failed");
            docbuilder.save_cache().expect("Failed to save cache");
        } else if let Some(_) = matches.subcommand_matches("add-essential-files") {
            docbuilder.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) = matches.subcommand_matches("database") {
        if let Some(_) = matches.subcommand_matches("init") {
            let conn = db::connect_db().unwrap();
            db::create_tables(&conn).expect("Failed to initialize database");
        } 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) = 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") {
        cratesfyi::utils::start_daemon();
    } else {
        println!("{}", matches.usage());
    }
}

fn logger_init() {
    let format = |record: &log::LogRecord| {
        format!("{} [{}] {}: {}",
                time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(),
                record.level(),
                record.target(),
                record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format);
    builder.parse(&env::var("RUST_LOG").unwrap_or("cratesfyi=info".to_owned()));
    builder.init().unwrap();
}
<|endoftext|>