<commit_before>//! Checks that all error codes have at least one test to prevent having error
//! codes that are silently not thrown by the compiler anymore.

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::read_to_string;
use std::path::Path;

// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
    "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461",
    "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480",
    "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514",
    "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727",
    "E0729",
];

// Some error codes don't have any tests apparently...
const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"];

fn check_error_code_explanation(
    f: &str,
    error_codes: &mut HashMap<String, bool>,
    err_code: String,
) -> bool {
    let mut invalid_compile_fail_format = false;
    let mut found_error_code = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains('E') {
                if !found_error_code {
                    error_codes.insert(err_code.clone(), true);
                    found_error_code = true;
                }
            } else if s.contains("compile-fail") {
                invalid_compile_fail_format = true;
            }
        } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            if !found_error_code {
                error_codes.get_mut(&err_code).map(|x| *x = true);
                found_error_code = true;
            }
        }
    }
    invalid_compile_fail_format
}

fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool {
    let mut ignore_found = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            return true;
        }
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains(err_code) {
                return true;
            } else if s.contains("ignore") {
                // It's very likely that we can't actually make it fail compilation...
                ignore_found = true;
            }
        }
    }
    ignore_found
}

macro_rules! some_or_continue {
    ($e:expr) => {
        match $e {
            Some(e) => e,
            None => continue,
        }
    };
}

fn extract_error_codes(
    f: &str,
    error_codes: &mut HashMap<String, bool>,
    path: &Path,
    errors: &mut Vec<String>,
) {
    let mut reached_no_explanation = false;

    for line in f.lines() {
        let s = line.trim();
        if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") {
            let err_code = s
                .split_once(':')
                .expect(
                    format!(
                        "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} without a `:` delimiter",
                        s,
                    ).as_str()
                )
                .0
                .to_owned();
            if !error_codes.contains_key(&err_code) {
                error_codes.insert(err_code.clone(), false);
            }
            // Now we extract the tests from the markdown file!
            let md_file_name = match s.split_once("include_str!(\"") {
                None => continue,
                Some((_, md)) => match md.split_once("\")") {
                    None => continue,
                    Some((file_name, _)) => file_name,
                },
            };
            let path = some_or_continue!(path.parent())
                .join(md_file_name)
                .canonicalize()
                .expect("failed to canonicalize error explanation file path");
            match read_to_string(&path) {
                Ok(content) => {
                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` doesn't use its own error code in compile_fail example",
                            path.display(),
                        ));
                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` has a compile_fail example with its own error code, it shouldn't \
                             be listed in IGNORE_EXPLANATION_CHECK!",
                            path.display(),
                        ));
                    }
                    if check_error_code_explanation(&content, error_codes, err_code) {
                        errors.push(format!(
                            "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
                            path.display(),
                        ));
                    }
                }
                Err(e) => {
                    eprintln!("Couldn't read `{}`: {}", path.display(), e);
                }
            }
        } else if reached_no_explanation && s.starts_with('E') {
            let err_code = match s.split_once(',') {
                None => s,
                Some((err_code, _)) => err_code,
            }
            .to_string();
            if !error_codes.contains_key(&err_code) {
                // this check should *never* fail!
                error_codes.insert(err_code, false);
            }
        } else if s == ";" {
            reached_no_explanation = true;
        }
    }
}

fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, bool>) {
    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("error[E") || s.starts_with("warning[E") {
            let err_code = match s.split_once(']') {
                None => continue,
                Some((err_code, _)) => match err_code.split_once('[') {
                    None => continue,
                    Some((_, err_code)) => err_code,
                },
            };
            let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
            *nb = true;
        }
    }
}

pub fn check(paths: &[&Path], bad: &mut bool) {
    let mut errors = Vec::new();
    let mut found_explanations = 0;
    let mut found_tests = 0;
    println!("Checking which error codes lack tests...");
    let mut error_codes: HashMap<String, bool> = HashMap::new();
    for path in paths {
        super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
            let file_name = entry.file_name();
            if file_name == "error_codes.rs" {
                extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
                found_explanations += 1;
            } else if entry.path().extension() == Some(OsStr::new("stderr")) {
                extract_error_codes_from_tests(contents, &mut error_codes);
                found_tests += 1;
            }
        });
    }
    if found_explanations == 0 {
        eprintln!("No error code explanation was tested!");
        *bad = true;
    }
    if found_tests == 0 {
        eprintln!("No error code was found in compilation errors!");
        *bad = true;
    }
    if errors.is_empty() {
        println!("Found {} error codes", error_codes.len());

        for (err_code, nb) in &error_codes {
            if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
            } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!(
                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
                    err_code
                ));
            }
        }
    }
    errors.sort();
    for err in &errors {
        eprintln!("{}", err);
    }
    println!("Found {} error codes with no tests", errors.len());
    if !errors.is_empty() {
        *bad = true;
    }
    println!("Done!");
}
<commit_msg>Clean up error codes from being ignored<commit_after>//! Checks that all error codes have at least one test to prevent having error
//! codes that are silently not thrown by the compiler anymore.

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::read_to_string;
use std::path::Path;

// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
    "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464",
    "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483",
    "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553",
    "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729",
];

// Some error codes don't have any tests apparently...
const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];

fn check_error_code_explanation(
    f: &str,
    error_codes: &mut HashMap<String, bool>,
    err_code: String,
) -> bool {
    let mut invalid_compile_fail_format = false;
    let mut found_error_code = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains('E') {
                if !found_error_code {
                    error_codes.insert(err_code.clone(), true);
                    found_error_code = true;
                }
            } else if s.contains("compile-fail") {
                invalid_compile_fail_format = true;
            }
        } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            if !found_error_code {
                error_codes.get_mut(&err_code).map(|x| *x = true);
                found_error_code = true;
            }
        }
    }
    invalid_compile_fail_format
}

fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool {
    let mut ignore_found = false;

    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
            return true;
        }
        if s.starts_with("```") {
            if s.contains("compile_fail") && s.contains(err_code) {
                return true;
            } else if s.contains("ignore") {
                // It's very likely that we can't actually make it fail compilation...
                ignore_found = true;
            }
        }
    }
    ignore_found
}

macro_rules! some_or_continue {
    ($e:expr) => {
        match $e {
            Some(e) => e,
            None => continue,
        }
    };
}

fn extract_error_codes(
    f: &str,
    error_codes: &mut HashMap<String, bool>,
    path: &Path,
    errors: &mut Vec<String>,
) {
    let mut reached_no_explanation = false;

    for line in f.lines() {
        let s = line.trim();
        if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") {
            let err_code = s
                .split_once(':')
                .expect(
                    format!(
                        "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} without a `:` delimiter",
                        s,
                    ).as_str()
                )
                .0
                .to_owned();
            if !error_codes.contains_key(&err_code) {
                error_codes.insert(err_code.clone(), false);
            }
            // Now we extract the tests from the markdown file!
            let md_file_name = match s.split_once("include_str!(\"") {
                None => continue,
                Some((_, md)) => match md.split_once("\")") {
                    None => continue,
                    Some((file_name, _)) => file_name,
                },
            };
            let path = some_or_continue!(path.parent())
                .join(md_file_name)
                .canonicalize()
                .expect("failed to canonicalize error explanation file path");
            match read_to_string(&path) {
                Ok(content) => {
                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` doesn't use its own error code in compile_fail example",
                            path.display(),
                        ));
                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                        errors.push(format!(
                            "`{}` has a compile_fail example with its own error code, it shouldn't \
                             be listed in IGNORE_EXPLANATION_CHECK!",
                            path.display(),
                        ));
                    }
                    if check_error_code_explanation(&content, error_codes, err_code) {
                        errors.push(format!(
                            "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
                            path.display(),
                        ));
                    }
                }
                Err(e) => {
                    eprintln!("Couldn't read `{}`: {}", path.display(), e);
                }
            }
        } else if reached_no_explanation && s.starts_with('E') {
            let err_code = match s.split_once(',') {
                None => s,
                Some((err_code, _)) => err_code,
            }
            .to_string();
            if !error_codes.contains_key(&err_code) {
                // this check should *never* fail!
                error_codes.insert(err_code, false);
            }
        } else if s == ";" {
            reached_no_explanation = true;
        }
    }
}

fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, bool>) {
    for line in f.lines() {
        let s = line.trim();
        if s.starts_with("error[E") || s.starts_with("warning[E") {
            let err_code = match s.split_once(']') {
                None => continue,
                Some((err_code, _)) => match err_code.split_once('[') {
                    None => continue,
                    Some((_, err_code)) => err_code,
                },
            };
            let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
            *nb = true;
        }
    }
}

pub fn check(paths: &[&Path], bad: &mut bool) {
    let mut errors = Vec::new();
    let mut found_explanations = 0;
    let mut found_tests = 0;
    println!("Checking which error codes lack tests...");
    let mut error_codes: HashMap<String, bool> = HashMap::new();
    for path in paths {
        super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
            let file_name = entry.file_name();
            if file_name == "error_codes.rs" {
                extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
                found_explanations += 1;
            } else if entry.path().extension() == Some(OsStr::new("stderr")) {
                extract_error_codes_from_tests(contents, &mut error_codes);
                found_tests += 1;
            }
        });
    }
    if found_explanations == 0 {
        eprintln!("No error code explanation was tested!");
        *bad = true;
    }
    if found_tests == 0 {
        eprintln!("No error code was found in compilation errors!");
        *bad = true;
    }
    if errors.is_empty() {
        println!("Found {} error codes", error_codes.len());

        for (err_code, nb) in &error_codes {
            if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
            } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                errors.push(format!(
                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
                    err_code
                ));
            }
        }
    }
    errors.sort();
    for err in &errors {
        eprintln!("{}", err);
    }
    println!("Found {} error codes with no tests", errors.len());
    if !errors.is_empty() {
        *bad = true;
    }
    println!("Done!");
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate serde_json;
extern crate sputnikvm;

use sputnikvm::{read_hex, Gas};
use sputnikvm::vm::{Machine, FakeVectorMachine};

use serde_json::{Value, Error};
use std::fs::File;
use std::path::Path;
use std::io::BufReader;

fn test_transaction(v: &Value) {
    let current_coinbase = v["env"]["currentCoinbase"].as_str().unwrap();
    let current_difficulty = v["env"]["currentDifficulty"].as_str().unwrap();
    let current_gas_limit = v["env"]["currentGasLimit"].as_str().unwrap();
    let current_number = v["env"]["currentNumber"].as_str().unwrap();
    let current_timestamp = v["env"]["currentTimestamp"].as_str().unwrap();

    let address = v["exec"]["address"].as_str().unwrap();
    let caller = v["exec"]["caller"].as_str().unwrap();
    let code = v["exec"]["code"].as_str().unwrap();
    let data = v["exec"]["data"].as_str().unwrap();
    let gas = v["exec"]["gas"].as_str().unwrap();
    let gas_price = v["exec"]["gasPrice"].as_str().unwrap();
    let origin = v["exec"]["origin"].as_str().unwrap();
    let value = v["exec"]["value"].as_str().unwrap();

    let out = v["out"].as_str().unwrap();

    let ref pre_addresses = v["pre"];
    let ref post_addresses = v["post"];

    let code = read_hex(code).unwrap();
    let data = read_hex(data).unwrap();
    let gas = Gas::from_str(gas).unwrap();

    let mut machine = FakeVectorMachine::new(code.as_ref(), data.as_ref(), gas);
    machine.fire();

    let out = read_hex(out).unwrap();
    let out_ref: &[u8] = out.as_ref();
    assert!(machine.return_values() == out_ref);

}

fn main() {
    let app = clap_app!(jsonlighter =>
        (version: "0.1.0")
        (author: "SputnikVM Contributors")
        (@arg FILE: -f --file +takes_value +required "ethereumproject/tests JSON file to run for this test")
        (@arg TEST: -t --test +takes_value +required "test to run in the given file")
    ).get_matches();

    let path = Path::new(app.value_of("FILE").unwrap());
    let file = File::open(&path).unwrap();
    let reader = BufReader::new(file);
    let json: Value = serde_json::from_reader(reader).unwrap();
    let test = app.value_of("TEST").unwrap();

    test_transaction(&json[test]);
}
<commit_msg>Problem: storage equality is not checked Solution: check storage equality in tests<commit_after>#[macro_use]
extern crate clap;
extern crate serde_json;
extern crate sputnikvm;

use sputnikvm::{read_hex, Gas, U256, Address};
use sputnikvm::vm::{Machine, FakeVectorMachine};
use sputnikvm::blockchain::Block;

use serde_json::{Value, Error};
use std::fs::File;
use std::path::Path;
use std::io::BufReader;

fn test_transaction(v: &Value) {
    let current_coinbase = v["env"]["currentCoinbase"].as_str().unwrap();
    let current_difficulty = v["env"]["currentDifficulty"].as_str().unwrap();
    let current_gas_limit = v["env"]["currentGasLimit"].as_str().unwrap();
    let current_number = v["env"]["currentNumber"].as_str().unwrap();
    let current_timestamp = v["env"]["currentTimestamp"].as_str().unwrap();

    let address = v["exec"]["address"].as_str().unwrap();
    let caller = v["exec"]["caller"].as_str().unwrap();
    let code = v["exec"]["code"].as_str().unwrap();
    let data = v["exec"]["data"].as_str().unwrap();
    let gas = v["exec"]["gas"].as_str().unwrap();
    let gas_price = v["exec"]["gasPrice"].as_str().unwrap();
    let origin = v["exec"]["origin"].as_str().unwrap();
    let value = v["exec"]["value"].as_str().unwrap();

    let out = v["out"].as_str().unwrap();

    let ref pre_addresses = v["pre"];
    let ref post_addresses = v["post"];

    let code = read_hex(code).unwrap();
    let data = read_hex(data).unwrap();
    let gas = Gas::from_str(gas).unwrap();

    let mut machine = FakeVectorMachine::new(code.as_ref(), data.as_ref(), gas);
    machine.fire();

    let out = read_hex(out).unwrap();
    let out_ref: &[u8] = out.as_ref();
    assert!(machine.return_values() == out_ref);

    for (address, data) in post_addresses.as_object().unwrap() {
        let address = Address::from_str(address.as_str()).unwrap();
        let storage = data["storage"].as_object().unwrap();
        for (index, value) in storage {
            let index = U256::from_str(index.as_str()).unwrap();
            let value = U256::from_str(value.as_str().unwrap()).unwrap();
            // TODO: change Address::default() to the actual address
            assert!(value == machine.block().account_storage(Address::default(), index));
        }
    }
}

fn main() {
    let app = clap_app!(jsonlighter =>
        (version: "0.1.0")
        (author: "SputnikVM Contributors")
        (@arg FILE: -f --file +takes_value +required "ethereumproject/tests JSON file to run for this test")
        (@arg TEST: -t --test +takes_value +required "test to run in the given file")
    ).get_matches();

    let path = Path::new(app.value_of("FILE").unwrap());
    let file = File::open(&path).unwrap();
    let reader = BufReader::new(file);
    let json: Value = serde_json::from_reader(reader).unwrap();
    let test = app.value_of("TEST").unwrap();

    test_transaction(&json[test]);
}
<|endoftext|>


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

#![deny(warnings)]

extern crate cargo_registry;
extern crate postgres;
extern crate time;
extern crate semver;

use std::env;
use std::io;
use std::io::prelude::*;

use cargo_registry::{Crate, User};
use cargo_registry::owner::OwnerKind;
use cargo_registry::Model;

#[allow(dead_code)]
fn main() {
    let conn = cargo_registry::db::connect_now();
    {
        let tx = conn.transaction().unwrap();
        transfer(&tx);
        tx.set_commit();
        tx.finish().unwrap();
    }
}

fn transfer(tx: &postgres::transaction::Transaction) {
    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::find_by_login(tx, &from).unwrap();
    let to = User::find_by_login(tx, &to).unwrap();

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

        get_confirm("continue?");
    }

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

    let stmt = tx.prepare(
        "SELECT * FROM crate_owners
                                   WHERE owner_id = $1
                                     AND owner_kind = $2",
    ).unwrap();
    let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]).unwrap();
    for row in rows.iter() {
        let id: i32 = row.get("id");
        let krate = Crate::find(tx, row.get("crate_id")).unwrap();
        println!("transferring {}", krate.name);
        let owners = krate.owners_old(tx).unwrap();
        if owners.len() != 1 {
            println!("warning: not exactly one owner for {}", krate.name);
        }
        let n = tx.execute(
            "UPDATE crate_owners SET owner_id = $1
                             WHERE id $2",
            &[&to.id, &id],
        ).unwrap();
        assert_eq!(n, 1);
    }

    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") {
        std::process::exit(0);
    }
}
<commit_msg>Fix #645 and fix SQL query<commit_after>// Transfer all crates from one user to another.
//
// Usage:
//      cargo run --bin transfer-crates from-user to-user

#![deny(warnings)]

extern crate cargo_registry;
extern crate postgres;
extern crate time;
extern crate semver;

use std::env;
use std::io;
use std::io::prelude::*;

use cargo_registry::{Crate, User};
use cargo_registry::owner::OwnerKind;
use cargo_registry::Model;

#[allow(dead_code)]
fn main() {
    let conn = cargo_registry::db::connect_now();
    {
        let tx = conn.transaction().unwrap();
        transfer(&tx);
        tx.set_commit();
        tx.finish().unwrap();
    }
}

fn transfer(tx: &postgres::transaction::Transaction) {
    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::find_by_login(tx, &from).unwrap();
    let to = User::find_by_login(tx, &to).unwrap();

    if from.gh_avatar != to.gh_avatar {
        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 stmt = tx.prepare(
        "SELECT * FROM crate_owners
                                   WHERE owner_id = $1
                                     AND owner_kind = $2",
    ).unwrap();
    let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]).unwrap();
    for row in rows.iter() {
        let owner_id: i32 = row.get("owner_id");
        let krate = Crate::find(tx, row.get("crate_id")).unwrap();
        println!("transferring {}", krate.name);
        let owners = krate.owners_old(tx).unwrap();
        if owners.len() != 1 {
            println!("warning: not exactly one owner for {}", krate.name);
        }
        let n = tx.execute(
            "UPDATE crate_owners SET owner_id = $1
                             WHERE owner_id = $2",
            &[&to.id, &owner_id],
        ).unwrap();
        assert_eq!(n, 1);
    }

    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") {
        std::process::exit(0);
    }
}
<|endoftext|>


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

use std::io::Write;

use syn;

use bindgen::annotation::*;
use bindgen::cdecl;
use bindgen::config::{Config, Layout};
use bindgen::ir::*;
use bindgen::library::*;
use bindgen::rename::*;
use bindgen::utilities::*;
use bindgen::writer::*;

#[derive(Debug, Clone)]
pub struct Function {
    pub name: String,
    pub annotations: AnnotationSet,
    pub ret: Type,
    pub args: Vec<(String, Type)>,
    pub extern_decl: bool,
    pub documentation: Documentation,
}

impl Function {
    pub fn load(name: String,
                annotations: AnnotationSet,
                decl: &syn::FnDecl,
                extern_decl: bool,
                doc: String) -> Result<Function, String>
    {
        let args = decl.inputs.iter()
                              .try_skip_map(|x| x.as_ident_and_type())?;
        let ret = decl.output.as_type()?;

        Ok(Function {
            name: name,
            annotations: annotations,
            ret: ret,
            args: args,
            extern_decl: extern_decl,
            documentation: Documentation::load(doc),
        })
    }

    pub fn add_deps(&self, library: &Library, out: &mut DependencyList) {
        self.ret.add_deps(library, out);
        for &(_, ref ty) in &self.args {
            ty.add_deps(library, out);
        }
    }

    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
        self.ret.add_monomorphs(library, out);
        for &(_, ref ty) in &self.args {
            ty.add_monomorphs(library, out);
        }
    }

    pub fn add_specializations(&self, library: &Library, out: &mut SpecializationList) {
        self.ret.add_specializations(library, out);
        for &(_, ref ty) in &self.args {
            ty.add_specializations(library, out);
        }
    }

    pub fn rename_args(&mut self, config: &Config) {
        let rules = [self.annotations.parse_atom::<RenameRule>("rename-all"),
                     config.function.rename_args];

        if let Some(r) = find_first_some(&rules) {
            self.args = self.args.iter()
                                 .map(|x| (r.apply_to_snake_case(&x.0,
                                                                 IdentifierType::FunctionArg),
                                           x.1.clone()))
                                  .collect()
        }
    }

    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
        for &mut (_, ref mut ty) in &mut self.args {
            ty.mangle_paths(monomorphs);
        }
    }
}

impl Source for Function {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        fn write_1<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
            let prefix = config.function.prefix(&func.annotations);
            let postfix = config.function.postfix(&func.annotations);

            if let Some(ref prefix) = prefix {
                out.write(prefix);
                out.write(" ");
            }
            func.documentation.write(config, out);
            cdecl::write_func(out, &func, false);
            if let Some(ref postfix) = postfix {
                out.write(" ");
                out.write(postfix);
            }
            out.write(";");
        }

        fn write_2<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
            let prefix = config.function.prefix(&func.annotations);
            let postfix = config.function.postfix(&func.annotations);

            if let Some(ref prefix) = prefix {
                out.write(prefix);
                out.new_line();
            }
            func.documentation.write(config, out);
            cdecl::write_func(out, &func, true);
            if let Some(ref postfix) = postfix {
                out.new_line();
                out.write(postfix);
            }
            out.write(";");
        };

        let option_1 = out.measure(|out| write_1(self, config, out));

        if (config.function.args == Layout::Auto && option_1 <= config.line_length) ||
           config.function.args == Layout::Horizontal {
            write_1(self, config, out);
        } else {
            write_2(self, config, out);
        }
    }
}

pub trait SynFnArgHelpers {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type)>, String>;
}

impl SynFnArgHelpers for syn::FnArg {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type)>, String> {
        match self {
            &syn::FnArg::Captured(syn::Pat::Ident(_, ref ident, _), ref ty) => {
                if let Some(x) = Type::load(ty)? {
                    Ok(Some((ident.to_string(), x)))
                } else {
                    Ok(None)
                }
            }
            _ => Err(format!("parameter has unexpected type")),
        }
    }
}
<commit_msg>Write function documentation before the function prefix<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::annotation::*;
use bindgen::cdecl;
use bindgen::config::{Config, Layout};
use bindgen::ir::*;
use bindgen::library::*;
use bindgen::rename::*;
use bindgen::utilities::*;
use bindgen::writer::*;

#[derive(Debug, Clone)]
pub struct Function {
    pub name: String,
    pub annotations: AnnotationSet,
    pub ret: Type,
    pub args: Vec<(String, Type)>,
    pub extern_decl: bool,
    pub documentation: Documentation,
}

impl Function {
    pub fn load(name: String,
                annotations: AnnotationSet,
                decl: &syn::FnDecl,
                extern_decl: bool,
                doc: String) -> Result<Function, String>
    {
        let args = decl.inputs.iter()
                              .try_skip_map(|x| x.as_ident_and_type())?;
        let ret = decl.output.as_type()?;

        Ok(Function {
            name: name,
            annotations: annotations,
            ret: ret,
            args: args,
            extern_decl: extern_decl,
            documentation: Documentation::load(doc),
        })
    }

    pub fn add_deps(&self, library: &Library, out: &mut DependencyList) {
        self.ret.add_deps(library, out);
        for &(_, ref ty) in &self.args {
            ty.add_deps(library, out);
        }
    }

    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
        self.ret.add_monomorphs(library, out);
        for &(_, ref ty) in &self.args {
            ty.add_monomorphs(library, out);
        }
    }

    pub fn add_specializations(&self, library: &Library, out: &mut SpecializationList) {
        self.ret.add_specializations(library, out);
        for &(_, ref ty) in &self.args {
            ty.add_specializations(library, out);
        }
    }

    pub fn rename_args(&mut self, config: &Config) {
        let rules = [self.annotations.parse_atom::<RenameRule>("rename-all"),
                     config.function.rename_args];

        if let Some(r) = find_first_some(&rules) {
            self.args = self.args.iter()
                                 .map(|x| (r.apply_to_snake_case(&x.0,
                                                                 IdentifierType::FunctionArg),
                                           x.1.clone()))
                                  .collect()
        }
    }

    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
        for &mut (_, ref mut ty) in &mut self.args {
            ty.mangle_paths(monomorphs);
        }
    }
}

impl Source for Function {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        fn write_1<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
            let prefix = config.function.prefix(&func.annotations);
            let postfix = config.function.postfix(&func.annotations);

            func.documentation.write(config, out);
            if let Some(ref prefix) = prefix {
                out.write(prefix);
                out.write(" ");
            }
            cdecl::write_func(out, &func, false);
            if let Some(ref postfix) = postfix {
                out.write(" ");
                out.write(postfix);
            }
            out.write(";");
        }

        fn write_2<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
            let prefix = config.function.prefix(&func.annotations);
            let postfix = config.function.postfix(&func.annotations);

            func.documentation.write(config, out);
            if let Some(ref prefix) = prefix {
                out.write(prefix);
                out.new_line();
            }
            cdecl::write_func(out, &func, true);
            if let Some(ref postfix) = postfix {
                out.new_line();
                out.write(postfix);
            }
            out.write(";");
        };

        let option_1 = out.measure(|out| write_1(self, config, out));

        if (config.function.args == Layout::Auto && option_1 <= config.line_length) ||
           config.function.args == Layout::Horizontal {
            write_1(self, config, out);
        } else {
            write_2(self, config, out);
        }
    }
}

pub trait SynFnArgHelpers {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type)>, String>;
}

impl SynFnArgHelpers for syn::FnArg {
    fn as_ident_and_type(&self) -> Result<Option<(String, Type)>, String> {
        match self {
            &syn::FnArg::Captured(syn::Pat::Ident(_, ref ident, _), ref ty) => {
                if let Some(x) = Type::load(ty)? {
                    Ok(Some((ident.to_string(), x)))
                } else {
                    Ok(None)
                }
            }
            _ => Err(format!("parameter has unexpected type")),
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::io::{stdout, stderr, Write};
use std::path::{Path, PathBuf};
use std::fs::metadata;
use std::os::unix::fs::MetadataExt;

use libc::getuid;

use options::build_mode::{build_mode, BuildMode};
use config::{Config, Settings, find_config};
use config::read_settings::{read_settings, MergedSettings};
use argparse::{ArgumentParser, Store, List, Collect, Print, StoreFalse, StoreTrue};

mod list;
mod user;
mod pack;
mod push;
pub mod build;
mod storage;
mod underscore;
mod completion;
mod commands;
mod storage_dir;

mod supervisor;
mod simple;
mod capsule;

pub mod wrap;
pub mod system;
pub mod network;
mod socket;
mod volumes;
mod options;
mod prerequisites;

pub struct Context {
    pub config: Config,
    pub settings: Settings,
    pub ext_settings: MergedSettings,
    pub workdir: PathBuf,
    pub config_dir: PathBuf,
    pub build_mode: BuildMode,
    pub prerequisites: bool,
    pub isolate_network: bool
}

fn check_export(cmd: &String) -> Option<String> {
    if cmd == "/proc/self/exe" || cmd == "vagga" {
        return None;
    }
    match cmd.rfind("/") {
        Some(slash) => {
            let exe = &cmd[slash+1..];
            if exe == "vagga" || exe.starts_with("vagga_") {
                None
            } else {
                Some(exe.to_owned())
            }
        }
        None => Some(cmd.clone()),
    }
}

pub fn run(input_args: Vec<String>) -> i32 {
    let mut err = stderr();
    let workdir = env::current_dir().unwrap();

    let (config, cfg_dir) = match find_config(&workdir, true) {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };
    // Not sure this is a best place, but the variable is needed for correct
    // reading of settings
    if let Some(x) = env::var_os("HOME") {
        env::set_var("_VAGGA_HOME", x);
    }

    let (ext_settings, int_settings) = match read_settings(&cfg_dir)
    {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };

    let mut commands = Vec::<String>::new();
    let mut cname = "".to_string();
    let mut args = vec!();
    let mut set_env = Vec::<String>::new();
    let mut propagate_env = Vec::<String>::new();
    let mut bmode = Default::default();
    let mut owner_check = true;
    let mut prerequisites = true;
    let mut isolate_network = false;

    let export_command = input_args.get(0).and_then(check_export);
    if !int_settings.run_symlinks_as_commands || export_command.is_none() {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a command in container, optionally builds container if that
            does not exists or outdated.

            Run `vagga` without arguments to see the list of commands.
            ");
        ap.add_option(&["-V", "--version"],
            Print(env!("VAGGA_VERSION").to_string()),
            "Show vagga version and exit");
        ap.refer(&mut set_env)
          .add_option(&["-E", "--env", "--environ"], Collect,
                "Set environment variable for running command")
          .metavar("NAME=VALUE");
        ap.refer(&mut propagate_env)
          .add_option(&["-e", "--use-env"], Collect,
                "Propagate variable VAR into command environment")
          .metavar("VAR");
        ap.refer(&mut owner_check)
          .add_option(&["--ignore-owner-check"], StoreFalse,
                "Ignore checking owner of the project directory");
        ap.refer(&mut prerequisites)
            .add_option(&["--no-prerequisites"], StoreFalse,
            "Run only specified command(s), don't run prerequisites");
        ap.refer(&mut isolate_network)
            .add_option(
                &["--isolate-network", "--no-network", "--no-net"],
                StoreTrue,
                "Run command(s) inside isolated network");
        build_mode(&mut ap, &mut bmode);
        ap.refer(&mut commands)
          .add_option(&["-m", "--run-multi"], List, "
            Run the following list of commands. Each without an arguments.
            When any of them fails, stop the chain. Basically it's the
            shortcut to `vagga cmd1 && vagga cmd2` except containers for
            `cmd2` are built beforehand, for your convenience. Also builtin
            commands (those starting with underscore) do not work with
            `vagga -m`");
        ap.refer(&mut cname)
          .add_argument("command", Store,
                "A vagga command to run");
        ap.refer(&mut args)
          .add_argument("args", List,
                "Arguments for the command");
        ap.stop_on_first_argument(true);
        ap.silence_double_dash(false);
        match ap.parse(input_args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return 0,
            Err(_) => return 122,
        }
    } else {
        let export_command = export_command.unwrap();
        for (name, cmd) in &config.commands {
            match cmd.link() {
                Some(ref lnk) if lnk.name == export_command => {
                    cname = name.clone();
                }
                _ => {}
            }
        }
        if cname == "" {
            writeln!(&mut err, "Can't find command {:?}", export_command).ok();
            return 127;
        }
        args = input_args;
        args.remove(0);  // the command itself
    }

    if &cname[..] == "_network" {
        args.insert(0, "vagga _network".to_string());
        return ::network::run(args);
    }

    if owner_check {
        let uid = unsafe { getuid() };
        match metadata(&cfg_dir) {
            Ok(ref stat) if stat.uid() == uid  => {}
            Ok(_) => {
                if uid == 0 {
                    writeln!(&mut err, "You should not run vagga as root \
                        (see http://bit.ly/err_root)").ok();
                    return 122;
                } else {
                    warn!("You are running vagga as a user \
                        different from the owner of project directory. \
                        You may not have needed permissions \
                        (see http://bit.ly/err_root)");
                }
            }
            Err(e) => {
                writeln!(&mut err, "Can't stat {:?}: {}", cfg_dir, e).ok();
                return 126;
            }
        }
    }

    let int_workdir = workdir.strip_prefix(&cfg_dir)
                             .unwrap_or(&Path::new("."));

    for k in propagate_env.into_iter() {
        if k.chars().find(|&c| c == '=').is_some() {
            writeln!(&mut err, "Environment variable name \
                (for option `-e`/`--use-env`) \
                can't contain equals `=` character. \
                To set key-value pair use `-E`/`--environ` option").ok();
            return 126;
        } else {
            env::set_var(&("VAGGAENV_".to_string() + &k[..]),
                env::var_os(&k).unwrap_or(From::from("")));
        }
    }
    for pair in set_env.into_iter() {
        let mut pairiter = pair[..].splitn(2, '=');
        let key = "VAGGAENV_".to_string() + pairiter.next().unwrap();
        if let Some(value) = pairiter.next() {
            env::set_var(&key, value.to_string());
        } else {
            env::remove_var(&key);
        }
    }

    let context = Context {
        config: config,
        settings: int_settings,
        ext_settings: ext_settings,
        workdir: int_workdir.to_path_buf(),
        config_dir: cfg_dir.to_path_buf(),
        build_mode: bmode,
        prerequisites: prerequisites,
        isolate_network: isolate_network,
    };

    if commands.len() > 0 {
        let result = user::run_multiple_commands(&context, commands);
        match result {
            Ok(rc) => {
                return rc;
            }
            Err(text) =>  {
                writeln!(&mut err, "{}", text).ok();
                return 121;
            }
        }
    }

    let result:Result<i32, String> = match &cname[..] {
        "" => {
            list::print_help(&context.config)
        }
        "_create_netns" => {
            network::create_netns(&context.config, args)
        }
        "_destroy_netns" => {
            network::destroy_netns(&context.config, args)
        }
        "_list" => {
            list::print_list(&context.config, args)
        }
        "_version_hash" => {
            underscore::version_hash(&context, &cname, args)
        }
        "_build_shell" | "_clean" | "_check_overlayfs_support" => {
            underscore::passthrough(&context, &cname, args)
        }
        "_base_dir" => {
            println!("{}", cfg_dir.display());
            Ok(0)
        }
        "_relative_work_dir" => {
            println!("{}", int_workdir.display());
            Ok(0)
        }
        "_build" => {
            build::build_command(&context, args)
        }
        "_run" => {
            underscore::run_command(&context, args)
        }
        "_run_in_netns" => {
            underscore::run_in_netns(&context, cname, args)
        }
        "_pack_image" => {
            pack::pack_command(&context, args)
        }
        "_push_image" => {
            push::push_command(&context, args)
        }
        "_init_storage_dir" => {
            storage::init_dir(&context.ext_settings, &cfg_dir, args)
        }
        "_compgen" => {
            completion::generate_completions(&context.config, args)
        }
        "_help" => {
            completion::generate_command_help(&context, args)
        }
        "_update_symlinks" => {
            commands::update_symlinks(&context, args)
        }
        "_capsule" => {
            ::capsule::run_command(&context, args)
        }
        _ => {
            user::run_user_command(&context, cname, args)
        }
    };

    match result {
        Ok(rc) => {
            return rc;
        }
        Err(text) =>  {
            writeln!(&mut err, "{}", text).ok();
            return 121;
        }
    }
}
<commit_msg>Adds support for `vagga --config` without vagga.yaml (fixes #460, #457, #459)<commit_after>use std::env;
use std::io::{stdout, stderr, Write};
use std::path::{Path, PathBuf};
use std::fs::metadata;
use std::os::unix::fs::MetadataExt;

use libc::getuid;

use options::build_mode::{build_mode, BuildMode};
use config::{Config, Settings, find_config};
use config::read_settings::{read_settings, MergedSettings};
use argparse::{ArgumentParser, Store, List, Collect, Print, StoreFalse, StoreTrue};

mod list;
mod user;
mod pack;
mod push;
pub mod build;
mod storage;
mod underscore;
mod completion;
mod commands;
mod storage_dir;

mod supervisor;
mod simple;
mod capsule;

pub mod wrap;
pub mod system;
pub mod network;
mod socket;
mod volumes;
mod options;
mod prerequisites;

pub struct Context {
    pub config: Config,
    pub settings: Settings,
    pub ext_settings: MergedSettings,
    pub workdir: PathBuf,
    pub config_dir: PathBuf,
    pub build_mode: BuildMode,
    pub prerequisites: bool,
    pub isolate_network: bool
}

fn check_export(cmd: &String) -> Option<String> {
    if cmd == "/proc/self/exe" || cmd == "vagga" {
        return None;
    }
    match cmd.rfind("/") {
        Some(slash) => {
            let exe = &cmd[slash+1..];
            if exe == "vagga" || exe.starts_with("vagga_") {
                None
            } else {
                Some(exe.to_owned())
            }
        }
        None => Some(cmd.clone()),
    }
}

pub fn run(input_args: Vec<String>) -> i32 {
    let mut err = stderr();

    let mut commands = Vec::<String>::new();
    let mut cname = "".to_string();
    let mut args = vec!();
    let mut set_env = Vec::<String>::new();
    let mut propagate_env = Vec::<String>::new();
    let mut bmode = Default::default();
    let mut owner_check = true;
    let mut prerequisites = true;
    let mut isolate_network = false;

    let export_command = input_args.get(0).and_then(check_export);
    let (cli_ok, cli_out, cli_err) = {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a command in container, optionally builds container if that
            does not exists or outdated.

            Run `vagga` without arguments to see the list of commands.
            ");
        ap.add_option(&["-V", "--version"],
            Print(env!("VAGGA_VERSION").to_string()),
            "Show vagga version and exit");
        ap.refer(&mut set_env)
          .add_option(&["-E", "--env", "--environ"], Collect,
                "Set environment variable for running command")
          .metavar("NAME=VALUE");
        ap.refer(&mut propagate_env)
          .add_option(&["-e", "--use-env"], Collect,
                "Propagate variable VAR into command environment")
          .metavar("VAR");
        ap.refer(&mut owner_check)
          .add_option(&["--ignore-owner-check"], StoreFalse,
                "Ignore checking owner of the project directory");
        ap.refer(&mut prerequisites)
            .add_option(&["--no-prerequisites"], StoreFalse,
            "Run only specified command(s), don't run prerequisites");
        ap.refer(&mut isolate_network)
            .add_option(
                &["--isolate-network", "--no-network", "--no-net"],
                StoreTrue,
                "Run command(s) inside isolated network");
        build_mode(&mut ap, &mut bmode);
        ap.refer(&mut commands)
          .add_option(&["-m", "--run-multi"], List, "
            Run the following list of commands. Each without an arguments.
            When any of them fails, stop the chain. Basically it's the
            shortcut to `vagga cmd1 && vagga cmd2` except containers for
            `cmd2` are built beforehand, for your convenience. Also builtin
            commands (those starting with underscore) do not work with
            `vagga -m`");
        ap.refer(&mut cname)
          .add_argument("command", Store,
                "A vagga command to run");
        ap.refer(&mut args)
          .add_argument("args", List,
                "Arguments for the command");
        ap.stop_on_first_argument(true);
        ap.silence_double_dash(false);
        let mut cli_out = Vec::new();
        let mut cli_err = Vec::new();
        match ap.parse(input_args.clone(), &mut cli_out, &mut cli_err) {
            Err(0) if export_command.is_none() => {
                stdout().write_all(&cli_out).ok();
                stderr().write_all(&cli_err).ok();
                return 0;
            }
            r => (r, cli_out, cli_err),
        }
    };

    let workdir = env::current_dir().unwrap();

    let (config, cfg_dir) = match find_config(&workdir, true) {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };
    // Not sure this is a best place, but the variable is needed for correct
    // reading of settings
    if let Some(x) = env::var_os("HOME") {
        env::set_var("_VAGGA_HOME", x);
    }

    let (ext_settings, int_settings) = match read_settings(&cfg_dir)
    {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };
    if !int_settings.run_symlinks_as_commands || export_command.is_none() {
        stdout().write_all(&cli_out).ok();
        stderr().write_all(&cli_err).ok();
        match cli_ok {
            Ok(()) => {}
            Err(0) => return 0,
            Err(_) => return 122,
        }
    } else {
        let export_command = export_command.unwrap();
        for (name, cmd) in &config.commands {
            match cmd.link() {
                Some(ref lnk) if lnk.name == export_command => {
                    cname = name.clone();
                }
                _ => {}
            }
        }
        if cname == "" {
            writeln!(&mut err, "Can't find command {:?}", export_command).ok();
            return 127;
        }
        args = input_args;
        args.remove(0);  // the command itself
    }

    if &cname[..] == "_network" {
        args.insert(0, "vagga _network".to_string());
        return ::network::run(args);
    }

    if owner_check {
        let uid = unsafe { getuid() };
        match metadata(&cfg_dir) {
            Ok(ref stat) if stat.uid() == uid  => {}
            Ok(_) => {
                if uid == 0 {
                    writeln!(&mut err, "You should not run vagga as root \
                        (see http://bit.ly/err_root)").ok();
                    return 122;
                } else {
                    warn!("You are running vagga as a user \
                        different from the owner of project directory. \
                        You may not have needed permissions \
                        (see http://bit.ly/err_root)");
                }
            }
            Err(e) => {
                writeln!(&mut err, "Can't stat {:?}: {}", cfg_dir, e).ok();
                return 126;
            }
        }
    }

    let int_workdir = workdir.strip_prefix(&cfg_dir)
                             .unwrap_or(&Path::new("."));

    for k in propagate_env.into_iter() {
        if k.chars().find(|&c| c == '=').is_some() {
            writeln!(&mut err, "Environment variable name \
                (for option `-e`/`--use-env`) \
                can't contain equals `=` character. \
                To set key-value pair use `-E`/`--environ` option").ok();
            return 126;
        } else {
            env::set_var(&("VAGGAENV_".to_string() + &k[..]),
                env::var_os(&k).unwrap_or(From::from("")));
        }
    }
    for pair in set_env.into_iter() {
        let mut pairiter = pair[..].splitn(2, '=');
        let key = "VAGGAENV_".to_string() + pairiter.next().unwrap();
        if let Some(value) = pairiter.next() {
            env::set_var(&key, value.to_string());
        } else {
            env::remove_var(&key);
        }
    }

    let context = Context {
        config: config,
        settings: int_settings,
        ext_settings: ext_settings,
        workdir: int_workdir.to_path_buf(),
        config_dir: cfg_dir.to_path_buf(),
        build_mode: bmode,
        prerequisites: prerequisites,
        isolate_network: isolate_network,
    };

    if commands.len() > 0 {
        let result = user::run_multiple_commands(&context, commands);
        match result {
            Ok(rc) => {
                return rc;
            }
            Err(text) =>  {
                writeln!(&mut err, "{}", text).ok();
                return 121;
            }
        }
    }

    let result:Result<i32, String> = match &cname[..] {
        "" => {
            list::print_help(&context.config)
        }
        "_create_netns" => {
            network::create_netns(&context.config, args)
        }
        "_destroy_netns" => {
            network::destroy_netns(&context.config, args)
        }
        "_list" => {
            list::print_list(&context.config, args)
        }
        "_version_hash" => {
            underscore::version_hash(&context, &cname, args)
        }
        "_build_shell" | "_clean" | "_check_overlayfs_support" => {
            underscore::passthrough(&context, &cname, args)
        }
        "_base_dir" => {
            println!("{}", cfg_dir.display());
            Ok(0)
        }
        "_relative_work_dir" => {
            println!("{}", int_workdir.display());
            Ok(0)
        }
        "_build" => {
            build::build_command(&context, args)
        }
        "_run" => {
            underscore::run_command(&context, args)
        }
        "_run_in_netns" => {
            underscore::run_in_netns(&context, cname, args)
        }
        "_pack_image" => {
            pack::pack_command(&context, args)
        }
        "_push_image" => {
            push::push_command(&context, args)
        }
        "_init_storage_dir" => {
            storage::init_dir(&context.ext_settings, &cfg_dir, args)
        }
        "_compgen" => {
            completion::generate_completions(&context.config, args)
        }
        "_help" => {
            completion::generate_command_help(&context, args)
        }
        "_update_symlinks" => {
            commands::update_symlinks(&context, args)
        }
        "_capsule" => {
            ::capsule::run_command(&context, args)
        }
        _ => {
            user::run_user_command(&context, cname, args)
        }
    };

    match result {
        Ok(rc) => {
            return rc;
        }
        Err(text) =>  {
            writeln!(&mut err, "{}", text).ok();
            return 121;
        }
    }
}
<|endoftext|>


<commit_before>#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    let data = data.get(..10240).unwrap_or(data);
    let _ = serde_yaml::from_slice::<serde_yaml::Value>(data);
});
<commit_msg>Early return on too big fuzz case<commit_after>#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    if data.len() <= 10240 {
        let _ = serde_yaml::from_slice::<serde_yaml::Value>(data);
    }
});
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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::Span;
use syn::{Ident, LitStr, Result as ParseResult};

/// Allowlist configuration.
#[derive(Hash, Debug)]
pub enum Allowlist {
    Unspecified,
    All,
    Specific(Vec<String>),
}

impl Allowlist {
    pub(crate) fn push(&mut self, item: LitStr) -> ParseResult<()> {
        match self {
            Allowlist::Unspecified => {
                *self = Allowlist::Specific(vec![item.value()]);
            }
            Allowlist::All => {
                return Err(syn::Error::new(
                    item.span(),
                    "use either generate!/generate_pod! or generate_all!, not both.",
                ))
            }
            Allowlist::Specific(list) => list.push(item.value()),
        };
        Ok(())
    }

    pub(crate) fn set_all(&mut self, ident: &Ident) -> ParseResult<()> {
        if matches!(self, Allowlist::Specific(..)) {
            return Err(syn::Error::new(
                ident.span(),
                "use either generate!/generate_pod! or generate_all!, not both.",
            ));
        }
        *self = Allowlist::All;
        Ok(())
    }
}

impl Default for Allowlist {
    fn default() -> Self {
        Allowlist::Unspecified
    }
}

#[derive(Default, Hash, Debug)]
pub(crate) struct TypeConfigInput {
    pub(crate) pod_requests: Vec<String>,
    pub(crate) allowlist: Allowlist,
    pub(crate) blocklist: Vec<String>,
    pub(crate) exclude_utilities: bool,
}

/// Configuration about types.
/// At present this is very minimal; in future we should roll
/// known_types.rs into this and possibly other things as well.
/// This type can only be created once we know that the allowlist
/// is specified.
#[derive(Hash, Debug)]
pub struct TypeConfig(TypeConfigInput);

const UTILITIES: &[&str] = &["make_string"];
const NO_UTILITIES: &[&str] = &[];

impl TypeConfigInput {
    pub(crate) fn into_type_config(self) -> ParseResult<TypeConfig> {
        if matches!(self.allowlist, Allowlist::Unspecified) {
            Err(syn::Error::new(
                Span::call_site(),
                "expected generate! or generate_all!",
            ))
        } else {
            Ok(TypeConfig(self))
        }
    }
}

impl TypeConfig {
    pub fn get_pod_requests(&self) -> &[String] {
        &self.0.pod_requests
    }

    /// Whether to avoid generating the standard helpful utility
    /// functions which we normally include in every mod.
    pub fn exclude_utilities(&self) -> bool {
        self.0.exclude_utilities
    }

    /// Items which the user has explicitly asked us to generate;
    /// we should raise an error if we weren't able to do so.
    pub fn must_generate_list(&self) -> Box<dyn Iterator<Item = String> + '_> {
        if let Allowlist::Specific(items) = &self.0.allowlist {
            Box::new(items.iter().chain(self.0.pod_requests.iter()).cloned())
        } else {
            Box::new(self.0.pod_requests.iter().cloned())
        }
    }

    /// The allowlist of items to be passed into bindgen, if any.
    pub fn bindgen_allowlist(&self) -> Option<Box<dyn Iterator<Item = String> + '_>> {
        match &self.0.allowlist {
            Allowlist::All => None,
            Allowlist::Specific(items) => Some(Box::new(
                items
                    .iter()
                    .chain(self.0.pod_requests.iter())
                    .cloned()
                    .chain(self.active_utilities().iter().map(|s| s.to_string())),
            )),
            Allowlist::Unspecified => unreachable!(),
        }
    }

    fn active_utilities(&self) -> &'static [&'static str] {
        if self.0.exclude_utilities {
            NO_UTILITIES
        } else {
            UTILITIES
        }
    }

    /// Whether this type is on the allowlist specified by the user.
    ///
    /// A note on the allowlist handling in general. It's used in two places:
    /// 1) As directives to bindgen
    /// 2) After bindgen has generated code, to filter the APIs which
    ///    we pass to cxx.
    /// This second pass may seem redundant. But sometimes bindgen generates
    /// unnecessary stuff.
    pub fn is_on_allowlist(&self, cpp_name: &str) -> bool {
        match self.bindgen_allowlist() {
            None => true,
            Some(mut items) => {
                items.any(|item| item == cpp_name)
                    || self.active_utilities().iter().any(|item| *item == cpp_name)
            }
        }
    }

    pub fn is_on_blocklist(&self, cpp_name: &str) -> bool {
        self.0.blocklist.contains(&cpp_name.to_string())
    }

    pub fn get_blocklist(&self) -> impl Iterator<Item = &String> {
        self.0.blocklist.iter()
    }

    pub fn new_for_test() -> Self {
        let mut input = TypeConfigInput::default();
        input.allowlist = Allowlist::All;
        input.into_type_config().unwrap()
    }
}
<commit_msg>Clippy lint.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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::Span;
use syn::{Ident, LitStr, Result as ParseResult};

/// Allowlist configuration.
#[derive(Hash, Debug)]
pub enum Allowlist {
    Unspecified,
    All,
    Specific(Vec<String>),
}

impl Allowlist {
    pub(crate) fn push(&mut self, item: LitStr) -> ParseResult<()> {
        match self {
            Allowlist::Unspecified => {
                *self = Allowlist::Specific(vec![item.value()]);
            }
            Allowlist::All => {
                return Err(syn::Error::new(
                    item.span(),
                    "use either generate!/generate_pod! or generate_all!, not both.",
                ))
            }
            Allowlist::Specific(list) => list.push(item.value()),
        };
        Ok(())
    }

    pub(crate) fn set_all(&mut self, ident: &Ident) -> ParseResult<()> {
        if matches!(self, Allowlist::Specific(..)) {
            return Err(syn::Error::new(
                ident.span(),
                "use either generate!/generate_pod! or generate_all!, not both.",
            ));
        }
        *self = Allowlist::All;
        Ok(())
    }
}

impl Default for Allowlist {
    fn default() -> Self {
        Allowlist::Unspecified
    }
}

#[derive(Default, Hash, Debug)]
pub(crate) struct TypeConfigInput {
    pub(crate) pod_requests: Vec<String>,
    pub(crate) allowlist: Allowlist,
    pub(crate) blocklist: Vec<String>,
    pub(crate) exclude_utilities: bool,
}

/// Configuration about types.
/// At present this is very minimal; in future we should roll
/// known_types.rs into this and possibly other things as well.
/// This type can only be created once we know that the allowlist
/// is specified.
#[derive(Hash, Debug)]
pub struct TypeConfig(TypeConfigInput);

const UTILITIES: &[&str] = &["make_string"];
const NO_UTILITIES: &[&str] = &[];

impl TypeConfigInput {
    pub(crate) fn into_type_config(self) -> ParseResult<TypeConfig> {
        if matches!(self.allowlist, Allowlist::Unspecified) {
            Err(syn::Error::new(
                Span::call_site(),
                "expected generate! or generate_all!",
            ))
        } else {
            Ok(TypeConfig(self))
        }
    }
}

impl TypeConfig {
    pub fn get_pod_requests(&self) -> &[String] {
        &self.0.pod_requests
    }

    /// Whether to avoid generating the standard helpful utility
    /// functions which we normally include in every mod.
    pub fn exclude_utilities(&self) -> bool {
        self.0.exclude_utilities
    }

    /// Items which the user has explicitly asked us to generate;
    /// we should raise an error if we weren't able to do so.
    pub fn must_generate_list(&self) -> Box<dyn Iterator<Item = String> + '_> {
        if let Allowlist::Specific(items) = &self.0.allowlist {
            Box::new(items.iter().chain(self.0.pod_requests.iter()).cloned())
        } else {
            Box::new(self.0.pod_requests.iter().cloned())
        }
    }

    /// The allowlist of items to be passed into bindgen, if any.
    pub fn bindgen_allowlist(&self) -> Option<Box<dyn Iterator<Item = String> + '_>> {
        match &self.0.allowlist {
            Allowlist::All => None,
            Allowlist::Specific(items) => Some(Box::new(
                items
                    .iter()
                    .chain(self.0.pod_requests.iter())
                    .cloned()
                    .chain(self.active_utilities().iter().map(|s| s.to_string())),
            )),
            Allowlist::Unspecified => unreachable!(),
        }
    }

    fn active_utilities(&self) -> &'static [&'static str] {
        if self.0.exclude_utilities {
            NO_UTILITIES
        } else {
            UTILITIES
        }
    }

    /// Whether this type is on the allowlist specified by the user.
    ///
    /// A note on the allowlist handling in general. It's used in two places:
    /// 1) As directives to bindgen
    /// 2) After bindgen has generated code, to filter the APIs which
    ///    we pass to cxx.
    /// This second pass may seem redundant. But sometimes bindgen generates
    /// unnecessary stuff.
    pub fn is_on_allowlist(&self, cpp_name: &str) -> bool {
        match self.bindgen_allowlist() {
            None => true,
            Some(mut items) => {
                items.any(|item| item == cpp_name)
                    || self.active_utilities().iter().any(|item| *item == cpp_name)
            }
        }
    }

    pub fn is_on_blocklist(&self, cpp_name: &str) -> bool {
        self.0.blocklist.contains(&cpp_name.to_string())
    }

    pub fn get_blocklist(&self) -> impl Iterator<Item = &String> {
        self.0.blocklist.iter()
    }

    pub fn new_for_test() -> Self {
        let input = TypeConfigInput {
            allowlist: Allowlist::All,
            ..Default::default()
        };
        input.into_type_config().unwrap()
    }
}
<|endoftext|>


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

//! Panic support in the standard library

#![unstable(feature = "std_panic", reason = "awaiting feedback",
            issue = "27719")]

use any::Any;
use boxed::Box;
use cell::UnsafeCell;
use ops::{Deref, DerefMut};
use ptr::{Unique, Shared};
use rc::Rc;
use sync::{Arc, Mutex, RwLock};
use sys_common::unwind;
use thread::Result;

pub use panicking::{take_handler, set_handler, PanicInfo, Location};

/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
/// terms of inference of implementation to the `Send` and `Sync` traits. The
/// purpose of this trait is to encode what types are safe to cross a `recover`
/// boundary with no fear of panic safety.
///
/// ## What is panic safety?
///
/// In Rust a function can "return" early if it either panics or calls a
/// function which transitively panics. This sort of control flow is not always
/// anticipated, and has the possibility of causing subtle bugs through a
/// combination of two cricial components:
///
/// 1. A data structure is in a temporarily invalid state when the thread
///    panics.
/// 2. This broken invariant is then later observed.
///
/// Typically in Rust, it is difficult to perform step (2) because catching a
/// panic involves either spawning a thread (which in turns makes it difficult
/// to later witness broken invariants) or using the `recover` function in this
/// module. Additionally, even if an invariant is witnessed, it typically isn't a
/// problem in Rust because there's no uninitialized values (like in C or C++).
///
/// It is possible, however, for **logical** invariants to be broken in Rust,
/// which can end up causing behavioral bugs. Another key aspect of panic safety
/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
/// memory unsafety.
///
/// That was a bit of a whirlwind tour of panic safety, but for more information
/// about panic safety and how it applies to Rust, see an [associated RFC][rfc].
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// ## What is `RecoverSafe`?
///
/// Now that we've got an idea of what panic safety is in Rust, it's also
/// important to understand what this trait represents. As mentioned above, one
/// way to witness broken invariants is through the `recover` function in this
/// module as it allows catching a panic and then re-using the environment of
/// the closure.
///
/// Simply put, a type `T` implements `RecoverSafe` if it cannot easily allow
/// witnessing a broken invariant through the use of `recover` (catching a
/// panic). This trait is a marker trait, so it is automatically implemented for
/// many types, and it is also structurally composed (e.g. a struct is recover
/// safe if all of its components are recover safe).
///
/// Note, however, that this is not an unsafe trait, so there is not a succinct
/// contract that this trait is providing. Instead it is intended as more of a
/// "speed bump" to alert users of `recover` that broken invariants may be
/// witnessed and may need to be accounted for.
///
/// ## Who implements `RecoverSafe`?
///
/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
/// recover safe. The general idea is that any mutable state which can be shared
/// across `recover` is not recover safe by default. This is because it is very
/// easy to witness a broken invariant outside of `recover` as the data is
/// simply accessed as usual.
///
/// Types like `&Mutex<T>`, however, are recover safe because they implement
/// poisoning by default. They still allow witnessing a broken invariant, but
/// they already provide their own "speed bumps" to do so.
///
/// ## When should `RecoverSafe` be used?
///
/// Is not intended that most types or functions need to worry about this trait.
/// It is only used as a bound on the `recover` function and as mentioned above,
/// the lack of `unsafe` means it is mostly an advisory. The `AssertRecoverSafe`
/// wrapper struct in this module can be used to force this trait to be
/// implemented for any closed over variables passed to the `recover` function
/// (more on this below).
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \
                            across a recover boundary"]
pub trait RecoverSafe {}

/// A marker trait representing types where a shared reference is considered
/// recover safe.
///
/// This trait is namely not implemented by `UnsafeCell`, the root of all
/// interior mutability.
///
/// This is a "helper marker trait" used to provide impl blocks for the
/// `RecoverSafe` trait, for more information see that documentation.
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
#[rustc_on_unimplemented = "the type {Self} contains interior mutability \
                            and a reference may not be safely transferrable \
                            across a recover boundary"]
pub trait RefRecoverSafe {}

/// A simple wrapper around a type to assert that it is panic safe.
///
/// When using `recover` it may be the case that some of the closed over
/// variables are not panic safe. For example if `&mut T` is captured the
/// compiler will generate a warning indicating that it is not panic safe. It
/// may not be the case, however, that this is actually a problem due to the
/// specific usage of `recover` if panic safety is specifically taken into
/// account. This wrapper struct is useful for a quick and lightweight
/// annotation that a variable is indeed panic safe.
///
/// # Examples
///
/// ```
/// #![feature(recover, std_panic)]
///
/// use std::panic::{self, AssertRecoverSafe};
///
/// let mut variable = 4;
///
/// // This code will not compile because the closure captures `&mut variable`
/// // which is not considered panic safe by default.
///
/// // panic::recover(|| {
/// //     variable += 3;
/// // });
///
/// // This, however, will compile due to the `AssertRecoverSafe` wrapper
/// let result = {
///     let mut wrapper = AssertRecoverSafe::new(&mut variable);
///     panic::recover(move || {
///         **wrapper += 3;
///     })
/// };
/// // ...
/// ```
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
pub struct AssertRecoverSafe<T>(T);

// Implementations of the `RecoverSafe` trait:
//
// * By default everything is recover safe
// * pointers T contains mutability of some form are not recover safe
// * Unique, an owning pointer, lifts an implementation
// * Types like Mutex/RwLock which are explicilty poisoned are recover safe
// * Our custom AssertRecoverSafe wrapper is indeed recover safe
impl RecoverSafe for .. {}
impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {}
impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {}
impl<T: RecoverSafe> RecoverSafe for Unique<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {}
impl<T: ?Sized> RecoverSafe for Mutex<T> {}
impl<T: ?Sized> RecoverSafe for RwLock<T> {}
impl<T> RecoverSafe for AssertRecoverSafe<T> {}

// not covered via the Shared impl above b/c the inner contents use
// Cell/AtomicUsize, but the usage here is recover safe so we can lift the
// impl up one level to Arc/Rc itself
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {}

// Pretty simple implementations for the `RefRecoverSafe` marker trait,
// basically just saying that this is a marker trait and `UnsafeCell` is the
// only thing which doesn't implement it (which then transitively applies to
// everything else).
impl RefRecoverSafe for .. {}
impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {}
impl<T> RefRecoverSafe for AssertRecoverSafe<T> {}

impl<T> AssertRecoverSafe<T> {
    /// Creates a new `AssertRecoverSafe` wrapper around the provided type.
    #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
    pub fn new(t: T) -> AssertRecoverSafe<T> {
        AssertRecoverSafe(t)
    }
}

impl<T> Deref for AssertRecoverSafe<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> DerefMut for AssertRecoverSafe<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

/// Invokes a closure, capturing the cause of panic if one occurs.
///
/// This function will return `Ok` with the closure's result if the closure
/// does not panic, and will return `Err(cause)` if the closure panics. The
/// `cause` returned is the object with which panic was originally invoked.
///
/// It is currently undefined behavior to unwind from Rust code into foreign
/// code, so this function is particularly useful when Rust is called from
/// another language (normally C). This can run arbitrary Rust code, capturing a
/// panic and allowing a graceful handling of the error.
///
/// It is **not** recommended to use this function for a general try/catch
/// mechanism. The `Result` type is more appropriate to use for functions that
/// can fail on a regular basis.
///
/// The closure provided is required to adhere to the `RecoverSafe` to ensure
/// that all captured variables are safe to cross this recover boundary. The
/// purpose of this bound is to encode the concept of [exception safety][rfc] in
/// the type system. Most usage of this function should not need to worry about
/// this bound as programs are naturally panic safe without `unsafe` code. If it
/// becomes a problem the associated `AssertRecoverSafe` wrapper type in this
/// module can be used to quickly assert that the usage here is indeed exception
/// safe.
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// # Examples
///
/// ```
/// #![feature(recover, std_panic)]
///
/// use std::panic;
///
/// let result = panic::recover(|| {
///     println!("hello!");
/// });
/// assert!(result.is_ok());
///
/// let result = panic::recover(|| {
///     panic!("oh no!");
/// });
/// assert!(result.is_err());
/// ```
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
pub fn recover<F: FnOnce() -> R + RecoverSafe, R>(f: F) -> Result<R> {
    let mut result = None;
    unsafe {
        let result = &mut result;
        try!(unwind::try(move || *result = Some(f())))
    }
    Ok(result.unwrap())
}

/// Triggers a panic without invoking the panic handler.
///
/// This is designed to be used in conjunction with `recover` to, for example,
/// carry a panic across a layer of C code.
///
/// # Examples
///
/// ```should_panic
/// #![feature(std_panic, recover, panic_propagate)]
///
/// use std::panic;
///
/// let result = panic::recover(|| {
///     panic!("oh no!");
/// });
///
/// if let Err(err) = result {
///     panic::propagate(err);
/// }
/// ```
#[unstable(feature = "panic_propagate", reason = "awaiting feedback", issue = "30752")]
pub fn propagate(payload: Box<Any + Send>) -> ! {
    unwind::rust_panic(payload)
}
<commit_msg>Auto merge of #31728 - Amanieu:recoversafe_into_inner, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Panic support in the standard library

#![unstable(feature = "std_panic", reason = "awaiting feedback",
            issue = "27719")]

use any::Any;
use boxed::Box;
use cell::UnsafeCell;
use ops::{Deref, DerefMut};
use ptr::{Unique, Shared};
use rc::Rc;
use sync::{Arc, Mutex, RwLock};
use sys_common::unwind;
use thread::Result;

pub use panicking::{take_handler, set_handler, PanicInfo, Location};

/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
/// terms of inference of implementation to the `Send` and `Sync` traits. The
/// purpose of this trait is to encode what types are safe to cross a `recover`
/// boundary with no fear of panic safety.
///
/// ## What is panic safety?
///
/// In Rust a function can "return" early if it either panics or calls a
/// function which transitively panics. This sort of control flow is not always
/// anticipated, and has the possibility of causing subtle bugs through a
/// combination of two cricial components:
///
/// 1. A data structure is in a temporarily invalid state when the thread
///    panics.
/// 2. This broken invariant is then later observed.
///
/// Typically in Rust, it is difficult to perform step (2) because catching a
/// panic involves either spawning a thread (which in turns makes it difficult
/// to later witness broken invariants) or using the `recover` function in this
/// module. Additionally, even if an invariant is witnessed, it typically isn't a
/// problem in Rust because there's no uninitialized values (like in C or C++).
///
/// It is possible, however, for **logical** invariants to be broken in Rust,
/// which can end up causing behavioral bugs. Another key aspect of panic safety
/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
/// memory unsafety.
///
/// That was a bit of a whirlwind tour of panic safety, but for more information
/// about panic safety and how it applies to Rust, see an [associated RFC][rfc].
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// ## What is `RecoverSafe`?
///
/// Now that we've got an idea of what panic safety is in Rust, it's also
/// important to understand what this trait represents. As mentioned above, one
/// way to witness broken invariants is through the `recover` function in this
/// module as it allows catching a panic and then re-using the environment of
/// the closure.
///
/// Simply put, a type `T` implements `RecoverSafe` if it cannot easily allow
/// witnessing a broken invariant through the use of `recover` (catching a
/// panic). This trait is a marker trait, so it is automatically implemented for
/// many types, and it is also structurally composed (e.g. a struct is recover
/// safe if all of its components are recover safe).
///
/// Note, however, that this is not an unsafe trait, so there is not a succinct
/// contract that this trait is providing. Instead it is intended as more of a
/// "speed bump" to alert users of `recover` that broken invariants may be
/// witnessed and may need to be accounted for.
///
/// ## Who implements `RecoverSafe`?
///
/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
/// recover safe. The general idea is that any mutable state which can be shared
/// across `recover` is not recover safe by default. This is because it is very
/// easy to witness a broken invariant outside of `recover` as the data is
/// simply accessed as usual.
///
/// Types like `&Mutex<T>`, however, are recover safe because they implement
/// poisoning by default. They still allow witnessing a broken invariant, but
/// they already provide their own "speed bumps" to do so.
///
/// ## When should `RecoverSafe` be used?
///
/// Is not intended that most types or functions need to worry about this trait.
/// It is only used as a bound on the `recover` function and as mentioned above,
/// the lack of `unsafe` means it is mostly an advisory. The `AssertRecoverSafe`
/// wrapper struct in this module can be used to force this trait to be
/// implemented for any closed over variables passed to the `recover` function
/// (more on this below).
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \
                            across a recover boundary"]
pub trait RecoverSafe {}

/// A marker trait representing types where a shared reference is considered
/// recover safe.
///
/// This trait is namely not implemented by `UnsafeCell`, the root of all
/// interior mutability.
///
/// This is a "helper marker trait" used to provide impl blocks for the
/// `RecoverSafe` trait, for more information see that documentation.
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
#[rustc_on_unimplemented = "the type {Self} contains interior mutability \
                            and a reference may not be safely transferrable \
                            across a recover boundary"]
pub trait RefRecoverSafe {}

/// A simple wrapper around a type to assert that it is panic safe.
///
/// When using `recover` it may be the case that some of the closed over
/// variables are not panic safe. For example if `&mut T` is captured the
/// compiler will generate a warning indicating that it is not panic safe. It
/// may not be the case, however, that this is actually a problem due to the
/// specific usage of `recover` if panic safety is specifically taken into
/// account. This wrapper struct is useful for a quick and lightweight
/// annotation that a variable is indeed panic safe.
///
/// # Examples
///
/// ```
/// #![feature(recover, std_panic)]
///
/// use std::panic::{self, AssertRecoverSafe};
///
/// let mut variable = 4;
///
/// // This code will not compile because the closure captures `&mut variable`
/// // which is not considered panic safe by default.
///
/// // panic::recover(|| {
/// //     variable += 3;
/// // });
///
/// // This, however, will compile due to the `AssertRecoverSafe` wrapper
/// let result = {
///     let mut wrapper = AssertRecoverSafe::new(&mut variable);
///     panic::recover(move || {
///         **wrapper += 3;
///     })
/// };
/// // ...
/// ```
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
pub struct AssertRecoverSafe<T>(T);

// Implementations of the `RecoverSafe` trait:
//
// * By default everything is recover safe
// * pointers T contains mutability of some form are not recover safe
// * Unique, an owning pointer, lifts an implementation
// * Types like Mutex/RwLock which are explicilty poisoned are recover safe
// * Our custom AssertRecoverSafe wrapper is indeed recover safe
impl RecoverSafe for .. {}
impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {}
impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {}
impl<T: RecoverSafe> RecoverSafe for Unique<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {}
impl<T: ?Sized> RecoverSafe for Mutex<T> {}
impl<T: ?Sized> RecoverSafe for RwLock<T> {}
impl<T> RecoverSafe for AssertRecoverSafe<T> {}

// not covered via the Shared impl above b/c the inner contents use
// Cell/AtomicUsize, but the usage here is recover safe so we can lift the
// impl up one level to Arc/Rc itself
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {}

// Pretty simple implementations for the `RefRecoverSafe` marker trait,
// basically just saying that this is a marker trait and `UnsafeCell` is the
// only thing which doesn't implement it (which then transitively applies to
// everything else).
impl RefRecoverSafe for .. {}
impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {}
impl<T> RefRecoverSafe for AssertRecoverSafe<T> {}

impl<T> AssertRecoverSafe<T> {
    /// Creates a new `AssertRecoverSafe` wrapper around the provided type.
    #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
    pub fn new(t: T) -> AssertRecoverSafe<T> {
        AssertRecoverSafe(t)
    }

    /// Consumes the `AssertRecoverSafe`, returning the wrapped value.
    #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> Deref for AssertRecoverSafe<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> DerefMut for AssertRecoverSafe<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

/// Invokes a closure, capturing the cause of panic if one occurs.
///
/// This function will return `Ok` with the closure's result if the closure
/// does not panic, and will return `Err(cause)` if the closure panics. The
/// `cause` returned is the object with which panic was originally invoked.
///
/// It is currently undefined behavior to unwind from Rust code into foreign
/// code, so this function is particularly useful when Rust is called from
/// another language (normally C). This can run arbitrary Rust code, capturing a
/// panic and allowing a graceful handling of the error.
///
/// It is **not** recommended to use this function for a general try/catch
/// mechanism. The `Result` type is more appropriate to use for functions that
/// can fail on a regular basis.
///
/// The closure provided is required to adhere to the `RecoverSafe` to ensure
/// that all captured variables are safe to cross this recover boundary. The
/// purpose of this bound is to encode the concept of [exception safety][rfc] in
/// the type system. Most usage of this function should not need to worry about
/// this bound as programs are naturally panic safe without `unsafe` code. If it
/// becomes a problem the associated `AssertRecoverSafe` wrapper type in this
/// module can be used to quickly assert that the usage here is indeed exception
/// safe.
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// # Examples
///
/// ```
/// #![feature(recover, std_panic)]
///
/// use std::panic;
///
/// let result = panic::recover(|| {
///     println!("hello!");
/// });
/// assert!(result.is_ok());
///
/// let result = panic::recover(|| {
///     panic!("oh no!");
/// });
/// assert!(result.is_err());
/// ```
#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")]
pub fn recover<F: FnOnce() -> R + RecoverSafe, R>(f: F) -> Result<R> {
    let mut result = None;
    unsafe {
        let result = &mut result;
        try!(unwind::try(move || *result = Some(f())))
    }
    Ok(result.unwrap())
}

/// Triggers a panic without invoking the panic handler.
///
/// This is designed to be used in conjunction with `recover` to, for example,
/// carry a panic across a layer of C code.
///
/// # Examples
///
/// ```should_panic
/// #![feature(std_panic, recover, panic_propagate)]
///
/// use std::panic;
///
/// let result = panic::recover(|| {
///     panic!("oh no!");
/// });
///
/// if let Err(err) = result {
///     panic::propagate(err);
/// }
/// ```
#[unstable(feature = "panic_propagate", reason = "awaiting feedback", issue = "30752")]
pub fn propagate(payload: Box<Any + Send>) -> ! {
    unwind::rust_panic(payload)
}
<|endoftext|>