<commit_before>//! # System MenuBar Sample
//!
//! This sample demonstrates how to create a "system" menu bar. It should always be preferred
//! over the `gtk::MenuBar` since it adapts to the targetted system.

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::{AboutDialog, ToVariant};

use std::env::args;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn build_system_menu(application: &gtk::Application) {
    let menu = gio::Menu::new();
    let menu_bar = gio::Menu::new();
    let more_menu = gio::Menu::new();
    let switch_menu = gio::Menu::new();
    let settings_menu = gio::Menu::new();
    let submenu = gio::Menu::new();

    // The first argument is the label of the menu item whereas the second is the action name. It'll
    // makes more sense when you'll be reading the "add_actions" function.
    menu.append(Some("Quit"), Some("app.quit"));

    switch_menu.append(Some("Switch"), Some("app.switch"));
    menu_bar.append_submenu(Some("_Switch"), &switch_menu);

    settings_menu.append(Some("Sub another"), Some("app.sub_another"));
    submenu.append(Some("Sub sub another"), Some("app.sub_sub_another"));
    submenu.append(Some("Sub sub another2"), Some("app.sub_sub_another2"));
    settings_menu.append_submenu(Some("Sub menu"), &submenu);
    menu_bar.append_submenu(Some("_Another"), &settings_menu);

    more_menu.append(Some("About"), Some("app.about"));
    menu_bar.append_submenu(Some("?"), &more_menu);

    application.set_app_menu(Some(&menu));
    application.set_menubar(Some(&menu_bar));
}

// This function creates "actions" which connect on the declared actions from the menu items.
fn add_actions(
    application: &gtk::Application,
    switch: &gtk::Switch,
    label: &gtk::Label,
    window: &gtk::ApplicationWindow,
) {
    // Thanks to this method, we can say that this item is actually a checkbox.
    let switch_action = gio::SimpleAction::new_stateful("switch", None, &false.to_variant());
    switch_action.connect_activate(clone!(switch => move |g, _| {
        let mut is_active = false;
        if let Some(g) = g.get_state() {
            is_active = g.get().expect("couldn't get bool");
            // We update the state of the toggle.
            switch.set_active(!is_active);
        }
        // We need to change the toggle state ourselves. `gio` dark magic.
        g.change_state(&(!is_active).to_variant());
    }));

    // The same goes the around way: if we update the switch state, we need to update the menu
    // item's state.
    switch.connect_property_active_notify(clone!(switch_action => move |s| {
        switch_action.change_state(&s.get_active().to_variant());
    }));

    let sub_another = gio::SimpleAction::new("sub_another", None);
    sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub another menu item clicked");
    }));
    let sub_sub_another = gio::SimpleAction::new("sub_sub_another", None);
    sub_sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another menu item clicked");
    }));
    let sub_sub_another2 = gio::SimpleAction::new("sub_sub_another2", None);
    sub_sub_another2.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another2 menu item clicked");
    }));

    let quit = gio::SimpleAction::new("quit", None);
    quit.connect_activate(clone!(window => move |_, _| {
        window.destroy();
    }));

    let about = gio::SimpleAction::new("about", None);
    about.connect_activate(clone!(window => move |_, _| {
        let p = AboutDialog::new();
        p.set_authors(&["gtk-rs developers"]);
        p.set_website_label(Some("gtk-rs"));
        p.set_website(Some("http://gtk-rs.org"));
        p.set_authors(&["Gtk-rs developers"]);
        p.set_title("About!");
        p.set_transient_for(Some(&window));
        p.run();
        p.destroy();
    }));

    // We need to add all the actions to the application so they can be taken into account.
    application.add_action(&about);
    application.add_action(&quit);
    application.add_action(&sub_another);
    application.add_action(&sub_sub_another);
    application.add_action(&sub_sub_another2);
    application.add_action(&switch_action);
}

fn add_accelerators(application: &gtk::Application) {
    application.set_accels_for_action("app.about", &["F1"]);
    // `Primary` is a platform-agnostic accelerator modifier.
    // On Windows and Linux, `Primary` maps to the `Ctrl` key,
    // and on macOS it maps to the `command` key.
    application.set_accels_for_action("app.quit", &["<Primary>Q"]);
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("System menu bar");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(350, 70);

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 10);
    let label = gtk::Label::new(Some("Nothing happened yet"));
    let switch = gtk::Switch::new();

    v_box.pack_start(&label, false, false, 0);
    v_box.pack_start(&switch, true, true, 0);
    window.add(&v_box);

    build_system_menu(application);

    add_actions(application, &switch, &label, &window);

    window.show_all();
}

fn main() {
    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.menu_bar_system"),
        Default::default(),
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
        add_accelerators(app);
    });
    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<commit_msg>Update menu_bar_system.rs<commit_after>//! # System MenuBar Sample
//!
//! This sample demonstrates how to create a "system" menu bar. It should always be preferred
//! over the `gtk::MenuBar` since it adapts to the targetted system.

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::{AboutDialog, ToVariant};

use std::env::args;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn build_system_menu(application: &gtk::Application) {
    let menu = gio::Menu::new();
    let menu_bar = gio::Menu::new();
    let more_menu = gio::Menu::new();
    let switch_menu = gio::Menu::new();
    let settings_menu = gio::Menu::new();
    let submenu = gio::Menu::new();

    // The first argument is the label of the menu item whereas the second is the action name. It'll
    // makes more sense when you'll be reading the "add_actions" function.
    menu.append(Some("Quit"), Some("app.quit"));

    switch_menu.append(Some("Switch"), Some("app.switch"));
    menu_bar.append_submenu(Some("_Switch"), &switch_menu);

    settings_menu.append(Some("Sub another"), Some("app.sub_another"));
    submenu.append(Some("Sub sub another"), Some("app.sub_sub_another"));
    submenu.append(Some("Sub sub another2"), Some("app.sub_sub_another2"));
    settings_menu.append_submenu(Some("Sub menu"), &submenu);
    menu_bar.append_submenu(Some("_Another"), &settings_menu);

    more_menu.append(Some("About"), Some("app.about"));
    menu_bar.append_submenu(Some("?"), &more_menu);

    application.set_app_menu(Some(&menu));
    application.set_menubar(Some(&menu_bar));
}

/// This function creates "actions" which connect on the declared actions from the menu items.
fn add_actions(
    application: &gtk::Application,
    switch: &gtk::Switch,
    label: &gtk::Label,
    window: &gtk::ApplicationWindow,
) {
    // Thanks to this method, we can say that this item is actually a checkbox.
    let switch_action = gio::SimpleAction::new_stateful("switch", None, &false.to_variant());
    switch_action.connect_activate(clone!(switch => move |g, _| {
        let mut is_active = false;
        if let Some(g) = g.get_state() {
            is_active = g.get().expect("couldn't get bool");
            // We update the state of the toggle.
            switch.set_active(!is_active);
        }
        // We need to change the toggle state ourselves. `gio` dark magic.
        g.change_state(&(!is_active).to_variant());
    }));

    // The same goes the around way: if we update the switch state, we need to update the menu
    // item's state.
    switch.connect_property_active_notify(clone!(switch_action => move |s| {
        switch_action.change_state(&s.get_active().to_variant());
    }));

    let sub_another = gio::SimpleAction::new("sub_another", None);
    sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub another menu item clicked");
    }));
    let sub_sub_another = gio::SimpleAction::new("sub_sub_another", None);
    sub_sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another menu item clicked");
    }));
    let sub_sub_another2 = gio::SimpleAction::new("sub_sub_another2", None);
    sub_sub_another2.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another2 menu item clicked");
    }));

    let quit = gio::SimpleAction::new("quit", None);
    quit.connect_activate(clone!(window => move |_, _| {
        window.destroy();
    }));

    let about = gio::SimpleAction::new("about", None);
    about.connect_activate(clone!(window => move |_, _| {
        let p = AboutDialog::new();
        p.set_website_label(Some("gtk-rs"));
        p.set_website(Some("http://gtk-rs.org"));
        p.set_authors(&["Gtk-rs developers"]);
        p.set_title("About!");
        p.set_transient_for(Some(&window));
        p.run();
        p.destroy();
    }));

    // We need to add all the actions to the application so they can be taken into account.
    application.add_action(&about);
    application.add_action(&quit);
    application.add_action(&sub_another);
    application.add_action(&sub_sub_another);
    application.add_action(&sub_sub_another2);
    application.add_action(&switch_action);
}

fn add_accelerators(application: &gtk::Application) {
    application.set_accels_for_action("app.about", &["F1"]);
    // `Primary` is a platform-agnostic accelerator modifier.
    // On Windows and Linux, `Primary` maps to the `Ctrl` key,
    // and on macOS it maps to the `command` key.
    application.set_accels_for_action("app.quit", &["<Primary>Q"]);
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("System menu bar");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(350, 70);

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 10);
    let label = gtk::Label::new(Some("Nothing happened yet"));
    let switch = gtk::Switch::new();

    v_box.pack_start(&label, false, false, 0);
    v_box.pack_start(&switch, true, true, 0);
    window.add(&v_box);

    build_system_menu(application);

    add_actions(application, &switch, &label, &window);

    window.show_all();
}

fn main() {
    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.menu_bar_system"),
        Default::default(),
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
        add_accelerators(app);
    });
    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before>// Transfer all crates from one user to another.
//
// Usage:
//      cargo run --bin transfer-crates from-user to-user

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{
    db,
    models::{Crate, OwnerKind, User},
    schema::{crate_owners, crates, users},
};
use std::{
    env,
    io::{self, prelude::*},
    process::exit,
};

use diesel::prelude::*;

fn main() {
    let conn = db::connect_now().unwrap();
    conn.transaction::<_, diesel::result::Error, _>(|| {
        transfer(&conn);
        Ok(())
    })
    .unwrap()
}

fn transfer(conn: &PgConnection) {
    let from = match env::args().nth(1) {
        None => {
            println!("needs a from-user argument");
            return;
        }
        Some(s) => s,
    };
    let to = match env::args().nth(2) {
        None => {
            println!("needs a to-user argument");
            return;
        }
        Some(s) => s,
    };

    let from: User = users::table
        .filter(users::gh_login.eq(from))
        .first(conn)
        .unwrap();
    let to: User = users::table
        .filter(users::gh_login.eq(to))
        .first(conn)
        .unwrap();

    if from.gh_id != to.gh_id {
        println!("====================================================");
        println!("WARNING");
        println!();
        println!("this may not be the same github user, different github IDs");
        println!();
        println!("from: {:?}", from.gh_id);
        println!("to:   {:?}", to.gh_id);

        get_confirm("continue?");
    }

    println!(
        "Are you sure you want to transfer crates from {} to {}",
        from.gh_login, to.gh_login
    );
    get_confirm("continue");

    let crate_owners = crate_owners::table
        .filter(crate_owners::owner_id.eq(from.id))
        .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32));
    let crates: Vec<Crate> = Crate::all()
        .filter(crates::id.eq_any(crate_owners.select(crate_owners::crate_id)))
        .load(conn)
        .unwrap();

    for krate in crates {
        let owners = krate.owners(conn).unwrap();
        if owners.len() != 1 {
            println!("warning: not exactly one owner for {}", krate.name);
        }
    }

    diesel::update(crate_owners)
        .set(crate_owners::owner_id.eq(to.id))
        .execute(conn)
        .unwrap();

    get_confirm("commit?");
}

fn get_confirm(msg: &str) {
    print!("{} [y/N]: ", msg);
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with('y') {
        exit(0);
    }
}
<commit_msg>bin/transfer-crates: Use `clap` for CLI argument parsing<commit_after>#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{
    db,
    models::{Crate, OwnerKind, User},
    schema::{crate_owners, crates, users},
};
use std::{
    io::{self, prelude::*},
    process::exit,
};

use clap::Clap;
use diesel::prelude::*;

#[derive(Clap, Debug)]
#[clap(
    name = "transfer-crates",
    about = "Transfer all crates from one user to another."
)]
struct Opts {
    /// GitHub login of the "from" user
    from_user: String,
    /// GitHub login of the "to" user
    to_user: String,
}

fn main() {
    let conn = db::connect_now().unwrap();
    conn.transaction::<_, diesel::result::Error, _>(|| {
        transfer(&conn);
        Ok(())
    })
    .unwrap()
}

fn transfer(conn: &PgConnection) {
    let opts: Opts = Opts::parse();

    let from: User = users::table
        .filter(users::gh_login.eq(opts.from_user))
        .first(conn)
        .unwrap();

    let to: User = users::table
        .filter(users::gh_login.eq(opts.to_user))
        .first(conn)
        .unwrap();

    if from.gh_id != to.gh_id {
        println!("====================================================");
        println!("WARNING");
        println!();
        println!("this may not be the same github user, different github IDs");
        println!();
        println!("from: {:?}", from.gh_id);
        println!("to:   {:?}", to.gh_id);

        get_confirm("continue?");
    }

    println!(
        "Are you sure you want to transfer crates from {} to {}",
        from.gh_login, to.gh_login
    );
    get_confirm("continue");

    let crate_owners = crate_owners::table
        .filter(crate_owners::owner_id.eq(from.id))
        .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32));
    let crates: Vec<Crate> = Crate::all()
        .filter(crates::id.eq_any(crate_owners.select(crate_owners::crate_id)))
        .load(conn)
        .unwrap();

    for krate in crates {
        let owners = krate.owners(conn).unwrap();
        if owners.len() != 1 {
            println!("warning: not exactly one owner for {}", krate.name);
        }
    }

    diesel::update(crate_owners)
        .set(crate_owners::owner_id.eq(to.id))
        .execute(conn)
        .unwrap();

    get_confirm("commit?");
}

fn get_confirm(msg: &str) {
    print!("{} [y/N]: ", msg);
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with('y') {
        exit(0);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::path::PathBuf;

use git2;
use regex::Regex;

use prelude::*;
use api::{Repo, Ref};

#[derive(Copy, Clone)]
pub enum GitReference<'a> {
    Commit(git2::Oid),
    Symbolic(&'a str),
}

impl<'a> fmt::Display for GitReference<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GitReference::Commit(ref c) => write!(f, "{}", c),
            GitReference::Symbolic(ref s) => write!(f, "{}", s),
        }
    }
}

#[derive(Debug)]
pub struct CommitSpec {
    pub repo: String,
    pub path: Option<PathBuf>,
    pub rev: String,
    pub prev_rev: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct VcsUrl {
    pub provider: &'static str,
    pub id: String,
}

fn parse_rev_range(rng: &str) -> (Option<String>, String) {
    if rng == "" {
        return (None, "HEAD".into());
    }
    let mut iter = rng.rsplitn(2, "..");
    let rev = iter.next().unwrap_or("HEAD");
    (iter.next().map(|x| x.to_string()), rev.to_string())
}

impl CommitSpec {
    pub fn parse(s: &str) -> Result<CommitSpec> {
        lazy_static! {
            static ref SPEC_RE: Regex = Regex::new(
                r"^([^@#]+)(?:#([^@]+))?(?:@(.+))?$").unwrap();
        }
        if let Some(caps) = SPEC_RE.captures(s) {
            let (prev_rev, rev) = parse_rev_range(caps.get(3).map(|x| x.as_str()).unwrap_or(""));
            Ok(CommitSpec {
                repo: caps[1].to_string(),
                path: caps.get(2).map(|x| PathBuf::from(x.as_str())),
                rev: rev,
                prev_rev: prev_rev,
            })
        } else {
            Err(Error::from(format!("Could not parse commit spec '{}'", s)))
        }
    }

    pub fn reference<'a>(&'a self) -> GitReference<'a> {
        if let Ok(oid) = git2::Oid::from_str(&self.rev) {
            GitReference::Commit(oid)
        } else {
            GitReference::Symbolic(&self.rev)
        }
    }

    pub fn prev_reference<'a>(&'a self) -> Option<GitReference<'a>> {
        self.prev_rev.as_ref().map(|rev| {
            if let Ok(oid) = git2::Oid::from_str(rev) {
                GitReference::Commit(oid)
            } else {
                GitReference::Symbolic(rev)
            }
        })
    }
}

fn strip_git_suffix(s: &str) -> &str {
    if s.ends_with(".git") {
        &s[0..s.len() - 4]
    } else {
        s
    }
}

impl VcsUrl {
    pub fn parse(url: &str) -> VcsUrl {
        lazy_static! {
            static ref GITHUB_URL_RE: Regex = Regex::new(
                r"^(?:ssh|https?)://(?:[^@]+@)?github.com/([^/]+)/([^/]+)").unwrap();
            static ref GITHUB_SSH_RE: Regex = Regex::new(
                r"^(?:[^@]+@)?github.com:([^/]+)/([^/]+)").unwrap();
        }
        if let Some(caps) = GITHUB_URL_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else if let Some(caps) = GITHUB_SSH_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else {
            VcsUrl {
                provider: "generic",
                id: url.into(),
            }
        }
    }
}

fn is_matching_url(a: &str, b: &str) -> bool {
    VcsUrl::parse(a) == VcsUrl::parse(b)
}

fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<String> {
    for configured_repo in repos {
        if configured_repo.name != repo {
            continue;
        }
        if &configured_repo.provider.id != "github" &&
           &configured_repo.provider.id != "git" {
            return Err(Error::from("For non git repositories \
                                   explicit revisions are required"));
        }

        return Ok(configured_repo.url.clone())
    }

    Err(Error::from(format!("Could not find matching repository for {}", repo)))
}

fn find_matching_rev(reference: GitReference, spec: &CommitSpec,
                     repos: &[Repo], disable_discovery: bool)
    -> Result<Option<String>>
{
    let r = match reference {
        GitReference::Commit(commit) => {
            return Ok(Some(commit.to_string()));
        }
        GitReference::Symbolic(r) => r,
    };

    let (repo, discovery) = if let Some(ref path) = spec.path {
        (git2::Repository::open(path)?, false)
    } else {
        (git2::Repository::open_from_env()?, !disable_discovery)
    };

    let reference_url = find_reference_url(&spec.repo, repos)?;

    // direct reference in root repository found.  If we are in discovery
    // mode we want to also check for matching URLs.
    if_chain! {
        if let Ok(remote) = repo.find_remote("origin");
        if let Some(url) = remote.url();
        if !discovery || is_matching_url(url, &reference_url);
        then {
            let head = repo.revparse_single(r)?;
            return Ok(Some(head.id().to_string()));
        }
    }

    // in discovery mode we want to find that repo in associated submodules.
    for submodule in repo.submodules()? {
        if_chain! {
            if let Some(submodule_url) = submodule.url();
            if is_matching_url(submodule_url, &reference_url);
            then {
                // heads on submodules is easier so let's start with that
                // because that does not require the submodule to be
                // checked out.
                if_chain! {
                    if r == "HEAD";
                    if let Some(head_oid) = submodule.head_id();
                    then {
                        return Ok(Some(head_oid.to_string()));
                    }
                }

                // otherwise we need to open the submodule which requires
                // it to be checked out.
                if_chain! {
                    if let Ok(subrepo) = submodule.open();
                    then {
                        let head = subrepo.revparse_single(r)?;
                        return Ok(Some(head.id().to_string()));
                    }
                }
            }
        }
    }

    Ok(None)
}

fn find_matching_revs(spec: &CommitSpec, repos: &[Repo], disable_discovery: bool)
    -> Result<(Option<String>, String)>
{
    fn error(r: GitReference, repo: &str) -> Error {
        Error::from(format!(
            "Could not find commit '{}' for '{}'. If you do not have local \
             checkouts of the repositories in question referencing tags or \
             other references will not work and you need to refer to \
             revisions explicitly.",
            r, repo))
    }

    let rev = if let Some(rev) = find_matching_rev(
        spec.reference(), &spec, &repos[..], disable_discovery)? {
        rev
    } else {
        return Err(error(spec.reference(), &spec.repo));
    };

    let prev_rev = if let Some(rev) = spec.prev_reference() {
        if let Some(rv) = find_matching_rev(
            rev, &spec, &repos[..], disable_discovery)? {
            Some(rv)
        } else {
            return Err(error(rev, &spec.repo));
        }
    } else {
        None
    };

    Ok((prev_rev, rev))
}

pub fn find_head() -> Result<String> {
    let repo = git2::Repository::open_from_env()?;
    let head = repo.revparse_single("HEAD")?;
    Ok(head.id().to_string())
}

/// Given commit specs and repos this returns a list of head commits
/// from it.
pub fn find_heads(specs: Option<Vec<CommitSpec>>, repos: Vec<Repo>)
    -> Result<Vec<Ref>>
{
    let mut rv = vec![];

    // if commit specs were explicitly provided find head commits with
    // limited amounts of magic.
    if let Some(specs) = specs {
        for spec in &specs {
            let (prev_rev, rev) = find_matching_revs(
                &spec, &repos[..], specs.len() == 1)?;
            rv.push(Ref {
                repo: spec.repo.clone(),
                rev: rev,
                prev_rev: prev_rev,
            });
        }

    // otherwise apply all the magic available
    } else {
        for repo in &repos {
            let spec = CommitSpec {
                repo: repo.name.to_string(),
                path: None,
                rev: "HEAD".into(),
                prev_rev: None,
            };
            if let Some(rev) = find_matching_rev(
                spec.reference(), &spec, &repos[..], false)? {
                rv.push(Ref {
                    repo: repo.name.to_string(),
                    rev: rev,
                    prev_rev: None,
                });
            }
        }
    }

    Ok(rv)
}

#[test]
fn test_url_parsing() {
    assert_eq!(VcsUrl::parse("http://github.com/mitsuhiko/flask"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@github.com:mitsuhiko/flask.git"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
}

#[test]
fn test_url_normalization() {
    assert!(is_matching_url("http://github.com/mitsuhiko/flask",
                            "git@github.com:mitsuhiko/flask.git"));
}
<commit_msg>Added support for bitbucket urls<commit_after>use std::fmt;
use std::path::PathBuf;

use git2;
use regex::Regex;

use prelude::*;
use api::{Repo, Ref};

#[derive(Copy, Clone)]
pub enum GitReference<'a> {
    Commit(git2::Oid),
    Symbolic(&'a str),
}

impl<'a> fmt::Display for GitReference<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GitReference::Commit(ref c) => write!(f, "{}", c),
            GitReference::Symbolic(ref s) => write!(f, "{}", s),
        }
    }
}

#[derive(Debug)]
pub struct CommitSpec {
    pub repo: String,
    pub path: Option<PathBuf>,
    pub rev: String,
    pub prev_rev: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct VcsUrl {
    pub provider: &'static str,
    pub id: String,
}

fn parse_rev_range(rng: &str) -> (Option<String>, String) {
    if rng == "" {
        return (None, "HEAD".into());
    }
    let mut iter = rng.rsplitn(2, "..");
    let rev = iter.next().unwrap_or("HEAD");
    (iter.next().map(|x| x.to_string()), rev.to_string())
}

impl CommitSpec {
    pub fn parse(s: &str) -> Result<CommitSpec> {
        lazy_static! {
            static ref SPEC_RE: Regex = Regex::new(
                r"^([^@#]+)(?:#([^@]+))?(?:@(.+))?$").unwrap();
        }
        if let Some(caps) = SPEC_RE.captures(s) {
            let (prev_rev, rev) = parse_rev_range(caps.get(3).map(|x| x.as_str()).unwrap_or(""));
            Ok(CommitSpec {
                repo: caps[1].to_string(),
                path: caps.get(2).map(|x| PathBuf::from(x.as_str())),
                rev: rev,
                prev_rev: prev_rev,
            })
        } else {
            Err(Error::from(format!("Could not parse commit spec '{}'", s)))
        }
    }

    pub fn reference<'a>(&'a self) -> GitReference<'a> {
        if let Ok(oid) = git2::Oid::from_str(&self.rev) {
            GitReference::Commit(oid)
        } else {
            GitReference::Symbolic(&self.rev)
        }
    }

    pub fn prev_reference<'a>(&'a self) -> Option<GitReference<'a>> {
        self.prev_rev.as_ref().map(|rev| {
            if let Ok(oid) = git2::Oid::from_str(rev) {
                GitReference::Commit(oid)
            } else {
                GitReference::Symbolic(rev)
            }
        })
    }
}

fn strip_git_suffix(s: &str) -> &str {
    if s.ends_with(".git") {
        &s[0..s.len() - 4]
    } else {
        s
    }
}

fn get_git_provider(hostname: &str) -> &'static str {
    match hostname {
        "github.com" => "github",
        "bitbucket.org" => "bitbucket",
        _ => "generic",
    }
}

impl VcsUrl {
    pub fn parse(url: &str) -> VcsUrl {
        lazy_static! {
            static ref GIT_URL_RE: Regex = Regex::new(
                r"^(?:ssh|https?)://(?:[^@]+@)?(github\.com|bitbucket\.org)/([^/]+)/([^/]+)").unwrap();
            static ref GIT_SSH_RE: Regex = Regex::new(
                r"^(?:[^@]+@)?(github\.com|bitbucket\.org):([^/]+)/([^/]+)").unwrap();
        }
        if let Some(caps) = GIT_URL_RE.captures(url) {
            VcsUrl {
                provider: get_git_provider(&caps[1]),
                id: format!("{}/{}", &caps[2], strip_git_suffix(&caps[3])),
            }
        } else if let Some(caps) = GIT_SSH_RE.captures(url) {
            VcsUrl {
                provider: get_git_provider(&caps[1]),
                id: format!("{}/{}", &caps[2], strip_git_suffix(&caps[3])),
            }
        } else {
            VcsUrl {
                provider: "generic",
                id: url.into(),
            }
        }
    }
}

fn is_matching_url(a: &str, b: &str) -> bool {
    VcsUrl::parse(a) == VcsUrl::parse(b)
}

fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<String> {
    for configured_repo in repos {
        if configured_repo.name != repo {
            continue;
        }
        if &configured_repo.provider.id != "github" &&
           &configured_repo.provider.id != "git" {
            return Err(Error::from("For non git repositories \
                                   explicit revisions are required"));
        }

        return Ok(configured_repo.url.clone())
    }

    Err(Error::from(format!("Could not find matching repository for {}", repo)))
}

fn find_matching_rev(reference: GitReference, spec: &CommitSpec,
                     repos: &[Repo], disable_discovery: bool)
    -> Result<Option<String>>
{
    let r = match reference {
        GitReference::Commit(commit) => {
            return Ok(Some(commit.to_string()));
        }
        GitReference::Symbolic(r) => r,
    };

    let (repo, discovery) = if let Some(ref path) = spec.path {
        (git2::Repository::open(path)?, false)
    } else {
        (git2::Repository::open_from_env()?, !disable_discovery)
    };

    let reference_url = find_reference_url(&spec.repo, repos)?;

    // direct reference in root repository found.  If we are in discovery
    // mode we want to also check for matching URLs.
    if_chain! {
        if let Ok(remote) = repo.find_remote("origin");
        if let Some(url) = remote.url();
        if !discovery || is_matching_url(url, &reference_url);
        then {
            let head = repo.revparse_single(r)?;
            return Ok(Some(head.id().to_string()));
        }
    }

    // in discovery mode we want to find that repo in associated submodules.
    for submodule in repo.submodules()? {
        if_chain! {
            if let Some(submodule_url) = submodule.url();
            if is_matching_url(submodule_url, &reference_url);
            then {
                // heads on submodules is easier so let's start with that
                // because that does not require the submodule to be
                // checked out.
                if_chain! {
                    if r == "HEAD";
                    if let Some(head_oid) = submodule.head_id();
                    then {
                        return Ok(Some(head_oid.to_string()));
                    }
                }

                // otherwise we need to open the submodule which requires
                // it to be checked out.
                if_chain! {
                    if let Ok(subrepo) = submodule.open();
                    then {
                        let head = subrepo.revparse_single(r)?;
                        return Ok(Some(head.id().to_string()));
                    }
                }
            }
        }
    }

    Ok(None)
}

fn find_matching_revs(spec: &CommitSpec, repos: &[Repo], disable_discovery: bool)
    -> Result<(Option<String>, String)>
{
    fn error(r: GitReference, repo: &str) -> Error {
        Error::from(format!(
            "Could not find commit '{}' for '{}'. If you do not have local \
             checkouts of the repositories in question referencing tags or \
             other references will not work and you need to refer to \
             revisions explicitly.",
            r, repo))
    }

    let rev = if let Some(rev) = find_matching_rev(
        spec.reference(), &spec, &repos[..], disable_discovery)? {
        rev
    } else {
        return Err(error(spec.reference(), &spec.repo));
    };

    let prev_rev = if let Some(rev) = spec.prev_reference() {
        if let Some(rv) = find_matching_rev(
            rev, &spec, &repos[..], disable_discovery)? {
            Some(rv)
        } else {
            return Err(error(rev, &spec.repo));
        }
    } else {
        None
    };

    Ok((prev_rev, rev))
}

pub fn find_head() -> Result<String> {
    let repo = git2::Repository::open_from_env()?;
    let head = repo.revparse_single("HEAD")?;
    Ok(head.id().to_string())
}

/// Given commit specs and repos this returns a list of head commits
/// from it.
pub fn find_heads(specs: Option<Vec<CommitSpec>>, repos: Vec<Repo>)
    -> Result<Vec<Ref>>
{
    let mut rv = vec![];

    // if commit specs were explicitly provided find head commits with
    // limited amounts of magic.
    if let Some(specs) = specs {
        for spec in &specs {
            let (prev_rev, rev) = find_matching_revs(
                &spec, &repos[..], specs.len() == 1)?;
            rv.push(Ref {
                repo: spec.repo.clone(),
                rev: rev,
                prev_rev: prev_rev,
            });
        }

    // otherwise apply all the magic available
    } else {
        for repo in &repos {
            let spec = CommitSpec {
                repo: repo.name.to_string(),
                path: None,
                rev: "HEAD".into(),
                prev_rev: None,
            };
            if let Some(rev) = find_matching_rev(
                spec.reference(), &spec, &repos[..], false)? {
                rv.push(Ref {
                    repo: repo.name.to_string(),
                    rev: rev,
                    prev_rev: None,
                });
            }
        }
    }

    Ok(rv)
}

#[test]
fn test_url_parsing() {
    assert_eq!(VcsUrl::parse("http://github.com/mitsuhiko/flask"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@github.com:mitsuhiko/flask.git"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("http://bitbucket.org/mitsuhiko/flask"), VcsUrl {
        provider: "bitbucket",
        id: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@bitbucket.org:mitsuhiko/flask.git"), VcsUrl {
        provider: "bitbucket",
        id: "mitsuhiko/flask".into(),
    });
}

#[test]
fn test_url_normalization() {
    assert!(is_matching_url("http://github.com/mitsuhiko/flask",
                            "git@github.com:mitsuhiko/flask.git"));
}
<|endoftext|>


<commit_before>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use proc_macro2::TokenStream;
use quote::{format_ident, quote};

/// Returns a [`TokenStream`] representing the specified Rust type.
///
/// This is necessary because in most cases the type will be a generated protobuf struct, but for
/// instance the `Empty` protobuf is represented as `()` by prost, which is not a valid identifier.
fn type_ident(type_: &str) -> TokenStream {
    if type_ == "()" {
        quote!(())
    } else {
        let t = format_ident!("{}", type_);
        quote!(#t)
    }
}

/// Returns the name to use to refer to the `oak` package.
///
/// When compiling from within the `oak` crate we need to use `crate` to refer to itself.
fn oak_package() -> TokenStream {
    if std::env::var("CARGO_PKG_NAME").unwrap() == "oak" {
        quote!(crate)
    } else {
        quote!(::oak)
    }
}

struct OakServiceGenerator;

impl prost_build::ServiceGenerator for OakServiceGenerator {
    fn generate(&mut self, service: prost_build::Service, out: &mut std::string::String) {
        let oak_package = oak_package();

        let service_name = format_ident!("{}", service.name);
        let service_methods = service.methods.iter().map(|method| {
            let method_name = format_ident!("{}", method.name);
            let input_type = type_ident(&method.input_type);
            let output_type = type_ident(&method.output_type);
            // TODO(#97): Better client-side streaming.
            match (method.client_streaming, method.server_streaming) {
                (false, false) => quote! {
                    fn #method_name(&mut self, req: #input_type) -> #oak_package::grpc::Result<#output_type>
                },
                (false, true) => quote! {
                    fn #method_name(&mut self, req: #input_type, writer: #oak_package::grpc::ChannelResponseWriter)
                },
                (true, false) => quote! {
                    fn #method_name(&mut self, reqs: Vec<#input_type>) -> #oak_package::grpc::Result<#output_type>
                },
                (true, true) => quote! {
                    fn #method_name(&mut self, reqs: Vec<#input_type>, writer: #oak_package::grpc::ChannelResponseWriter)
                },
            }
        });

        let dispatcher_name = format_ident!("{}Dispatcher", service.name);
        let dispatcher_methods = service.methods.iter().map(|method| {
            let method_name = format_ident!("{}", method.name);
            let method_name_string = format!("/{}.{}/{}", service.package, service.proto_name, method.proto_name);
            // Figure out which generic function applies.
            let handle_invocation = match (method.client_streaming, method.server_streaming) {
                (false, false) => quote! {
                    #oak_package::grpc::handle_req_rsp(|r| (self.0).#method_name(r), req, writer)
                },
                (false, true) => quote! {
                    #oak_package::grpc::handle_req_stream(|r, w| (self.0).#method_name(r, w), req, writer)
                },
                (true, false) => quote! {
                    #oak_package::grpc::handle_stream_rsp(|rr| (self.0).#method_name(rr), req, writer)
                },
                (true, true) => quote! {
                    #oak_package::grpc::handle_stream_stream(|rr, w| (self.0).#method_name(rr, w), req, writer)
                },
            };
            quote! {
                #method_name_string => #handle_invocation
            }
        });

        let client_name = format_ident!("{}Client", service.name);
        let client_methods = service.methods.iter().map(|method| {
            let method_name = format_ident!("{}", method.name);
            let input_type = type_ident(&method.input_type);
            let output_type = type_ident(&method.output_type);
            let method_name_string = format!("/{}.{}/{}", service.package, service.proto_name, method.proto_name);
            // TODO(#97): Support client-side streaming.
            #[allow(clippy::match_bool)]
            match method.server_streaming {
                false =>
                    quote! {
                        pub fn #method_name(&self, req: #input_type) -> #oak_package::grpc::Result<#output_type> {
                            #oak_package::grpc::invoke_grpc_method(#method_name_string, &req, &self.0.invocation_sender)
                        }
                    },
                true =>
                    // TODO(#592): ideally the return type for a streaming method would be
                    //   format!("oak::io::Receiver<{}>", self.output_message());
                    // This is not possible with the current io::Receiver's direct use of
                    // the underlying handle.
                    quote! {
                        pub fn #method_name(&self, req: #input_type) -> #oak_package::grpc::Result<#oak_package::io::Receiver<#oak_package::grpc::GrpcResponse>> {
                            #oak_package::grpc::invoke_grpc_method_stream(#method_name_string, &req, &self.0.invocation_sender)
                        }
                    },
            }
        });
        let gen = quote! {
            pub trait #service_name {
                #(#service_methods;)*
            }

            #[allow(dead_code)]
            pub struct #dispatcher_name<T: #service_name>(T);

            #[allow(dead_code)]
            impl <T: #service_name> #dispatcher_name<T> {
                pub fn new(node: T) -> #dispatcher_name<T> {
                    #dispatcher_name(node)
                }
            }

            #[allow(clippy::unit_arg)]
            impl <T: #service_name> #oak_package::grpc::ServerNode for #dispatcher_name<T> {
                fn invoke(&mut self, method: &str, req: &[u8], writer: #oak_package::grpc::ChannelResponseWriter) {
                    match method {
                        #(#dispatcher_methods,)*
                        _ => {
                            ::log::error!("unknown method name: {}", method);
                        }
                    }
                }
            }

            #[allow(dead_code)]
            pub struct #client_name(pub #oak_package::grpc::client::Client);

            #[allow(dead_code)]
            impl #client_name {
                #(#client_methods)*
            }
        };
        out.push_str("\n");
        // TODO(#832): Currently the generated output is squashed on a single line; consider passing
        // it through rustfmt, if it does not increase compile time too much.
        out.push_str(&format!("{}", gen));
        out.push_str("\n");
    }
}

pub fn compile_protos_to<P, Q>(inputs: &[P], includes: &[P], out_dir: Q)
where
    P: AsRef<std::path::Path>,
    Q: Into<std::path::PathBuf>,
{
    compile_protos_with(
        prost_build::Config::new().out_dir(out_dir),
        true,
        inputs,
        includes,
    );
}

pub fn compile_protos<P>(inputs: &[P], includes: &[P])
where
    P: AsRef<std::path::Path>,
{
    compile_protos_with(&mut prost_build::Config::new(), true, inputs, includes);
}

pub fn compile_protos_without_services<P>(inputs: &[P], includes: &[P])
where
    P: AsRef<std::path::Path>,
{
    compile_protos_with(&mut prost_build::Config::new(), false, inputs, includes);
}

fn compile_protos_with<P>(
    prost_config: &mut prost_build::Config,
    generate_services: bool,
    inputs: &[P],
    includes: &[P],
) where
    P: AsRef<std::path::Path>,
{
    for input in inputs {
        // Tell cargo to rerun this build script if the proto file has changed.
        // https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath
        println!("cargo:rerun-if-changed={}", input.as_ref().display());
    }
    if generate_services {
        prost_config.service_generator(Box::new(OakServiceGenerator));
    }
    prost_config
        // We require label-related types to be comparable and hashable so that they can be used in
        // hash-based collections.
        .type_attribute(".oak.label", "#[derive(Eq, Hash)]")
        .compile_protos(inputs, includes)
        .expect("could not run prost-build");
}
<commit_msg>oak_utils: drop unused compile_protos_to function<commit_after>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use proc_macro2::TokenStream;
use quote::{format_ident, quote};

/// Returns a [`TokenStream`] representing the specified Rust type.
///
/// This is necessary because in most cases the type will be a generated protobuf struct, but for
/// instance the `Empty` protobuf is represented as `()` by prost, which is not a valid identifier.
fn type_ident(type_: &str) -> TokenStream {
    if type_ == "()" {
        quote!(())
    } else {
        let t = format_ident!("{}", type_);
        quote!(#t)
    }
}

/// Returns the name to use to refer to the `oak` package.
///
/// When compiling from within the `oak` crate we need to use `crate` to refer to itself.
fn oak_package() -> TokenStream {
    if std::env::var("CARGO_PKG_NAME").unwrap() == "oak" {
        quote!(crate)
    } else {
        quote!(::oak)
    }
}

struct OakServiceGenerator;

impl prost_build::ServiceGenerator for OakServiceGenerator {
    fn generate(&mut self, service: prost_build::Service, out: &mut std::string::String) {
        let oak_package = oak_package();

        let service_name = format_ident!("{}", service.name);
        let service_methods = service.methods.iter().map(|method| {
            let method_name = format_ident!("{}", method.name);
            let input_type = type_ident(&method.input_type);
            let output_type = type_ident(&method.output_type);
            // TODO(#97): Better client-side streaming.
            match (method.client_streaming, method.server_streaming) {
                (false, false) => quote! {
                    fn #method_name(&mut self, req: #input_type) -> #oak_package::grpc::Result<#output_type>
                },
                (false, true) => quote! {
                    fn #method_name(&mut self, req: #input_type, writer: #oak_package::grpc::ChannelResponseWriter)
                },
                (true, false) => quote! {
                    fn #method_name(&mut self, reqs: Vec<#input_type>) -> #oak_package::grpc::Result<#output_type>
                },
                (true, true) => quote! {
                    fn #method_name(&mut self, reqs: Vec<#input_type>, writer: #oak_package::grpc::ChannelResponseWriter)
                },
            }
        });

        let dispatcher_name = format_ident!("{}Dispatcher", service.name);
        let dispatcher_methods = service.methods.iter().map(|method| {
            let method_name = format_ident!("{}", method.name);
            let method_name_string = format!("/{}.{}/{}", service.package, service.proto_name, method.proto_name);
            // Figure out which generic function applies.
            let handle_invocation = match (method.client_streaming, method.server_streaming) {
                (false, false) => quote! {
                    #oak_package::grpc::handle_req_rsp(|r| (self.0).#method_name(r), req, writer)
                },
                (false, true) => quote! {
                    #oak_package::grpc::handle_req_stream(|r, w| (self.0).#method_name(r, w), req, writer)
                },
                (true, false) => quote! {
                    #oak_package::grpc::handle_stream_rsp(|rr| (self.0).#method_name(rr), req, writer)
                },
                (true, true) => quote! {
                    #oak_package::grpc::handle_stream_stream(|rr, w| (self.0).#method_name(rr, w), req, writer)
                },
            };
            quote! {
                #method_name_string => #handle_invocation
            }
        });

        let client_name = format_ident!("{}Client", service.name);
        let client_methods = service.methods.iter().map(|method| {
            let method_name = format_ident!("{}", method.name);
            let input_type = type_ident(&method.input_type);
            let output_type = type_ident(&method.output_type);
            let method_name_string = format!("/{}.{}/{}", service.package, service.proto_name, method.proto_name);
            // TODO(#97): Support client-side streaming.
            #[allow(clippy::match_bool)]
            match method.server_streaming {
                false =>
                    quote! {
                        pub fn #method_name(&self, req: #input_type) -> #oak_package::grpc::Result<#output_type> {
                            #oak_package::grpc::invoke_grpc_method(#method_name_string, &req, &self.0.invocation_sender)
                        }
                    },
                true =>
                    // TODO(#592): ideally the return type for a streaming method would be
                    //   format!("oak::io::Receiver<{}>", self.output_message());
                    // This is not possible with the current io::Receiver's direct use of
                    // the underlying handle.
                    quote! {
                        pub fn #method_name(&self, req: #input_type) -> #oak_package::grpc::Result<#oak_package::io::Receiver<#oak_package::grpc::GrpcResponse>> {
                            #oak_package::grpc::invoke_grpc_method_stream(#method_name_string, &req, &self.0.invocation_sender)
                        }
                    },
            }
        });
        let gen = quote! {
            pub trait #service_name {
                #(#service_methods;)*
            }

            #[allow(dead_code)]
            pub struct #dispatcher_name<T: #service_name>(T);

            #[allow(dead_code)]
            impl <T: #service_name> #dispatcher_name<T> {
                pub fn new(node: T) -> #dispatcher_name<T> {
                    #dispatcher_name(node)
                }
            }

            #[allow(clippy::unit_arg)]
            impl <T: #service_name> #oak_package::grpc::ServerNode for #dispatcher_name<T> {
                fn invoke(&mut self, method: &str, req: &[u8], writer: #oak_package::grpc::ChannelResponseWriter) {
                    match method {
                        #(#dispatcher_methods,)*
                        _ => {
                            ::log::error!("unknown method name: {}", method);
                        }
                    }
                }
            }

            #[allow(dead_code)]
            pub struct #client_name(pub #oak_package::grpc::client::Client);

            #[allow(dead_code)]
            impl #client_name {
                #(#client_methods)*
            }
        };
        out.push_str("\n");
        // TODO(#832): Currently the generated output is squashed on a single line; consider passing
        // it through rustfmt, if it does not increase compile time too much.
        out.push_str(&format!("{}", gen));
        out.push_str("\n");
    }
}

/// Build Rust code corresponding to a set of protocol buffer message and service definitions,
/// emitting generated code to crate's `OUT_DIR`.  For gRPC service definitions, this
/// function generates Oak-specific code that is suitable for use inside an Oak Node (i.e.  *not*
/// code that is suitable for use in a normal application running on the host platform).
pub fn compile_protos<P>(inputs: &[P], includes: &[P])
where
    P: AsRef<std::path::Path>,
{
    compile_protos_with(true, inputs, includes);
}

/// Build Rust code corresponding to a set of protocol buffer messages, skipping any service
/// definitions, emitting generated code to crate's `OUT_DIR`.
pub fn compile_protos_without_services<P>(inputs: &[P], includes: &[P])
where
    P: AsRef<std::path::Path>,
{
    compile_protos_with(false, inputs, includes);
}

fn compile_protos_with<P>(generate_services: bool, inputs: &[P], includes: &[P])
where
    P: AsRef<std::path::Path>,
{
    for input in inputs {
        // Tell cargo to rerun this build script if the proto file has changed.
        // https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath
        println!("cargo:rerun-if-changed={}", input.as_ref().display());
    }

    let mut prost_config = prost_build::Config::new();
    if generate_services {
        prost_config.service_generator(Box::new(OakServiceGenerator));
    }
    prost_config
        // We require label-related types to be comparable and hashable so that they can be used in
        // hash-based collections.
        .type_attribute(".oak.label", "#[derive(Eq, Hash)]")
        .compile_protos(inputs, includes)
        .expect("could not run prost-build");
}
<|endoftext|>


<commit_before>#![allow(clippy::option_if_let_else)]

use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;

#[cfg(all(feature = "backtrace", not(feature = "std")))]
compile_error! {
    "`backtrace` feature without `std` feature is not supported"
}

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(error_generic_member_access, provide_any)]

    use std::any::Demand;
    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E {
        backtrace: Backtrace,
    }

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
            demand.provide_ref(&self.backtrace);
        }
    }

    const _: fn() = || {
        let backtrace: Backtrace = Backtrace::capture();
        let status: BacktraceStatus = backtrace.status();
        match status {
            BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
        }
    };

    const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::<Backtrace>();
"#;

fn main() {
    if cfg!(feature = "std") {
        match compile_probe() {
            Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
            _ => {}
        }
    }

    let rustc = match rustc_minor_version() {
        Some(rustc) => rustc,
        None => return,
    };

    if rustc < 51 {
        println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
    }

    if rustc < 52 {
        println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;

    // Make sure to pick up Cargo rustc configuration.
    let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
        let mut cmd = Command::new(wrapper);
        // The wrapper's first argument is supposed to be the path to rustc.
        cmd.arg(rustc);
        cmd
    } else {
        Command::new(rustc)
    };

    cmd.stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile);

    if let Some(target) = env::var_os("TARGET") {
        cmd.arg("--target").arg(target);
    }

    // If Cargo wants to set RUSTFLAGS, use that.
    if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
        if !rustflags.is_empty() {
            for arg in rustflags.split('\x1f') {
                cmd.arg(arg);
            }
        }
    }

    cmd.status().ok()
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<commit_msg>Add impl Provider in build.rs probe<commit_after>#![allow(clippy::option_if_let_else)]

use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;

#[cfg(all(feature = "backtrace", not(feature = "std")))]
compile_error! {
    "`backtrace` feature without `std` feature is not supported"
}

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(error_generic_member_access, provide_any)]

    use std::any::{Demand, Provider};
    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E {
        backtrace: Backtrace,
    }

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
            demand.provide_ref(&self.backtrace);
        }
    }

    struct P;

    impl Provider for P {
        fn provide<'a>(&'a self, _demand: &mut Demand<'a>) {}
    }

    const _: fn() = || {
        let backtrace: Backtrace = Backtrace::capture();
        let status: BacktraceStatus = backtrace.status();
        match status {
            BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
        }
    };

    const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::<Backtrace>();
"#;

fn main() {
    if cfg!(feature = "std") {
        match compile_probe() {
            Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
            _ => {}
        }
    }

    let rustc = match rustc_minor_version() {
        Some(rustc) => rustc,
        None => return,
    };

    if rustc < 51 {
        println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
    }

    if rustc < 52 {
        println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;

    // Make sure to pick up Cargo rustc configuration.
    let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
        let mut cmd = Command::new(wrapper);
        // The wrapper's first argument is supposed to be the path to rustc.
        cmd.arg(rustc);
        cmd
    } else {
        Command::new(rustc)
    };

    cmd.stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile);

    if let Some(target) = env::var_os("TARGET") {
        cmd.arg("--target").arg(target);
    }

    // If Cargo wants to set RUSTFLAGS, use that.
    if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
        if !rustflags.is_empty() {
            for arg in rustflags.split('\x1f') {
                cmd.arg(arg);
            }
        }
    }

    cmd.status().ok()
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    gcc::compile_library("libmnl_ext.a", &["src/nlmsg_ext.c"]);
}
<commit_msg>build: delete deprecated function for gcc<commit_after>extern crate gcc;

fn main() {
    gcc::Build::new()
        .file("src/nlmsg_ext.c")
        .static_flag(true)
        .compile("libmnl_ext.a");
}
<|endoftext|>


<commit_before>extern crate embed_resource;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate cc;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::env;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::io::Write;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::path::Path;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::fs::{self, File};

/// The last line of this, after running it through a preprocessor, will expand to the value of `BLKGETSIZE`
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
static IOCTL_CHECK_SOURCE: &str = r#"
#include <linux/fs.h>

BLKGETSIZE
"#;

/// Replace `{}` with the `BLKGETSIZE` expression from `IOCTL_CHECK_SOURCE`
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
static IOCTL_INCLUDE_SKELETON: &str = r#"
/// Return `device size / 512` (`long *` arg)
static BLKGETSIZE: c_ulong = {};
"#;

fn main() {
    embed_resources();
    get_ioctl_data();
}

fn embed_resources() {
    embed_resource::compile("http-manifest.rc");
}

#[cfg(any(target_os = "windows", target_os = "macos"))]
fn get_ioctl_data() {}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn get_ioctl_data() {
    let ioctl_dir = Path::new(&env::var("OUT_DIR").unwrap()).join("ioctl-data");
    fs::create_dir_all(&ioctl_dir).unwrap();

    let ioctl_source = ioctl_dir.join("ioctl.c");
    File::create(&ioctl_source).unwrap().write_all(IOCTL_CHECK_SOURCE.as_bytes()).unwrap();

    let ioctl_preprocessed = String::from_utf8(cc::Build::new().file(ioctl_source).expand()).unwrap();
    let blkgetsize_expr = ioctl_preprocessed.lines().next_back().unwrap().replace("U", " as c_ulong");

    let ioctl_include = ioctl_dir.join("ioctl.rs");
    File::create(&ioctl_include).unwrap().write_all(IOCTL_INCLUDE_SKELETON.replace("{}", &blkgetsize_expr).as_bytes()).unwrap();
}
<commit_msg>Use sys/mount.h instead of linux/fs.h in BLKGETSIZE check<commit_after>extern crate embed_resource;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate cc;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::env;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::io::Write;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::path::Path;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
use std::fs::{self, File};

/// The last line of this, after running it through a preprocessor, will expand to the value of `BLKGETSIZE`
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
static IOCTL_CHECK_SOURCE: &str = r#"
#include <sys/mount.h>

BLKGETSIZE
"#;

/// Replace `{}` with the `BLKGETSIZE` expression from `IOCTL_CHECK_SOURCE`
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
static IOCTL_INCLUDE_SKELETON: &str = r#"
/// Return `device size / 512` (`long *` arg)
static BLKGETSIZE: c_ulong = {};
"#;

fn main() {
    embed_resources();
    get_ioctl_data();
}

fn embed_resources() {
    embed_resource::compile("http-manifest.rc");
}

#[cfg(any(target_os = "windows", target_os = "macos"))]
fn get_ioctl_data() {}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn get_ioctl_data() {
    let ioctl_dir = Path::new(&env::var("OUT_DIR").unwrap()).join("ioctl-data");
    fs::create_dir_all(&ioctl_dir).unwrap();

    let ioctl_source = ioctl_dir.join("ioctl.c");
    File::create(&ioctl_source).unwrap().write_all(IOCTL_CHECK_SOURCE.as_bytes()).unwrap();

    let ioctl_preprocessed = String::from_utf8(cc::Build::new().file(ioctl_source).expand()).unwrap();
    let blkgetsize_expr = ioctl_preprocessed.lines().next_back().unwrap().replace("U", " as c_ulong");

    let ioctl_include = ioctl_dir.join("ioctl.rs");
    File::create(&ioctl_include).unwrap().write_all(IOCTL_INCLUDE_SKELETON.replace("{}", &blkgetsize_expr).as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#![feature(old_io, old_path, path, fs, os)]

extern crate "pkg-config" as pkg_config;

use std::path::Path;
use std::fs::PathExt;
use std::env;

#[cfg(all(unix, not(target_os = "linux")))]
use unix_platform as platform;

fn main() {
    if env::var("PORTAUDIO_ONLY_STATIC").is_err() {
        // If pkg-config finds a library on the system, we are done
        if pkg_config::Config::new().atleast_version("19").find("portaudio-2.0").is_ok() {
            return;
        }
    }

    build();
}

fn build() {
    // retrieve cargo deps out dir
    let out_dir_str = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir_str);

    let static_lib = out_dir.join("lib/libportaudio.a");
    if !static_lib.exists() {
        platform::download();
        platform::build(out_dir);
    }

    platform::print_libs(out_dir);
}

#[allow(dead_code)]
mod unix_platform {
    use std::old_io::process::Command;
    use std::path::Path;
    use std::old_path::Path as OldPath;

    use std::{env, os};

    pub const PORTAUDIO_URL: &'static str = "http://www.portaudio.com/archives/pa_stable_v19_20140130.tgz";
    pub const PORTAUDIO_TAR: &'static str = "pa_stable_v19_20140130.tgz";
    pub const PORTAUDIO_FOLDER: &'static str = "portaudio";

    pub fn download() {
        match Command::new("curl").arg(PORTAUDIO_URL).arg("-O").output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }
    }

    pub fn build(out_dir: &Path) {
        // untar portaudio sources
        match Command::new("tar").arg("xvf").arg(PORTAUDIO_TAR).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // change dir to the portaudio folder
        match env::set_current_dir(&OldPath::new(PORTAUDIO_FOLDER)) {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // run portaudio autoconf
        Command::new("./configure")
            .args(&["--disable-shared", "--enable-static"]) // Only build static lib
            .args(&["--prefix", out_dir.to_str().unwrap()]) // Install on the outdir
            .arg("--with-pic") // Build position-independent code (required by Rust)
            .output()
            .unwrap();

        // then make
        match Command::new("make").arg(format!("-j{}", os::num_cpus())).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // "install" on the outdir
        match Command::new("make").arg("install").output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // return to rust-portaudio root
        match env::set_current_dir(&OldPath::new("..")) {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // cleaning portaudio sources
        match Command::new("rm").arg("-rf").args(&[PORTAUDIO_TAR, PORTAUDIO_FOLDER]).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }
    }

    pub fn print_libs(out_dir: &Path) {
        let out_str = out_dir.to_str().unwrap();
        println!("cargo:rustc-flags=-L native={}/lib -l static=portaudio", out_str);
    }
}

#[cfg(target_os = "linux")]
mod platform {
    use pkg_config;
    use std::old_io::process::Command;
    use super::unix_platform;
    use std::path::Path;

    pub fn download() {
        match Command::new("wget").arg(unix_platform::PORTAUDIO_URL).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }
    }

    pub fn build(out_dir: &Path) {
        unix_platform::build(out_dir);
    }

    pub fn print_libs(out_dir: &Path) {
        let portaudio_pc_file = out_dir.join("lib/pkgconfig/portaudio-2.0.pc");
        let portaudio_pc_file = portaudio_pc_file.to_str().unwrap();

        pkg_config::Config::new().statik(true).find(portaudio_pc_file).unwrap();
    }
}

#[cfg(windows)]
mod platform {
    use std::path::Path;

    pub fn download(_: &Path) {
        panic!("Don't know how to build portaudio on Windows yet!");
    }

    pub fn build(_: &Path) {
        panic!("Don't know how to build portaudio on Windows yet!");
    }

    pub fn print_libs(_: &Path) {
        panic!("Don't know how to build portaudio on Windows yet!");
    }
}
<commit_msg>Move buildscript away from old_io/old_path<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#![feature(path, fs, os)]

extern crate "pkg-config" as pkg_config;

use std::path::Path;
use std::fs::PathExt;
use std::env;

#[cfg(all(unix, not(target_os = "linux")))]
use unix_platform as platform;

fn main() {
    if env::var("PORTAUDIO_ONLY_STATIC").is_err() {
        // If pkg-config finds a library on the system, we are done
        if pkg_config::Config::new().atleast_version("19").find("portaudio-2.0").is_ok() {
            return;
        }
    }

    build();
}

fn build() {
    // retrieve cargo deps out dir
    let out_dir_str = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir_str);

    let static_lib = out_dir.join("lib/libportaudio.a");
    if !static_lib.exists() {
        platform::download();
        platform::build(out_dir);
    }

    platform::print_libs(out_dir);
}

#[allow(dead_code)]
mod unix_platform {
    use std::process::Command;
    use std::path::Path;

    use std::{env, os};

    pub const PORTAUDIO_URL: &'static str = "http://www.portaudio.com/archives/pa_stable_v19_20140130.tgz";
    pub const PORTAUDIO_TAR: &'static str = "pa_stable_v19_20140130.tgz";
    pub const PORTAUDIO_FOLDER: &'static str = "portaudio";

    pub fn download() {
        match Command::new("curl").arg(PORTAUDIO_URL).arg("-O").output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }
    }

    pub fn build(out_dir: &Path) {
        // untar portaudio sources
        match Command::new("tar").arg("xvf").arg(PORTAUDIO_TAR).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // change dir to the portaudio folder
        match env::set_current_dir(PORTAUDIO_FOLDER) {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // run portaudio autoconf
        Command::new("./configure")
            .args(&["--disable-shared", "--enable-static"]) // Only build static lib
            .args(&["--prefix", out_dir.to_str().unwrap()]) // Install on the outdir
            .arg("--with-pic") // Build position-independent code (required by Rust)
            .output()
            .unwrap();

        // then make
        match Command::new("make").arg(&format!("-j{}", os::num_cpus())).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // "install" on the outdir
        match Command::new("make").arg("install").output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // return to rust-portaudio root
        match env::set_current_dir("..") {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }

        // cleaning portaudio sources
        match Command::new("rm").arg("-rf").args(&[PORTAUDIO_TAR, PORTAUDIO_FOLDER]).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }
    }

    pub fn print_libs(out_dir: &Path) {
        let out_str = out_dir.to_str().unwrap();
        println!("cargo:rustc-flags=-L native={}/lib -l static=portaudio", out_str);
    }
}

#[cfg(target_os = "linux")]
mod platform {
    use pkg_config;
    use std::process::Command;
    use super::unix_platform;
    use std::path::Path;

    pub fn download() {
        match Command::new("wget").arg(unix_platform::PORTAUDIO_URL).output() {
            Ok(_) => {},
            Err(e) => panic!("{}", e)
        }
    }

    pub fn build(out_dir: &Path) {
        unix_platform::build(out_dir);
    }

    pub fn print_libs(out_dir: &Path) {
        let portaudio_pc_file = out_dir.join("lib/pkgconfig/portaudio-2.0.pc");
        let portaudio_pc_file = portaudio_pc_file.to_str().unwrap();

        pkg_config::Config::new().statik(true).find(portaudio_pc_file).unwrap();
    }
}

#[cfg(windows)]
mod platform {
    use std::path::Path;

    pub fn download(_: &Path) {
        panic!("Don't know how to build portaudio on Windows yet!");
    }

    pub fn build(_: &Path) {
        panic!("Don't know how to build portaudio on Windows yet!");
    }

    pub fn print_libs(_: &Path) {
        panic!("Don't know how to build portaudio on Windows yet!");
    }
}
<|endoftext|>


<commit_before>use static_string_indexing::index_static_strings;
use instructions_template::generate_instructions_rs;

use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;

fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
    let entries = match current_dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return,
    };

    for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
        if entry.is_dir() {
            if let Some(file_name) = entry.file_name() {
                let new_prefix = prefix.to_owned() + file_name.to_str().unwrap() + "/";
                find_prolog_files(libraries, &new_prefix, &entry);
            }
        } else if entry.is_file() {
            let ext = std::ffi::OsStr::new("pl");
            if entry.extension() == Some(ext) {
                let contain = String::from_utf8(fs::read(&entry).unwrap()).unwrap();
                let name = entry.file_stem().unwrap().to_str().unwrap();

                let line = format!(
                    "        m.insert(\"{}\",\n{:?});\n",
                    prefix.to_owned() + name,
                    contain
                );

                libraries.write_all(line.as_bytes()).unwrap();
            }
        }
    }
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("libraries.rs");

    let mut libraries = File::create(&dest_path).unwrap();
    let lib_path = Path::new("src/lib");

    libraries
        .write_all(
            b"ref_thread_local::ref_thread_local! {
    pub(crate) static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
        let mut m = IndexMap::new();\n",
        )
        .unwrap();

    find_prolog_files(&mut libraries, "", &lib_path);
    libraries.write_all(b"\n        m\n    };\n}\n").unwrap();

    let instructions_path = Path::new(&out_dir).join("instructions.rs");
    let mut instructions_file = File::create(&instructions_path).unwrap();

    let quoted_output = generate_instructions_rs();

    instructions_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    Command::new("rustfmt")
        .arg(instructions_path.as_os_str())
        .spawn().unwrap()
        .wait().unwrap();

    let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
    let mut static_atoms_file = File::create(&static_atoms_path).unwrap();

    let quoted_output = index_static_strings(&instructions_path);

    static_atoms_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    Command::new("rustfmt")
        .arg(static_atoms_path.as_os_str())
        .spawn().unwrap()
        .wait().unwrap();
}
<commit_msg>only rerun build.rs when something in src/ has changed<commit_after>use static_string_indexing::index_static_strings;
use instructions_template::generate_instructions_rs;

use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;

fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
    let entries = match current_dir.read_dir() {
        Ok(entries) => entries,
        Err(_) => return,
    };

    for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
        if entry.is_dir() {
            if let Some(file_name) = entry.file_name() {
                let new_prefix = prefix.to_owned() + file_name.to_str().unwrap() + "/";
                find_prolog_files(libraries, &new_prefix, &entry);
            }
        } else if entry.is_file() {
            let ext = std::ffi::OsStr::new("pl");
            if entry.extension() == Some(ext) {
                let contain = String::from_utf8(fs::read(&entry).unwrap()).unwrap();
                let name = entry.file_stem().unwrap().to_str().unwrap();

                let line = format!(
                    "        m.insert(\"{}\",\n{:?});\n",
                    prefix.to_owned() + name,
                    contain
                );

                libraries.write_all(line.as_bytes()).unwrap();
            }
        }
    }
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("libraries.rs");

    let mut libraries = File::create(&dest_path).unwrap();
    let lib_path = Path::new("src/lib");

    libraries
        .write_all(
            b"ref_thread_local::ref_thread_local! {
    pub(crate) static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
        let mut m = IndexMap::new();\n",
        )
        .unwrap();

    find_prolog_files(&mut libraries, "", &lib_path);
    libraries.write_all(b"\n        m\n    };\n}\n").unwrap();

    let instructions_path = Path::new(&out_dir).join("instructions.rs");
    let mut instructions_file = File::create(&instructions_path).unwrap();

    let quoted_output = generate_instructions_rs();

    instructions_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    Command::new("rustfmt")
        .arg(instructions_path.as_os_str())
        .spawn().unwrap()
        .wait().unwrap();

    let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
    let mut static_atoms_file = File::create(&static_atoms_path).unwrap();

    let quoted_output = index_static_strings(&instructions_path);

    static_atoms_file
        .write_all(quoted_output.to_string().as_bytes())
        .unwrap();

    Command::new("rustfmt")
        .arg(static_atoms_path.as_os_str())
        .spawn().unwrap()
        .wait().unwrap();

    println!("cargo:rerun-if-changed=src/");
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::env;

fn dlerror_is_mtsafe(target_os: &str) {
    match target_os {
        // Confirmed MT-safe:
        "linux"
        | "android"
        | "openbsd"
        | "macos"
        | "ios"
        | "solaris"
        | "illumos"
        | "redox"
        | "fuchsia" => {
            println!("cargo:rustc-cfg=mtsafe_dlerror");
        }
        // Confirmed not MT-safe:
        "freebsd"
        | "dragonfly"
        | "netbsd"
        | "bitrig"
        | "haiku" => {}
        // Unknown:
        _ => {}
    }
}

fn link_libraries(target_os: &str) {
    match target_os {
        "linux" | "android" => println!("cargo:rustc-link-lib=dl"),
        "freebsd" | "dragonfly" => println!("cargo:rustc-link-lib=c"),
        // netbsd claims dl* will be available to any dynamically linked binary, but I haven’t
        // found any libraries that have to be linked to on other platforms.
        // What happens if the executable is not linked up dynamically?
        "openbsd" | "bitrig" | "netbsd" | "macos" | "ios" => {}
        "solaris" => {}
        "haiku" => {}
        "redox" => {}
        "fuchsia" => {}
        // dependencies come with winapi
        "windows" => {}
        tos => {
            writeln!(::std::io::stderr(),
                     "Building for an unknown target_os=`{:?}`!\nPlease report an issue ",
                     tos).expect("could not report the error");
            ::std::process::exit(0xfc);
        }
    }
}

fn main() {
    match env::var("CARGO_CFG_TARGET_OS") {
        Ok(target_os) => {
            dlerror_is_mtsafe(&target_os);
            link_libraries(&target_os);
        }
        Err(e) => {
            writeln!(::std::io::stderr(),
                     "Unable to get target_os=`{}`!", e).expect("could not report the error");
            ::std::process::exit(0xfd);
        }
    }
}
<commit_msg>Add illumos to the list of link_libraries<commit_after>use std::io::Write;
use std::env;

fn dlerror_is_mtsafe(target_os: &str) {
    match target_os {
        // Confirmed MT-safe:
        "linux"
        | "android"
        | "openbsd"
        | "macos"
        | "ios"
        | "solaris"
        | "illumos"
        | "redox"
        | "fuchsia" => {
            println!("cargo:rustc-cfg=mtsafe_dlerror");
        }
        // Confirmed not MT-safe:
        "freebsd"
        | "dragonfly"
        | "netbsd"
        | "bitrig"
        | "haiku" => {}
        // Unknown:
        _ => {}
    }
}

fn link_libraries(target_os: &str) {
    match target_os {
        "linux" | "android" => println!("cargo:rustc-link-lib=dl"),
        "freebsd" | "dragonfly" => println!("cargo:rustc-link-lib=c"),
        // netbsd claims dl* will be available to any dynamically linked binary, but I haven’t
        // found any libraries that have to be linked to on other platforms.
        // What happens if the executable is not linked up dynamically?
        "openbsd" | "bitrig" | "netbsd" | "macos" | "ios" => {}
        "solaris" | "illumos" => {}
        "haiku" => {}
        "redox" => {}
        "fuchsia" => {}
        // dependencies come with winapi
        "windows" => {}
        tos => {
            writeln!(::std::io::stderr(),
                     "Building for an unknown target_os=`{:?}`!\nPlease report an issue ",
                     tos).expect("could not report the error");
            ::std::process::exit(0xfc);
        }
    }
}

fn main() {
    match env::var("CARGO_CFG_TARGET_OS") {
        Ok(target_os) => {
            dlerror_is_mtsafe(&target_os);
            link_libraries(&target_os);
        }
        Err(e) => {
            writeln!(::std::io::stderr(),
                     "Unable to get target_os=`{}`!", e).expect("could not report the error");
            ::std::process::exit(0xfd);
        }
    }
}
<|endoftext|>