<commit_before>//! These structs are a subset of the ones found in `rustc_errors::json`.
//! They are only used for deserialization of JSON output provided by libtest.

use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize)]
struct ArtifactNotification {
    #[allow(dead_code)]
    artifact: PathBuf,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

#[derive(Deserialize)]
struct FutureIncompatReport {
    future_incompat_report: Vec<FutureBreakageItem>,
}

#[derive(Deserialize)]
struct FutureBreakageItem {
    diagnostic: Diagnostic,
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn rustfix_diagnostics_only(output: &str) -> String {
    output
        .lines()
        .filter(|line| line.starts_with('{') && serde_json::from_str::<Diagnostic>(line).is_ok())
        .collect()
}

pub fn extract_rendered(output: &str) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                    diagnostic.rendered
                } else if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(line) {
                    if report.future_incompat_report.is_empty() {
                        None
                    } else {
                        Some(format!(
                            "Future incompatibility report: {}",
                            report
                                .future_incompat_report
                                .into_iter()
                                .map(|item| {
                                    format!(
                                        "Future breakage diagnostic:\n{}",
                                        item.diagnostic
                                            .rendered
                                            .unwrap_or_else(|| "Not rendered".to_string())
                                    )
                                })
                                .collect::<String>()
                        ))
                    }
                } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                    // Ignore the notification.
                    None
                } else {
                    print!(
                        "failed to decode compiler output as json: line: {}\noutput: {}",
                        line, output
                    );
                    panic!()
                }
            } else {
                // preserve non-JSON lines, such as ICEs
                Some(format!("{}\n", line))
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                // Ignore the future compat report message - this is handled
                // by `extract_rendered`
                if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
                    vec![]
                } else {
                    proc_res.fatal(
                        Some(&format!(
                            "failed to decode compiler output as json: \
                         `{}`\nline: {}\noutput: {}",
                            error, line, output
                        )),
                        || (),
                    );
                }
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();

    let primary_spans: Vec<_> = spans_info_in_this_file
        .iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
            // FIXME(#33000) -- it'd be better to use a dedicated
            // UI harness than to include the line/col number like
            // this, but some current tests rely on it.
            //
            // Note: Do NOT include the filename. These can easily
            // cause false matches where the expected message
            // appears in the filename, and hence the message
            // changes but the test still passes.
            {
                format!(
                    "{}:{}: {}:{}: {} [{}]",
                    span.line_start,
                    span.column_start,
                    span.line_end,
                    span.column_end,
                    text,
                    code.code.clone()
                )
            }
            None =>
            // FIXME(#33000) -- it'd be better to use a dedicated UI harness
            {
                format!(
                    "{}:{}: {}:{}: {}",
                    span.line_start, span.column_start, span.line_end, span.column_end, text
                )
            }
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error { line_num: span.line_start, kind, msg });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<commit_msg>Remove dead code from `compiletest::json`<commit_after>//! These structs are a subset of the ones found in `rustc_errors::json`.
//! They are only used for deserialization of JSON output provided by libtest.

use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize)]
struct ArtifactNotification {
    #[allow(dead_code)]
    artifact: PathBuf,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

#[derive(Deserialize)]
struct FutureIncompatReport {
    future_incompat_report: Vec<FutureBreakageItem>,
}

#[derive(Deserialize)]
struct FutureBreakageItem {
    diagnostic: Diagnostic,
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
}

pub fn rustfix_diagnostics_only(output: &str) -> String {
    output
        .lines()
        .filter(|line| line.starts_with('{') && serde_json::from_str::<Diagnostic>(line).is_ok())
        .collect()
}

pub fn extract_rendered(output: &str) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                    diagnostic.rendered
                } else if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(line) {
                    if report.future_incompat_report.is_empty() {
                        None
                    } else {
                        Some(format!(
                            "Future incompatibility report: {}",
                            report
                                .future_incompat_report
                                .into_iter()
                                .map(|item| {
                                    format!(
                                        "Future breakage diagnostic:\n{}",
                                        item.diagnostic
                                            .rendered
                                            .unwrap_or_else(|| "Not rendered".to_string())
                                    )
                                })
                                .collect::<String>()
                        ))
                    }
                } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                    // Ignore the notification.
                    None
                } else {
                    print!(
                        "failed to decode compiler output as json: line: {}\noutput: {}",
                        line, output
                    );
                    panic!()
                }
            } else {
                // preserve non-JSON lines, such as ICEs
                Some(format!("{}\n", line))
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                // Ignore the future compat report message - this is handled
                // by `extract_rendered`
                if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
                    vec![]
                } else {
                    proc_res.fatal(
                        Some(&format!(
                            "failed to decode compiler output as json: \
                         `{}`\nline: {}\noutput: {}",
                            error, line, output
                        )),
                        || (),
                    );
                }
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();

    let primary_spans: Vec<_> = spans_info_in_this_file
        .iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
            // FIXME(#33000) -- it'd be better to use a dedicated
            // UI harness than to include the line/col number like
            // this, but some current tests rely on it.
            //
            // Note: Do NOT include the filename. These can easily
            // cause false matches where the expected message
            // appears in the filename, and hence the message
            // changes but the test still passes.
            {
                format!(
                    "{}:{}: {}:{}: {} [{}]",
                    span.line_start,
                    span.column_start,
                    span.line_end,
                    span.column_end,
                    text,
                    code.code.clone()
                )
            }
            None =>
            // FIXME(#33000) -- it'd be better to use a dedicated UI harness
            {
                format!(
                    "{}:{}: {}:{}: {}",
                    span.line_start, span.column_start, span.line_end, span.column_end, text
                )
            }
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error { line_num: span.line_start, kind, msg });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use {RequestedSlice, VersionMatchStrategy};
use commands::command::Command;
use formatters;
use options_parse::Options;
use os::Os;
use slice::{List, Slice};

pub struct MakeCommand<'a> {
    slices: Vec<RequestedSlice>,
    os: Os,
    root_directory: &'a Path,
    slice_root_directory: &'a Path,
    options: Options
}

struct DependenciesSearchResult<'a> {
    found_requested_slices: Vec<&'a Slice>,
    missing_requested_slices: Vec<&'a str>,
    unresolved_dependencies: HashMap<&'a str, Vec<&'a str>>,
}

impl<'a> MakeCommand<'a> {
    /// # Panics
    /// If `slices` is empty
    pub fn new(slices: Vec<RequestedSlice>, os: Os, root_directory: &'a Path,
           slice_root_directory: &'a Path, options: Options) -> MakeCommand<'a> {
        assert_not_empty!(slices);
        assert!(!slices.is_empty(), "There is no specified layers");
        MakeCommand { slices: slices, os: os, root_directory: root_directory,
                      slice_root_directory: slice_root_directory,
                      options: options }
    }

    fn create_code_from_slices(&self, slices: Vec<&Slice>, visited_slices: &mut Vec<&str>) -> String {
        let mut code = String::new();
        for slice in slices {
            let slice_name = slice.name() as &str;
            if visited_slices.contains(&slice_name) {
                continue;
            }
            let dependencies = slice.resolved_dependencies();
            if !dependencies.is_empty() {
                let dependency_code = self.create_code_from_slices(dependencies, visited_slices);
                code.push_str(&dependency_code);
            }
            let slice_code = formatters::generate_code(&slice, &self.options.format);
            code.push_str(&slice_code);
        }
        code
    }

    fn get_output_file_path(&self) -> PathBuf {
        if self.options.outpath.is_empty() {
            let mut path = self.root_directory.to_path_buf();
            path.push(&self.slices.first().unwrap().name);
            path
        } else {
            let mut path = PathBuf::new();
            path.push(&self.options.outpath);
            path
        }
    }

    fn find_unresolved_dependencies<'b>(&'b self, list: &'b List) -> DependenciesSearchResult {
        let mut result = DependenciesSearchResult { found_requested_slices: Vec::new(),
                                                    missing_requested_slices: Vec::new(),
                                                    unresolved_dependencies: HashMap::new() };
        for slice in &self.slices {
            if let Some(slice) = list.find_slice(&slice.name, &slice.version,
                                                 slice.version_match_strategy) {
                let dependencies = slice.unresolved_dependencies_include_nested();
                if !dependencies.is_empty() {
                    for dep in dependencies {
                        let entry = result.unresolved_dependencies.entry(&slice.name());
                        entry.or_insert(Vec::new()).push(dep);
                    }
                } else {
                    result.found_requested_slices.push(slice.borrow());
                }
            } else {
                result.missing_requested_slices.push(&slice.name);
            }
        }
        result
    }

    fn generate_code(&self) -> String {
        match List::new(&self.slice_root_directory, &self.os,
                        VersionMatchStrategy::ExactOrGreater) {
            Ok(list) => {
                match self.generate_code_for_list(&list) {
                    Some(code) => code,
                    None => panic!("Code generation failed")
                }
            }
            Err(error) => panic!("{}", error)
        }
    }

    fn generate_code_for_list(&self, list: &List) -> Option<String> {
        let result = self.find_unresolved_dependencies(list);
        let has_missing_slice = !result.unresolved_dependencies.is_empty() ||
                                !result.missing_requested_slices.is_empty();
        if has_missing_slice {
            if !result.missing_requested_slices.is_empty() {
                println!("Missing requested slices:");
                for slice in &result.missing_requested_slices {
                    println!("{}", slice);
                }
            }
            if !result.unresolved_dependencies.is_empty() {
                println!("Missing dependencies:");
                for (requested_slice, missing_dependencies) in &result.unresolved_dependencies {
                    for missing_dep in missing_dependencies {
                        println!("{} depends on {}, but it is missing", requested_slice, missing_dep);
                    }
                }
            }
            return None;
        }

        let mut visited_slices = Vec::new();
        Some(self.create_code_from_slices(result.found_requested_slices, &mut visited_slices))
    }

    fn write_code(&self, code: String) {
        match File::create(self.get_output_file_path()) {
            Ok(mut file) => {
                if let Err(error) = file.write_fmt(format_args!("{}", code)) {
                    panic!("{}", error);
                }
            }
            Err(error) =>  panic!("File cannot be created at path {}\nReason = {}",
                                  self.get_output_file_path().display(), error)
        }
    }
}

impl<'a> Command for MakeCommand<'a> {
    fn run(&mut self) {
        let code = self.generate_code();
        self.write_code(code);
    }
}

#[cfg(test)]
mod tests {
    use std::env;
    use std::path::Path;
    use {MakeCommand, RequestedSlice, VersionMatchStrategy};
    use options_parse::{Format, Options};
    use os::Os;
    use version;

    fn generate_code_for_jekyll_with_format(format: Format) -> String {
        let version_match_strategy = VersionMatchStrategy::ExactOrGreater;
        let slice = RequestedSlice { name: String::from("jekyll"), version: version::zero(),
                                     version_match_strategy: version_match_strategy };
        let slices = vec![slice];

        let os = Os { name: String::from("debian"), version: version::zero() };

        let mut path = env::current_dir().expect("Current dir is not set").to_path_buf();
        path.push("test_slices");

        let options = Options { format: format, .. Options::new() };

        let command = MakeCommand::new(slices, os, Path::new("/"), &path, options);
        println!("{}", command.generate_code());
        command.generate_code()
    }

    #[test]
    fn generate_code_for_jekyll_in_docker_format() {
        let code = generate_code_for_jekyll_with_format(Format::Docker);
        assert_eq!(code, "RUN export DEBIAN_FRONTEND=noninteractive && \\
apt-get update -q -y && \\
alias apt-get='apt-get --no-install-recommends' && \\
apt-get install -q -y apt-utils
RUN apt-get install -q -y wget
RUN cd /tmp && \\
wget https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.3.tar.gz && \\
tar xvzf ruby-2.2.3.tar.gz && \\
cd ruby-2.2.3 && \\
./configure --prefix=/usr/local && \\
make && \\
make install && \\
cd .. && \\
rm -rf ruby-2.2.3 && \\
wget https://rubygems.org/rubygems/rubygems-2.4.8.tgz && \\
tar xvzf rubygems-2.4.8.tgz && \\
cd rubygems-2.4.8 && \\
ruby setup.rb && \\
cd .. && \\
rm -rf rubygems-2.4.8
RUN gem install jekyll -v '3.0.0.pre.beta9'
");
    }

    #[test]
    fn generate_code_for_jekyll_in_shell_format() {
        let code = generate_code_for_jekyll_with_format(Format::Shell);
        assert_eq!(code, "export DEBIAN_FRONTEND=noninteractive
apt-get update -q -y
alias apt-get='apt-get --no-install-recommends'
apt-get install -q -y apt-utils
apt-get install -q -y wget
cd /tmp
wget https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.3.tar.gz
tar xvzf ruby-2.2.3.tar.gz
cd ruby-2.2.3
./configure --prefix=/usr/local
make
make install
cd ..
rm -rf ruby-2.2.3
wget https://rubygems.org/rubygems/rubygems-2.4.8.tgz
tar xvzf rubygems-2.4.8.tgz
cd rubygems-2.4.8
ruby setup.rb
cd ..
rm -rf rubygems-2.4.8
gem install jekyll -v '3.0.0.pre.beta9'
");
    }
}<commit_msg>Fixed #25<commit_after>use std::borrow::Borrow;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use {RequestedSlice, VersionMatchStrategy};
use commands::command::Command;
use formatters;
use options_parse::Options;
use os::Os;
use slice::{List, Slice};

pub struct MakeCommand<'a> {
    slices: Vec<RequestedSlice>,
    os: Os,
    root_directory: &'a Path,
    slice_root_directory: &'a Path,
    options: Options
}

struct DependenciesSearchResult<'a> {
    found_requested_slices: Vec<&'a Slice>,
    missing_requested_slices: Vec<&'a str>,
    unresolved_dependencies: HashMap<&'a str, Vec<&'a str>>,
}

impl<'a> MakeCommand<'a> {
    /// # Panics
    /// If `slices` is empty
    pub fn new(slices: Vec<RequestedSlice>, os: Os, root_directory: &'a Path,
           slice_root_directory: &'a Path, options: Options) -> MakeCommand<'a> {
        assert_not_empty!(slices);
        assert!(!slices.is_empty(), "There is no specified layers");
        MakeCommand { slices: slices, os: os, root_directory: root_directory,
                      slice_root_directory: slice_root_directory,
                      options: options }
    }

    fn create_code_from_slices(&self, slices: Vec<&Slice>, visited_slices: &mut Vec<&str>) -> String {
        let mut code = String::new();
        for slice in slices {
            let slice_name = slice.name() as &str;
            if visited_slices.contains(&slice_name) {
                continue;
            }
            let dependencies = slice.resolved_dependencies();
            if !dependencies.is_empty() {
                let dependency_code = self.create_code_from_slices(dependencies, visited_slices);
                code.push_str(&dependency_code);
            }
            let slice_code = formatters::generate_code(&slice, &self.options.format);
            code.push_str(&slice_code);
        }
        code
    }

    fn get_output_file_path(&self) -> PathBuf {
        if self.options.outpath.is_empty() {
            let mut path = self.root_directory.to_path_buf();
            path.push("make");
            path.push(&self.slices.first().unwrap().name);
            path
        } else {
            let mut path = PathBuf::new();
            path.push(&self.options.outpath);
            path
        }
    }

    fn find_unresolved_dependencies<'b>(&'b self, list: &'b List) -> DependenciesSearchResult {
        let mut result = DependenciesSearchResult { found_requested_slices: Vec::new(),
                                                    missing_requested_slices: Vec::new(),
                                                    unresolved_dependencies: HashMap::new() };
        for slice in &self.slices {
            if let Some(slice) = list.find_slice(&slice.name, &slice.version,
                                                 slice.version_match_strategy) {
                let dependencies = slice.unresolved_dependencies_include_nested();
                if !dependencies.is_empty() {
                    for dep in dependencies {
                        let entry = result.unresolved_dependencies.entry(&slice.name());
                        entry.or_insert(Vec::new()).push(dep);
                    }
                } else {
                    result.found_requested_slices.push(slice.borrow());
                }
            } else {
                result.missing_requested_slices.push(&slice.name);
            }
        }
        result
    }

    fn generate_code(&self) -> String {
        match List::new(&self.slice_root_directory, &self.os,
                        VersionMatchStrategy::ExactOrGreater) {
            Ok(list) => {
                match self.generate_code_for_list(&list) {
                    Some(code) => code,
                    None => panic!("Code generation failed")
                }
            }
            Err(error) => panic!("{}", error)
        }
    }

    fn generate_code_for_list(&self, list: &List) -> Option<String> {
        let result = self.find_unresolved_dependencies(list);
        let has_missing_slice = !result.unresolved_dependencies.is_empty() ||
                                !result.missing_requested_slices.is_empty();
        if has_missing_slice {
            if !result.missing_requested_slices.is_empty() {
                println!("Missing requested slices:");
                for slice in &result.missing_requested_slices {
                    println!("{}", slice);
                }
            }
            if !result.unresolved_dependencies.is_empty() {
                println!("Missing dependencies:");
                for (requested_slice, missing_dependencies) in &result.unresolved_dependencies {
                    for missing_dep in missing_dependencies {
                        println!("{} depends on {}, but it is missing", requested_slice, missing_dep);
                    }
                }
            }
            return None;
        }

        let mut visited_slices = Vec::new();
        Some(self.create_code_from_slices(result.found_requested_slices, &mut visited_slices))
    }

    fn write_code(&self, code: String) {
        match File::create(self.get_output_file_path()) {
            Ok(mut file) => {
                if let Err(error) = file.write_fmt(format_args!("{}", code)) {
                    panic!("{}", error);
                }
            }
            Err(error) =>  panic!("File cannot be created at path {}\nReason = {}",
                                  self.get_output_file_path().display(), error)
        }
    }
}

impl<'a> Command for MakeCommand<'a> {
    fn run(&mut self) {
        let code = self.generate_code();
        self.write_code(code);
    }
}

#[cfg(test)]
mod tests {
    use std::env;
    use std::path::Path;
    use {MakeCommand, RequestedSlice, VersionMatchStrategy};
    use options_parse::{Format, Options};
    use os::Os;
    use version;

    fn generate_code_for_jekyll_with_format(format: Format) -> String {
        let version_match_strategy = VersionMatchStrategy::ExactOrGreater;
        let slice = RequestedSlice { name: String::from("jekyll"), version: version::zero(),
                                     version_match_strategy: version_match_strategy };
        let slices = vec![slice];

        let os = Os { name: String::from("debian"), version: version::zero() };

        let mut path = env::current_dir().expect("Current dir is not set").to_path_buf();
        path.push("test_slices");

        let options = Options { format: format, .. Options::new() };

        let command = MakeCommand::new(slices, os, Path::new("/"), &path, options);
        println!("{}", command.generate_code());
        command.generate_code()
    }

    #[test]
    fn generate_code_for_jekyll_in_docker_format() {
        let code = generate_code_for_jekyll_with_format(Format::Docker);
        assert_eq!(code, "RUN export DEBIAN_FRONTEND=noninteractive && \\
apt-get update -q -y && \\
alias apt-get='apt-get --no-install-recommends' && \\
apt-get install -q -y apt-utils
RUN apt-get install -q -y wget
RUN cd /tmp && \\
wget https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.3.tar.gz && \\
tar xvzf ruby-2.2.3.tar.gz && \\
cd ruby-2.2.3 && \\
./configure --prefix=/usr/local && \\
make && \\
make install && \\
cd .. && \\
rm -rf ruby-2.2.3 && \\
wget https://rubygems.org/rubygems/rubygems-2.4.8.tgz && \\
tar xvzf rubygems-2.4.8.tgz && \\
cd rubygems-2.4.8 && \\
ruby setup.rb && \\
cd .. && \\
rm -rf rubygems-2.4.8
RUN gem install jekyll -v '3.0.0.pre.beta9'
");
    }

    #[test]
    fn generate_code_for_jekyll_in_shell_format() {
        let code = generate_code_for_jekyll_with_format(Format::Shell);
        assert_eq!(code, "export DEBIAN_FRONTEND=noninteractive
apt-get update -q -y
alias apt-get='apt-get --no-install-recommends'
apt-get install -q -y apt-utils
apt-get install -q -y wget
cd /tmp
wget https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.3.tar.gz
tar xvzf ruby-2.2.3.tar.gz
cd ruby-2.2.3
./configure --prefix=/usr/local
make
make install
cd ..
rm -rf ruby-2.2.3
wget https://rubygems.org/rubygems/rubygems-2.4.8.tgz
tar xvzf rubygems-2.4.8.tgz
cd rubygems-2.4.8
ruby setup.rb
cd ..
rm -rf rubygems-2.4.8
gem install jekyll -v '3.0.0.pre.beta9'
");
    }
}<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![no_main]

use std::io::{Cursor, Read, Seek, SeekFrom};
use std::mem::size_of;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::{base_features, Block, Interrupt, Queue, VirtioDevice};
use tempfile;
use vm_memory::{GuestAddress, GuestMemory};

const MEM_SIZE: u64 = 256 * 1024 * 1024;
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
const CMD_SIZE: usize = 16; // Bytes in the command.

fuzz_target!(|bytes| {
    let size_u64 = size_of::<u64>();
    let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();

    // The fuzz data is interpreted as:
    // starting index 8 bytes
    // command location 8 bytes
    // command 16 bytes
    // descriptors circular buffer 16 bytes * 3
    if bytes.len() < 4 * size_u64 {
        // Need an index to start.
        return;
    }

    let mut data_image = Cursor::new(bytes);

    let first_index = read_u64(&mut data_image);
    if first_index > MEM_SIZE / DESC_SIZE {
        return;
    }
    let first_offset = first_index * DESC_SIZE;
    if first_offset as usize + size_u64 > bytes.len() {
        return;
    }

    let command_addr = read_u64(&mut data_image);
    if command_addr > MEM_SIZE - CMD_SIZE as u64 {
        return;
    }
    if mem
        .write_all_at_addr(
            &bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
            GuestAddress(command_addr as u64),
        )
        .is_err()
    {
        return;
    }

    data_image.seek(SeekFrom::Start(first_offset)).unwrap();
    let desc_table = read_u64(&mut data_image);

    if mem
        .write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
        .is_err()
    {
        return;
    }

    let mut q = Queue::new(QUEUE_SIZE);
    q.ready = true;
    q.size = QUEUE_SIZE / 2;
    q.max_size = QUEUE_SIZE;

    let queue_evts: Vec<Event> = vec![Event::new().unwrap()];
    let queue_fd = queue_evts[0].as_raw_fd();
    let queue_evt = unsafe { Event::from_raw_fd(libc::dup(queue_fd)) };

    let features = base_features();

    let disk_file = tempfile::tempfile().unwrap();
    let mut block = Block::new(features, Box::new(disk_file), false, true, 512, None).unwrap();

    block.activate(
        mem,
        Interrupt::new(
            Arc::new(AtomicUsize::new(0)),
            Event::new().unwrap(),
            Event::new().unwrap(),
            None,   // msix_config
            0xFFFF, // VIRTIO_MSI_NO_VECTOR
        ),
        vec![q],
        queue_evts,
    );

    queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do.
});

fn read_u64<T: Read>(readable: &mut T) -> u64 {
    let mut buf = [0u8; size_of::<u64>()];
    readable.read_exact(&mut buf[..]).unwrap();
    u64::from_le_bytes(buf)
}
<commit_msg>fuzz: block_fuzzer: add new base_features arg<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![no_main]

use std::io::{Cursor, Read, Seek, SeekFrom};
use std::mem::size_of;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::{base_features, Block, Interrupt, Queue, VirtioDevice};
use tempfile;
use vm_memory::{GuestAddress, GuestMemory};

const MEM_SIZE: u64 = 256 * 1024 * 1024;
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
const CMD_SIZE: usize = 16; // Bytes in the command.

fuzz_target!(|bytes| {
    let size_u64 = size_of::<u64>();
    let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();

    // The fuzz data is interpreted as:
    // starting index 8 bytes
    // command location 8 bytes
    // command 16 bytes
    // descriptors circular buffer 16 bytes * 3
    if bytes.len() < 4 * size_u64 {
        // Need an index to start.
        return;
    }

    let mut data_image = Cursor::new(bytes);

    let first_index = read_u64(&mut data_image);
    if first_index > MEM_SIZE / DESC_SIZE {
        return;
    }
    let first_offset = first_index * DESC_SIZE;
    if first_offset as usize + size_u64 > bytes.len() {
        return;
    }

    let command_addr = read_u64(&mut data_image);
    if command_addr > MEM_SIZE - CMD_SIZE as u64 {
        return;
    }
    if mem
        .write_all_at_addr(
            &bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
            GuestAddress(command_addr as u64),
        )
        .is_err()
    {
        return;
    }

    data_image.seek(SeekFrom::Start(first_offset)).unwrap();
    let desc_table = read_u64(&mut data_image);

    if mem
        .write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
        .is_err()
    {
        return;
    }

    let mut q = Queue::new(QUEUE_SIZE);
    q.ready = true;
    q.size = QUEUE_SIZE / 2;
    q.max_size = QUEUE_SIZE;

    let queue_evts: Vec<Event> = vec![Event::new().unwrap()];
    let queue_fd = queue_evts[0].as_raw_fd();
    let queue_evt = unsafe { Event::from_raw_fd(libc::dup(queue_fd)) };

    let features = base_features(false);

    let disk_file = tempfile::tempfile().unwrap();
    let mut block = Block::new(features, Box::new(disk_file), false, true, 512, None).unwrap();

    block.activate(
        mem,
        Interrupt::new(
            Arc::new(AtomicUsize::new(0)),
            Event::new().unwrap(),
            Event::new().unwrap(),
            None,   // msix_config
            0xFFFF, // VIRTIO_MSI_NO_VECTOR
        ),
        vec![q],
        queue_evts,
    );

    queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do.
});

fn read_u64<T: Read>(readable: &mut T) -> u64 {
    let mut buf = [0u8; size_of::<u64>()];
    readable.read_exact(&mut buf[..]).unwrap();
    u64::from_le_bytes(buf)
}
<|endoftext|>


<commit_before>//! Largest prime factor
//! Problem 3
//!
//! The prime factors of 13195 are 5, 7, 13 and 29.
//!
//! What is the largest prime factor of the number 600851475143 ?

extern crate core;
extern crate num;

use self::core::ops::Shr;
use self::num::BigUint;
use self::num::bigint::ToBigUint;

/// Maximo Comun Divisor usando el algoritmo de Euclides
fn gcd(mut a: usize, mut b: usize) -> usize {
    let mut remainder: usize;

    while b != 0 {
        remainder = a % b;
        a = b;
        b = remainder;
    }

    a
}

/// Prueba de primalidad de Miller-Rabin
fn is_prime(n: usize) -> bool {
    if n == 2 || n == 3 { return true; }
    if n < 2 || n % 2 == 0 { return false; }

    fn witnesses(n: usize) -> &'static[usize] {
        match n {
            1 ... 1373652                   => { static A: &'static[usize] = &[2, 3]; A },
            1373652 ... 4759123140          => { static A: &'static[usize] = &[2, 7, 61]; A },
            4759123141 ... 2152302898746    => { static A: &'static[usize] = &[2, 3, 5, 7, 11]; A },
            2152302898747 ... 3474749660382 => { static A: &'static[usize] = &[2, 3, 5, 7, 11, 13]; A },
            _                               => { static A: &'static[usize] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022]; A }
        }
    }

    let big_n = n.to_biguint().unwrap();
    let big_1 = 1.to_biguint().unwrap();

    let s = (n - 1).trailing_zeros();
    let d = (n - 1).shr(s);

    for a in witnesses(n) {
        if a >= &n { break; }

        let mut x = num::pow::<BigUint>(a.to_biguint().unwrap(), d) % &big_n;
        if x == big_1 || x == &big_n - &big_1 { continue; }

        let mut t = s;
        while x != &big_n - &big_1 {
            t -= 1;
            if t <= 0 { return false; }
            x = (&x * &x) % &big_n;
            if x == big_1 { return false; }
        }
    }

    true
}

#[cfg(test)]
mod tests {
    #[test]
    fn gcd() {
        assert_eq!(4, super::gcd(8, 12));
        assert_eq!(6, super::gcd(54, 24));
        assert_eq!(14, super::gcd(42, 56));
        assert_eq!(1, super::gcd(9, 28));
    }

    fn assert_is_prime(n: usize) {
        assert!(super::is_prime(n));
    }

    #[test]
    fn first_primes_below_1000() {
        assert_eq!(
            vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
                 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
                 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
                 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
                 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
                 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
                 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
                 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
                 991, 997],
            (1usize..1000).filter(|&x| super::is_prime(x)).collect::<Vec<_>>());
    }

    #[test]
    fn large_prime() {
        assert_is_prime(600851475143);
    }
}<commit_msg>wip: problema 3<commit_after>//! Largest prime factor
//! Problem 3
//!
//! The prime factors of 13195 are 5, 7, 13 and 29.
//!
//! What is the largest prime factor of the number 600851475143 ?

extern crate core;
extern crate num;

use self::core::ops::Shr;
use self::num::BigUint;
use self::num::bigint::ToBigUint;

/// Maximo Comun Divisor usando el algoritmo de Euclides
fn gcd(mut a: usize, mut b: usize) -> usize {
    let mut remainder: usize;

    while b != 0 {
        remainder = a % b;
        a = b;
        b = remainder;
    }

    a
}

/// Prueba de primalidad de Miller-Rabin
fn is_prime(n: usize) -> bool {
    if n == 2 || n == 3 { return true; }
    if n < 2 || n % 2 == 0 { return false; }

    fn witnesses(n: usize) -> &'static[usize] {
        match n {
            1 ... 1373652                   => { static A: &'static[usize] = &[2, 3]; A },
            1373653 ... 4759123140          => { static A: &'static[usize] = &[2, 7, 61]; A },
            4759123141 ... 2152302898746    => { static A: &'static[usize] = &[2, 3, 5, 7, 11]; A },
            2152302898747 ... 3474749660382 => { static A: &'static[usize] = &[2, 3, 5, 7, 11, 13]; A },
            _                               => { static A: &'static[usize] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022]; A }
        }
    }

    let big_n = n.to_biguint().unwrap();
    let big_1 = 1.to_biguint().unwrap();

    let s = (n - 1).trailing_zeros();
    let d = (n - 1).shr(s);

    for a in witnesses(n) {
        if a >= &n { break; }

        let mut x = num::pow::<BigUint>(a.to_biguint().unwrap(), d) % &big_n;
        if x == big_1 { continue; }

        let mut t = s;
        while x != &big_n - &big_1 {
            t -= 1;
            if t <= 0 { return false; }
            x = (&x * &x) % &big_n;
            if x == big_1 { return false; }
        }
    }

    true
}

#[cfg(test)]
mod tests {
    #[test]
    fn gcd() {
        assert_eq!(4, super::gcd(8, 12));
        assert_eq!(6, super::gcd(54, 24));
        assert_eq!(14, super::gcd(42, 56));
        assert_eq!(1, super::gcd(9, 28));
    }

    fn assert_is_prime(n: usize) {
        assert!(super::is_prime(n));
    }

    #[test]
    fn first_primes_below_1000() {
        assert_eq!(
            vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
                 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
                 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
                 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
                 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
                 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
                 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
                 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
                 991, 997],
            (1usize..1000).filter(|&x| super::is_prime(x)).collect::<Vec<_>>());
    }

    #[test]
    fn medium_prime() {
        assert_is_prime(9973);
    }

    #[test]
    fn large_prime() {
        assert_is_prime(600851475143);
    }
}<|endoftext|>


<commit_before>
use std::ops::{Index, IndexMut};
use std::str::FromStr;

use error::{NcclError, ErrorKind};

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: String,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new(key: &str) -> Self {
        Pair {
            key: key.to_owned(),
            value: vec![]
        }
    }

    pub fn add(&mut self, value: &str) {
        self.value.push(Pair::new(value));
    }

    pub fn has_key(&self, key: &str) -> bool {
        for item in self.value.iter() {
            if &item.key == key {
                return true;
            }
        }

        return false;
    }

    pub fn get(&mut self, value: &str) -> Result<&mut Pair, NcclError> {
        let value_owned = value.to_owned();

        if self.value.is_empty() {
            return Err(NcclError::new(ErrorKind::KeyNotFound, &format!("Pair does not have key: {}", value), 0));
        } else {
            for item in self.value.iter_mut() {
                if item.key == value_owned {
                    return Ok(item);
                }
            }
        }

        Err(NcclError::new(ErrorKind::KeyNotFound, &format!("Could not find key: {}", value), 0))
    }

    pub fn get_ref(&self, value: &str) -> Result<&Pair, NcclError> {
        let value_owned = value.to_owned();

        if self.value.is_empty() {
            return Ok(self);
        } else {
            for item in self.value.iter() {
                if item.key == value_owned {
                    return Ok(item);
                }
            }
        }

        Err(NcclError::new(ErrorKind::KeyNotFound, "Cound not find key", 0))
    }

    pub fn value(&self) -> Result<String, NcclError>  {
        if self.value.len() == 1 {
            Ok(self.value[0].key.clone())
        } else if self.value.len() > 1 {
            Err(NcclError::new(ErrorKind::NoValue, "Key has multiple values", 0))
        } else {
            Err(NcclError::new(ErrorKind::NoValue, "Key does not have value", 0))
        }
    }

    pub fn value_as<T>(&self) -> Result<T, NcclError> where T: FromStr {
        match self.value() {
            Ok(value) => match value.parse::<T>() {
                Ok(ok) => Ok(ok),
                Err(err) => Err(NcclError::new(ErrorKind::ParseError, "Could not parse value", 0))
            },
            Err(err) => Err(err)
        }
    }

    pub fn keys(&self) -> Vec<String> {
        self.value.clone().into_iter().map(|x| x.key).collect()
    }

    pub fn keys_as<T: FromStr>(&self) -> Result<Vec<T>, NcclError> {
        // XXX this is gross
        match self.keys().iter().map(|s| s.parse::<T>()).collect::<Result<Vec<T>, _>>() {
            Ok(ok) => Ok(ok),
            Err(_) => Err(NcclError::new(ErrorKind::FromStrError, "Could not parse keys", 0))
        }
    }
}

impl<'a> Index<&'a str> for Pair {
    type Output = Pair;
    fn index(&self, i: &str) -> &Pair {
        self.get_ref(i).unwrap()
    }
}

impl<'a> IndexMut<&'a str> for Pair {
    fn index_mut(&mut self, i: &str) -> &mut Pair {
        self.get(i).unwrap()
    }
}

<commit_msg>remove warning<commit_after>
use std::ops::{Index, IndexMut};
use std::str::FromStr;

use error::{NcclError, ErrorKind};

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: String,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new(key: &str) -> Self {
        Pair {
            key: key.to_owned(),
            value: vec![]
        }
    }

    pub fn add(&mut self, value: &str) {
        self.value.push(Pair::new(value));
    }

    pub fn has_key(&self, key: &str) -> bool {
        for item in self.value.iter() {
            if &item.key == key {
                return true;
            }
        }

        return false;
    }

    pub fn get(&mut self, value: &str) -> Result<&mut Pair, NcclError> {
        let value_owned = value.to_owned();

        if self.value.is_empty() {
            return Err(NcclError::new(ErrorKind::KeyNotFound, &format!("Pair does not have key: {}", value), 0));
        } else {
            for item in self.value.iter_mut() {
                if item.key == value_owned {
                    return Ok(item);
                }
            }
        }

        Err(NcclError::new(ErrorKind::KeyNotFound, &format!("Could not find key: {}", value), 0))
    }

    pub fn get_ref(&self, value: &str) -> Result<&Pair, NcclError> {
        let value_owned = value.to_owned();

        if self.value.is_empty() {
            return Ok(self);
        } else {
            for item in self.value.iter() {
                if item.key == value_owned {
                    return Ok(item);
                }
            }
        }

        Err(NcclError::new(ErrorKind::KeyNotFound, "Cound not find key", 0))
    }

    pub fn value(&self) -> Result<String, NcclError>  {
        if self.value.len() == 1 {
            Ok(self.value[0].key.clone())
        } else if self.value.len() > 1 {
            Err(NcclError::new(ErrorKind::NoValue, "Key has multiple values", 0))
        } else {
            Err(NcclError::new(ErrorKind::NoValue, "Key does not have value", 0))
        }
    }

    pub fn value_as<T>(&self) -> Result<T, NcclError> where T: FromStr {
        match self.value() {
            Ok(value) => match value.parse::<T>() {
                Ok(ok) => Ok(ok),
                Err(_) => Err(NcclError::new(ErrorKind::ParseError, "Could not parse value", 0))
            },
            Err(err) => Err(err)
        }
    }

    pub fn keys(&self) -> Vec<String> {
        self.value.clone().into_iter().map(|x| x.key).collect()
    }

    pub fn keys_as<T: FromStr>(&self) -> Result<Vec<T>, NcclError> {
        // XXX this is gross
        match self.keys().iter().map(|s| s.parse::<T>()).collect::<Result<Vec<T>, _>>() {
            Ok(ok) => Ok(ok),
            Err(_) => Err(NcclError::new(ErrorKind::FromStrError, "Could not parse keys", 0))
        }
    }
}

impl<'a> Index<&'a str> for Pair {
    type Output = Pair;
    fn index(&self, i: &str) -> &Pair {
        self.get_ref(i).unwrap()
    }
}

impl<'a> IndexMut<&'a str> for Pair {
    fn index_mut(&mut self, i: &str) -> &mut Pair {
        self.get(i).unwrap()
    }
}

<|endoftext|>


<commit_before>use parse::MaybeOkResponse;
use super::{HttpResponse, FromResponse, ApiResult};

use std::io::Read;

/// Response for a cluster ping request.
#[derive(Deserialize, Debug)]
pub struct PingResponse {
    pub name: String,
    pub cluster_name: String,
    pub tagline: String,
    pub version: ClusterVersion,
}

#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub struct ClusterVersion {
    pub number: String,
    pub build_hash: String,
    pub build_date: String,
    pub build_snapshot: bool,
    pub lucene_version: String
}

impl FromResponse for PingResponse {
    fn from_response<I: Into<HttpResponse<R>>, R: Read>(res: I) -> ApiResult<Self> {
        let res = res.into();

        res.response(|res| {
            match res.status() {
                200...299 => Ok(MaybeOkResponse::new(true, res)),
                _ => Ok(MaybeOkResponse::err(res)),
            }
        })
    }
}
<commit_msg>use ok for ping res parser<commit_after>use parse::MaybeOkResponse;
use super::{HttpResponse, FromResponse, ApiResult};

use std::io::Read;

/// Response for a cluster ping request.
#[derive(Deserialize, Debug)]
pub struct PingResponse {
    pub name: String,
    pub cluster_name: String,
    pub tagline: String,
    pub version: ClusterVersion,
}

#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub struct ClusterVersion {
    pub number: String,
    pub build_hash: String,
    pub build_date: String,
    pub build_snapshot: bool,
    pub lucene_version: String
}

impl FromResponse for PingResponse {
    fn from_response<I: Into<HttpResponse<R>>, R: Read>(res: I) -> ApiResult<Self> {
        let res = res.into();

        res.response(|res| {
            match res.status() {
                200...299 => Ok(MaybeOkResponse::ok(res)),
                _ => Ok(MaybeOkResponse::err(res)),
            }
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

use std::rc::Rc;
use std::io;

use mio;

use endpoint::*;
use EventLoop;
use Message;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum OperationStatus {
    Completed,  // done
    InProgress, // ongoing
    Postponed,  // tried, but would have blocked
    Failed,     // tried and failed
    Discarded   // was asked to give up
}

fn can_resume_operation(status: Option<OperationStatus>) -> bool {
    status.map_or_else(|| true, |os| os == OperationStatus::Postponed)
}

fn is_operation_finished(status: Option<OperationStatus>) -> bool {
    match status {
        Some(OperationStatus::Completed) => true,
        Some(OperationStatus::Failed)    => true,
        Some(OperationStatus::Discarded) => true,
        None => false,
        _    => false
    }
}

// A pipe is responsible for keeping track of the send & recv operation progress of an endpoint.
// It is used to link a protocol to an endpoint.
pub struct Pipe {
    token: mio::Token,
    endpoint: Endpoint,
    send_status: Option<OperationStatus>,
    recv_status: Option<OperationStatus>
}

impl Pipe {
    pub fn new(token: mio::Token, endpoint: Endpoint) -> Pipe {
        Pipe {
            token: token,
            endpoint: endpoint,
            send_status: None,
            recv_status: None
        }
    }

    pub fn token(&self) -> mio::Token {
        self.token
    }

    pub fn send(&mut self, msg: Rc<Message>) -> io::Result<SendStatus> {
        let result = match self.endpoint.send(msg) {
            Ok(SendStatus::Completed) => {
                self.send_status = Some(OperationStatus::Completed);
                Ok(SendStatus::Completed)
            },
            Ok(SendStatus::InProgress) => {
                self.send_status = Some(OperationStatus::InProgress);
                Ok(SendStatus::InProgress)
            },
            Ok(SendStatus::Postponed(msg)) => {
                self.send_status = Some(OperationStatus::Postponed);
                Ok(SendStatus::Postponed(msg))
            }
            Err(e) => {
                self.send_status = Some(OperationStatus::Failed);
                Err(e)
            }
        };

        result
    }

    pub fn can_resume_send(&self) -> bool {
        can_resume_operation(self.send_status)
    }

    pub fn is_send_finished(&self) -> bool {
        is_operation_finished(self.send_status)
    }

    pub fn finish_send(&mut self) {
        self.send_status = None;
    }

    pub fn cancel_send(&mut self) {
        self.send_status = None;
        self.endpoint.cancel_sending();
    }

    pub fn discard_send(&mut self) {
        self.send_status = Some(OperationStatus::Discarded);
    }

    pub fn recv(&mut self) -> io::Result<RecvStatus> {
        let result = match self.endpoint.recv() {
            Ok(RecvStatus::Completed(msg)) => {
                self.send_status = Some(OperationStatus::Completed);
                Ok(RecvStatus::Completed(msg))
            },
            Ok(RecvStatus::InProgress) => {
                self.send_status = Some(OperationStatus::InProgress);
                Ok(RecvStatus::InProgress)
            },
            Ok(RecvStatus::Postponed) => {
                self.send_status = Some(OperationStatus::Postponed);
                Ok(RecvStatus::Postponed)
            }
            Err(e) => {
                self.send_status = Some(OperationStatus::Failed);
                Err(e)
            }
        };

        result
    }

    pub fn can_resume_recv(&self) -> bool {
        can_resume_operation(self.recv_status)
    }

    pub fn finish_recv(&mut self) {
        self.recv_status = None;
    }

    pub fn cancel_recv(&mut self) {
        self.recv_status = None;
        self.endpoint.cancel_receiving();
    }

    pub fn discard_recv(&mut self) {
        self.recv_status = Some(OperationStatus::Discarded);
    }

    pub fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet) -> io::Result<(bool, Option<Message>)> {
        self.endpoint.ready(event_loop, events)
    }

    pub fn ready_tx(&mut self, event_loop: &mut EventLoop, events: mio::EventSet) -> io::Result<bool> {
        let (sent, _) = try!(self.endpoint.ready(event_loop, events));

        Ok(sent)
    }

    pub fn ready_rx(&mut self, event_loop: &mut EventLoop, events: mio::EventSet) -> io::Result<Option<Message>> {
        let (_, received) = try!(self.endpoint.ready(event_loop, events));

        Ok(received)
    }

    pub fn remove(self) -> Endpoint {
        self.endpoint
    }
}<commit_msg>Fixes bug in pipe operation state<commit_after>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

use std::rc::Rc;
use std::io;

use mio;

use endpoint::*;
use EventLoop;
use Message;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum OperationStatus {
    Completed,  // done
    InProgress, // ongoing
    Postponed,  // tried, but would have blocked
    Failed,     // tried and failed
    Discarded   // was asked to give up
}

fn can_resume_operation(status: Option<OperationStatus>) -> bool {
    status.map_or_else(|| true, |os| os == OperationStatus::Postponed)
}

fn is_operation_finished(status: Option<OperationStatus>) -> bool {
    match status {
        Some(OperationStatus::Completed) => true,
        Some(OperationStatus::Failed)    => true,
        Some(OperationStatus::Discarded) => true,
        None => false,
        _    => false
    }
}

// A pipe is responsible for keeping track of the send & recv operation progress of an endpoint.
// It is used to link a protocol to an endpoint.
pub struct Pipe {
    token: mio::Token,
    endpoint: Endpoint,
    send_status: Option<OperationStatus>,
    recv_status: Option<OperationStatus>
}

impl Pipe {
    pub fn new(token: mio::Token, endpoint: Endpoint) -> Pipe {
        Pipe {
            token: token,
            endpoint: endpoint,
            send_status: None,
            recv_status: None
        }
    }

    pub fn token(&self) -> mio::Token {
        self.token
    }

    pub fn send(&mut self, msg: Rc<Message>) -> io::Result<SendStatus> {
        let result = match self.endpoint.send(msg) {
            Ok(SendStatus::Completed) => {
                self.send_status = Some(OperationStatus::Completed);
                Ok(SendStatus::Completed)
            },
            Ok(SendStatus::InProgress) => {
                self.send_status = Some(OperationStatus::InProgress);
                Ok(SendStatus::InProgress)
            },
            Ok(SendStatus::Postponed(msg)) => {
                self.send_status = Some(OperationStatus::Postponed);
                Ok(SendStatus::Postponed(msg))
            }
            Err(e) => {
                self.send_status = Some(OperationStatus::Failed);
                Err(e)
            }
        };

        result
    }

    pub fn can_resume_send(&self) -> bool {
        can_resume_operation(self.send_status)
    }

    pub fn is_send_finished(&self) -> bool {
        is_operation_finished(self.send_status)
    }

    pub fn finish_send(&mut self) {
        self.send_status = None;
    }

    pub fn cancel_send(&mut self) {
        self.send_status = None;
        self.endpoint.cancel_sending();
    }

    pub fn discard_send(&mut self) {
        self.send_status = Some(OperationStatus::Discarded);
    }

    pub fn recv(&mut self) -> io::Result<RecvStatus> {
        let result = match self.endpoint.recv() {
            Ok(RecvStatus::Completed(msg)) => {
                self.send_status = Some(OperationStatus::Completed);
                Ok(RecvStatus::Completed(msg))
            },
            Ok(RecvStatus::InProgress) => {
                self.send_status = Some(OperationStatus::InProgress);
                Ok(RecvStatus::InProgress)
            },
            Ok(RecvStatus::Postponed) => {
                self.send_status = Some(OperationStatus::Postponed);
                Ok(RecvStatus::Postponed)
            }
            Err(e) => {
                self.send_status = Some(OperationStatus::Failed);
                Err(e)
            }
        };

        result
    }

    pub fn can_resume_recv(&self) -> bool {
        can_resume_operation(self.recv_status)
    }

    pub fn finish_recv(&mut self) {
        self.recv_status = None;
    }

    pub fn cancel_recv(&mut self) {
        self.recv_status = None;
        self.endpoint.cancel_receiving();
    }

    pub fn discard_recv(&mut self) {
        self.recv_status = Some(OperationStatus::Discarded);
    }

    pub fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet) -> io::Result<(bool, Option<Message>)> {
        let (sent, received) = try!(self.endpoint.ready(event_loop, events));

        if sent {
            self.send_status = Some(OperationStatus::Completed);
        }

        if received.is_some() {
            self.recv_status = Some(OperationStatus::Completed);
        }

        Ok((sent, received))
    }

    pub fn ready_tx(&mut self, event_loop: &mut EventLoop, events: mio::EventSet) -> io::Result<bool> {
        let (sent, _) = try!(self.ready(event_loop, events));

        Ok(sent)
    }

    pub fn ready_rx(&mut self, event_loop: &mut EventLoop, events: mio::EventSet) -> io::Result<Option<Message>> {
        let (_, received) = try!(self.ready(event_loop, events));

        Ok(received)
    }

    pub fn remove(self) -> Endpoint {
        self.endpoint
    }
}<|endoftext|>


<commit_before>extern crate rustbox;
use std::comm::{Receiver, Sender};
use std::io::{File, BufferedReader};

pub struct Editor {
    pub sender: Sender<rustbox::Event>,
    pub events: Receiver<rustbox::Event>,
    pub buffers: Vec<Buf>
}

pub struct Buf {
    pub first_line: Line,
    pub last_line: Line,
}

pub struct Line {
    pub data: Vec<u8>,
    pub prev: Option<Box<Line>>,
    pub next: Option<Box<Line>>,
}

pub enum Response {
    Continue,
    Quit,
}

impl Buf {
    pub fn new() -> Buf {
        Buf {
            first_line: Line::new(),
            last_line: Line::new(),
        }
    }
}

impl Line {
    pub fn new() -> Line {
        Line {
            data: Vec::new(),
            prev: None,
            next: None,
        }
    }
}

impl Editor {
    pub fn new() -> Editor {
        let (send, recv) = channel();
        Editor {
            sender: send,
            events: recv,
            buffers: Vec::new(),
        }
    }

    pub fn handle_key_event(&self, ch: u32) -> Response {
        match std::char::from_u32(ch) {
            Some('q') => Quit,
            _ => Continue,
        }
    }

    pub fn start(&self) -> bool {
        loop {
            let status = match self.events.recv() {
                rustbox::KeyEvent(_, _, ch) => {
                    let status = self.handle_key_event(ch);
                    match status {
                        Quit => { false },
                        _ => { true },
                    }
                },
                _ => { true }
            };
            if status == false {
                return false;
            }
        }
    }

}

<commit_msg>Remove warnings<commit_after>extern crate rustbox;
use std::comm::{Receiver, Sender};
//use std::io::{File, BufferedReader};

pub struct Editor {
    pub sender: Sender<rustbox::Event>,
    pub events: Receiver<rustbox::Event>,
    pub buffers: Vec<Buf>
}

pub struct Buf {
    pub first_line: Line,
    pub last_line: Line,
}

pub struct Line {
    pub data: Vec<u8>,
    pub prev: Option<Box<Line>>,
    pub next: Option<Box<Line>>,
}

pub enum Response {
    Continue,
    Quit,
}

impl Buf {
    pub fn new() -> Buf {
        Buf {
            first_line: Line::new(),
            last_line: Line::new(),
        }
    }
}

impl Line {
    pub fn new() -> Line {
        Line {
            data: Vec::new(),
            prev: None,
            next: None,
        }
    }
}

impl Editor {
    pub fn new() -> Editor {
        let (send, recv) = channel();
        Editor {
            sender: send,
            events: recv,
            buffers: Vec::new(),
        }
    }

    pub fn handle_key_event(&self, ch: u32) -> Response {
        match std::char::from_u32(ch) {
            Some('q') => Quit,
            _ => Continue,
        }
    }

    pub fn start(&self) -> bool {
        loop {
            let status = match self.events.recv() {
                rustbox::KeyEvent(_, _, ch) => {
                    let status = self.handle_key_event(ch);
                    match status {
                        Quit => { false },
                        _ => { true },
                    }
                },
                _ => { true }
            };
            if status == false {
                return false;
            }
        }
    }

}

<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
// (c) Mitchell Mebane <mitchell.mebane@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) clrtoeol dircolors eightbit endcode fnmatch leftcode multihardlink rightcode setenv sgid suid

#[macro_use]
extern crate uucore;

use std::borrow::Borrow;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};

use clap::{crate_version, App, Arg};

mod options {
    pub const BOURNE_SHELL: &str = "bourne-shell";
    pub const C_SHELL: &str = "c-shell";
    pub const PRINT_DATABASE: &str = "print-database";
    pub const FILE: &str = "FILE";
}

static SYNTAX: &str = "[OPTION]... [FILE]";
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
static LONG_HELP: &str = "
 If FILE is specified, read it to determine which colors to use for which
 file types and extensions.  Otherwise, a precompiled database is used.
 For details on the format of these files, run 'dircolors --print-database'
";

mod colors;
use self::colors::INTERNAL_DB;

#[derive(PartialEq, Debug)]
pub enum OutputFmt {
    Shell,
    CShell,
    Unknown,
}

pub fn guess_syntax() -> OutputFmt {
    use std::path::Path;
    match env::var("SHELL") {
        Ok(ref s) if !s.is_empty() => {
            let shell_path: &Path = s.as_ref();
            if let Some(name) = shell_path.file_name() {
                if name == "csh" || name == "tcsh" {
                    OutputFmt::CShell
                } else {
                    OutputFmt::Shell
                }
            } else {
                OutputFmt::Shell
            }
        }
        _ => OutputFmt::Unknown,
    }
}

fn get_usage() -> String {
    format!("{0} {1}", executable!(), SYNTAX)
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = get_usage();

    let matches = App::new(executable!())
        .version(crate_version!())
        .about(SUMMARY)
        .usage(&usage[..])
        .after_help(LONG_HELP)
        .arg(
            Arg::with_name(options::BOURNE_SHELL)
                .long("sh")
                .short("b")
                .visible_alias("bourne-shell")
                .help("output Bourne shell code to set LS_COLORS")
                .display_order(1),
        )
        .arg(
            Arg::with_name(options::C_SHELL)
                .long("csh")
                .short("c")
                .visible_alias("c-shell")
                .help("output C shell code to set LS_COLORS")
                .display_order(2),
        )
        .arg(
            Arg::with_name(options::PRINT_DATABASE)
                .long("print-database")
                .short("p")
                .help("print the byte counts")
                .display_order(3),
        )
        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
        .get_matches_from(&args);

    let files = matches
        .values_of(options::FILE)
        .map_or(vec![], |file_values| file_values.collect());

    // clap provides .conflicts_with / .conflicts_with_all, but we want to
    // manually handle conflicts so we can match the output of GNU coreutils
    if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL))
        && matches.is_present(options::PRINT_DATABASE)
    {
        show_usage_error!(
            "the options to output dircolors' internal database and\nto select a shell \
             syntax are mutually exclusive"
        );
        return 1;
    }

    if matches.is_present(options::PRINT_DATABASE) {
        if !files.is_empty() {
            show_usage_error!(
                "extra operand ‘{}’\nfile operands cannot be combined with \
                 --print-database (-p)",
                files[0]
            );
            return 1;
        }
        println!("{}", INTERNAL_DB);
        return 0;
    }

    let mut out_format = OutputFmt::Unknown;
    if matches.is_present(options::C_SHELL) {
        out_format = OutputFmt::CShell;
    } else if matches.is_present(options::BOURNE_SHELL) {
        out_format = OutputFmt::Shell;
    }

    if out_format == OutputFmt::Unknown {
        match guess_syntax() {
            OutputFmt::Unknown => {
                show_error!("no SHELL environment variable, and no shell type option given");
                return 1;
            }
            fmt => out_format = fmt,
        }
    }

    let result;
    if files.is_empty() {
        result = parse(INTERNAL_DB.lines(), out_format, "")
    } else {
        if files.len() > 1 {
            show_usage_error!("extra operand ‘{}’", files[1]);
            return 1;
        }
        match File::open(files[0]) {
            Ok(f) => {
                let fin = BufReader::new(f);
                result = parse(fin.lines().filter_map(Result::ok), out_format, files[0])
            }
            Err(e) => {
                show_error!("{}: {}", files[0], e);
                return 1;
            }
        }
    }
    match result {
        Ok(s) => {
            println!("{}", s);
            0
        }
        Err(s) => {
            show_error!("{}", s);
            1
        }
    }
}

pub trait StrUtils {
    /// Remove comments and trim whitespace
    fn purify(&self) -> &Self;
    /// Like split_whitespace() but only produce 2 components
    fn split_two(&self) -> (&str, &str);
    fn fnmatch(&self, pattern: &str) -> bool;
}

impl StrUtils for str {
    fn purify(&self) -> &Self {
        let mut line = self;
        for (n, c) in self.chars().enumerate() {
            if c != '#' {
                continue;
            }

            // Ignore if '#' is at the beginning of line
            if n == 0 {
                line = &self[..0];
                break;
            }

            // Ignore the content after '#'
            // only if it is preceded by at least one whitespace
            if self.chars().nth(n - 1).unwrap().is_whitespace() {
                line = &self[..n];
            }
        }
        line.trim()
    }

    fn split_two(&self) -> (&str, &str) {
        if let Some(b) = self.find(char::is_whitespace) {
            let key = &self[..b];
            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
                (key, &self[b + e..])
            } else {
                (key, "")
            }
        } else {
            ("", "")
        }
    }

    fn fnmatch(&self, pat: &str) -> bool {
        pat.parse::<glob::Pattern>().unwrap().matches(self)
    }
}

#[derive(PartialEq)]
enum ParseState {
    Global,
    Matched,
    Continue,
    Pass,
}
use std::collections::HashMap;
use uucore::InvalidEncodingHandling;

fn parse<T>(lines: T, fmt: OutputFmt, fp: &str) -> Result<String, String>
where
    T: IntoIterator,
    T::Item: Borrow<str>,
{
    // 1440 > $(dircolors | wc -m)
    let mut result = String::with_capacity(1440);
    match fmt {
        OutputFmt::Shell => result.push_str("LS_COLORS='"),
        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
        _ => unreachable!(),
    }

    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
    table.insert("normal", "no");
    table.insert("norm", "no");
    table.insert("file", "fi");
    table.insert("reset", "rs");
    table.insert("dir", "di");
    table.insert("lnk", "ln");
    table.insert("link", "ln");
    table.insert("symlink", "ln");
    table.insert("orphan", "or");
    table.insert("missing", "mi");
    table.insert("fifo", "pi");
    table.insert("pipe", "pi");
    table.insert("sock", "so");
    table.insert("blk", "bd");
    table.insert("block", "bd");
    table.insert("chr", "cd");
    table.insert("char", "cd");
    table.insert("door", "do");
    table.insert("exec", "ex");
    table.insert("left", "lc");
    table.insert("leftcode", "lc");
    table.insert("right", "rc");
    table.insert("rightcode", "rc");
    table.insert("end", "ec");
    table.insert("endcode", "ec");
    table.insert("suid", "su");
    table.insert("setuid", "su");
    table.insert("sgid", "sg");
    table.insert("setgid", "sg");
    table.insert("sticky", "st");
    table.insert("other_writable", "ow");
    table.insert("owr", "ow");
    table.insert("sticky_other_writable", "tw");
    table.insert("owt", "tw");
    table.insert("capability", "ca");
    table.insert("multihardlink", "mh");
    table.insert("clrtoeol", "cl");

    let term = env::var("TERM").unwrap_or_else(|_| "none".to_owned());
    let term = term.as_str();

    let mut state = ParseState::Global;

    for (num, line) in lines.into_iter().enumerate() {
        let num = num + 1;
        let line = line.borrow().purify();
        if line.is_empty() {
            continue;
        }

        let (key, val) = line.split_two();
        if val.is_empty() {
            return Err(format!(
                "{}:{}: invalid line;  missing second token",
                fp, num
            ));
        }
        let lower = key.to_lowercase();

        if lower == "term" {
            if term.fnmatch(val) {
                state = ParseState::Matched;
            } else if state != ParseState::Matched {
                state = ParseState::Pass;
            }
        } else {
            if state == ParseState::Matched {
                // prevent subsequent mismatched TERM from
                // cancelling the input
                state = ParseState::Continue;
            }
            if state != ParseState::Pass {
                if key.starts_with('.') {
                    result.push_str(format!("*{}={}:", key, val).as_str());
                } else if key.starts_with('*') {
                    result.push_str(format!("{}={}:", key, val).as_str());
                } else if lower == "options" || lower == "color" || lower == "eightbit" {
                    // Slackware only. Ignore
                } else if let Some(s) = table.get(lower.as_str()) {
                    result.push_str(format!("{}={}:", s, val).as_str());
                } else {
                    return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key));
                }
            }
        }
    }

    match fmt {
        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
        OutputFmt::CShell => result.push('\''),
        _ => unreachable!(),
    }

    Ok(result)
}
<commit_msg>Prevent double scanning from dircolors<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
// (c) Mitchell Mebane <mitchell.mebane@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) clrtoeol dircolors eightbit endcode fnmatch leftcode multihardlink rightcode setenv sgid suid

#[macro_use]
extern crate uucore;

use std::borrow::Borrow;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};

use clap::{crate_version, App, Arg};

mod options {
    pub const BOURNE_SHELL: &str = "bourne-shell";
    pub const C_SHELL: &str = "c-shell";
    pub const PRINT_DATABASE: &str = "print-database";
    pub const FILE: &str = "FILE";
}

static SYNTAX: &str = "[OPTION]... [FILE]";
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
static LONG_HELP: &str = "
 If FILE is specified, read it to determine which colors to use for which
 file types and extensions.  Otherwise, a precompiled database is used.
 For details on the format of these files, run 'dircolors --print-database'
";

mod colors;
use self::colors::INTERNAL_DB;

#[derive(PartialEq, Debug)]
pub enum OutputFmt {
    Shell,
    CShell,
    Unknown,
}

pub fn guess_syntax() -> OutputFmt {
    use std::path::Path;
    match env::var("SHELL") {
        Ok(ref s) if !s.is_empty() => {
            let shell_path: &Path = s.as_ref();
            if let Some(name) = shell_path.file_name() {
                if name == "csh" || name == "tcsh" {
                    OutputFmt::CShell
                } else {
                    OutputFmt::Shell
                }
            } else {
                OutputFmt::Shell
            }
        }
        _ => OutputFmt::Unknown,
    }
}

fn get_usage() -> String {
    format!("{0} {1}", executable!(), SYNTAX)
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = get_usage();

    let matches = App::new(executable!())
        .version(crate_version!())
        .about(SUMMARY)
        .usage(&usage[..])
        .after_help(LONG_HELP)
        .arg(
            Arg::with_name(options::BOURNE_SHELL)
                .long("sh")
                .short("b")
                .visible_alias("bourne-shell")
                .help("output Bourne shell code to set LS_COLORS")
                .display_order(1),
        )
        .arg(
            Arg::with_name(options::C_SHELL)
                .long("csh")
                .short("c")
                .visible_alias("c-shell")
                .help("output C shell code to set LS_COLORS")
                .display_order(2),
        )
        .arg(
            Arg::with_name(options::PRINT_DATABASE)
                .long("print-database")
                .short("p")
                .help("print the byte counts")
                .display_order(3),
        )
        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
        .get_matches_from(&args);

    let files = matches
        .values_of(options::FILE)
        .map_or(vec![], |file_values| file_values.collect());

    // clap provides .conflicts_with / .conflicts_with_all, but we want to
    // manually handle conflicts so we can match the output of GNU coreutils
    if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL))
        && matches.is_present(options::PRINT_DATABASE)
    {
        show_usage_error!(
            "the options to output dircolors' internal database and\nto select a shell \
             syntax are mutually exclusive"
        );
        return 1;
    }

    if matches.is_present(options::PRINT_DATABASE) {
        if !files.is_empty() {
            show_usage_error!(
                "extra operand ‘{}’\nfile operands cannot be combined with \
                 --print-database (-p)",
                files[0]
            );
            return 1;
        }
        println!("{}", INTERNAL_DB);
        return 0;
    }

    let mut out_format = OutputFmt::Unknown;
    if matches.is_present(options::C_SHELL) {
        out_format = OutputFmt::CShell;
    } else if matches.is_present(options::BOURNE_SHELL) {
        out_format = OutputFmt::Shell;
    }

    if out_format == OutputFmt::Unknown {
        match guess_syntax() {
            OutputFmt::Unknown => {
                show_error!("no SHELL environment variable, and no shell type option given");
                return 1;
            }
            fmt => out_format = fmt,
        }
    }

    let result;
    if files.is_empty() {
        result = parse(INTERNAL_DB.lines(), out_format, "")
    } else {
        if files.len() > 1 {
            show_usage_error!("extra operand ‘{}’", files[1]);
            return 1;
        }
        match File::open(files[0]) {
            Ok(f) => {
                let fin = BufReader::new(f);
                result = parse(fin.lines().filter_map(Result::ok), out_format, files[0])
            }
            Err(e) => {
                show_error!("{}: {}", files[0], e);
                return 1;
            }
        }
    }
    match result {
        Ok(s) => {
            println!("{}", s);
            0
        }
        Err(s) => {
            show_error!("{}", s);
            1
        }
    }
}

pub trait StrUtils {
    /// Remove comments and trim whitespace
    fn purify(&self) -> &Self;
    /// Like split_whitespace() but only produce 2 components
    fn split_two(&self) -> (&str, &str);
    fn fnmatch(&self, pattern: &str) -> bool;
}

impl StrUtils for str {
    fn purify(&self) -> &Self {
        let line = if self.as_bytes().first() == Some(&b'#') {
            // Ignore if '#' is at the beginning of line
            &self[..0]
        } else {
            let mut line = self;
            for (n, _) in self
                .as_bytes()
                .iter()
                .enumerate()
                .rev()
                .filter(|(_, c)| **c == b'#')
            {
                // Ignore the content after '#'
                // only if it is preceded by at least one whitespace
                if self[..n].chars().last().unwrap().is_whitespace() {
                    line = &self[..n];
                    break;
                }
            }
            line
        };
        line.trim()
    }

    fn split_two(&self) -> (&str, &str) {
        if let Some(b) = self.find(char::is_whitespace) {
            let key = &self[..b];
            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
                (key, &self[b + e..])
            } else {
                (key, "")
            }
        } else {
            ("", "")
        }
    }

    fn fnmatch(&self, pat: &str) -> bool {
        pat.parse::<glob::Pattern>().unwrap().matches(self)
    }
}

#[derive(PartialEq)]
enum ParseState {
    Global,
    Matched,
    Continue,
    Pass,
}
use std::collections::HashMap;
use uucore::InvalidEncodingHandling;

fn parse<T>(lines: T, fmt: OutputFmt, fp: &str) -> Result<String, String>
where
    T: IntoIterator,
    T::Item: Borrow<str>,
{
    // 1440 > $(dircolors | wc -m)
    let mut result = String::with_capacity(1440);
    match fmt {
        OutputFmt::Shell => result.push_str("LS_COLORS='"),
        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
        _ => unreachable!(),
    }

    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
    table.insert("normal", "no");
    table.insert("norm", "no");
    table.insert("file", "fi");
    table.insert("reset", "rs");
    table.insert("dir", "di");
    table.insert("lnk", "ln");
    table.insert("link", "ln");
    table.insert("symlink", "ln");
    table.insert("orphan", "or");
    table.insert("missing", "mi");
    table.insert("fifo", "pi");
    table.insert("pipe", "pi");
    table.insert("sock", "so");
    table.insert("blk", "bd");
    table.insert("block", "bd");
    table.insert("chr", "cd");
    table.insert("char", "cd");
    table.insert("door", "do");
    table.insert("exec", "ex");
    table.insert("left", "lc");
    table.insert("leftcode", "lc");
    table.insert("right", "rc");
    table.insert("rightcode", "rc");
    table.insert("end", "ec");
    table.insert("endcode", "ec");
    table.insert("suid", "su");
    table.insert("setuid", "su");
    table.insert("sgid", "sg");
    table.insert("setgid", "sg");
    table.insert("sticky", "st");
    table.insert("other_writable", "ow");
    table.insert("owr", "ow");
    table.insert("sticky_other_writable", "tw");
    table.insert("owt", "tw");
    table.insert("capability", "ca");
    table.insert("multihardlink", "mh");
    table.insert("clrtoeol", "cl");

    let term = env::var("TERM").unwrap_or_else(|_| "none".to_owned());
    let term = term.as_str();

    let mut state = ParseState::Global;

    for (num, line) in lines.into_iter().enumerate() {
        let num = num + 1;
        let line = line.borrow().purify();
        if line.is_empty() {
            continue;
        }

        let (key, val) = line.split_two();
        if val.is_empty() {
            return Err(format!(
                "{}:{}: invalid line;  missing second token",
                fp, num
            ));
        }
        let lower = key.to_lowercase();

        if lower == "term" {
            if term.fnmatch(val) {
                state = ParseState::Matched;
            } else if state != ParseState::Matched {
                state = ParseState::Pass;
            }
        } else {
            if state == ParseState::Matched {
                // prevent subsequent mismatched TERM from
                // cancelling the input
                state = ParseState::Continue;
            }
            if state != ParseState::Pass {
                if key.starts_with('.') {
                    result.push_str(format!("*{}={}:", key, val).as_str());
                } else if key.starts_with('*') {
                    result.push_str(format!("{}={}:", key, val).as_str());
                } else if lower == "options" || lower == "color" || lower == "eightbit" {
                    // Slackware only. Ignore
                } else if let Some(s) = table.get(lower.as_str()) {
                    result.push_str(format!("{}={}:", s, val).as_str());
                } else {
                    return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key));
                }
            }
        }
    }

    match fmt {
        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
        OutputFmt::CShell => result.push('\''),
        _ => unreachable!(),
    }

    Ok(result)
}
<|endoftext|>