<commit_before>use toml_edit::Document;

#[track_caller]
fn run_contains(toml: &str, msg: &str) {
    let doc = toml.parse::<Document>();

    let err = match doc {
        Err(e) => e.to_string(),
        _ => unreachable!("must fail"),
    };
    dbg!(msg);
    dbg!(&err);
    assert!(err.contains(msg));
}

macro_rules! t_file_contains(
    ($name:ident, $toml:expr, $msg:expr, ) => (
        #[test]
        fn $name() {
            run_contains(include_str!($toml), $msg);
        }
    )
);

t_file_contains!(
    test_datetime_malformed_no_leads,
    "fixtures/invalid/datetime-malformed-no-leads.toml",
    "While parsing a Date-Time",
);
t_file_contains!(
    test_datetime_malformed_no_secs,
    "fixtures/invalid/datetime-malformed-no-secs.toml",
    "While parsing a Date-Time",
);
t_file_contains!(
    test_datetime_malformed_no_t,
    "fixtures/invalid/datetime-malformed-no-t.toml",
    "",
);
t_file_contains!(
    test_datetime_malformed_with_milli,
    "fixtures/invalid/datetime-malformed-with-milli.toml",
    "While parsing a Date-Time",
);
t_file_contains!(
    test_duplicate_keys,
    "fixtures/invalid/duplicate-keys.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_key_table,
    "fixtures/invalid/duplicate-key-table.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_tables,
    "fixtures/invalid/duplicate-tables.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_key_std_into_dotted,
    "fixtures/invalid/duplicate-key-std-into-dotted.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_key_dotted_into_std,
    "fixtures/invalid/duplicate-key-dotted-into-std.toml",
    "Duplicate key",
);
t_file_contains!(
    test_empty_implicit_table,
    "fixtures/invalid/empty-implicit-table.toml",
    "While parsing a Table Header",
);
t_file_contains!(
    test_empty_table,
    "fixtures/invalid/empty-table.toml",
    "While parsing a Table Header",
);
t_file_contains!(
    test_float_leading_zero_neg,
    "fixtures/invalid/float-leading-zero-neg.toml",
    "Unexpected `3`",
);
t_file_contains!(
    test_float_leading_zero_pos,
    "fixtures/invalid/float-leading-zero-pos.toml",
    "Unexpected `3`",
);
t_file_contains!(
    test_float_leading_zero,
    "fixtures/invalid/float-leading-zero.toml",
    "Unexpected `3`",
);
t_file_contains!(
    test_float_no_leading_zero,
    "fixtures/invalid/float-no-leading-zero.toml",
    "Unexpected `.`",
);
t_file_contains!(
    test_float_no_trailing_digits,
    "fixtures/invalid/float-no-trailing-digits.toml",
    "While parsing a Float",
);
t_file_contains!(
    test_float_underscore_after_point,
    "fixtures/invalid/float-underscore-after-point.toml",
    "While parsing a Float",
);
t_file_contains!(
    test_float_underscore_after,
    "fixtures/invalid/float-underscore-after.toml",
    "column 11",
);
t_file_contains!(
    test_float_underscore_before_point,
    "fixtures/invalid/float-underscore-before-point.toml",
    "column 9",
);
t_file_contains!(
    test_float_underscore_before,
    "fixtures/invalid/float-underscore-before.toml",
    "column 7",
);
t_file_contains!(
    test_integer_leading_zero_neg,
    "fixtures/invalid/integer-leading-zero-neg.toml",
    "",
);
t_file_contains!(
    test_integer_leading_zero_pos,
    "fixtures/invalid/integer-leading-zero-pos.toml",
    "",
);
t_file_contains!(
    test_integer_leading_zero,
    "fixtures/invalid/integer-leading-zero.toml",
    "",
);
t_file_contains!(
    test_integer_underscore_after,
    "fixtures/invalid/integer-underscore-after.toml",
    "",
);
t_file_contains!(
    test_integer_underscore_before,
    "fixtures/invalid/integer-underscore-before.toml",
    "",
);
t_file_contains!(
    test_integer_underscore_double,
    "fixtures/invalid/integer-underscore-double.toml",
    "",
);
t_file_contains!(
    test_integer_invalid_hex_char,
    "fixtures/invalid/integer-invalid-hex-char.toml",
    "",
);
t_file_contains!(
    test_integer_invalid_octal_char,
    "fixtures/invalid/integer-invalid-octal-char.toml",
    "",
);
t_file_contains!(
    test_integer_invalid_binary_char,
    "fixtures/invalid/integer-invalid-binary-char.toml",
    "",
);
t_file_contains!(
    test_key_after_array,
    "fixtures/invalid/key-after-array.toml",
    "",
);
t_file_contains!(
    test_key_after_table,
    "fixtures/invalid/key-after-table.toml",
    "",
);
t_file_contains!(test_key_empty, "fixtures/invalid/key-empty.toml", "",);
t_file_contains!(test_key_hash, "fixtures/invalid/key-hash.toml", "",);
t_file_contains!(test_key_newline, "fixtures/invalid/key-newline.toml", "",);
t_file_contains!(test_key_no_eol, "fixtures/invalid/key-no-eol.toml", "",);
t_file_contains!(
    test_key_open_bracket,
    "fixtures/invalid/key-open-bracket.toml",
    "",
);
t_file_contains!(
    test_key_single_open_bracket,
    "fixtures/invalid/key-single-open-bracket.toml",
    "",
);
t_file_contains!(test_key_space, "fixtures/invalid/key-space.toml", "",);
t_file_contains!(
    test_key_start_bracket,
    "fixtures/invalid/key-start-bracket.toml",
    "",
);
t_file_contains!(
    test_key_two_equals,
    "fixtures/invalid/key-two-equals.toml",
    "",
);
t_file_contains!(test_llbrace, "fixtures/invalid/llbrace.toml", "",);
t_file_contains!(test_rrbrace, "fixtures/invalid/rrbrace.toml", "",);
t_file_contains!(
    test_string_bad_byte_escape,
    "fixtures/invalid/string-bad-byte-escape.toml",
    "",
);
t_file_contains!(
    test_string_bad_escape,
    "fixtures/invalid/string-bad-escape.toml",
    "",
);
t_file_contains!(
    test_string_bad_surrogate,
    "fixtures/invalid/string-bad-surrogate.toml",
    "",
);
t_file_contains!(
    test_string_bad_uni_esc,
    "fixtures/invalid/string-bad-uni-esc.toml",
    "",
);
t_file_contains!(
    test_string_byte_escapes,
    "fixtures/invalid/string-byte-escapes.toml",
    "",
);
t_file_contains!(
    test_string_no_close,
    "fixtures/invalid/string-no-close.toml",
    "",
);
t_file_contains!(
    test_table_array_implicit,
    "fixtures/invalid/table-array-implicit.toml",
    "",
);
t_file_contains!(
    test_table_array_malformed_bracket,
    "fixtures/invalid/table-array-malformed-bracket.toml",
    "",
);
t_file_contains!(
    test_table_array_malformed_empty,
    "fixtures/invalid/table-array-malformed-empty.toml",
    "",
);
t_file_contains!(test_table_empty, "fixtures/invalid/table-empty.toml", "",);
t_file_contains!(
    test_table_nested_brackets_close,
    "fixtures/invalid/table-nested-brackets-close.toml",
    "",
);
t_file_contains!(
    test_table_nested_brackets_open,
    "fixtures/invalid/table-nested-brackets-open.toml",
    "",
);
t_file_contains!(
    test_table_whitespace,
    "fixtures/invalid/table-whitespace.toml",
    "",
);
t_file_contains!(
    test_table_with_pound,
    "fixtures/invalid/table-with-pound.toml",
    "",
);
t_file_contains!(
    test_text_after_array_entries,
    "fixtures/invalid/text-after-array-entries.toml",
    "",
);
t_file_contains!(
    test_text_after_integer,
    "fixtures/invalid/text-after-integer.toml",
    "",
);
t_file_contains!(
    test_text_after_string,
    "fixtures/invalid/text-after-string.toml",
    "",
);
t_file_contains!(
    test_text_after_table,
    "fixtures/invalid/text-after-table.toml",
    "",
);
t_file_contains!(
    test_text_before_array_separator,
    "fixtures/invalid/text-before-array-separator.toml",
    "",
);
t_file_contains!(
    test_text_in_array,
    "fixtures/invalid/text-in-array.toml",
    "",
);
<commit_msg>test(invalid): Add bare word tests<commit_after>use toml_edit::Document;

#[track_caller]
fn run_contains(toml: &str, msg: &str) {
    let doc = toml.parse::<Document>();

    let err = match doc {
        Err(e) => e.to_string(),
        _ => unreachable!("must fail"),
    };
    dbg!(msg);
    dbg!(&err);
    assert!(err.contains(msg));
}

#[track_caller]
fn run_exact(toml: &str, msg: &str) {
    let doc = toml.parse::<Document>();

    let err = match doc {
        Err(e) => e.to_string(),
        _ => unreachable!("must fail"),
    };
    assert_eq!(err, msg);
}

macro_rules! t_exact(
    ($name:ident, $toml:expr, $msg:expr, ) => (
        #[test]
        fn $name() {
            run_exact($toml, $msg);
        }
    )
);

macro_rules! t_file_contains(
    ($name:ident, $toml:expr, $msg:expr, ) => (
        #[test]
        fn $name() {
            run_contains(include_str!($toml), $msg);
        }
    )
);

t_file_contains!(
    test_datetime_malformed_no_leads,
    "fixtures/invalid/datetime-malformed-no-leads.toml",
    "While parsing a Date-Time",
);
t_file_contains!(
    test_datetime_malformed_no_secs,
    "fixtures/invalid/datetime-malformed-no-secs.toml",
    "While parsing a Date-Time",
);
t_file_contains!(
    test_datetime_malformed_no_t,
    "fixtures/invalid/datetime-malformed-no-t.toml",
    "",
);
t_file_contains!(
    test_datetime_malformed_with_milli,
    "fixtures/invalid/datetime-malformed-with-milli.toml",
    "While parsing a Date-Time",
);
t_file_contains!(
    test_duplicate_keys,
    "fixtures/invalid/duplicate-keys.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_key_table,
    "fixtures/invalid/duplicate-key-table.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_tables,
    "fixtures/invalid/duplicate-tables.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_key_std_into_dotted,
    "fixtures/invalid/duplicate-key-std-into-dotted.toml",
    "Duplicate key",
);
t_file_contains!(
    test_duplicate_key_dotted_into_std,
    "fixtures/invalid/duplicate-key-dotted-into-std.toml",
    "Duplicate key",
);
t_file_contains!(
    test_empty_implicit_table,
    "fixtures/invalid/empty-implicit-table.toml",
    "While parsing a Table Header",
);
t_file_contains!(
    test_empty_table,
    "fixtures/invalid/empty-table.toml",
    "While parsing a Table Header",
);
t_file_contains!(
    test_float_leading_zero_neg,
    "fixtures/invalid/float-leading-zero-neg.toml",
    "Unexpected `3`",
);
t_file_contains!(
    test_float_leading_zero_pos,
    "fixtures/invalid/float-leading-zero-pos.toml",
    "Unexpected `3`",
);
t_file_contains!(
    test_float_leading_zero,
    "fixtures/invalid/float-leading-zero.toml",
    "Unexpected `3`",
);
t_file_contains!(
    test_float_no_leading_zero,
    "fixtures/invalid/float-no-leading-zero.toml",
    "Unexpected `.`",
);
t_file_contains!(
    test_float_no_trailing_digits,
    "fixtures/invalid/float-no-trailing-digits.toml",
    "While parsing a Float",
);
t_file_contains!(
    test_float_underscore_after_point,
    "fixtures/invalid/float-underscore-after-point.toml",
    "While parsing a Float",
);
t_file_contains!(
    test_float_underscore_after,
    "fixtures/invalid/float-underscore-after.toml",
    "column 11",
);
t_file_contains!(
    test_float_underscore_before_point,
    "fixtures/invalid/float-underscore-before-point.toml",
    "column 9",
);
t_file_contains!(
    test_float_underscore_before,
    "fixtures/invalid/float-underscore-before.toml",
    "column 7",
);
t_file_contains!(
    test_integer_leading_zero_neg,
    "fixtures/invalid/integer-leading-zero-neg.toml",
    "",
);
t_file_contains!(
    test_integer_leading_zero_pos,
    "fixtures/invalid/integer-leading-zero-pos.toml",
    "",
);
t_file_contains!(
    test_integer_leading_zero,
    "fixtures/invalid/integer-leading-zero.toml",
    "",
);
t_file_contains!(
    test_integer_underscore_after,
    "fixtures/invalid/integer-underscore-after.toml",
    "",
);
t_file_contains!(
    test_integer_underscore_before,
    "fixtures/invalid/integer-underscore-before.toml",
    "",
);
t_file_contains!(
    test_integer_underscore_double,
    "fixtures/invalid/integer-underscore-double.toml",
    "",
);
t_file_contains!(
    test_integer_invalid_hex_char,
    "fixtures/invalid/integer-invalid-hex-char.toml",
    "",
);
t_file_contains!(
    test_integer_invalid_octal_char,
    "fixtures/invalid/integer-invalid-octal-char.toml",
    "",
);
t_file_contains!(
    test_integer_invalid_binary_char,
    "fixtures/invalid/integer-invalid-binary-char.toml",
    "",
);
t_file_contains!(
    test_key_after_array,
    "fixtures/invalid/key-after-array.toml",
    "",
);
t_file_contains!(
    test_key_after_table,
    "fixtures/invalid/key-after-table.toml",
    "",
);
t_file_contains!(test_key_empty, "fixtures/invalid/key-empty.toml", "",);
t_file_contains!(test_key_hash, "fixtures/invalid/key-hash.toml", "",);
t_file_contains!(test_key_newline, "fixtures/invalid/key-newline.toml", "",);
t_file_contains!(test_key_no_eol, "fixtures/invalid/key-no-eol.toml", "",);
t_file_contains!(
    test_key_open_bracket,
    "fixtures/invalid/key-open-bracket.toml",
    "",
);
t_file_contains!(
    test_key_single_open_bracket,
    "fixtures/invalid/key-single-open-bracket.toml",
    "",
);
t_file_contains!(test_key_space, "fixtures/invalid/key-space.toml", "",);
t_file_contains!(
    test_key_start_bracket,
    "fixtures/invalid/key-start-bracket.toml",
    "",
);
t_file_contains!(
    test_key_two_equals,
    "fixtures/invalid/key-two-equals.toml",
    "",
);
t_file_contains!(test_llbrace, "fixtures/invalid/llbrace.toml", "",);
t_file_contains!(test_rrbrace, "fixtures/invalid/rrbrace.toml", "",);
t_file_contains!(
    test_string_bad_byte_escape,
    "fixtures/invalid/string-bad-byte-escape.toml",
    "",
);
t_file_contains!(
    test_string_bad_escape,
    "fixtures/invalid/string-bad-escape.toml",
    "",
);
t_file_contains!(
    test_string_bad_surrogate,
    "fixtures/invalid/string-bad-surrogate.toml",
    "",
);
t_file_contains!(
    test_string_bad_uni_esc,
    "fixtures/invalid/string-bad-uni-esc.toml",
    "",
);
t_file_contains!(
    test_string_byte_escapes,
    "fixtures/invalid/string-byte-escapes.toml",
    "",
);
t_file_contains!(
    test_string_no_close,
    "fixtures/invalid/string-no-close.toml",
    "",
);
t_file_contains!(
    test_table_array_implicit,
    "fixtures/invalid/table-array-implicit.toml",
    "",
);
t_file_contains!(
    test_table_array_malformed_bracket,
    "fixtures/invalid/table-array-malformed-bracket.toml",
    "",
);
t_file_contains!(
    test_table_array_malformed_empty,
    "fixtures/invalid/table-array-malformed-empty.toml",
    "",
);
t_file_contains!(test_table_empty, "fixtures/invalid/table-empty.toml", "",);
t_file_contains!(
    test_table_nested_brackets_close,
    "fixtures/invalid/table-nested-brackets-close.toml",
    "",
);
t_file_contains!(
    test_table_nested_brackets_open,
    "fixtures/invalid/table-nested-brackets-open.toml",
    "",
);
t_file_contains!(
    test_table_whitespace,
    "fixtures/invalid/table-whitespace.toml",
    "",
);
t_file_contains!(
    test_table_with_pound,
    "fixtures/invalid/table-with-pound.toml",
    "",
);
t_file_contains!(
    test_text_after_array_entries,
    "fixtures/invalid/text-after-array-entries.toml",
    "",
);
t_file_contains!(
    test_text_after_integer,
    "fixtures/invalid/text-after-integer.toml",
    "",
);
t_file_contains!(
    test_text_after_string,
    "fixtures/invalid/text-after-string.toml",
    "",
);
t_file_contains!(
    test_text_after_table,
    "fixtures/invalid/text-after-table.toml",
    "",
);
t_file_contains!(
    test_text_before_array_separator,
    "fixtures/invalid/text-before-array-separator.toml",
    "",
);
t_file_contains!(
    test_text_in_array,
    "fixtures/invalid/text-in-array.toml",
    "",
);

t_exact!(
    test_quote_suggestion_in_key_value_pair,
    "value= ZZZ",
    "TOML parse error at line 1, column 8
  |
1 | value= ZZZ
  |        ^
Unexpected `Z`
Expected `-`, `+`, `inf`, `nan`, `0x`, `0o` or `0b`
expected 4 more elements
expected 2 more elements
While parsing a Time
While parsing a hexadecimal Integer
While parsing a octal Integer
While parsing a binary Integer
While parsing an Integer
While parsing a Date-Time
While parsing a Float
",
);
t_exact!(
    test_quote_suggestion_in_array,
    "value=[ZZZ]",
    "TOML parse error at line 1, column 8
  |
1 | value=[ZZZ]
  |        ^
Unexpected `Z`
Expected `a newline` or `#`
",
);
t_exact!(
    test_quote_suggestion_in_inline_table,
    "value={key = ZZZ}",
    "TOML parse error at line 1, column 14
  |
1 | value={key = ZZZ}
  |              ^
Unexpected `Z`
Expected `-`, `+`, `inf`, `nan`, `0x`, `0o` or `0b`
expected 4 more elements
expected 2 more elements
While parsing a Time
While parsing a hexadecimal Integer
While parsing a octal Integer
While parsing a binary Integer
While parsing an Integer
While parsing a Date-Time
While parsing a Float
",
);
t_exact!(
    test_quote_suggestion_similar_to_constants_in_key_value_pair,
    "value= trust",
    "TOML parse error at line 1, column 9
  |
1 | value= trust
  |         ^
Unexpected `r`
Expected `rue`
",
);
<|endoftext|>


<commit_before>use std::error::Error;

use diesel::dsl::sql;
use diesel::*;

use super::data_structures::*;
use super::table_data::TableName;
use crate::print_schema::ColumnSorting;

table! {
    sqlite_master (name) {
        name -> VarChar,
    }
}

table! {
    pragma_table_info (cid) {
        cid ->Integer,
        name -> VarChar,
        type_name -> VarChar,
        notnull -> Bool,
        dflt_value -> Nullable<VarChar>,
        pk -> Bool,
        hidden -> Integer,
    }
}

table! {
    pragma_foreign_key_list {
        id -> Integer,
        seq -> Integer,
        _table -> VarChar,
        from -> VarChar,
        to -> VarChar,
        on_update -> VarChar,
        on_delete -> VarChar,
        _match -> VarChar,
    }
}

pub fn load_table_names(
    connection: &mut SqliteConnection,
    schema_name: Option<&str>,
) -> Result<Vec<TableName>, Box<dyn Error + Send + Sync + 'static>> {
    use self::sqlite_master::dsl::*;

    if schema_name.is_some() {
        return Err("sqlite cannot infer schema for databases other than the \
                    main database"
            .into());
    }

    Ok(sqlite_master
        .select(name)
        .filter(name.not_like("\\_\\_%").escape('\\'))
        .filter(name.not_like("sqlite%"))
        .filter(sql::<sql_types::Bool>("type='table'"))
        .order(name)
        .load::<String>(connection)?
        .into_iter()
        .map(TableName::from_name)
        .collect())
}

pub fn load_foreign_key_constraints(
    connection: &mut SqliteConnection,
    schema_name: Option<&str>,
) -> Result<Vec<ForeignKeyConstraint>, Box<dyn Error + Send + Sync + 'static>> {
    let tables = load_table_names(connection, schema_name)?;
    let rows = tables
        .into_iter()
        .map(|child_table| {
            let query = format!("PRAGMA FOREIGN_KEY_LIST('{}')", child_table.sql_name);
            Ok(sql::<pragma_foreign_key_list::SqlType>(&query)
                .load::<ForeignKeyListRow>(connection)?
                .into_iter()
                .map(|row| {
                    let parent_table = TableName::from_name(row.parent_table);
                    ForeignKeyConstraint {
                        child_table: child_table.clone(),
                        parent_table,
                        foreign_key: row.foreign_key.clone(),
                        foreign_key_rust_name: row.foreign_key,
                        primary_key: row.primary_key,
                    }
                })
                .collect())
        })
        .collect::<QueryResult<Vec<Vec<_>>>>()?;
    Ok(rows.into_iter().flatten().collect())
}

pub fn get_table_data(
    conn: &mut SqliteConnection,
    table: &TableName,
    column_sorting: &ColumnSorting,
) -> QueryResult<Vec<ColumnInformation>> {
    let query = format!("PRAGMA TABLE_XINFO('{}')", &table.sql_name);
    let mut result = sql::<pragma_table_info::SqlType>(&query).load(conn)?;
    match column_sorting {
        ColumnSorting::OrdinalPosition => {}
        ColumnSorting::Name => {
            result.sort_by(|a: &ColumnInformation, b: &ColumnInformation| {
                a.column_name.partial_cmp(&b.column_name).unwrap()
            });
        }
    };
    Ok(result)
}

#[derive(Queryable)]
struct FullTableInfo {
    _cid: i32,
    name: String,
    _type_name: String,
    _not_null: bool,
    _dflt_value: Option<String>,
    primary_key: bool,
    _hidden: i32,
}

#[derive(Queryable)]
struct ForeignKeyListRow {
    _id: i32,
    _seq: i32,
    parent_table: String,
    foreign_key: String,
    primary_key: String,
    _on_update: String,
    _on_delete: String,
    _match: String,
}

pub fn get_primary_keys(
    conn: &mut SqliteConnection,
    table: &TableName,
) -> QueryResult<Vec<String>> {
    let query = format!("PRAGMA TABLE_XINFO('{}')", &table.sql_name);
    let results = sql::<pragma_table_info::SqlType>(&query).load::<FullTableInfo>(conn)?;
    Ok(results
        .into_iter()
        .filter_map(|i| if i.primary_key { Some(i.name) } else { None })
        .collect())
}

pub fn determine_column_type(
    attr: &ColumnInformation,
) -> Result<ColumnType, Box<dyn Error + Send + Sync + 'static>> {
    let mut type_name = attr.type_name.to_lowercase();
    if type_name == "generated always" {
        type_name.clear();
    }

    let path = if is_bool(&type_name) {
        String::from("Bool")
    } else if is_smallint(&type_name) {
        String::from("SmallInt")
    } else if is_bigint(&type_name) {
        String::from("BigInt")
    } else if type_name.contains("int") {
        String::from("Integer")
    } else if is_text(&type_name) {
        String::from("Text")
    } else if is_binary(&type_name) {
        String::from("Binary")
    } else if is_float(&type_name) {
        String::from("Float")
    } else if is_double(&type_name) {
        String::from("Double")
    } else if type_name == "datetime" || type_name == "timestamp" {
        String::from("Timestamp")
    } else if type_name == "date" {
        String::from("Date")
    } else if type_name == "time" {
        String::from("Time")
    } else {
        return Err(format!("Unsupported type: {}", type_name).into());
    };

    Ok(ColumnType {
        schema: None,
        rust_name: path.clone(),
        sql_name: path,
        is_array: false,
        is_nullable: attr.nullable,
        is_unsigned: false,
    })
}

fn is_text(type_name: &str) -> bool {
    type_name.contains("char") || type_name.contains("clob") || type_name.contains("text")
}

fn is_binary(type_name: &str) -> bool {
    type_name.contains("blob") || type_name.contains("binary") || type_name.is_empty()
}

fn is_bool(type_name: &str) -> bool {
    type_name == "boolean" || type_name.contains("tiny") && type_name.contains("int")
}

fn is_smallint(type_name: &str) -> bool {
    type_name == "int2" || type_name.contains("small") && type_name.contains("int")
}

fn is_bigint(type_name: &str) -> bool {
    type_name == "int8" || type_name.contains("big") && type_name.contains("int")
}

fn is_float(type_name: &str) -> bool {
    type_name.contains("float") || type_name.contains("real")
}

fn is_double(type_name: &str) -> bool {
    type_name.contains("double") || type_name.contains("num") || type_name.contains("dec")
}

#[test]
fn load_table_names_returns_nothing_when_no_tables_exist() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    assert_eq!(
        Vec::<TableName>::new(),
        load_table_names(&mut conn, None).unwrap()
    );
}

#[test]
fn load_table_names_includes_tables_that_exist() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    let table_names = load_table_names(&mut conn, None).unwrap();
    assert!(table_names.contains(&TableName::from_name("users")));
}

#[test]
fn load_table_names_excludes_diesel_metadata_tables() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE __diesel_metadata (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    let table_names = load_table_names(&mut conn, None).unwrap();
    assert!(!table_names.contains(&TableName::from_name("__diesel_metadata")));
}

#[test]
fn load_table_names_excludes_sqlite_metadata_tables() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE __diesel_metadata (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    let table_names = load_table_names(&mut conn, None);
    assert_eq!(vec![TableName::from_name("users")], table_names.unwrap());
}

#[test]
fn load_table_names_excludes_views() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE VIEW answer AS SELECT 42").unwrap();
    let table_names = load_table_names(&mut conn, None);
    assert_eq!(vec![TableName::from_name("users")], table_names.unwrap());
}

#[test]
fn load_table_names_returns_error_when_given_schema_name() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    // We're testing the error message rather than using #[should_panic]
    // to ensure this is returning an error and not actually panicking.
    let table_names = load_table_names(&mut conn, Some("stuff"));
    match table_names {
        Ok(_) => panic!("Expected load_table_names to return an error"),
        Err(e) => assert!(e.to_string().starts_with(
            "sqlite cannot infer \
             schema for databases"
        )),
    }
}

#[test]
fn load_table_names_output_is_ordered() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE bbb (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE TABLE aaa (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE TABLE ccc (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();

    let table_names = load_table_names(&mut conn, None)
        .unwrap()
        .iter()
        .map(|table| table.to_string())
        .collect::<Vec<_>>();
    assert_eq!(vec!["aaa", "bbb", "ccc"], table_names);
}

#[test]
fn load_foreign_key_constraints_loads_foreign_keys() {
    let mut connection = SqliteConnection::establish(":memory:").unwrap();

    connection.execute("CREATE TABLE table_1 (id)").unwrap();
    connection
        .execute("CREATE TABLE table_2 (id, fk_one REFERENCES table_1(id))")
        .unwrap();
    connection
        .execute("CREATE TABLE table_3 (id, fk_two REFERENCES table_2(id))")
        .unwrap();

    let table_1 = TableName::from_name("table_1");
    let table_2 = TableName::from_name("table_2");
    let table_3 = TableName::from_name("table_3");
    let fk_one = ForeignKeyConstraint {
        child_table: table_2.clone(),
        parent_table: table_1.clone(),
        foreign_key: "fk_one".into(),
        foreign_key_rust_name: "fk_one".into(),
        primary_key: "id".into(),
    };
    let fk_two = ForeignKeyConstraint {
        child_table: table_3.clone(),
        parent_table: table_2.clone(),
        foreign_key: "fk_two".into(),
        foreign_key_rust_name: "fk_two".into(),
        primary_key: "id".into(),
    };
    let fks = load_foreign_key_constraints(&mut connection, None).unwrap();
    assert_eq!(vec![fk_one, fk_two], fks);
}
<commit_msg>Added version check to table_xinfo<commit_after>use std::error::Error;

use diesel::dsl::sql;
use diesel::*;

use super::data_structures::*;
use super::table_data::TableName;
use crate::print_schema::ColumnSorting;

table! {
    sqlite_master (name) {
        name -> VarChar,
    }
}

table! {
    pragma_table_info (cid) {
        cid ->Integer,
        name -> VarChar,
        type_name -> VarChar,
        notnull -> Bool,
        dflt_value -> Nullable<VarChar>,
        pk -> Bool,
        hidden -> Integer,
    }
}

table! {
    pragma_foreign_key_list {
        id -> Integer,
        seq -> Integer,
        _table -> VarChar,
        from -> VarChar,
        to -> VarChar,
        on_update -> VarChar,
        on_delete -> VarChar,
        _match -> VarChar,
    }
}

pub fn load_table_names(
    connection: &mut SqliteConnection,
    schema_name: Option<&str>,
) -> Result<Vec<TableName>, Box<dyn Error + Send + Sync + 'static>> {
    use self::sqlite_master::dsl::*;

    if schema_name.is_some() {
        return Err("sqlite cannot infer schema for databases other than the \
                    main database"
            .into());
    }

    Ok(sqlite_master
        .select(name)
        .filter(name.not_like("\\_\\_%").escape('\\'))
        .filter(name.not_like("sqlite%"))
        .filter(sql::<sql_types::Bool>("type='table'"))
        .order(name)
        .load::<String>(connection)?
        .into_iter()
        .map(TableName::from_name)
        .collect())
}

pub fn load_foreign_key_constraints(
    connection: &mut SqliteConnection,
    schema_name: Option<&str>,
) -> Result<Vec<ForeignKeyConstraint>, Box<dyn Error + Send + Sync + 'static>> {
    let tables = load_table_names(connection, schema_name)?;
    let rows = tables
        .into_iter()
        .map(|child_table| {
            let query = format!("PRAGMA FOREIGN_KEY_LIST('{}')", child_table.sql_name);
            Ok(sql::<pragma_foreign_key_list::SqlType>(&query)
                .load::<ForeignKeyListRow>(connection)?
                .into_iter()
                .map(|row| {
                    let parent_table = TableName::from_name(row.parent_table);
                    ForeignKeyConstraint {
                        child_table: child_table.clone(),
                        parent_table,
                        foreign_key: row.foreign_key.clone(),
                        foreign_key_rust_name: row.foreign_key,
                        primary_key: row.primary_key,
                    }
                })
                .collect())
        })
        .collect::<QueryResult<Vec<Vec<_>>>>()?;
    Ok(rows.into_iter().flatten().collect())
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct SqliteVersion {
    major: u32,
    minor: u32,
    patch: u32,
}

impl SqliteVersion {
    pub fn new(major: u32, minor: u32, patch: u32) -> SqliteVersion {
        SqliteVersion {
            major,
            minor,
            patch,
        }
    }
}

fn get_sqlite_version(
    conn: &mut SqliteConnection
) -> SqliteVersion {
    let query = "SELECT sqlite_version()";
    let result = sql::<sql_types::Text>(&query).load::<String>(conn).unwrap();
    let parts = result[0]
        .split('.')
        .map(|part| { part.parse().unwrap() })
        .collect::<Vec<u32>>();
    assert_eq!(parts.len(), 3);
    SqliteVersion::new(
        parts[0],
        parts[1],
        parts[2],
    )
}

pub fn get_table_data(
    conn: &mut SqliteConnection,
    table: &TableName,
    column_sorting: &ColumnSorting,
) -> QueryResult<Vec<ColumnInformation>> {
    let sqlite_version = get_sqlite_version(conn);
    let query = if sqlite_version >= SqliteVersion::new(3, 26, 0) {
        format!("PRAGMA TABLE_XINFO('{}')", &table.sql_name)
    } else {
        format!("PRAGMA TABLE_INFO('{}')", &table.sql_name)
    };
    let mut result = sql::<pragma_table_info::SqlType>(&query).load(conn)?;
    match column_sorting {
        ColumnSorting::OrdinalPosition => {}
        ColumnSorting::Name => {
            result.sort_by(|a: &ColumnInformation, b: &ColumnInformation| {
                a.column_name.partial_cmp(&b.column_name).unwrap()
            });
        }
    };
    Ok(result)
}

#[derive(Queryable)]
struct FullTableInfo {
    _cid: i32,
    name: String,
    _type_name: String,
    _not_null: bool,
    _dflt_value: Option<String>,
    primary_key: bool,
    _hidden: i32,
}

#[derive(Queryable)]
struct ForeignKeyListRow {
    _id: i32,
    _seq: i32,
    parent_table: String,
    foreign_key: String,
    primary_key: String,
    _on_update: String,
    _on_delete: String,
    _match: String,
}

pub fn get_primary_keys(
    conn: &mut SqliteConnection,
    table: &TableName,
) -> QueryResult<Vec<String>> {
    let sqlite_version = get_sqlite_version(conn);
    let query = if sqlite_version >= SqliteVersion::new(3, 26, 0) {
        format!("PRAGMA TABLE_XINFO('{}')", &table.sql_name)
    } else {
        format!("PRAGMA TABLE_INFO('{}')", &table.sql_name)
    };
    let results = sql::<pragma_table_info::SqlType>(&query).load::<FullTableInfo>(conn)?;
    Ok(results
        .into_iter()
        .filter_map(|i| if i.primary_key { Some(i.name) } else { None })
        .collect())
}

pub fn determine_column_type(
    attr: &ColumnInformation,
) -> Result<ColumnType, Box<dyn Error + Send + Sync + 'static>> {
    let mut type_name = attr.type_name.to_lowercase();
    if type_name == "generated always" {
        type_name.clear();
    }

    let path = if is_bool(&type_name) {
        String::from("Bool")
    } else if is_smallint(&type_name) {
        String::from("SmallInt")
    } else if is_bigint(&type_name) {
        String::from("BigInt")
    } else if type_name.contains("int") {
        String::from("Integer")
    } else if is_text(&type_name) {
        String::from("Text")
    } else if is_binary(&type_name) {
        String::from("Binary")
    } else if is_float(&type_name) {
        String::from("Float")
    } else if is_double(&type_name) {
        String::from("Double")
    } else if type_name == "datetime" || type_name == "timestamp" {
        String::from("Timestamp")
    } else if type_name == "date" {
        String::from("Date")
    } else if type_name == "time" {
        String::from("Time")
    } else {
        return Err(format!("Unsupported type: {}", type_name).into());
    };

    Ok(ColumnType {
        schema: None,
        rust_name: path.clone(),
        sql_name: path,
        is_array: false,
        is_nullable: attr.nullable,
        is_unsigned: false,
    })
}

fn is_text(type_name: &str) -> bool {
    type_name.contains("char") || type_name.contains("clob") || type_name.contains("text")
}

fn is_binary(type_name: &str) -> bool {
    type_name.contains("blob") || type_name.contains("binary") || type_name.is_empty()
}

fn is_bool(type_name: &str) -> bool {
    type_name == "boolean" || type_name.contains("tiny") && type_name.contains("int")
}

fn is_smallint(type_name: &str) -> bool {
    type_name == "int2" || type_name.contains("small") && type_name.contains("int")
}

fn is_bigint(type_name: &str) -> bool {
    type_name == "int8" || type_name.contains("big") && type_name.contains("int")
}

fn is_float(type_name: &str) -> bool {
    type_name.contains("float") || type_name.contains("real")
}

fn is_double(type_name: &str) -> bool {
    type_name.contains("double") || type_name.contains("num") || type_name.contains("dec")
}

#[test]
fn load_table_names_returns_nothing_when_no_tables_exist() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    assert_eq!(
        Vec::<TableName>::new(),
        load_table_names(&mut conn, None).unwrap()
    );
}

#[test]
fn load_table_names_includes_tables_that_exist() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    let table_names = load_table_names(&mut conn, None).unwrap();
    assert!(table_names.contains(&TableName::from_name("users")));
}

#[test]
fn load_table_names_excludes_diesel_metadata_tables() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE __diesel_metadata (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    let table_names = load_table_names(&mut conn, None).unwrap();
    assert!(!table_names.contains(&TableName::from_name("__diesel_metadata")));
}

#[test]
fn load_table_names_excludes_sqlite_metadata_tables() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE __diesel_metadata (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    let table_names = load_table_names(&mut conn, None);
    assert_eq!(vec![TableName::from_name("users")], table_names.unwrap());
}

#[test]
fn load_table_names_excludes_views() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE VIEW answer AS SELECT 42").unwrap();
    let table_names = load_table_names(&mut conn, None);
    assert_eq!(vec![TableName::from_name("users")], table_names.unwrap());
}

#[test]
fn load_table_names_returns_error_when_given_schema_name() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    // We're testing the error message rather than using #[should_panic]
    // to ensure this is returning an error and not actually panicking.
    let table_names = load_table_names(&mut conn, Some("stuff"));
    match table_names {
        Ok(_) => panic!("Expected load_table_names to return an error"),
        Err(e) => assert!(e.to_string().starts_with(
            "sqlite cannot infer \
             schema for databases"
        )),
    }
}

#[test]
fn load_table_names_output_is_ordered() {
    let mut conn = SqliteConnection::establish(":memory:").unwrap();
    conn.execute("CREATE TABLE bbb (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE TABLE aaa (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();
    conn.execute("CREATE TABLE ccc (id INTEGER PRIMARY KEY AUTOINCREMENT)")
        .unwrap();

    let table_names = load_table_names(&mut conn, None)
        .unwrap()
        .iter()
        .map(|table| table.to_string())
        .collect::<Vec<_>>();
    assert_eq!(vec!["aaa", "bbb", "ccc"], table_names);
}

#[test]
fn load_foreign_key_constraints_loads_foreign_keys() {
    let mut connection = SqliteConnection::establish(":memory:").unwrap();

    connection.execute("CREATE TABLE table_1 (id)").unwrap();
    connection
        .execute("CREATE TABLE table_2 (id, fk_one REFERENCES table_1(id))")
        .unwrap();
    connection
        .execute("CREATE TABLE table_3 (id, fk_two REFERENCES table_2(id))")
        .unwrap();

    let table_1 = TableName::from_name("table_1");
    let table_2 = TableName::from_name("table_2");
    let table_3 = TableName::from_name("table_3");
    let fk_one = ForeignKeyConstraint {
        child_table: table_2.clone(),
        parent_table: table_1.clone(),
        foreign_key: "fk_one".into(),
        foreign_key_rust_name: "fk_one".into(),
        primary_key: "id".into(),
    };
    let fk_two = ForeignKeyConstraint {
        child_table: table_3.clone(),
        parent_table: table_2.clone(),
        foreign_key: "fk_two".into(),
        foreign_key_rust_name: "fk_two".into(),
        primary_key: "id".into(),
    };
    let fks = load_foreign_key_constraints(&mut connection, None).unwrap();
    assert_eq!(vec![fk_one, fk_two], fks);
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 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.

#[allow(non_camel_case_types)];

use std::cell::RefCell;
use std::os;
use std::io::fs;
use collections::HashSet;

pub enum FileMatch { FileMatches, FileDoesntMatch }

// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.

/// Functions with type `pick` take a parent directory as well as
/// a file found in that directory.
pub type pick<'a> = 'a |path: &Path| -> FileMatch;

pub struct FileSearch<'a> {
    sysroot: &'a Path,
    addl_lib_search_paths: &'a RefCell<HashSet<Path>>,
    target_triple: &'a str
}

impl<'a> FileSearch<'a> {
    pub fn for_each_lib_search_path(&self, f: |&Path| -> FileMatch) {
        let mut visited_dirs = HashSet::new();
        let mut found = false;

        debug!("filesearch: searching additional lib search paths [{:?}]",
               self.addl_lib_search_paths.borrow().len());
        for path in self.addl_lib_search_paths.borrow().iter() {
            match f(path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
            visited_dirs.insert(path.as_vec().to_owned());
        }

        debug!("filesearch: searching target lib path");
        let tlib_path = make_target_lib_path(self.sysroot,
                                    self.target_triple);
        if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
            match f(&tlib_path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
        }
        visited_dirs.insert(tlib_path.as_vec().to_owned());
        // Try RUST_PATH
        if !found {
            let rustpath = rust_path();
            for path in rustpath.iter() {
                let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple);
                debug!("is {} in visited_dirs? {:?}", tlib_path.display(),
                        visited_dirs.contains_equiv(&tlib_path.as_vec().to_owned()));

                if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
                    visited_dirs.insert(tlib_path.as_vec().to_owned());
                    // Don't keep searching the RUST_PATH if one match turns up --
                    // if we did, we'd get a "multiple matching crates" error
                    match f(&tlib_path) {
                       FileMatches => {
                           break;
                       }
                       FileDoesntMatch => ()
                    }
                }
            }
        }
    }

    pub fn get_target_lib_path(&self) -> Path {
        make_target_lib_path(self.sysroot, self.target_triple)
    }

    pub fn get_target_lib_file_path(&self, file: &Path) -> Path {
        let mut p = self.get_target_lib_path();
        p.push(file);
        p
    }

    pub fn search(&self, pick: pick) {
        self.for_each_lib_search_path(|lib_search_path| {
            debug!("searching {}", lib_search_path.display());
            match fs::readdir(lib_search_path) {
                Ok(files) => {
                    let mut rslt = FileDoesntMatch;
                    let is_rlib = |p: & &Path| {
                        p.extension_str() == Some("rlib")
                    };
                    // Reading metadata out of rlibs is faster, and if we find both
                    // an rlib and a dylib we only read one of the files of
                    // metadata, so in the name of speed, bring all rlib files to
                    // the front of the search list.
                    let files1 = files.iter().filter(|p| is_rlib(p));
                    let files2 = files.iter().filter(|p| !is_rlib(p));
                    for path in files1.chain(files2) {
                        debug!("testing {}", path.display());
                        let maybe_picked = pick(path);
                        match maybe_picked {
                            FileMatches => {
                                debug!("picked {}", path.display());
                                rslt = FileMatches;
                            }
                            FileDoesntMatch => {
                                debug!("rejected {}", path.display());
                            }
                        }
                    }
                    rslt
                }
                Err(..) => FileDoesntMatch,
            }
        });
    }

    pub fn new(sysroot: &'a Path,
               target_triple: &'a str,
               addl_lib_search_paths: &'a RefCell<HashSet<Path>>) -> FileSearch<'a> {
        debug!("using sysroot = {}", sysroot.display());
        FileSearch {
            sysroot: sysroot,
            addl_lib_search_paths: addl_lib_search_paths,
            target_triple: target_triple
        }
    }
}

pub fn relative_target_lib_path(target_triple: &str) -> Path {
    let mut p = Path::new(libdir());
    assert!(p.is_relative());
    p.push(rustlibdir());
    p.push(target_triple);
    p.push("lib");
    p
}

fn make_target_lib_path(sysroot: &Path,
                        target_triple: &str) -> Path {
    sysroot.join(&relative_target_lib_path(target_triple))
}

fn make_rustpkg_target_lib_path(dir: &Path,
                        target_triple: &str) -> Path {
    let mut p = dir.join(libdir());
    p.push(target_triple);
    p
}

pub fn get_or_default_sysroot() -> Path {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: Option<Path>) -> Option<Path> {
        path.and_then(|mut path|
            match fs::readlink(&path) {
                Ok(canon) => {
                    if canon.is_absolute() {
                        Some(canon)
                    } else {
                        path.pop();
                        Some(path.join(canon))
                    }
                },
                Err(..) => Some(path),
            })
    }

    match canonicalize(os::self_exe_name()) {
        Some(mut p) => { p.pop(); p.pop(); p }
        None => fail!("can't determine value for sysroot")
    }
}

#[cfg(windows)]
static PATH_ENTRY_SEPARATOR: &'static str = ";";
#[cfg(not(windows))]
static PATH_ENTRY_SEPARATOR: &'static str = ":";

/// Returns RUST_PATH as a string, without default paths added
pub fn get_rust_path() -> Option<~str> {
    os::getenv("RUST_PATH")
}

/// Returns the value of RUST_PATH, as a list
/// of Paths. Includes default entries for, if they exist:
/// $HOME/.rust
/// DIR/.rust for any DIR that's the current working directory
/// or an ancestor of it
pub fn rust_path() -> Vec<Path> {
    let mut env_rust_path: Vec<Path> = match get_rust_path() {
        Some(env_path) => {
            let env_path_components: Vec<&str> =
                env_path.split_str(PATH_ENTRY_SEPARATOR).collect();
            env_path_components.map(|&s| Path::new(s))
        }
        None => Vec::new()
    };
    let mut cwd = os::getcwd();
    // now add in default entries
    let cwd_dot_rust = cwd.join(".rust");
    if !env_rust_path.contains(&cwd_dot_rust) {
        env_rust_path.push(cwd_dot_rust);
    }
    if !env_rust_path.contains(&cwd) {
        env_rust_path.push(cwd.clone());
    }
    loop {
        if { let f = cwd.filename(); f.is_none() || f.unwrap() == bytes!("..") } {
            break
        }
        cwd.set_filename(".rust");
        if !env_rust_path.contains(&cwd) && cwd.exists() {
            env_rust_path.push(cwd.clone());
        }
        cwd.pop();
    }
    let h = os::homedir();
    for h in h.iter() {
        let p = h.join(".rust");
        if !env_rust_path.contains(&p) && p.exists() {
            env_rust_path.push(p);
        }
    }
    env_rust_path
}

// The name of the directory rustc expects libraries to be located.
// On Unix should be "lib", on windows "bin"
pub fn libdir() -> ~str {
    (env!("CFG_LIBDIR_RELATIVE")).to_owned()
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
pub fn rustlibdir() -> ~str {
    ~"rustlib"
}
<commit_msg>rustc: Stop relying on CFG_LIBDIR_RELATIVE<commit_after>// Copyright 2012-2014 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.

#[allow(non_camel_case_types)];

use std::cell::RefCell;
use std::os;
use std::io::fs;
use collections::HashSet;

pub enum FileMatch { FileMatches, FileDoesntMatch }

// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.

/// Functions with type `pick` take a parent directory as well as
/// a file found in that directory.
pub type pick<'a> = 'a |path: &Path| -> FileMatch;

pub struct FileSearch<'a> {
    sysroot: &'a Path,
    addl_lib_search_paths: &'a RefCell<HashSet<Path>>,
    target_triple: &'a str
}

impl<'a> FileSearch<'a> {
    pub fn for_each_lib_search_path(&self, f: |&Path| -> FileMatch) {
        let mut visited_dirs = HashSet::new();
        let mut found = false;

        debug!("filesearch: searching additional lib search paths [{:?}]",
               self.addl_lib_search_paths.borrow().len());
        for path in self.addl_lib_search_paths.borrow().iter() {
            match f(path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
            visited_dirs.insert(path.as_vec().to_owned());
        }

        debug!("filesearch: searching target lib path");
        let tlib_path = make_target_lib_path(self.sysroot,
                                    self.target_triple);
        if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
            match f(&tlib_path) {
                FileMatches => found = true,
                FileDoesntMatch => ()
            }
        }
        visited_dirs.insert(tlib_path.as_vec().to_owned());
        // Try RUST_PATH
        if !found {
            let rustpath = rust_path();
            for path in rustpath.iter() {
                let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple);
                debug!("is {} in visited_dirs? {:?}", tlib_path.display(),
                        visited_dirs.contains_equiv(&tlib_path.as_vec().to_owned()));

                if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
                    visited_dirs.insert(tlib_path.as_vec().to_owned());
                    // Don't keep searching the RUST_PATH if one match turns up --
                    // if we did, we'd get a "multiple matching crates" error
                    match f(&tlib_path) {
                       FileMatches => {
                           break;
                       }
                       FileDoesntMatch => ()
                    }
                }
            }
        }
    }

    pub fn get_target_lib_path(&self) -> Path {
        make_target_lib_path(self.sysroot, self.target_triple)
    }

    pub fn get_target_lib_file_path(&self, file: &Path) -> Path {
        let mut p = self.get_target_lib_path();
        p.push(file);
        p
    }

    pub fn search(&self, pick: pick) {
        self.for_each_lib_search_path(|lib_search_path| {
            debug!("searching {}", lib_search_path.display());
            match fs::readdir(lib_search_path) {
                Ok(files) => {
                    let mut rslt = FileDoesntMatch;
                    let is_rlib = |p: & &Path| {
                        p.extension_str() == Some("rlib")
                    };
                    // Reading metadata out of rlibs is faster, and if we find both
                    // an rlib and a dylib we only read one of the files of
                    // metadata, so in the name of speed, bring all rlib files to
                    // the front of the search list.
                    let files1 = files.iter().filter(|p| is_rlib(p));
                    let files2 = files.iter().filter(|p| !is_rlib(p));
                    for path in files1.chain(files2) {
                        debug!("testing {}", path.display());
                        let maybe_picked = pick(path);
                        match maybe_picked {
                            FileMatches => {
                                debug!("picked {}", path.display());
                                rslt = FileMatches;
                            }
                            FileDoesntMatch => {
                                debug!("rejected {}", path.display());
                            }
                        }
                    }
                    rslt
                }
                Err(..) => FileDoesntMatch,
            }
        });
    }

    pub fn new(sysroot: &'a Path,
               target_triple: &'a str,
               addl_lib_search_paths: &'a RefCell<HashSet<Path>>) -> FileSearch<'a> {
        debug!("using sysroot = {}", sysroot.display());
        FileSearch {
            sysroot: sysroot,
            addl_lib_search_paths: addl_lib_search_paths,
            target_triple: target_triple
        }
    }
}

pub fn relative_target_lib_path(target_triple: &str) -> Path {
    let mut p = Path::new(libdir());
    assert!(p.is_relative());
    p.push(rustlibdir());
    p.push(target_triple);
    p.push("lib");
    p
}

fn make_target_lib_path(sysroot: &Path,
                        target_triple: &str) -> Path {
    sysroot.join(&relative_target_lib_path(target_triple))
}

fn make_rustpkg_target_lib_path(dir: &Path,
                        target_triple: &str) -> Path {
    let mut p = dir.join(libdir());
    p.push(target_triple);
    p
}

pub fn get_or_default_sysroot() -> Path {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: Option<Path>) -> Option<Path> {
        path.and_then(|mut path|
            match fs::readlink(&path) {
                Ok(canon) => {
                    if canon.is_absolute() {
                        Some(canon)
                    } else {
                        path.pop();
                        Some(path.join(canon))
                    }
                },
                Err(..) => Some(path),
            })
    }

    match canonicalize(os::self_exe_name()) {
        Some(mut p) => { p.pop(); p.pop(); p }
        None => fail!("can't determine value for sysroot")
    }
}

#[cfg(windows)]
static PATH_ENTRY_SEPARATOR: &'static str = ";";
#[cfg(not(windows))]
static PATH_ENTRY_SEPARATOR: &'static str = ":";

/// Returns RUST_PATH as a string, without default paths added
pub fn get_rust_path() -> Option<~str> {
    os::getenv("RUST_PATH")
}

/// Returns the value of RUST_PATH, as a list
/// of Paths. Includes default entries for, if they exist:
/// $HOME/.rust
/// DIR/.rust for any DIR that's the current working directory
/// or an ancestor of it
pub fn rust_path() -> Vec<Path> {
    let mut env_rust_path: Vec<Path> = match get_rust_path() {
        Some(env_path) => {
            let env_path_components: Vec<&str> =
                env_path.split_str(PATH_ENTRY_SEPARATOR).collect();
            env_path_components.map(|&s| Path::new(s))
        }
        None => Vec::new()
    };
    let mut cwd = os::getcwd();
    // now add in default entries
    let cwd_dot_rust = cwd.join(".rust");
    if !env_rust_path.contains(&cwd_dot_rust) {
        env_rust_path.push(cwd_dot_rust);
    }
    if !env_rust_path.contains(&cwd) {
        env_rust_path.push(cwd.clone());
    }
    loop {
        if { let f = cwd.filename(); f.is_none() || f.unwrap() == bytes!("..") } {
            break
        }
        cwd.set_filename(".rust");
        if !env_rust_path.contains(&cwd) && cwd.exists() {
            env_rust_path.push(cwd.clone());
        }
        cwd.pop();
    }
    let h = os::homedir();
    for h in h.iter() {
        let p = h.join(".rust");
        if !env_rust_path.contains(&p) && p.exists() {
            env_rust_path.push(p);
        }
    }
    env_rust_path
}

// The name of the directory rustc expects libraries to be located.
// On Unix should be "lib", on windows "bin"
#[cfg(unix)]
pub fn libdir() -> ~str {
    ~"lib"
}

#[cfg(windows)]
pub fn libdir() -> ~str {
    ~"bin"
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
pub fn rustlibdir() -> ~str {
    ~"rustlib"
}
<|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.

//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://www.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(unboxed_closures)]
#![feature(fn_traits)]
#![feature(unsize)]
#![feature(specialization)]
#![feature(optin_builtin_traits)]
#![feature(macro_vis_matcher)]
#![feature(allow_internal_unstable)]
#![feature(vec_resize_with)]

#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]

extern crate core;
extern crate ena;
#[macro_use]
extern crate log;
extern crate serialize as rustc_serialize; // used by deriving
#[cfg(unix)]
extern crate libc;
extern crate parking_lot;
#[macro_use]
extern crate cfg_if;
extern crate stable_deref_trait;
extern crate rustc_rayon as rayon;
extern crate rustc_rayon_core as rayon_core;
extern crate rustc_hash;

// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
extern crate rustc_cratesio_shim;

pub use rustc_serialize::hex::ToHex;

pub mod accumulate_vec;
pub mod array_vec;
pub mod base_n;
pub mod bitslice;
pub mod bitvec;
pub mod flock;
pub mod fx;
pub mod graph;
pub mod indexed_set;
pub mod indexed_vec;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_vec;
pub mod snapshot_map;
pub use ena::snapshot_vec;
pub mod sorted_map;
pub mod stable_hasher;
pub mod sync;
pub mod tiny_list;
pub mod transitive_relation;
pub mod tuple_slice;
pub use ena::unify;
pub mod work_queue;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
      /// Forgets the function which prevents it from running.
      /// Ensure that the function owns no memory, otherwise it will be leaked.
      pub fn disable(self) {
            std::mem::forget(self);
      }
}

impl<F: Fn()> Drop for OnDrop<F> {
      fn drop(&mut self) {
            (self.0)();
      }
}

// See comments in src/librustc/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<commit_msg>[nll] librustc_data_structures: enable feature(nll) for bootstrap<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.

//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://www.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(unboxed_closures)]
#![feature(fn_traits)]
#![feature(unsize)]
#![feature(specialization)]
#![feature(optin_builtin_traits)]
#![feature(macro_vis_matcher)]
#![cfg_attr(not(stage0), feature(nll))]
#![feature(allow_internal_unstable)]
#![feature(vec_resize_with)]

#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]

extern crate core;
extern crate ena;
#[macro_use]
extern crate log;
extern crate serialize as rustc_serialize; // used by deriving
#[cfg(unix)]
extern crate libc;
extern crate parking_lot;
#[macro_use]
extern crate cfg_if;
extern crate stable_deref_trait;
extern crate rustc_rayon as rayon;
extern crate rustc_rayon_core as rayon_core;
extern crate rustc_hash;

// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
extern crate rustc_cratesio_shim;

pub use rustc_serialize::hex::ToHex;

pub mod accumulate_vec;
pub mod array_vec;
pub mod base_n;
pub mod bitslice;
pub mod bitvec;
pub mod flock;
pub mod fx;
pub mod graph;
pub mod indexed_set;
pub mod indexed_vec;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_vec;
pub mod snapshot_map;
pub use ena::snapshot_vec;
pub mod sorted_map;
pub mod stable_hasher;
pub mod sync;
pub mod tiny_list;
pub mod transitive_relation;
pub mod tuple_slice;
pub use ena::unify;
pub mod work_queue;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
      /// Forgets the function which prevents it from running.
      /// Ensure that the function owns no memory, otherwise it will be leaked.
      pub fn disable(self) {
            std::mem::forget(self);
      }
}

impl<F: Fn()> Drop for OnDrop<F> {
      fn drop(&mut self) {
            (self.0)();
      }
}

// See comments in src/librustc/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<|endoftext|>


<commit_before>//! Static files bundled with documentation output.
//!
//! All the static files are included here for centralized access in case anything other than the
//! HTML rendering code (say, the theme checker) needs to access one of these files.
//!
//! Note about types: CSS and JavaScript files are included as `&'static str` to allow for the
//! minifier to run on them. All other files are included as `&'static [u8]` so they can be
//! directly written to a `Write` handle.

/// The file contents of the main `rustdoc.css` file, responsible for the core layout of the page.
pub static RUSTDOC_CSS: &'static str = include_str!("static/rustdoc.css");

/// The file contents of `settings.css`, responsible for the items on the settings page.
pub static SETTINGS_CSS: &'static str = include_str!("static/settings.css");

/// The file contents of the `noscript.css` file, used in case JS isn't supported or is disabled.
pub static NOSCRIPT_CSS: &'static str = include_str!("static/noscript.css");

/// The file contents of `normalize.css`, included to even out standard elements between browser
/// implementations.
pub static NORMALIZE_CSS: &'static str = include_str!("static/normalize.css");

/// The file contents of `main.js`, which contains the core JavaScript used on documentation pages,
/// including search behavior and docblock folding, among others.
pub static MAIN_JS: &'static str = include_str!("static/main.js");

/// The file contents of `settings.js`, which contains the JavaScript used to handle the settings
/// page.
pub static SETTINGS_JS: &'static str = include_str!("static/settings.js");

/// The file contents of `storage.js`, which contains functionality related to browser Local
/// Storage, used to store documentation settings.
pub static STORAGE_JS: &'static str = include_str!("static/storage.js");

/// The file contents of `brush.svg`, the icon used for the theme-switch button.
pub static BRUSH_SVG: &'static [u8] = include_bytes!("static/brush.svg");

/// The file contents of `wheel.svg`, the icon used for the settings button.
pub static WHEEL_SVG: &'static [u8] = include_bytes!("static/wheel.svg");

/// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox.
pub static DOWN_ARROW_SVG: &'static [u8] = include_bytes!("static/down-arrow.svg");

/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
/// output.
pub static COPYRIGHT: &'static [u8] = include_bytes!("static/COPYRIGHT.txt");

/// The contents of `LICENSE-APACHE.txt`, the text of the Apache License, version 2.0.
pub static LICENSE_APACHE: &'static [u8] = include_bytes!("static/LICENSE-APACHE.txt");

/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
pub static LICENSE_MIT: &'static [u8] = include_bytes!("static/LICENSE-MIT.txt");

/// The contents of `rust-logo.png`, the default icon of the documentation.
pub static RUST_LOGO: &'static [u8] = include_bytes!("static/rust-logo.png");
/// The contents of `favicon.ico`, the default favicon of the documentation.
pub static RUST_FAVICON: &'static [u8] = include_bytes!("static/favicon.ico");

/// The built-in themes given to every documentation site.
pub mod themes {
    /// The "light" theme, selected by default when no setting is available. Used as the basis for
    /// the `--check-theme` functionality.
    pub static LIGHT: &'static str = include_str!("static/themes/light.css");

    /// The "dark" theme.
    pub static DARK: &'static str = include_str!("static/themes/dark.css");
}

/// Files related to the Fira Sans font.
pub mod fira_sans {
    /// The file `FiraSans-Regular.woff`, the Regular variant of the Fira Sans font.
    pub static REGULAR: &'static [u8] = include_bytes!("static/FiraSans-Regular.woff");

    /// The file `FiraSans-Medium.woff`, the Medium variant of the Fira Sans font.
    pub static MEDIUM: &'static [u8] = include_bytes!("static/FiraSans-Medium.woff");

    /// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
    pub static LICENSE: &'static [u8] = include_bytes!("static/FiraSans-LICENSE.txt");
}

/// Files related to the Source Serif Pro font.
pub mod source_serif_pro {
    /// The file `SourceSerifPro-Regular.ttf.woff`, the Regular variant of the Source Serif Pro
    /// font.
    pub static REGULAR: &'static [u8] = include_bytes!("static/SourceSerifPro-Regular.ttf.woff");

    /// The file `SourceSerifPro-Bold.ttf.woff`, the Bold variant of the Source Serif Pro font.
    pub static BOLD: &'static [u8] = include_bytes!("static/SourceSerifPro-Bold.ttf.woff");

    /// The file `SourceSerifPro-It.ttf.woff`, the Italic variant of the Source Serif Pro font.
    pub static ITALIC: &'static [u8] = include_bytes!("static/SourceSerifPro-It.ttf.woff");

    /// The file `SourceSerifPro-LICENSE.txt`, the license text for the Source Serif Pro font.
    pub static LICENSE: &'static [u8] = include_bytes!("static/SourceSerifPro-LICENSE.md");
}

/// Files related to the Source Code Pro font.
pub mod source_code_pro {
    /// The file `SourceCodePro-Regular.woff`, the Regular variant of the Source Code Pro font.
    pub static REGULAR: &'static [u8] = include_bytes!("static/SourceCodePro-Regular.woff");

    /// The file `SourceCodePro-Semibold.woff`, the Semibold variant of the Source Code Pro font.
    pub static SEMIBOLD: &'static [u8] = include_bytes!("static/SourceCodePro-Semibold.woff");

    /// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
    pub static LICENSE: &'static [u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
}

/// Files related to the sidebar in rustdoc sources.
pub mod sidebar {
    /// File script to handle sidebar.
    pub static SOURCE_SCRIPT: &'static str = include_str!("static/source-script.js");
}
<commit_msg>rustdoc: remove redundant static lifetimes (clippy::redundant_static_lifetimes)<commit_after>//! Static files bundled with documentation output.
//!
//! All the static files are included here for centralized access in case anything other than the
//! HTML rendering code (say, the theme checker) needs to access one of these files.
//!
//! Note about types: CSS and JavaScript files are included as `&'static str` to allow for the
//! minifier to run on them. All other files are included as `&'static [u8]` so they can be
//! directly written to a `Write` handle.

/// The file contents of the main `rustdoc.css` file, responsible for the core layout of the page.
pub static RUSTDOC_CSS: &str = include_str!("static/rustdoc.css");

/// The file contents of `settings.css`, responsible for the items on the settings page.
pub static SETTINGS_CSS: &str = include_str!("static/settings.css");

/// The file contents of the `noscript.css` file, used in case JS isn't supported or is disabled.
pub static NOSCRIPT_CSS: &str = include_str!("static/noscript.css");

/// The file contents of `normalize.css`, included to even out standard elements between browser
/// implementations.
pub static NORMALIZE_CSS: &str = include_str!("static/normalize.css");

/// The file contents of `main.js`, which contains the core JavaScript used on documentation pages,
/// including search behavior and docblock folding, among others.
pub static MAIN_JS: &str = include_str!("static/main.js");

/// The file contents of `settings.js`, which contains the JavaScript used to handle the settings
/// page.
pub static SETTINGS_JS: &str = include_str!("static/settings.js");

/// The file contents of `storage.js`, which contains functionality related to browser Local
/// Storage, used to store documentation settings.
pub static STORAGE_JS: &str = include_str!("static/storage.js");

/// The file contents of `brush.svg`, the icon used for the theme-switch button.
pub static BRUSH_SVG: &[u8] = include_bytes!("static/brush.svg");

/// The file contents of `wheel.svg`, the icon used for the settings button.
pub static WHEEL_SVG: &[u8] = include_bytes!("static/wheel.svg");

/// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox.
pub static DOWN_ARROW_SVG: &[u8] = include_bytes!("static/down-arrow.svg");

/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
/// output.
pub static COPYRIGHT: &[u8] = include_bytes!("static/COPYRIGHT.txt");

/// The contents of `LICENSE-APACHE.txt`, the text of the Apache License, version 2.0.
pub static LICENSE_APACHE: &[u8] = include_bytes!("static/LICENSE-APACHE.txt");

/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
pub static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt");

/// The contents of `rust-logo.png`, the default icon of the documentation.
pub static RUST_LOGO: &[u8] = include_bytes!("static/rust-logo.png");
/// The contents of `favicon.ico`, the default favicon of the documentation.
pub static RUST_FAVICON: &[u8] = include_bytes!("static/favicon.ico");

/// The built-in themes given to every documentation site.
pub mod themes {
    /// The "light" theme, selected by default when no setting is available. Used as the basis for
    /// the `--check-theme` functionality.
    pub static LIGHT: &str = include_str!("static/themes/light.css");

    /// The "dark" theme.
    pub static DARK: &str = include_str!("static/themes/dark.css");
}

/// Files related to the Fira Sans font.
pub mod fira_sans {
    /// The file `FiraSans-Regular.woff`, the Regular variant of the Fira Sans font.
    pub static REGULAR: &[u8] = include_bytes!("static/FiraSans-Regular.woff");

    /// The file `FiraSans-Medium.woff`, the Medium variant of the Fira Sans font.
    pub static MEDIUM: &[u8] = include_bytes!("static/FiraSans-Medium.woff");

    /// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
    pub static LICENSE: &[u8] = include_bytes!("static/FiraSans-LICENSE.txt");
}

/// Files related to the Source Serif Pro font.
pub mod source_serif_pro {
    /// The file `SourceSerifPro-Regular.ttf.woff`, the Regular variant of the Source Serif Pro
    /// font.
    pub static REGULAR: &[u8] = include_bytes!("static/SourceSerifPro-Regular.ttf.woff");

    /// The file `SourceSerifPro-Bold.ttf.woff`, the Bold variant of the Source Serif Pro font.
    pub static BOLD: &[u8] = include_bytes!("static/SourceSerifPro-Bold.ttf.woff");

    /// The file `SourceSerifPro-It.ttf.woff`, the Italic variant of the Source Serif Pro font.
    pub static ITALIC: &[u8] = include_bytes!("static/SourceSerifPro-It.ttf.woff");

    /// The file `SourceSerifPro-LICENSE.txt`, the license text for the Source Serif Pro font.
    pub static LICENSE: &[u8] = include_bytes!("static/SourceSerifPro-LICENSE.md");
}

/// Files related to the Source Code Pro font.
pub mod source_code_pro {
    /// The file `SourceCodePro-Regular.woff`, the Regular variant of the Source Code Pro font.
    pub static REGULAR: &[u8] = include_bytes!("static/SourceCodePro-Regular.woff");

    /// The file `SourceCodePro-Semibold.woff`, the Semibold variant of the Source Code Pro font.
    pub static SEMIBOLD: &[u8] = include_bytes!("static/SourceCodePro-Semibold.woff");

    /// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
    pub static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
}

/// Files related to the sidebar in rustdoc sources.
pub mod sidebar {
    /// File script to handle sidebar.
    pub static SOURCE_SCRIPT: &str = include_str!("static/source-script.js");
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs;

use super::{git2, GitStatuses, GitError, GitReference, GitBranch, FileStatus};

pub struct GitRepo {
    repo: git2::Repository,
    path: PathBuf,
}

unsafe impl Send for GitRepo {}
unsafe impl Sync for GitRepo {}

impl GitRepo {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, GitError> {
        let path_ref = path.as_ref();
        let repo = git2::Repository::open(path_ref)
            .map_err(|_| GitError::OpenRepo)?;

        Ok(Self {
               repo: repo,
               path: path_ref.to_owned(),
           })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn statuses(&self) -> Result<GitStatuses, GitError> {
        // self.repo.graph_ahead_behind

        let mut opts = git2::StatusOptions::new();

        opts.include_ignored(false)
            .include_untracked(true)
            .recurse_untracked_dirs(true)
            .include_unreadable_as_untracked(true)
            .disable_pathspec_match(true)
            .exclude_submodules(true);

        let statuses = self.repo
            .statuses(Some(&mut opts))
            .map_err(|_| GitError::Status)?;

        Ok(GitStatuses::new(statuses))
    }

    pub fn reset(&self) -> Result<GitReference, GitError> {
        let head = self.repo.head().map_err(|_| GitError::Reset)?;
        let obj = head.peel(git2::ObjectType::Any)
            .map_err(|_| GitError::Reset)?;

        let mut builder = git2::build::CheckoutBuilder::new();
        let options = builder
            .remove_untracked(true) // this is ignored for a reset :()
            .progress(|path, a, b| {
                          if path == None {
                              return;
                          }

                          println!("{:?} {:?} {:?}", path, a, b)
                      });

        self.repo
            .reset(&obj, git2::ResetType::Hard, Some(options))
            .map_err(|_| GitError::Reset)?;

        Ok(GitReference::new(&head))
    }

    pub fn checkout(&self, branch_name: &str) -> Result<bool, GitError> {
        let branch_type = match branch_name.find("origin/") {
            Some(_) => git2::BranchType::Remote,
            None => git2::BranchType::Local,
        };

        let branch = self.repo
            .find_branch(branch_name, branch_type)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let obj = branch
            .get()
            .peel(git2::ObjectType::Commit)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        // This needs to get non-hacky.
        // Should only set head and reset if not already pointing to head.
        if branch_type == git2::BranchType::Remote {
            let head_id = self.repo
                .head()
                .expect("Could not resolve head")
                .peel(git2::ObjectType::Any)
                .expect("Could not get head ref")
                .id();

            if head_id == obj.id() {
                //println!("bailing out");
                return Ok(false);
            }

            self.repo.set_head_detached(obj.id()).expect("wut");
            self.repo
                .reset(&obj, git2::ResetType::Hard, None)
                .expect("wuufttttt");
            //let branch_str = "refs/heads/topic/ARTC-233";
            //self.repo.set_head(&branch_str).expect("wut");
            return Ok(true);
        }

        let mut opts = git2::build::CheckoutBuilder::new();

        self.repo
            .checkout_tree(&obj, Some(&mut opts))
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let branch_str = format!("refs/heads/{}", branch_name);
        //println!("- checking out '{}'", &branch_str);
        let branch_ref = match self.repo.find_reference(&branch_str) {
            Ok(r) => r,
            Err(e) => {
                println!("- checkout error: {}", e.message());
                return Err(GitError::Checkout(GitBranch::from(branch_type)));
            }
        };

        self.repo
            .set_head(branch_ref.name().unwrap())
            .expect("Error setting head");

        Ok(true)
    }

    pub fn remove_untracked(&self) -> Result<(), GitError> {
        let statuses = self.statuses()?;
        let iter = statuses
            .iter()
            .filter(|x| match *x.status() {
                        FileStatus::New => true,
                        _ => false,
                    });

        // TODO: Finish this nonsense
        for entry in iter {
            let p = self.path.join(entry.path());

            // The whole file/directory distinction might be useless.
            // If a untracked file is removed from an untracked directory, should also
            // remove now empty directory?
            if p.is_file() {
                fs::remove_file(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            } else if p.is_dir() {
                fs::remove_dir_all(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            }
        }

        Ok(())
    }

    pub fn state(&self) -> RepoState {
        RepoState::from(self.repo.state())
    }
}

#[derive(Debug)]
pub enum RepoState {
    Clean,
    Merge,
    Revert,
    RevertSequence,
    CherryPick,
    CherryPickSequence,
    Bisect,
    Rebase,
    RebaseInteractive,
    RebaseMerge,
    ApplyMailbox,
    ApplyMailboxOrRebase,
}

impl From<git2::RepositoryState> for RepoState {
    fn from(state: git2::RepositoryState) -> Self {
        use git2::RepositoryState;

        match state {
            RepositoryState::Clean => RepoState::Clean,
            RepositoryState::Merge => RepoState::Merge,
            RepositoryState::Revert => RepoState::Revert,
            RepositoryState::RevertSequence => RepoState::RevertSequence,
            RepositoryState::CherryPick => RepoState::CherryPick,
            RepositoryState::CherryPickSequence => RepoState::CherryPickSequence,
            RepositoryState::Bisect => RepoState::Bisect,
            RepositoryState::Rebase => RepoState::Rebase,
            RepositoryState::RebaseInteractive => RepoState::RebaseInteractive,
            RepositoryState::RebaseMerge => RepoState::RebaseMerge,
            RepositoryState::ApplyMailbox => RepoState::ApplyMailbox,
            RepositoryState::ApplyMailboxOrRebase => RepoState::ApplyMailboxOrRebase,
        }
    }
}
<commit_msg>Split out remote/local checkout into separate functions<commit_after>use std::path::{Path, PathBuf};
use std::fs;

use super::{git2, GitStatuses, GitError, GitReference, GitBranch, FileStatus};

pub struct GitRepo {
    repo: git2::Repository,
    path: PathBuf,
}

unsafe impl Send for GitRepo {}
unsafe impl Sync for GitRepo {}

impl GitRepo {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, GitError> {
        let path_ref = path.as_ref();
        let repo = git2::Repository::open(path_ref)
            .map_err(|_| GitError::OpenRepo)?;

        Ok(Self {
               repo: repo,
               path: path_ref.to_owned(),
           })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn statuses(&self) -> Result<GitStatuses, GitError> {
        // self.repo.graph_ahead_behind

        let mut opts = git2::StatusOptions::new();

        opts.include_ignored(false)
            .include_untracked(true)
            .recurse_untracked_dirs(true)
            .include_unreadable_as_untracked(true)
            .disable_pathspec_match(true)
            .exclude_submodules(true);

        let statuses = self.repo
            .statuses(Some(&mut opts))
            .map_err(|_| GitError::Status)?;

        Ok(GitStatuses::new(statuses))
    }

    pub fn reset(&self) -> Result<GitReference, GitError> {
        let head = self.repo.head().map_err(|_| GitError::Reset)?;
        let obj = head.peel(git2::ObjectType::Any)
            .map_err(|_| GitError::Reset)?;

        let mut builder = git2::build::CheckoutBuilder::new();
        let options = builder
            .remove_untracked(true) // this is ignored for a reset :()
            .progress(|path, a, b| {
                          if path == None {
                              return;
                          }

                          println!("{:?} {:?} {:?}", path, a, b)
                      });

        self.repo
            .reset(&obj, git2::ResetType::Hard, Some(options))
            .map_err(|_| GitError::Reset)?;

        Ok(GitReference::new(&head))
    }

    pub fn checkout(&self, branch_name: &str) -> Result<bool, GitError> {
        let branch_type = match branch_name.find("origin/") {
            Some(_) => git2::BranchType::Remote,
            None => git2::BranchType::Local,
        };

        let branch = self.repo
            .find_branch(branch_name, branch_type)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let obj = branch
            .get()
            .peel(git2::ObjectType::Commit)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        match branch_type {
            git2::BranchType::Local => self.checkout_local(branch_name, &obj),
            git2::BranchType::Remote => self.checkout_remote(&obj)
        }
    }

    fn checkout_local(&self, branch_name: &str, obj: &git2::Object) -> Result<bool, GitError> {
        let mut opts = git2::build::CheckoutBuilder::new();

        self.repo
            .checkout_tree(&obj, Some(&mut opts))
            .map_err(|_| GitError::Checkout(GitBranch::from(git2::BranchType::Local)))?;

        let branch_str = format!("refs/heads/{}", branch_name);
        //println!("- checking out '{}'", &branch_str);
        let branch_ref = match self.repo.find_reference(&branch_str) {
            Ok(r) => r,
            Err(e) => {
                println!("- checkout error: {}", e.message());
                return Err(GitError::Checkout(GitBranch::from(git2::BranchType::Local)));
            }
        };

        self.repo
            .set_head(branch_ref.name().unwrap())
            .expect("Error setting head");

        Ok(true)
    }

    fn checkout_remote(&self, obj: &git2::Object) -> Result<bool, GitError> {
        let head_id = self.repo
            .head()
            .expect("Could not resolve head")
            .peel(git2::ObjectType::Any)
            .expect("Could not get head ref")
            .id();

        if head_id == obj.id() {
            //println!("bailing out");
            return Ok(false);
        }

        self.repo.set_head_detached(obj.id()).expect("wut");
        self.repo
            .reset(&obj, git2::ResetType::Hard, None)
            .expect("wuufttttt");
        //let branch_str = "refs/heads/topic/ARTC-233";
        //self.repo.set_head(&branch_str).expect("wut");
        Ok(true)
    }

    pub fn remove_untracked(&self) -> Result<(), GitError> {
        let statuses = self.statuses()?;
        let iter = statuses
            .iter()
            .filter(|x| match *x.status() {
                        FileStatus::New => true,
                        _ => false,
                    });

        // TODO: Finish this nonsense
        for entry in iter {
            let p = self.path.join(entry.path());

            // The whole file/directory distinction might be useless.
            // If a untracked file is removed from an untracked directory, should also
            // remove now empty directory?
            if p.is_file() {
                fs::remove_file(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            } else if p.is_dir() {
                fs::remove_dir_all(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            }
        }

        Ok(())
    }

    pub fn state(&self) -> RepoState {
        RepoState::from(self.repo.state())
    }
}

#[derive(Debug)]
pub enum RepoState {
    Clean,
    Merge,
    Revert,
    RevertSequence,
    CherryPick,
    CherryPickSequence,
    Bisect,
    Rebase,
    RebaseInteractive,
    RebaseMerge,
    ApplyMailbox,
    ApplyMailboxOrRebase,
}

impl From<git2::RepositoryState> for RepoState {
    fn from(state: git2::RepositoryState) -> Self {
        use git2::RepositoryState;

        match state {
            RepositoryState::Clean => RepoState::Clean,
            RepositoryState::Merge => RepoState::Merge,
            RepositoryState::Revert => RepoState::Revert,
            RepositoryState::RevertSequence => RepoState::RevertSequence,
            RepositoryState::CherryPick => RepoState::CherryPick,
            RepositoryState::CherryPickSequence => RepoState::CherryPickSequence,
            RepositoryState::Bisect => RepoState::Bisect,
            RepositoryState::Rebase => RepoState::Rebase,
            RepositoryState::RebaseInteractive => RepoState::RebaseInteractive,
            RepositoryState::RebaseMerge => RepoState::RebaseMerge,
            RepositoryState::ApplyMailbox => RepoState::ApplyMailbox,
            RepositoryState::ApplyMailboxOrRebase => RepoState::ApplyMailboxOrRebase,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use executable_helpers::helpers::setup_executable;
use std::{
    path::PathBuf,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(about = "Libra Node")]
struct Args {
    #[structopt(short = "f", long, parse(from_os_str))]
    /// Path to NodeConfig
    config: Option<PathBuf>,
    #[structopt(short = "d", long)]
    /// Disable logging
    no_logging: bool,
}

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn main() {
    let args = Args::from_args();

    let (mut config, _logger) =
        setup_executable(args.config.as_ref().map(PathBuf::as_path), args.no_logging);

    let _node_handle = libra_node::main_node::setup_environment(&mut config);

    let term = Arc::new(AtomicBool::new(false));

    while !term.load(Ordering::Acquire) {
        std::thread::park();
    }
}
<commit_msg>[clippy] Fix instances of clippy::option_as_ref_deref<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use executable_helpers::helpers::setup_executable;
use std::{
    path::PathBuf,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(about = "Libra Node")]
struct Args {
    #[structopt(short = "f", long, parse(from_os_str))]
    /// Path to NodeConfig
    config: Option<PathBuf>,
    #[structopt(short = "d", long)]
    /// Disable logging
    no_logging: bool,
}

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn main() {
    let args = Args::from_args();

    let (mut config, _logger) =
        setup_executable(args.config.as_deref(), args.no_logging);

    let _node_handle = libra_node::main_node::setup_environment(&mut config);

    let term = Arc::new(AtomicBool::new(false));

    while !term.load(Ordering::Acquire) {
        std::thread::park();
    }
}
<|endoftext|>