<commit_before>//! Database operations

pub use self::add_package::add_package_into_database;
pub use self::add_package::add_build_into_database;
pub use self::file::add_path_into_database;

use postgres::{Connection, TlsMode};
use postgres::error::{Error, ConnectError};
use std::env;
use r2d2;
use r2d2_postgres;

mod add_package;
mod file;

/// Connects to database
pub fn connect_db() -> Result<Connection, ConnectError> {
    // FIXME: unwrap might not be the best here
    let db_url = env::var("CRATESFYI_DATABASE_URL")
        .expect("CRATESFYI_DATABASE_URL environment variable is not exists");
    Connection::connect(&db_url[..], TlsMode::None)
}

pub fn create_pool() -> r2d2::Pool<r2d2_postgres::PostgresConnectionManager> {
    let db_url = env::var("CRATESFYI_DATABASE_URL")
        .expect("CRATESFYI_DATABASE_URL environment variable is not exists");
    let config = r2d2::Config::default();
    let manager = r2d2_postgres::PostgresConnectionManager::new(&db_url[..],
                                                                r2d2_postgres::TlsMode::None)
        .expect("Failed to create PostgresConnectionManager");
    r2d2::Pool::new(config, manager).expect("Failed to create r2d2 pool")
}

/// Updates content column in crates table.
///
/// This column will be used for searches and always contains `tsvector` of:
///
///   * crate name (rank A-weight)
///   * latest release description (rank B-weight)
///   * latest release keywords (rank B-weight)
///   * latest release readme (rank C-weight)
///   * latest release root rustdoc (rank C-weight)
pub fn update_search_index(conn: &Connection) -> Result<u64, Error> {
    conn.execute("
        WITH doc as (
            SELECT DISTINCT ON(releases.crate_id)
                   releases.id,
                   releases.crate_id,
                   setweight(to_tsvector(crates.name), 'A')                                   ||
                   setweight(to_tsvector(coalesce(releases.description, '')), 'B')            ||
                   setweight(to_tsvector(coalesce((
                                SELECT string_agg(value, ' ')
                                FROM json_array_elements_text(releases.keywords)), '')), 'B') ||
                   setweight(to_tsvector(coalesce(releases.readme, '')), 'C')                 ||
                   setweight(to_tsvector(coalesce(releases.description_long, '')), 'C') as content
            FROM releases
            INNER JOIN crates ON crates.id = releases.crate_id
            ORDER BY releases.crate_id, releases.release_time DESC
        )
        UPDATE crates
        SET latest_version_id = doc.id,
            content = doc.content
        FROM doc
        WHERE crates.id = doc.crate_id AND
            (crates.latest_version_id = 0 OR crates.latest_version_id != doc.id);",
                 &[])
}

/// Creates database tables
pub fn create_tables(conn: &Connection) -> Result<(), Error> {
    let queries = ["CREATE TABLE crates (
                        id SERIAL PRIMARY KEY,
                        name VARCHAR(255) UNIQUE NOT NULL,
                        latest_version_id INT DEFAULT 0,
                        versions JSON DEFAULT '[]',
                        downloads_total INT DEFAULT 0,
                        github_description VARCHAR(1024),
                        github_stars INT DEFAULT 0,
                        github_forks INT DEFAULT 0,
                        github_issues INT DEFAULT 0,
                        github_last_commit TIMESTAMP,
                        github_last_update TIMESTAMP,
                        content tsvector
                    )",
                   "CREATE TABLE releases (
                        id SERIAL PRIMARY KEY,
                        crate_id INT NOT NULL REFERENCES crates(id),
                        version VARCHAR(100),
                        release_time TIMESTAMP,
                        dependencies JSON,
                        target_name VARCHAR(255),
                        yanked BOOL DEFAULT FALSE,
                        is_library BOOL DEFAULT TRUE,
                        build_status BOOL DEFAULT FALSE,
                        rustdoc_status BOOL DEFAULT FALSE,
                        test_status BOOL DEFAULT FALSE,
                        license VARCHAR(100),
                        repository_url VARCHAR(255),
                        homepage_url VARCHAR(255),
                        documentation_url VARCHAR(255),
                        description VARCHAR(1024),
                        description_long VARCHAR(51200),
                        readme VARCHAR(51200),
                        authors JSON,
                        keywords JSON,
                        have_examples BOOL DEFAULT FALSE,
                        downloads INT DEFAULT 0,
                        files JSON,
                        doc_targets JSON DEFAULT '[]',
                        doc_rustc_version VARCHAR(100) NOT NULL,
                        default_target VARCHAR(100),
                        UNIQUE (crate_id, version)
                    )",
                   "CREATE TABLE authors (
                        id SERIAL PRIMARY KEY,
                        name VARCHAR(255),
                        email VARCHAR(255),
                        slug VARCHAR(255) UNIQUE NOT NULL
                    )",
                   "CREATE TABLE author_rels (
                        rid INT REFERENCES releases(id),
                        aid INT REFERENCES authors(id),
                        UNIQUE(rid, aid)
                    )",
                   "CREATE TABLE keywords (
                        id SERIAL PRIMARY KEY,
                        name VARCHAR(255),
                        slug VARCHAR(255) NOT NULL UNIQUE
                    )",
                   "CREATE TABLE keyword_rels (
                        rid INT REFERENCES releases(id),
                        kid INT REFERENCES keywords(id),
                        UNIQUE(rid, kid)
                    )",
                   "CREATE TABLE owners (
                        id SERIAL PRIMARY KEY,
                        login VARCHAR(255) NOT NULL UNIQUE,
                        avatar VARCHAR(255),
                        name VARCHAR(255),
                        email VARCHAR(255)
                    )",
                   "CREATE TABLE owner_rels (
                        cid INT REFERENCES releases(id),
                        oid INT REFERENCES owners(id),
                        UNIQUE(cid, oid)
                    )",
                   "CREATE TABLE builds (
                        id SERIAL,
                        rid INT NOT NULL REFERENCES releases(id),
                        rustc_version VARCHAR(100) NOT NULL,
                        cratesfyi_version VARCHAR(100) NOT NULL,
                        build_status BOOL NOT NULL,
                        build_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        output TEXT
                    )",
                   "CREATE TABLE queue (
                        id SERIAL,
                        name VARCHAR(255),
                        version VARCHAR(100),
                        attempt INT DEFAULT 0,
                        date_added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        UNIQUE(name, version)
                    )",
                   "CREATE TABLE files (
                        path VARCHAR(4096) NOT NULL PRIMARY KEY,
                        mime VARCHAR(100) NOT NULL,
                        date_added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        date_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        content BYTEA
                    )",
                   "CREATE INDEX ON releases (release_time DESC)",
                   "CREATE INDEX content_idx ON crates USING gin(content)",
                   "CREATE TABLE config (
                        name VARCHAR(100) NOT NULL PRIMARY KEY,
                        value JSON NOT NULL
                    )",
                   "INSERT INTO config VALUES ('database_version', '1'::json)"];

    for query in queries.into_iter() {
        try!(conn.execute(query, &[]));
    }

    Ok(())
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::*;

    #[test]
    #[ignore]
    fn test_connect_db() {
        let conn = connect_db();
        assert!(conn.is_ok());
    }

    #[test]
    #[ignore]
    fn test_create_tables() {
        let _ = env_logger::init();
        let conn = connect_db();
        assert!(conn.is_ok());

        // FIXME: As expected this test always fails if database is already created
        let res = create_tables(&conn.unwrap());
        info!("RES: {:#?}", res);
        assert!(res.is_ok());
    }
}
<commit_msg>Remove README's from text search field<commit_after>//! Database operations

pub use self::add_package::add_package_into_database;
pub use self::add_package::add_build_into_database;
pub use self::file::add_path_into_database;

use postgres::{Connection, TlsMode};
use postgres::error::{Error, ConnectError};
use std::env;
use r2d2;
use r2d2_postgres;

mod add_package;
mod file;

/// Connects to database
pub fn connect_db() -> Result<Connection, ConnectError> {
    // FIXME: unwrap might not be the best here
    let db_url = env::var("CRATESFYI_DATABASE_URL")
        .expect("CRATESFYI_DATABASE_URL environment variable is not exists");
    Connection::connect(&db_url[..], TlsMode::None)
}

pub fn create_pool() -> r2d2::Pool<r2d2_postgres::PostgresConnectionManager> {
    let db_url = env::var("CRATESFYI_DATABASE_URL")
        .expect("CRATESFYI_DATABASE_URL environment variable is not exists");
    let config = r2d2::Config::default();
    let manager = r2d2_postgres::PostgresConnectionManager::new(&db_url[..],
                                                                r2d2_postgres::TlsMode::None)
        .expect("Failed to create PostgresConnectionManager");
    r2d2::Pool::new(config, manager).expect("Failed to create r2d2 pool")
}

/// Updates content column in crates table.
///
/// This column will be used for searches and always contains `tsvector` of:
///
///   * crate name (rank A-weight)
///   * latest release description (rank B-weight)
///   * latest release keywords (rank B-weight)
///   * latest release readme (rank C-weight)
///   * latest release root rustdoc (rank C-weight)
pub fn update_search_index(conn: &Connection) -> Result<u64, Error> {
    conn.execute("
        WITH doc as (
            SELECT DISTINCT ON(releases.crate_id)
                   releases.id,
                   releases.crate_id,
                   setweight(to_tsvector(crates.name), 'A')                                   ||
                   setweight(to_tsvector(coalesce(releases.description, '')), 'B')            ||
                   setweight(to_tsvector(coalesce((
                                SELECT string_agg(value, ' ')
                                FROM json_array_elements_text(releases.keywords)), '')), 'B')
                    as content
            FROM releases
            INNER JOIN crates ON crates.id = releases.crate_id
            ORDER BY releases.crate_id, releases.release_time DESC
        )
        UPDATE crates
        SET latest_version_id = doc.id,
            content = doc.content
        FROM doc
        WHERE crates.id = doc.crate_id AND
            (crates.latest_version_id = 0 OR crates.latest_version_id != doc.id);",
                 &[])
}

/// Creates database tables
pub fn create_tables(conn: &Connection) -> Result<(), Error> {
    let queries = ["CREATE TABLE crates (
                        id SERIAL PRIMARY KEY,
                        name VARCHAR(255) UNIQUE NOT NULL,
                        latest_version_id INT DEFAULT 0,
                        versions JSON DEFAULT '[]',
                        downloads_total INT DEFAULT 0,
                        github_description VARCHAR(1024),
                        github_stars INT DEFAULT 0,
                        github_forks INT DEFAULT 0,
                        github_issues INT DEFAULT 0,
                        github_last_commit TIMESTAMP,
                        github_last_update TIMESTAMP,
                        content tsvector
                    )",
                   "CREATE TABLE releases (
                        id SERIAL PRIMARY KEY,
                        crate_id INT NOT NULL REFERENCES crates(id),
                        version VARCHAR(100),
                        release_time TIMESTAMP,
                        dependencies JSON,
                        target_name VARCHAR(255),
                        yanked BOOL DEFAULT FALSE,
                        is_library BOOL DEFAULT TRUE,
                        build_status BOOL DEFAULT FALSE,
                        rustdoc_status BOOL DEFAULT FALSE,
                        test_status BOOL DEFAULT FALSE,
                        license VARCHAR(100),
                        repository_url VARCHAR(255),
                        homepage_url VARCHAR(255),
                        documentation_url VARCHAR(255),
                        description VARCHAR(1024),
                        description_long VARCHAR(51200),
                        readme VARCHAR(51200),
                        authors JSON,
                        keywords JSON,
                        have_examples BOOL DEFAULT FALSE,
                        downloads INT DEFAULT 0,
                        files JSON,
                        doc_targets JSON DEFAULT '[]',
                        doc_rustc_version VARCHAR(100) NOT NULL,
                        default_target VARCHAR(100),
                        UNIQUE (crate_id, version)
                    )",
                   "CREATE TABLE authors (
                        id SERIAL PRIMARY KEY,
                        name VARCHAR(255),
                        email VARCHAR(255),
                        slug VARCHAR(255) UNIQUE NOT NULL
                    )",
                   "CREATE TABLE author_rels (
                        rid INT REFERENCES releases(id),
                        aid INT REFERENCES authors(id),
                        UNIQUE(rid, aid)
                    )",
                   "CREATE TABLE keywords (
                        id SERIAL PRIMARY KEY,
                        name VARCHAR(255),
                        slug VARCHAR(255) NOT NULL UNIQUE
                    )",
                   "CREATE TABLE keyword_rels (
                        rid INT REFERENCES releases(id),
                        kid INT REFERENCES keywords(id),
                        UNIQUE(rid, kid)
                    )",
                   "CREATE TABLE owners (
                        id SERIAL PRIMARY KEY,
                        login VARCHAR(255) NOT NULL UNIQUE,
                        avatar VARCHAR(255),
                        name VARCHAR(255),
                        email VARCHAR(255)
                    )",
                   "CREATE TABLE owner_rels (
                        cid INT REFERENCES releases(id),
                        oid INT REFERENCES owners(id),
                        UNIQUE(cid, oid)
                    )",
                   "CREATE TABLE builds (
                        id SERIAL,
                        rid INT NOT NULL REFERENCES releases(id),
                        rustc_version VARCHAR(100) NOT NULL,
                        cratesfyi_version VARCHAR(100) NOT NULL,
                        build_status BOOL NOT NULL,
                        build_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        output TEXT
                    )",
                   "CREATE TABLE queue (
                        id SERIAL,
                        name VARCHAR(255),
                        version VARCHAR(100),
                        attempt INT DEFAULT 0,
                        date_added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        UNIQUE(name, version)
                    )",
                   "CREATE TABLE files (
                        path VARCHAR(4096) NOT NULL PRIMARY KEY,
                        mime VARCHAR(100) NOT NULL,
                        date_added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        date_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        content BYTEA
                    )",
                   "CREATE INDEX ON releases (release_time DESC)",
                   "CREATE INDEX content_idx ON crates USING gin(content)",
                   "CREATE TABLE config (
                        name VARCHAR(100) NOT NULL PRIMARY KEY,
                        value JSON NOT NULL
                    )",
                   "INSERT INTO config VALUES ('database_version', '1'::json)"];

    for query in queries.into_iter() {
        try!(conn.execute(query, &[]));
    }

    Ok(())
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::*;

    #[test]
    #[ignore]
    fn test_connect_db() {
        let conn = connect_db();
        assert!(conn.is_ok());
    }

    #[test]
    #[ignore]
    fn test_create_tables() {
        let _ = env_logger::init();
        let conn = connect_db();
        assert!(conn.is_ok());

        // FIXME: As expected this test always fails if database is already created
        let res = create_tables(&conn.unwrap());
        info!("RES: {:#?}", res);
        assert!(res.is_ok());
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(try_from)]
#![allow(clippy::missing_docs_in_private_items)]

// FIXME: switch to something more ergonomic here, once available.
// (currently there is no way to opt into sysroot crates w/o `extern crate`)
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_plugin;
use self::rustc_driver::{driver::CompileController, Compilation};

use std::convert::TryInto;
use std::path::Path;
use std::process::{exit, Command};

fn show_version() {
    println!(env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    exit(
        rustc_driver::run(move || {
            use std::env;

            if std::env::args().any(|a| a == "--version" || a == "-V") {
                show_version();
                exit(0);
            }

            let sys_root = option_env!("SYSROOT")
                .map(String::from)
                .or_else(|| std::env::var("SYSROOT").ok())
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
                    home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain)))
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let mut orig_args: Vec<String> = env::args().collect();
            if orig_args.len() <= 1 {
                std::process::exit(1);
            }
            if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }
            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
                orig_args.clone()
            } else {
                orig_args
                    .clone()
                    .into_iter()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true")
                || orig_args.iter().any(|s| s == "--emit=dep-info,metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }

            let mut controller = CompileController::basic();
            if clippy_enabled {
                controller.after_parse.callback = Box::new(move |state| {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                 the crate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());

                    let conf = clippy_lints::read_conf(&registry);
                    clippy_lints::register_plugins(&mut registry, &conf);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, (to, deprecated_name)) in lint_groups {
                        ls.register_group(Some(sess), true, name, deprecated_name, to);
                    }
                    clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf);

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                });
            }
            controller.compilation_done.stop = Compilation::Stop;

            let args = args;
            rustc_driver::run_compiler(&args, Box::new(controller), None, None)
        })
        .try_into()
        .expect("exit code too large"),
    )
}
<commit_msg>Don't try to determine sysroot. rustc_driver will use default value.<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(try_from)]
#![allow(clippy::missing_docs_in_private_items)]

// FIXME: switch to something more ergonomic here, once available.
// (currently there is no way to opt into sysroot crates w/o `extern crate`)
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_plugin;
use self::rustc_driver::{driver::CompileController, Compilation};

use std::convert::TryInto;
use std::path::Path;
use std::process::exit;

fn show_version() {
    println!(env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    exit(
        rustc_driver::run(move || {
            use std::env;

            if std::env::args().any(|a| a == "--version" || a == "-V") {
                show_version();
                exit(0);
            }

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let mut args: Vec<String> = env::args().collect();
            if args.len() <= 1 {
                std::process::exit(1);
            }
            if Path::new(&args[1]).file_stem() == Some("rustc".as_ref()) {
                // we still want to be able to invoke it normally though
                args.remove(1);
            }

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true")
                || args.iter().any(|s| s == "--emit=dep-info,metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }

            let mut controller = CompileController::basic();
            if clippy_enabled {
                controller.after_parse.callback = Box::new(move |state| {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                 the crate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());

                    let conf = clippy_lints::read_conf(&registry);
                    clippy_lints::register_plugins(&mut registry, &conf);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, (to, deprecated_name)) in lint_groups {
                        ls.register_group(Some(sess), true, name, deprecated_name, to);
                    }
                    clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf);

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                });
            }
            controller.compilation_done.stop = Compilation::Stop;

            let args = args;
            rustc_driver::run_compiler(&args, Box::new(controller), None, None)
        })
        .try_into()
        .expect("exit code too large"),
    )
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use libc::c_void;
use std::mem;

pub use self::event_type::EventType;
pub use self::owner_change::OwnerChange;
pub use self::setting_action::SettingAction;
pub use self::property_state::PropertyState;
pub use self::crossing_mode::CrossingMode;
pub use self::notify_type::NotifyType;
pub use self::scroll_direction::ScrollDirection;
pub use self::visibility_state::VisibilityState;

pub mod event_type {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum EventType {
        Nothing           = -1,
        Delete            = 0,
        Destroy           = 1,
        Expose            = 2,
        MotionNotify      = 3,
        ButtonPress       = 4,
        DoubleButtonPress = 5,
        TripleButtonPress = 6,
        ButtonRelease     = 7,
        KeyPress          = 8,
        KeyRelease        = 9,
        EnterNotify       = 10,
        LeaveNotify       = 11,
        FocusChange       = 12,
        Configure         = 13,
        Map               = 14,
        Unmap             = 15,
        PropertyNotify    = 16,
        SelectionClear    = 17,
        SelectionRequest  = 18,
        SelectionNotify   = 19,
        ProximityIn       = 20,
        ProximityOut      = 21,
        DragEnter         = 22,
        DragLeave         = 23,
        DragMotion        = 24,
        DragStatus        = 25,
        DropStart         = 26,
        DropFinished      = 27,
        ClientEvent       = 28,
        VisibilityNotify  = 29,
        Scroll            = 31,
        WindowState       = 32,
        Setting           = 33,
        OwnerChange       = 34,
        GrabBroken        = 35,
        Damage            = 36,
        TouchBegin        = 37,
        TouchUpdate       = 38,
        TouchEnd          = 39,
        TouchCancel       = 40
    }
}

pub trait Event: Sized {
    fn get_send_event(&self) -> bool {
        unsafe {
            let event_any : &EventAny = mem::transmute(self);
            event_any.send_event == 0
        }
    }
}

#[repr(C)]
pub struct EventAny {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,
}

impl Event for EventAny {}

#[allow(dead_code)]
pub struct EventExpose {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub area : ffi::C_GdkRectangle,
    region : *mut c_void, //TODO cairo_region_t
    pub count : i8 /* If non-zero, how many more events follow. */
}

impl Event for EventExpose {}

#[allow(dead_code)]
pub struct EventVisibility{
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub state : ::VisibilityState
}

impl Event for EventVisibility {}

#[allow(dead_code)]
pub struct EventMotion {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub axes : *mut f64,
    pub state : ::enums::modifier_type::ModifierType,
    pub is_hint : i16,
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64
}

impl Event for EventMotion {}

#[allow(dead_code)]
pub struct EventButton {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub axes : *mut f64,
    pub state : ::enums::modifier_type::ModifierType,
    pub button : u32,
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64
}

impl Event for EventButton {}

#[allow(dead_code)]
pub struct EventTouch {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub axes : *mut f64,
    pub state : ::enums::modifier_type::ModifierType,
    sequence : *mut c_void, //::EventSequence
    pub emulating_pointer : i32, // boolean
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64
}

impl Event for EventTouch {}

#[allow(dead_code)]
pub struct EventScroll {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub state : ::enums::modifier_type::ModifierType,
    pub direction : ::ScrollDirection,
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64,
    pub delta_x : f64,
    pub delta_y : f64
}

impl Event for EventScroll {}

#[allow(dead_code)]
pub struct EventKey {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub state : ::enums::modifier_type::ModifierType,
    pub keyval : u32,
    pub length : i32,
    pub string : *mut char,
    pub hardware_keycode : u16,
    pub group : u8,
    pub is_modifier: u32
}

impl Event for EventKey {}

#[allow(dead_code)]
pub struct EventCrossing {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub subwindow : ::Window,
    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub x_root : f64,
    pub y_root : f64,
    pub mode : ::CrossingMode,
    pub detail : ::NotifyType,
    pub focus : i32, // boolean
    pub state : ::enums::modifier_type::ModifierType
}

impl Event for EventCrossing {}

#[allow(dead_code)]
pub struct EventFocus {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub _in : i16
}

impl Event for EventFocus {}

#[allow(dead_code)]
pub struct EventConfigure {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub x : i32,
    pub y : i32,
    pub width : i32,
    pub height : i32
}

impl Event for EventConfigure {}

#[allow(dead_code)]
pub struct EventProperty {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub atom : ::Atom,
    pub time : u32,
    pub state : u32 //FIXME
}

impl Event for EventProperty {}

#[allow(dead_code)]
pub struct EventSelection {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub selection : ::Atom,
    pub target : ::Atom,
    pub property : ::Atom,
    pub time : u32,
    requestor : *mut ::Window
}

impl Event for EventSelection {}

#[allow(dead_code)]
pub struct EventOwnerChange {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    owner : *mut ::Window,
    pub reason : ::OwnerChange,
    pub selection : ::Atom,
    pub time : u32,
    pub selection_time : u32
}

impl Event for EventOwnerChange {}

#[allow(dead_code)]
pub struct EventProximity {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    device : *mut ::Device
}

impl Event for EventProximity {}

#[allow(dead_code)]
pub struct EventSetting {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub action : ::SettingAction,
    pub name : *mut char
}

impl Event for EventSetting {}

#[allow(dead_code)]
pub struct EventWindowState {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub changed_mask : ::WindowState,
    pub new_window_state : ::WindowState
}

impl Event for EventWindowState {}

#[allow(dead_code)]
pub struct EventGrabBroken {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub keyboard : i32, // boolean
    pub implicit : i32, // boolean
    pub grab_window : *mut ::Window
}

impl Event for EventGrabBroken  {}

#[allow(dead_code)]
pub struct EventDND {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    context : *mut c_void, //::DragContext
    pub time : u32,
    pub x_root : i16, //short
    pub y_root : i16  //short
}

impl Event for EventDND  {}

//Supporting types

pub mod visibility_state {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum VisibilityState{
        VisibilityUnobscured,
        VisibilityPartial,
        VisibilityFullyObscured
    }
}

pub mod scroll_direction {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum ScrollDirection{
        ScrollUp,
        ScrollDown,
        ScrollLeft,
        ScrollRight,
        ScrollSmooth
    }
}

pub mod notify_type {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum NotifyType{
        NotifyAncestor   = 0,
        NotifyVirtual    = 1,
        NotifyInferior   = 2,
        NotifyNonlinear  = 3,
        NotifyNonlinearVirtual  = 4,
        NotifyUnknown    = 5
    }
}

pub mod crossing_mode {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum CrossingMode{
        CrossingNormal,
        CrossingGrab,
        CrossingUngrab,
        CrossingGtkGrab,
        CrossingGtkUngrab,
        CrossingStateChanged,
        CrossingTouchBegin,
        CrossingTouchEnd,
        CrossingDeviceSwitch
    }
}

pub mod property_state {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum PropertyState{
        PropertyNewValue,
        PropertyDelete
    }
}

pub mod setting_action {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum SettingAction{
        SettingActionNew,
        SettingActionChanged,
        SettingActionDeleted
    }
}

pub mod owner_change {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum OwnerChange{
        OwnerChangeNewOwner,
        OwnerChangeDestroy,
        OwnerChangeClose
    }
}
<commit_msg>Add TODO to events file<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use libc::c_void;
use std::mem;

pub use self::event_type::EventType;
pub use self::owner_change::OwnerChange;
pub use self::setting_action::SettingAction;
pub use self::property_state::PropertyState;
pub use self::crossing_mode::CrossingMode;
pub use self::notify_type::NotifyType;
pub use self::scroll_direction::ScrollDirection;
pub use self::visibility_state::VisibilityState;

pub mod event_type {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum EventType {
        Nothing           = -1,
        Delete            = 0,
        Destroy           = 1,
        Expose            = 2,
        MotionNotify      = 3,
        ButtonPress       = 4,
        DoubleButtonPress = 5,
        TripleButtonPress = 6,
        ButtonRelease     = 7,
        KeyPress          = 8,
        KeyRelease        = 9,
        EnterNotify       = 10,
        LeaveNotify       = 11,
        FocusChange       = 12,
        Configure         = 13,
        Map               = 14,
        Unmap             = 15,
        PropertyNotify    = 16,
        SelectionClear    = 17,
        SelectionRequest  = 18,
        SelectionNotify   = 19,
        ProximityIn       = 20,
        ProximityOut      = 21,
        DragEnter         = 22,
        DragLeave         = 23,
        DragMotion        = 24,
        DragStatus        = 25,
        DropStart         = 26,
        DropFinished      = 27,
        ClientEvent       = 28,
        VisibilityNotify  = 29,
        Scroll            = 31,
        WindowState       = 32,
        Setting           = 33,
        OwnerChange       = 34,
        GrabBroken        = 35,
        Damage            = 36,
        TouchBegin        = 37,
        TouchUpdate       = 38,
        TouchEnd          = 39,
        TouchCancel       = 40
    }
}

pub trait Event: Sized {
    fn get_send_event(&self) -> bool {
        unsafe {
            let event_any : &EventAny = mem::transmute(self);
            event_any.send_event == 0
        }
    }
}

// TODO unfinished, see #25

#[repr(C)]
pub struct EventAny {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,
}

impl Event for EventAny {}

#[allow(dead_code)]
pub struct EventExpose {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub area : ffi::C_GdkRectangle,
    region : *mut c_void, //TODO cairo_region_t
    pub count : i8 /* If non-zero, how many more events follow. */
}

impl Event for EventExpose {}

#[allow(dead_code)]
pub struct EventVisibility{
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub state : ::VisibilityState
}

impl Event for EventVisibility {}

#[allow(dead_code)]
pub struct EventMotion {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub axes : *mut f64,
    pub state : ::enums::modifier_type::ModifierType,
    pub is_hint : i16,
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64
}

impl Event for EventMotion {}

#[allow(dead_code)]
pub struct EventButton {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub axes : *mut f64,
    pub state : ::enums::modifier_type::ModifierType,
    pub button : u32,
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64
}

impl Event for EventButton {}

#[allow(dead_code)]
pub struct EventTouch {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub axes : *mut f64,
    pub state : ::enums::modifier_type::ModifierType,
    sequence : *mut c_void, //::EventSequence
    pub emulating_pointer : i32, // boolean
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64
}

impl Event for EventTouch {}

#[allow(dead_code)]
pub struct EventScroll {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub state : ::enums::modifier_type::ModifierType,
    pub direction : ::ScrollDirection,
    device : *mut ::Device,
    pub x_root : f64,
    pub y_root : f64,
    pub delta_x : f64,
    pub delta_y : f64
}

impl Event for EventScroll {}

#[allow(dead_code)]
pub struct EventKey {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    pub state : ::enums::modifier_type::ModifierType,
    pub keyval : u32,
    pub length : i32,
    pub string : *mut char,
    pub hardware_keycode : u16,
    pub group : u8,
    pub is_modifier: u32
}

impl Event for EventKey {}

#[allow(dead_code)]
pub struct EventCrossing {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub subwindow : ::Window,
    pub time : u32,
    pub x : f64,
    pub y : f64,
    pub x_root : f64,
    pub y_root : f64,
    pub mode : ::CrossingMode,
    pub detail : ::NotifyType,
    pub focus : i32, // boolean
    pub state : ::enums::modifier_type::ModifierType
}

impl Event for EventCrossing {}

#[allow(dead_code)]
pub struct EventFocus {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub _in : i16
}

impl Event for EventFocus {}

#[allow(dead_code)]
pub struct EventConfigure {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub x : i32,
    pub y : i32,
    pub width : i32,
    pub height : i32
}

impl Event for EventConfigure {}

#[allow(dead_code)]
pub struct EventProperty {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub atom : ::Atom,
    pub time : u32,
    pub state : u32 //FIXME
}

impl Event for EventProperty {}

#[allow(dead_code)]
pub struct EventSelection {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub selection : ::Atom,
    pub target : ::Atom,
    pub property : ::Atom,
    pub time : u32,
    requestor : *mut ::Window
}

impl Event for EventSelection {}

#[allow(dead_code)]
pub struct EventOwnerChange {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    owner : *mut ::Window,
    pub reason : ::OwnerChange,
    pub selection : ::Atom,
    pub time : u32,
    pub selection_time : u32
}

impl Event for EventOwnerChange {}

#[allow(dead_code)]
pub struct EventProximity {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub time : u32,
    device : *mut ::Device
}

impl Event for EventProximity {}

#[allow(dead_code)]
pub struct EventSetting {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub action : ::SettingAction,
    pub name : *mut char
}

impl Event for EventSetting {}

#[allow(dead_code)]
pub struct EventWindowState {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub changed_mask : ::WindowState,
    pub new_window_state : ::WindowState
}

impl Event for EventWindowState {}

#[allow(dead_code)]
pub struct EventGrabBroken {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    pub keyboard : i32, // boolean
    pub implicit : i32, // boolean
    pub grab_window : *mut ::Window
}

impl Event for EventGrabBroken  {}

#[allow(dead_code)]
pub struct EventDND {
    pub _type : ::EventType,
    pub window : *mut ::Window,
    send_event : i8,

    context : *mut c_void, //::DragContext
    pub time : u32,
    pub x_root : i16, //short
    pub y_root : i16  //short
}

impl Event for EventDND  {}

//Supporting types

pub mod visibility_state {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum VisibilityState{
        VisibilityUnobscured,
        VisibilityPartial,
        VisibilityFullyObscured
    }
}

pub mod scroll_direction {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum ScrollDirection{
        ScrollUp,
        ScrollDown,
        ScrollLeft,
        ScrollRight,
        ScrollSmooth
    }
}

pub mod notify_type {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum NotifyType{
        NotifyAncestor   = 0,
        NotifyVirtual    = 1,
        NotifyInferior   = 2,
        NotifyNonlinear  = 3,
        NotifyNonlinearVirtual  = 4,
        NotifyUnknown    = 5
    }
}

pub mod crossing_mode {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum CrossingMode{
        CrossingNormal,
        CrossingGrab,
        CrossingUngrab,
        CrossingGtkGrab,
        CrossingGtkUngrab,
        CrossingStateChanged,
        CrossingTouchBegin,
        CrossingTouchEnd,
        CrossingDeviceSwitch
    }
}

pub mod property_state {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum PropertyState{
        PropertyNewValue,
        PropertyDelete
    }
}

pub mod setting_action {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum SettingAction{
        SettingActionNew,
        SettingActionChanged,
        SettingActionDeleted
    }
}

pub mod owner_change {
    #[repr(C)]
    #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
    pub enum OwnerChange{
        OwnerChangeNewOwner,
        OwnerChangeDestroy,
        OwnerChangeClose
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json;

use std::io::prelude::*;
use std::fs::File;

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Chapter {
    title: String,
    files: Vec<String>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Part {
    title: String,
    chapters: Vec<Chapter>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Structure {
    title: String,
    author: String,
    license: String,
    parts: Vec<Part>
}

impl Structure {
    pub fn from_json(js: &str) -> Result<Structure, json::DecoderError> {
        json::decode::<Structure>(js)
    }

    pub fn get_title(&self) -> &str { &self.title }
}

#[derive(Clone, PartialEq)]
pub struct Content {
    chunks: Vec<String>
}

impl Content {
    fn build_title_page(st: &Structure) -> Result<String, String> {
        let book_header =
                r#"
"#.to_string() +
                &st.author +
                r#"
"# +
                r#"
"# +
                r#""# +
                &st.title +
                "
\n\n" +
                r#"
(C) "# +
                &st.author +
                " - " +
                &st.license +
                "
\n\n";
        Ok(book_header)
    }

    fn build_toc(st: &Structure) -> Result<String, String> {
        let mut toc = String::new();
        toc = toc + r#"
"# + "\n\n";
        let mut part_index = 1;
        for part in st.parts.iter() {
            let part_link = format!(
                "- **[{0} {1}](#kos_ref_part_{0})**\n\n", part_index, part.title);
            toc = toc + &part_link;
            let mut chap_index = 1;
            for chap in part.chapters.iter() {
                let chap_link = format!(
                    "   - *[{0}.{1} {2}](#kos_ref_chap_{0}_{1})*\n\n",
                    part_index, chap_index, chap.title);
                toc = toc + &chap_link;
                chap_index += 1;
            }
            part_index += 1;
        }
        toc = toc + "
\n\n";
        Ok(toc)
    }

    fn build_chunks(st: &Structure) -> Result<Vec<String>, String> {
        let mut chunks = Vec::new();
        // Book cover first...
        match Content::build_title_page(st) {
            Ok(tp) => { chunks.push(tp); },
            Err(e) => { return Err(e); }
        }
        // Then TOC...
        match Content::build_toc(st) {
            Ok(toc) => { chunks.push(toc); },
            Err(e) => { return Err(e); }
        }
        // Then parts and chapters.
        let mut part_index = 1;
        for part in st.parts.iter() {
            let part_header =
                r#"
"#.to_string() +
                r#""# +
                &part_index.to_string() +
                " " +
                &part.title +
                "
\n\n";
            chunks.push(part_header);
            let mut chap_index = 1;
            for chap in part.chapters.iter() {
                let chap_header =
                    r#"#  "# +
                    &part_index.to_string() +
                    "." +
                    &chap_index.to_string() +
                    " " +
                    &chap.title +
                    "\n\n";
                chunks.push(chap_header);
                for f in chap.files.iter() {
                    let file_content = match File::open(f) {
                        Ok(mut fread) => {
                            let mut res = String::new();
                            match fread.read_to_string(&mut res) {
                                Ok(_) => (),
                                Err(_) => {
                                    return Err(
                                        "Error reading file ".to_string() +
                                        f + "!\n");
                                }
                            }
                            res
                        },
                        Err(_) => {
                            return Err(
                                "Error reading file ".to_string() + f + "!\n");
                        }
                    };
                    chunks.push(file_content);
                }
                chap_index += 1;
            }
            part_index += 1;
        }
        Ok(chunks)
    }

    pub fn from_structure(st: &Structure) -> Result<Content, String> {
        let chunks = Content::build_chunks(st);
        Ok(Content {
            chunks: match chunks {
                Ok(c) => c,
                Err(e) => { return Err(e); }
            }
        })
    }

    pub fn to_single_string(&self) -> String {
        self.chunks.iter().fold(String::new(), |acc, x| {
            acc + "\n\n" + &x
        })
    }
}
<commit_msg>Changed my mind, no numbers in chapter titles.<commit_after>use rustc_serialize::json;

use std::io::prelude::*;
use std::fs::File;

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Chapter {
    title: String,
    files: Vec<String>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Part {
    title: String,
    chapters: Vec<Chapter>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Structure {
    title: String,
    author: String,
    license: String,
    parts: Vec<Part>
}

impl Structure {
    pub fn from_json(js: &str) -> Result<Structure, json::DecoderError> {
        json::decode::<Structure>(js)
    }

    pub fn get_title(&self) -> &str { &self.title }
}

#[derive(Clone, PartialEq)]
pub struct Content {
    chunks: Vec<String>
}

impl Content {
    fn build_title_page(st: &Structure) -> Result<String, String> {
        let book_header =
                r#"
"#.to_string() +
                &st.author +
                r#"
"# +
                r#"
"# +
                r#""# +
                &st.title +
                "
\n\n" +
                r#"
(C) "# +
                &st.author +
                " - " +
                &st.license +
                "
\n\n";
        Ok(book_header)
    }

    fn build_toc(st: &Structure) -> Result<String, String> {
        let mut toc = String::new();
        toc = toc + r#"
"# + "\n\n";
        let mut part_index = 1;
        for part in st.parts.iter() {
            let part_link = format!(
                "- **[{0} {1}](#kos_ref_part_{0})**\n\n", part_index, part.title);
            toc = toc + &part_link;
            let mut chap_index = 1;
            for chap in part.chapters.iter() {
                let chap_link = format!(
                    "   - *[{0}.{1} {2}](#kos_ref_chap_{0}_{1})*\n\n",
                    part_index, chap_index, chap.title);
                toc = toc + &chap_link;
                chap_index += 1;
            }
            part_index += 1;
        }
        toc = toc + "
\n\n";
        Ok(toc)
    }

    fn build_chunks(st: &Structure) -> Result<Vec<String>, String> {
        let mut chunks = Vec::new();
        // Book cover first...
        match Content::build_title_page(st) {
            Ok(tp) => { chunks.push(tp); },
            Err(e) => { return Err(e); }
        }
        // Then TOC...
        match Content::build_toc(st) {
            Ok(toc) => { chunks.push(toc); },
            Err(e) => { return Err(e); }
        }
        // Then parts and chapters.
        let mut part_index = 1;
        for part in st.parts.iter() {
            let part_header =
                r#"
"#.to_string() +
                r#""# +
                &part.title +
                "
\n\n";
            chunks.push(part_header);
            let mut chap_index = 1;
            for chap in part.chapters.iter() {
                let chap_header =
                    r#"#  "# +
                    &chap.title +
                    "\n\n";
                chunks.push(chap_header);
                for f in chap.files.iter() {
                    let file_content = match File::open(f) {
                        Ok(mut fread) => {
                            let mut res = String::new();
                            match fread.read_to_string(&mut res) {
                                Ok(_) => (),
                                Err(_) => {
                                    return Err(
                                        "Error reading file ".to_string() +
                                        f + "!\n");
                                }
                            }
                            res
                        },
                        Err(_) => {
                            return Err(
                                "Error reading file ".to_string() + f + "!\n");
                        }
                    };
                    chunks.push(file_content);
                }
                chap_index += 1;
            }
            part_index += 1;
        }
        Ok(chunks)
    }

    pub fn from_structure(st: &Structure) -> Result<Content, String> {
        let chunks = Content::build_chunks(st);
        Ok(Content {
            chunks: match chunks {
                Ok(c) => c,
                Err(e) => { return Err(e); }
            }
        })
    }

    pub fn to_single_string(&self) -> String {
        self.chunks.iter().fold(String::new(), |acc, x| {
            acc + "\n\n" + &x
        })
    }
}
<|endoftext|>


<commit_before>//! Handle colors and themes in the UI.
//!
//! # Color palette
//!
//! To achieve a customizable, yet unified look, Cursive uses a configurable
//! palette of colors to be used through the entire application.
//!
//! These colors are:
//!
//! * **`background`**: used to color the application background
//!   (around views).
//!   Defaults to **blue**.
//! * **`shadow`**: used to color shadow around views.
//!   Defaults to **black**.
//! * **`view`**: used to color the background for views.
//!   Defaults to **white**.
//! * **`primary`**: used to print primary text.
//!   Defaults to **black**.
//! * **`secondary`**: used to print secondary text.
//!   Defaults to **blue**.
//! * **`tertiary`**: used to print tertiary text.
//!   Defaults to **white**.
//! * **`title_primary`**: used to print primary titles.
//!   Defaults to **red**.
//! * **`title_secondary`**: used to print secondary titles.
//!   Defaults to **yellow**.
//! * **`highlight`**: used to highlight selected items.
//!   Defaults to **red**.
//! * **`highlight_inactive`**: used to highlight selected but inactive items.
//!   Defaults to **blue**.
//!
//! # Color Styles
//!
//! Each cell of the terminal uses two colors: *foreground* and *background*.
//!
//! Color styles are defined to easily refer to a pair of colors from the
//! palette.
//!
//! * **`Background`**: style used to print the application background.
//!     * Its *background* color is `background`.
//!     * Its *foreground* color is unimportant as no characters are ever
//!       printed in the background.
//! * **`Shadow`**: style used to print shadows behind views.
//!     * Its *background* color is `shadow`.
//!     * Here again, the *foreground* color is unimportant.
//! * **`Primary`**: style used to print primary text.
//!     * Its *background* color is `view`.
//!     * Its *foreground* color is `primary`.
//! * **`Secondary`**: style used to print secondary text.
//!     * Its *background* color is `view`.
//!     * Its *foreground* color is `secondary`.
//! * **`Tertiary`**: style used to print tertiary text.
//!     * Its *background* color is `view`.
//!     * Its *foreground* color is `tertiary`.
//! * **`TitlePrimary`**: style used to print titles.
//!     * Its *background* color is `view`.
//!     * Its *foreground* color is `title_primary`.
//! * **`TitleSecondary`**: style used to print secondary titles.
//!     * Its *background* color is `view`.
//!     * Its *foreground* color is `title_secondary`.
//! * **`Highlight`**: style used to print selected items.
//!     * Its *background* color is `highlight`.
//!     * Its *foreground* color is `view`.
//! * **`HighlightInactive`**: style used to print selected,
//!   but inactive items.
//!     * Its *background* color is `highlight_inactive`.
//!     * Its *foreground* color is `view`.
//!
//! Using one of these pairs when styling your application helps give it a
//! coherent look.
//!
//! # Effects
//!
//! On top of a color style, some effects can be applied on cells: `Reverse`,
//! for instance, swaps the foreground and background colors of a cell.
//!
//! # Themes
//!
//! A theme defines the color palette an application will use, as well as
//! various options to style views.
//!
//! Themes are described in toml configuration files. All fields are optional.
//!
//! Here are the possible entries:
//!
//! ```toml
//! # Every field in a theme file is optional.
//!
//! # First come some various options
//! shadow = false  # Don't draw shadows around stacked views
//! borders = "simple"  # Alternatives are "none" and "outset"
//!
//! # Here we define the color palette.
//! [colors]
//! 	background = "black"
//! 	# If the value is an array, the first valid color will be used.
//! 	# If the terminal doesn't support custom color,
//! 	# non-base colors will be skipped.
//! 	shadow     = ["#000000", "black"]
//! 	view       = "#d3d7cf"
//!
//! 	# Array and simple values have the same effect.
//! 	primary   = ["#111111"]
//! 	secondary = "#EEEEEE"
//! 	tertiary  = "#444444"
//!
//! 	# Hex values can use lower or uppercase.
//! 	# (base color MUST be lowercase)
//! 	title_primary   = "#ff5555"
//! 	title_secondary = "#ffff55"
//!
//! 	# Lower precision values can use only 3 digits.
//! 	highlight          = "#F00"
//! 	highlight_inactive = "#5555FF"
//! ```
mod style;
mod effect;
mod color;
mod color_pair;
mod color_style;
mod border_style;
mod palette;

pub use self::border_style::BorderStyle;
pub use self::color::{BaseColor, Color};
pub use self::color_pair::ColorPair;
pub use self::color_style::{ColorStyle, ColorType};
pub use self::effect::Effect;
pub use self::palette::{Palette, PaletteColor};
pub use self::style::Style;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use toml;

/// Represents the style a Cursive application will use.
#[derive(Clone, Debug)]
pub struct Theme {
    /// Whether views in a StackView should have shadows.
    pub shadow: bool,
    /// How view borders should be drawn.
    pub borders: BorderStyle,
    /// What colors should be used through the application?
    pub palette: Palette,
}

impl Default for Theme {
    fn default() -> Self {
        Theme {
            shadow: true,
            borders: BorderStyle::Simple,
            palette: Palette::default(),
        }
    }
}

impl Theme {
    fn load(&mut self, table: &toml::value::Table) {
        if let Some(&toml::Value::Boolean(shadow)) = table.get("shadow") {
            self.shadow = shadow;
        }

        if let Some(&toml::Value::String(ref borders)) = table.get("borders") {
            self.borders = BorderStyle::from(borders);
        }

        if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
            self.palette.load(table);
        }
    }
}

/// Possible error returned when loading a theme.
#[derive(Debug)]
pub enum Error {
    /// An error occured when reading the file.
    Io(io::Error),
    /// An error occured when parsing the toml content.
    Parse(toml::de::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Self {
        Error::Parse(err)
    }
}

/// Loads a theme from file and sets it as active.
pub fn load_theme_file<P: AsRef<Path>>(filename: P) -> Result<Theme, Error> {
    let content = {
        let mut content = String::new();
        let mut file = try!(File::open(filename));
        try!(file.read_to_string(&mut content));
        content
    };

    load_theme(&content)
}

/// Loads a theme string and sets it as active.
pub fn load_theme(content: &str) -> Result<Theme, Error> {
    let table = toml::de::from_str(content)?;

    let mut theme = Theme::default();
    theme.load(&table);

    Ok(theme)
}

/// Loads the default theme, and returns its representation.
pub fn load_default() -> Theme {
    Theme::default()
}
<commit_msg>Update doc for theme module<commit_after>//! Handle colors and themes in the UI.
//!
//! # Colors
//!
//! Characters can be printed in the terminal with a specific color.
//! The [`Color`] enum represents the ways this can be set.
//!
//! [`Color`]: enum.Color.html
//!
//! # Palette
//!
//! To achieve a customizable, yet unified look, Cursive uses a configurable
//! palette of colors to be used through the entire application.
//!
//! The [`PaletteColor`] enum defines possible entries in this palette.
//!
//! [`PaletteColor`]: enum.PaletteColor.html
//!
//! These entries are:
//!
//! * **`Background`**: used to color the application background
//!   (around views).
//!   Defaults to **blue**.
//! * **`Shadow`**: used to color shadow around views.
//!   Defaults to **black**.
//! * **`View`**: used to color the background for views.
//!   Defaults to **white**.
//! * **`Primary`**: used to print primary text.
//!   Defaults to **black**.
//! * **`Secondary`**: used to print secondary text.
//!   Defaults to **blue**.
//! * **`Tertiary`**: used to print tertiary text.
//!   Defaults to **white**.
//! * **`TitlePrimary`**: used to print primary titles.
//!   Defaults to **red**.
//! * **`TitleSecondary`**: used to print secondary titles.
//!   Defaults to **yellow**.
//! * **`Highlight`**: used to highlight selected items.
//!   Defaults to **red**.
//! * **`HighlightInactive`**: used to highlight selected but inactive items.
//!   Defaults to **blue**.
//!
//! A [`Palette`] then maps each of these to an actual [`Color`].
//!
//! [`Palette`]: struct.Palette.html
//! [`Color`]: enum.Color.html
//!
//! # Color Types
//!
//! When drawing views, color can be picked in two way:
//!
//! * An exact [`Color`] can be given directly
//! * A [`PaletteColor`] entry can be given, which will fetch whatever color
//!   is currently defined for this.
//!
//! The [`ColorType`] enum abstract over these two choices.
//!
//! [`ColorType`]: enum.ColorType.html
//!
//! # Color Styles
//!
//! To actually print anything, two colors must be picked: one for the
//! foreground, and one for the background.
//!
//! As such, a [`ColorStyle`] is made of a pair of `ColorType`.
//!
//! Since some pairs are frequently used, `ColorStyle` defines some methods to
//! create these usual values:
//!
//! * **`ColorStyle::background()`**: style used to print the application background.
//!     * Its *background* color is `Background`.
//!     * Its *foreground* color is unimportant as no characters are ever
//!       printed in the background.
//! * **`ColorStyle::shadow()`**: style used to print shadows behind views.
//!     * Its *background* color is `Shadow`.
//!     * Here again, the *foreground* color is unimportant.
//! * **`ColorStyle::primary()`**: style used to print primary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Primary`.
//! * **`ColorStyle::secondary()`**: style used to print secondary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Secondary`.
//! * **`ColorStyle::tertiary()`**: style used to print tertiary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Tertiary`.
//! * **`ColorStyle::title_primary()`**: style used to print titles.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `TitlePrimary`.
//! * **`ColorStyle::title_secondary()`**: style used to print secondary titles.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `TitleSecondary`.
//! * **`ColorStyle::highlight()`**: style used to print selected items.
//!     * Its *background* color is `Highlight`.
//!     * Its *foreground* color is `View`.
//! * **`ColorStyle::highlight_inactive()`**: style used to print selected,
//!   but inactive items.
//!     * Its *background* color is `HighlightInactive`.
//!     * Its *foreground* color is `View`.
//!
//! Using one of these pairs when styling your application helps give it a
//! coherent look.
//!
//! [`ColorStyle`]: struct.ColorStyle.html
//!
//! # Effects
//!
//! On top of a color style, some effects can be applied on cells: `Reverse`,
//! for instance, swaps the foreground and background colors of a cell.
//!
//! # Style
//!
//! Finally, a style combine a [`ColorType`] and a set of [`Effect`]s, to
//! represent any way text should be printed on screen.
//!
//! # Themes
//!
//! A theme defines the color palette an application will use, as well as
//! various options to style views.
//!
//! Themes are described in toml configuration files. All fields are optional.
//!
//! Here are the possible entries:
//!
//! ```toml
//! # Every field in a theme file is optional.
//!
//! # First come some various options
//! shadow = false  # Don't draw shadows around stacked views
//! borders = "simple"  # Alternatives are "none" and "outset"
//!
//! # Here we define the color palette.
//! [colors]
//! 	background = "black"
//! 	# If the value is an array, the first valid color will be used.
//! 	# If the terminal doesn't support custom color,
//! 	# non-base colors will be skipped.
//! 	shadow     = ["#000000", "black"]
//! 	view       = "#d3d7cf"
//!
//! 	# Array and simple values have the same effect.
//! 	primary   = ["#111111"]
//! 	secondary = "#EEEEEE"
//! 	tertiary  = "#444444"
//!
//! 	# Hex values can use lower or uppercase.
//! 	# (base color MUST be lowercase)
//! 	title_primary   = "#ff5555"
//! 	title_secondary = "#ffff55"
//!
//! 	# Lower precision values can use only 3 digits.
//! 	highlight          = "#F00"
//! 	highlight_inactive = "#5555FF"
//! ```
mod style;
mod effect;
mod color;
mod color_pair;
mod color_style;
mod border_style;
mod palette;

pub use self::border_style::BorderStyle;
pub use self::color::{BaseColor, Color};
pub use self::color_pair::ColorPair;
pub use self::color_style::{ColorStyle, ColorType};
pub use self::effect::Effect;
pub use self::palette::{Palette, PaletteColor};
pub use self::style::Style;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use toml;

/// Represents the style a Cursive application will use.
#[derive(Clone, Debug)]
pub struct Theme {
    /// Whether views in a StackView should have shadows.
    pub shadow: bool,
    /// How view borders should be drawn.
    pub borders: BorderStyle,
    /// What colors should be used through the application?
    pub palette: Palette,
}

impl Default for Theme {
    fn default() -> Self {
        Theme {
            shadow: true,
            borders: BorderStyle::Simple,
            palette: Palette::default(),
        }
    }
}

impl Theme {
    fn load(&mut self, table: &toml::value::Table) {
        if let Some(&toml::Value::Boolean(shadow)) = table.get("shadow") {
            self.shadow = shadow;
        }

        if let Some(&toml::Value::String(ref borders)) = table.get("borders") {
            self.borders = BorderStyle::from(borders);
        }

        if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
            self.palette.load(table);
        }
    }
}

/// Possible error returned when loading a theme.
#[derive(Debug)]
pub enum Error {
    /// An error occured when reading the file.
    Io(io::Error),
    /// An error occured when parsing the toml content.
    Parse(toml::de::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Self {
        Error::Parse(err)
    }
}

/// Loads a theme from file and sets it as active.
pub fn load_theme_file<P: AsRef<Path>>(filename: P) -> Result<Theme, Error> {
    let content = {
        let mut content = String::new();
        let mut file = try!(File::open(filename));
        try!(file.read_to_string(&mut content));
        content
    };

    load_theme(&content)
}

/// Loads a theme string and sets it as active.
pub fn load_theme(content: &str) -> Result<Theme, Error> {
    let table = toml::de::from_str(content)?;

    let mut theme = Theme::default();
    theme.load(&table);

    Ok(theme)
}

/// Loads the default theme, and returns its representation.
pub fn load_default() -> Theme {
    Theme::default()
}
<|endoftext|>


<commit_before>use Graph;

use std::hash::Hash;
use std::collections::VecDeque;
use std::collections::HashSet;

#[derive(Clone)]
pub struct BfsNode<N> {
    value: N,
    parent: usize,
}

pub fn breadth_first_search<F, G: Graph>(graph: &G, start: G::NodeId, mut apply: F)
    where F: FnMut(&[BfsNode<G::NodeId>]),
          G::NodeId: Clone + Hash + Eq,
{
    let mut visited = HashSet::new();
    let mut visit_order = vec![];
    let mut frontier = VecDeque::new();

    frontier.push_back(BfsNode { value: start, parent: 0 });
    while let Some(node) = frontier.pop_front() {
        let node_id = visit_order.len();
        visit_order.push(node.clone());
        apply(&visit_order);

        for target in graph.outgoing_edges(&node.value).map(|e| graph.target(&e)) {
            if visited.insert(target.clone()) {
                frontier.push_back(BfsNode { value: target, parent: node_id });
            }
        }

    }
}

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

    #[test]
    pub fn basic_test() {
        // [1] -> [2] -> [3] -> [4] -> [5]
        let mut graph = AdjacencyMap::new();

        graph.add_node(1, ());
        graph.add_node(2, ());
        graph.add_node(3, ());
        graph.add_node(4, ());
        graph.add_node(5, ());

        graph.add_arc(1, 2, 0);
        graph.add_arc(2, 3, 0);
        graph.add_arc(3, 4, 0);
        graph.add_arc(4, 5, 0);

        let mut index = 1;
        breadth_first_search(&&graph, 1, |visited| {
            assert!(visited.last().is_some());
            let last = visited.last().unwrap();
            assert_eq!(last.value, index);
            index += 1;
        });
    }
}
<commit_msg>Allow the traversal to exit early.<commit_after>use Graph;

use std::hash::Hash;
use std::collections::VecDeque;
use std::collections::HashSet;

#[derive(Clone)]
pub struct BfsNode<N> {
    value: N,
    parent: usize,
}

pub fn breadth_first_search<F, G: Graph>(graph: &G, start: G::NodeId, mut apply: F)
    where F: FnMut(&[BfsNode<G::NodeId>]) -> bool,
          G::NodeId: Clone + Hash + Eq,
{
    let mut visited = HashSet::new();
    let mut visit_order = vec![];
    let mut frontier = VecDeque::new();

    frontier.push_back(BfsNode { value: start, parent: 0 });
    while let Some(node) = frontier.pop_front() {
        let node_id = visit_order.len();
        visit_order.push(node.clone());

        if !apply(&visit_order) { return }

        for target in graph.outgoing_edges(&node.value).map(|e| graph.target(&e)) {
            if visited.insert(target.clone()) {
                frontier.push_back(BfsNode { value: target, parent: node_id });
            }
        }

    }
}

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

    #[test]
    pub fn basic_test() {
        // [1] -> [2] -> [3] -> [4] -> [5]
        let mut graph = AdjacencyMap::new();

        graph.add_node(1, ());
        graph.add_node(2, ());
        graph.add_node(3, ());
        graph.add_node(4, ());
        graph.add_node(5, ());

        graph.add_arc(1, 2, 0);
        graph.add_arc(2, 3, 0);
        graph.add_arc(3, 4, 0);
        graph.add_arc(4, 5, 0);

        let mut index = 1;
        breadth_first_search(&&graph, 1, |visited| {
            assert!(visited.last().is_some());
            let last = visited.last().unwrap();
            assert_eq!(last.value, index);
            index += 1;
            true
        });
    }
}
<|endoftext|>


<commit_before>
use BuildQuery;
use Groups;

// https://docs.gitlab.com/ce/api/groups.html
// List groups:                 GET /groups
// List owned groups:           GET /groups/owned
// List a group's projects:     GET /groups/:id/projects
// Details of a group:          GET /groups/:id
// New group:                   POST /groups
// Transfer project to group:   POST  /groups/:id/projects/:project_id
// Update group:                PUT /groups/:id
// Remove group:                DELETE /groups/:id
// Search for group:            GET /groups?search=foobar

// https://docs.gitlab.com/ce/api/groups.html#list-groups

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Name,
    Path,
}

// impl Default for ListingOrderBy {
//     fn default() -> ListingOrderBy { ListingOrderBy::Name }
// }

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

// impl Default for ListingSort {
//     fn default() -> ListingSort { ListingSort::Asc }
// }

fn append_group_lister_options_order_by(order_by: ListingOrderBy, s: &mut String) {
    s.push_str(match order_by {
        ListingOrderBy::Name => "name",
        ListingOrderBy::Path => "path",
    });
}

fn append_group_lister_options_sort(order_by: ListingSort, s: &mut String) {
    s.push_str(match order_by {
        ListingSort::Asc => "asc",
        ListingSort::Desc => "desc",
    });
}

/// https://docs.gitlab.com/ce/api/groups.html#list-groups
#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Skip the group IDs passes
    skip_groups: Vec<i64>,
    /// Show all the groups you have access to
    all_available: Option<bool>,
    /// Return list of authorized groups matching the search criteria
    search: String,
    /// Order groups by `name` or `path`. Default is `name`
    order_by: Option<ListingOrderBy>,
    /// Order groups in `asc` or `desc` order. Default is `asc`
    sort: Option<ListingSort>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn skip_groups(&mut self, skip_groups: Vec<i64>) -> &mut Listing {
        self.skip_groups = skip_groups;
        self
    }
    pub fn all_available(&mut self, all_available: bool) -> &mut Listing {
        self.all_available = Some(all_available);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("groups");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?", only if one of the `Option` is `Some(_)`
        query.push_str(match (self.skip_groups.is_empty(),
                              &self.all_available,
                              self.search.is_empty(),
                              &self.order_by,
                              &self.sort) {
            (true, &None, true, &None, &None) => "",
            _ => "?",
        });

        if !self.skip_groups.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            let mut array_split_char = &none_char;
            for skip_group in &self.skip_groups {
                query.push_str(array_split_char);
                query.push_str("skip_groups[]=");
                query.push_str(&skip_group.to_string());
                array_split_char = &amp_char;
            }
        }

        self.all_available.map(|all_available| {
            query.push_str(&split_char);
            split_char = &amp_char;

            if all_available {
                query.push_str("all_available=true")
            } else {
                query.push_str("all_available=false")
            }
        });

        if !self.search.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.order_by.map(|order_by| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            append_group_lister_options_order_by(order_by, &mut query);
        });

        self.sort.map(|sort| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            append_group_lister_options_sort(sort, &mut query);
        });

        query
    }
}

#[test]
fn test_append_group_lister_options_order_by() {
    let expected_string = "Initialnamepathpathname";

    let mut s = String::from("Initial");

    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn test_append_group_lister_options_sort() {
    let expected_string = "Initialascdescascdesc";

    let mut s = String::from("Initial");

    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);
    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn groups_build_query_default() {
    let expected_string = "groups";
    let listing: Listing = Default::default();
    let query = listing.build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups";
    let listing = Listing::new();
    let query = listing.build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_skip_groups() {
    let expected_string = "groups?skip_groups[]=1&skip_groups[]=2&skip_groups[]=3";
    let query = Listing::new().skip_groups(vec![1,2,3]).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_all_available() {
    let expected_string = "groups?all_available=true";
    let query = Listing::new().all_available(true).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?all_available=false";
    let query = Listing::new().all_available(false).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search() {
    let expected_string = "groups?search=SearchPattern";
    let query = Listing::new().search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_name() {
    let expected_string = "groups?order_by=name";
    let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_path() {
    let expected_string = "groups?order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_sort() {
    let expected_string = "groups?sort=asc";
    let query = Listing::new().sort(ListingSort::Asc).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?sort=desc";
    let query = Listing::new().sort(ListingSort::Desc).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search_order_by_path() {
    let expected_string = "groups?search=SearchPattern&order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
    let query = Listing::new().search(String::from("SearchPattern")).order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}
<commit_msg>Cleanup: No need to impl Default<commit_after>
use BuildQuery;
use Groups;

// https://docs.gitlab.com/ce/api/groups.html
// List groups:                 GET /groups
// List owned groups:           GET /groups/owned
// List a group's projects:     GET /groups/:id/projects
// Details of a group:          GET /groups/:id
// New group:                   POST /groups
// Transfer project to group:   POST  /groups/:id/projects/:project_id
// Update group:                PUT /groups/:id
// Remove group:                DELETE /groups/:id
// Search for group:            GET /groups?search=foobar

// https://docs.gitlab.com/ce/api/groups.html#list-groups

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Name,
    Path,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

fn append_group_lister_options_order_by(order_by: ListingOrderBy, s: &mut String) {
    s.push_str(match order_by {
        ListingOrderBy::Name => "name",
        ListingOrderBy::Path => "path",
    });
}

fn append_group_lister_options_sort(order_by: ListingSort, s: &mut String) {
    s.push_str(match order_by {
        ListingSort::Asc => "asc",
        ListingSort::Desc => "desc",
    });
}

/// https://docs.gitlab.com/ce/api/groups.html#list-groups
#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Skip the group IDs passes
    skip_groups: Vec<i64>,
    /// Show all the groups you have access to
    all_available: Option<bool>,
    /// Return list of authorized groups matching the search criteria
    search: String,
    /// Order groups by `name` or `path`. Default is `name`
    order_by: Option<ListingOrderBy>,
    /// Order groups in `asc` or `desc` order. Default is `asc`
    sort: Option<ListingSort>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn skip_groups(&mut self, skip_groups: Vec<i64>) -> &mut Listing {
        self.skip_groups = skip_groups;
        self
    }
    pub fn all_available(&mut self, all_available: bool) -> &mut Listing {
        self.all_available = Some(all_available);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("groups");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?", only if one of the `Option` is `Some(_)`
        query.push_str(match (self.skip_groups.is_empty(),
                              &self.all_available,
                              self.search.is_empty(),
                              &self.order_by,
                              &self.sort) {
            (true, &None, true, &None, &None) => "",
            _ => "?",
        });

        if !self.skip_groups.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            let mut array_split_char = &none_char;
            for skip_group in &self.skip_groups {
                query.push_str(array_split_char);
                query.push_str("skip_groups[]=");
                query.push_str(&skip_group.to_string());
                array_split_char = &amp_char;
            }
        }

        self.all_available.map(|all_available| {
            query.push_str(&split_char);
            split_char = &amp_char;

            if all_available {
                query.push_str("all_available=true")
            } else {
                query.push_str("all_available=false")
            }
        });

        if !self.search.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.order_by.map(|order_by| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            append_group_lister_options_order_by(order_by, &mut query);
        });

        self.sort.map(|sort| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            append_group_lister_options_sort(sort, &mut query);
        });

        query
    }
}

#[test]
fn test_append_group_lister_options_order_by() {
    let expected_string = "Initialnamepathpathname";

    let mut s = String::from("Initial");

    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn test_append_group_lister_options_sort() {
    let expected_string = "Initialascdescascdesc";

    let mut s = String::from("Initial");

    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);
    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn groups_build_query_default() {
    let expected_string = "groups";
    let listing: Listing = Default::default();
    let query = listing.build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups";
    let listing = Listing::new();
    let query = listing.build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_skip_groups() {
    let expected_string = "groups?skip_groups[]=1&skip_groups[]=2&skip_groups[]=3";
    let query = Listing::new().skip_groups(vec![1,2,3]).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_all_available() {
    let expected_string = "groups?all_available=true";
    let query = Listing::new().all_available(true).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?all_available=false";
    let query = Listing::new().all_available(false).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search() {
    let expected_string = "groups?search=SearchPattern";
    let query = Listing::new().search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_name() {
    let expected_string = "groups?order_by=name";
    let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_path() {
    let expected_string = "groups?order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_sort() {
    let expected_string = "groups?sort=asc";
    let query = Listing::new().sort(ListingSort::Asc).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?sort=desc";
    let query = Listing::new().sort(ListingSort::Desc).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search_order_by_path() {
    let expected_string = "groups?search=SearchPattern&order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
    let query = Listing::new().search(String::from("SearchPattern")).order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

//! Helper functions allowing you to avoid writing boilerplate code for common operations, such as
//! parsing JSON or reading files.

// Copyright (c) 2016 Google Inc (lewinb@google.com).
//
// Refer to the project root for licensing information.

use serde_json;
use std::io;
use std::fs;

use types::ApplicationSecret;

pub fn read_application_secret(file: &String) -> io::Result<ApplicationSecret> {
    use std::io::Read;

    let mut secret = String::new();
    let mut file = try!(fs::OpenOptions::new().read(true).open(file));
    try!(file.read_to_string(&mut secret));

    parse_application_secret(&secret)
}

pub fn parse_application_secret(secret: &String) -> io::Result<ApplicationSecret> {
    match serde_json::from_str(secret) {
        Err(e) => {
            Err(io::Error::new(io::ErrorKind::InvalidData,
                               format!("Bad application secret: {}", e)))
        }
        Ok(decoded) => Ok(decoded),
    }
}
<commit_msg>fix(helper): Parse app secrets into right type<commit_after>#![allow(dead_code)]

//! Helper functions allowing you to avoid writing boilerplate code for common operations, such as
//! parsing JSON or reading files.

// Copyright (c) 2016 Google Inc (lewinb@google.com).
//
// Refer to the project root for licensing information.

use serde_json;
use std::io;
use std::fs;

use types::{ConsoleApplicationSecret, ApplicationSecret};

pub fn read_application_secret(file: &String) -> io::Result<ApplicationSecret> {
    use std::io::Read;

    let mut secret = String::new();
    let mut file = try!(fs::OpenOptions::new().read(true).open(file));
    try!(file.read_to_string(&mut secret));

    parse_application_secret(&secret)
}

pub fn parse_application_secret(secret: &String) -> io::Result<ApplicationSecret> {
    let result: serde_json::Result<ConsoleApplicationSecret> = serde_json::from_str(secret);
    match result {
        Err(e) => {
            Err(io::Error::new(io::ErrorKind::InvalidData,
                               format!("Bad application secret: {}", e)))
        }
        Ok(decoded) => {
            if decoded.web.is_some() {
                Ok(decoded.web.unwrap())
            } else if decoded.installed.is_some() {
                Ok(decoded.installed.unwrap())
            } else {
                Err(io::Error::new(io::ErrorKind::InvalidData,
                                   "Unknown application secret format"))
            }
        }
    }
}
<|endoftext|>