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

use crate::errors::{CompilationError, Error};
use crate::{eval_context::EvalCallbacks, EvalContext, EvalContextOutputs, EvalOutputs};

/// A higher level interface to EvalContext. A bit closer to a Repl. Provides commands (start with
/// ':') that alter context state or print information.
pub struct CommandContext {
    print_timings: bool,
    eval_context: EvalContext,
    last_errors: Vec<CompilationError>,
}

impl CommandContext {
    pub fn new() -> Result<(CommandContext, EvalContextOutputs), Error> {
        let (eval_context, eval_context_outputs) = EvalContext::new()?;
        let command_context = CommandContext::with_eval_context(eval_context);
        Ok((command_context, eval_context_outputs))
    }

    pub fn with_eval_context(eval_context: EvalContext) -> CommandContext {
        CommandContext {
            print_timings: false,
            eval_context,
            last_errors: Vec::new(),
        }
    }

    pub fn execute(&mut self, to_run: &str) -> Result<EvalOutputs, Error> {
        self.execute_with_callbacks(to_run, &mut EvalCallbacks::default())
    }

    pub fn execute_with_callbacks(
        &mut self,
        to_run: &str,
        callbacks: &mut EvalCallbacks,
    ) -> Result<EvalOutputs, Error> {
        use regex::Regex;
        use std::time::Instant;
        lazy_static! {
            static ref COMMAND_RE: Regex = Regex::new("^ *(:[^ ]+)( +(.*))?$").unwrap();
        }
        let mut eval_outputs = EvalOutputs::new();
        let start = Instant::now();
        let mut to_eval = Vec::new();
        for line in to_run.lines() {
            // We only accept commands up until the first non-command.
            if to_eval.is_empty() {
                if let Some(captures) = COMMAND_RE.captures(line) {
                    eval_outputs.merge(
                        self.process_command(&captures[1], captures.get(3).map(|m| m.as_str()))?,
                    );
                    continue;
                }
            }
            to_eval.push(line)
        }
        let result = if to_run.is_empty() {
            Ok(EvalOutputs::new())
        } else {
            self.eval_context
                .eval_with_callbacks(&to_eval.join("\n"), callbacks)
        };
        let duration = start.elapsed();
        match result {
            Ok(m) => {
                eval_outputs.merge(m);
                if self.print_timings {
                    eval_outputs.timing = Some(duration);
                }
                Ok(eval_outputs)
            }
            Err(Error::CompilationErrors(errors)) => {
                self.last_errors = errors.clone();
                Err(Error::CompilationErrors(errors))
            }
            x => x,
        }
    }

    pub fn set_opt_level(&mut self, level: &str) -> Result<(), Error> {
        self.eval_context.set_opt_level(level)
    }

    fn load_config(&mut self) -> Result<EvalOutputs, Error> {
        let mut outputs = EvalOutputs::new();
        if let Some(config_dir) = crate::config_dir() {
            let config_file = config_dir.join("init.evcxr");
            if config_file.exists() {
                println!("Loading startup commands from {:?}", config_file);
                let contents = std::fs::read_to_string(config_file)?;
                for line in contents.lines() {
                    outputs.merge(self.execute(line)?);
                }
            }
            // Note: Loaded *after* init.evcxr so that it can access `:dep`s (or
            // any other state changed by :commands) specified in the init file.
            let prelude_file = config_dir.join("prelude.rs");
            if prelude_file.exists() {
                println!("Executing prelude from {:?}", prelude_file);
                let prelude = std::fs::read_to_string(prelude_file)?;
                outputs.merge(self.execute(&prelude)?);
            }
        }
        Ok(outputs)
    }

    fn process_command(&mut self, command: &str, args: Option<&str>) -> Result<EvalOutputs, Error> {
        match command {
            ":internal_debug" => {
                let debug_mode = !self.eval_context.debug_mode();
                self.eval_context.set_debug_mode(debug_mode);
                text_output(format!("Internals debugging: {}", debug_mode))
            }
            ":load_config" => self.load_config(),
            ":version" => text_output(env!("CARGO_PKG_VERSION")),
            ":vars" => {
                let mut outputs = EvalOutputs::new();
                outputs
                    .content_by_mime_type
                    .insert("text/plain".to_owned(), self.vars_as_text());
                outputs
                    .content_by_mime_type
                    .insert("text/html".to_owned(), self.vars_as_html());
                Ok(outputs)
            }
            ":preserve_vars_on_panic" => {
                self.eval_context.preserve_vars_on_panic = args == Some("1");
                text_output(format!(
                    "Preserve vars on panic: {}",
                    self.eval_context.preserve_vars_on_panic
                ))
            }
            ":clear" => self.eval_context.clear().map(|_| EvalOutputs::new()),
            ":dep" => {
                use regex::Regex;
                let args = if let Some(v) = args {
                    v
                } else {
                    bail!(":dep requires arguments")
                };
                lazy_static! {
                    static ref DEP_RE: Regex = Regex::new("^([^= ]+) *(= *(.+))?$").unwrap();
                }
                if let Some(captures) = DEP_RE.captures(args) {
                    self.eval_context.add_dep(
                        &captures[1],
                        &captures.get(3).map_or("\"*\"", |m| m.as_str()),
                    )?;
                    Ok(EvalOutputs::new())
                } else {
                    bail!("Invalid :dep command. Expected: name = ... or just name");
                }
            }
            ":last_compile_dir" => {
                text_output(format!("{:?}", self.eval_context.last_compile_dir()))
            }
            ":opt" => {
                let new_level = if let Some(n) = args {
                    &n
                } else if self.eval_context.opt_level() == "2" {
                    "0"
                } else {
                    "2"
                };
                self.eval_context.set_opt_level(new_level)?;
                text_output(format!("Optimization: {}", self.eval_context.opt_level()))
            }
            ":fmt" => {
                let new_format = if let Some(f) = args { f } else { "{:?}" };
                self.eval_context.set_output_format(new_format.to_owned());
                text_output(format!(
                    "Output format: {}",
                    self.eval_context.output_format()
                ))
            }
            ":efmt" => {
                if let Some(f) = args {
                    self.eval_context.set_error_format(f)?;
                }
                text_output(format!(
                    "Error format: {} (errors must implement {})",
                    self.eval_context.error_format(),
                    self.eval_context.error_format_trait()
                ))
            }
            ":timing" => {
                self.print_timings = !self.print_timings;
                text_output(format!("Timing: {}", self.print_timings))
            }
            ":time_passes" => {
                self.eval_context
                    .set_time_passes(!self.eval_context.time_passes());
                text_output(format!("Time passes: {}", self.eval_context.time_passes()))
            }
            ":sccache" => {
                self.eval_context.set_sccache(args != Some("0"))?;
                text_output(format!("sccache: {}", self.eval_context.sccache()))
            }
            ":linker" => {
                if let Some(linker) = args {
                    self.eval_context.set_linker(linker.to_owned());
                }
                text_output(format!("linker: {}", self.eval_context.linker()))
            }
            ":explain" => {
                if self.last_errors.is_empty() {
                    bail!("No last error to explain");
                } else {
                    let mut all_explanations = String::new();
                    for error in &self.last_errors {
                        if let Some(explanation) = error.explanation() {
                            all_explanations.push_str(explanation);
                        } else {
                            bail!("Sorry, last error has no explanation");
                        }
                    }
                    text_output(all_explanations)
                }
            }
            ":last_error_json" => {
                let mut errors_out = String::new();
                for error in &self.last_errors {
                    use std::fmt::Write;
                    write!(&mut errors_out, "{}", error.json)?;
                    errors_out.push('\n');
                }
                bail!(errors_out);
            }
            ":help" => text_output(
                ":vars             List bound variables and their types\n\
                 :opt [level]      Toggle/set optimization level\n\
                 :fmt [format]     Set output formatter (default: {:?}). \n\
                 :efmt [format]    Set the formatter for errors returned by ?\n\
                 :explain          Print explanation of last error\n\
                 :clear            Clear all state, keeping compilation cache\n\
                 :dep              Add dependency. e.g. :dep regex = \"1.0\"\n\
                 :sccache [0|1]    Set whether to use sccache.\n\
                 :linker [linker]  Set/print linker. Supported: system, lld\n\
                 :version          Print Evcxr version\n\
                 :preserve_vars_on_panic [0|1]  Try to keep vars on panic\n\n\
                 Mostly for development / debugging purposes:\n\
                 :last_compile_dir Print the directory in which we last compiled\n\
                 :timing           Toggle printing of how long evaluations take\n\
                 :last_error_json  Print the last compilation error as JSON (for debugging)\n\
                 :time_passes      Toggle printing of rustc pass times (requires nightly)\n\
                 :internal_debug   Toggle various internal debugging code",
            ),
            _ => bail!("Unrecognised command {}", command),
        }
    }

    fn vars_as_text(&self) -> String {
        let mut out = String::new();
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str(var);
            out.push_str(": ");
            out.push_str(ty);
            out.push_str("\n");
        }
        out
    }

    fn vars_as_html(&self) -> String {
        let mut out = String::new();
        out.push_str("

Variable	Type
");
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str("
");
            html_escape(var, &mut out);
            out.push_str("	");
            html_escape(ty, &mut out);
            out.push_str("
");
        }
        out.push_str("
");
        out
    }
}

fn html_escape(input: &str, out: &mut String) {
    for ch in input.chars() {
        match ch {
            '<' => out.push_str("<"),
            '>' => out.push_str(">"),
            x => out.push(x),
        }
    }
}

fn text_output<T: Into<String>>(text: T) -> Result<EvalOutputs, Error> {
    let mut outputs = EvalOutputs::new();
    let mut content = text.into();
    content.push('\n');
    outputs
        .content_by_mime_type
        .insert("text/plain".to_owned(), content);
    Ok(outputs)
}
<commit_msg>added quit command<commit_after>// Copyright 2020 The Evcxr Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::errors::{CompilationError, Error};
use crate::{eval_context::EvalCallbacks, EvalContext, EvalContextOutputs, EvalOutputs};

/// A higher level interface to EvalContext. A bit closer to a Repl. Provides commands (start with
/// ':') that alter context state or print information.
pub struct CommandContext {
    print_timings: bool,
    eval_context: EvalContext,
    last_errors: Vec<CompilationError>,
}

impl CommandContext {
    pub fn new() -> Result<(CommandContext, EvalContextOutputs), Error> {
        let (eval_context, eval_context_outputs) = EvalContext::new()?;
        let command_context = CommandContext::with_eval_context(eval_context);
        Ok((command_context, eval_context_outputs))
    }

    pub fn with_eval_context(eval_context: EvalContext) -> CommandContext {
        CommandContext {
            print_timings: false,
            eval_context,
            last_errors: Vec::new(),
        }
    }

    pub fn execute(&mut self, to_run: &str) -> Result<EvalOutputs, Error> {
        self.execute_with_callbacks(to_run, &mut EvalCallbacks::default())
    }

    pub fn execute_with_callbacks(
        &mut self,
        to_run: &str,
        callbacks: &mut EvalCallbacks,
    ) -> Result<EvalOutputs, Error> {
        use regex::Regex;
        use std::time::Instant;
        lazy_static! {
            static ref COMMAND_RE: Regex = Regex::new("^ *(:[^ ]+)( +(.*))?$").unwrap();
        }
        let mut eval_outputs = EvalOutputs::new();
        let start = Instant::now();
        let mut to_eval = Vec::new();
        for line in to_run.lines() {
            // We only accept commands up until the first non-command.
            if to_eval.is_empty() {
                if let Some(captures) = COMMAND_RE.captures(line) {
                    eval_outputs.merge(
                        self.process_command(&captures[1], captures.get(3).map(|m| m.as_str()))?,
                    );
                    continue;
                }
            }
            to_eval.push(line)
        }
        let result = if to_run.is_empty() {
            Ok(EvalOutputs::new())
        } else {
            self.eval_context
                .eval_with_callbacks(&to_eval.join("\n"), callbacks)
        };
        let duration = start.elapsed();
        match result {
            Ok(m) => {
                eval_outputs.merge(m);
                if self.print_timings {
                    eval_outputs.timing = Some(duration);
                }
                Ok(eval_outputs)
            }
            Err(Error::CompilationErrors(errors)) => {
                self.last_errors = errors.clone();
                Err(Error::CompilationErrors(errors))
            }
            x => x,
        }
    }

    pub fn set_opt_level(&mut self, level: &str) -> Result<(), Error> {
        self.eval_context.set_opt_level(level)
    }

    fn load_config(&mut self) -> Result<EvalOutputs, Error> {
        let mut outputs = EvalOutputs::new();
        if let Some(config_dir) = crate::config_dir() {
            let config_file = config_dir.join("init.evcxr");
            if config_file.exists() {
                println!("Loading startup commands from {:?}", config_file);
                let contents = std::fs::read_to_string(config_file)?;
                for line in contents.lines() {
                    outputs.merge(self.execute(line)?);
                }
            }
            // Note: Loaded *after* init.evcxr so that it can access `:dep`s (or
            // any other state changed by :commands) specified in the init file.
            let prelude_file = config_dir.join("prelude.rs");
            if prelude_file.exists() {
                println!("Executing prelude from {:?}", prelude_file);
                let prelude = std::fs::read_to_string(prelude_file)?;
                outputs.merge(self.execute(&prelude)?);
            }
        }
        Ok(outputs)
    }

    fn process_command(&mut self, command: &str, args: Option<&str>) -> Result<EvalOutputs, Error> {
        match command {
            ":internal_debug" => {
                let debug_mode = !self.eval_context.debug_mode();
                self.eval_context.set_debug_mode(debug_mode);
                text_output(format!("Internals debugging: {}", debug_mode))
            }
            ":load_config" => self.load_config(),
            ":version" => text_output(env!("CARGO_PKG_VERSION")),
            ":vars" => {
                let mut outputs = EvalOutputs::new();
                outputs
                    .content_by_mime_type
                    .insert("text/plain".to_owned(), self.vars_as_text());
                outputs
                    .content_by_mime_type
                    .insert("text/html".to_owned(), self.vars_as_html());
                Ok(outputs)
            }
            ":preserve_vars_on_panic" => {
                self.eval_context.preserve_vars_on_panic = args == Some("1");
                text_output(format!(
                    "Preserve vars on panic: {}",
                    self.eval_context.preserve_vars_on_panic
                ))
            }
            ":clear" => self.eval_context.clear().map(|_| EvalOutputs::new()),
            ":dep" => {
                use regex::Regex;
                let args = if let Some(v) = args {
                    v
                } else {
                    bail!(":dep requires arguments")
                };
                lazy_static! {
                    static ref DEP_RE: Regex = Regex::new("^([^= ]+) *(= *(.+))?$").unwrap();
                }
                if let Some(captures) = DEP_RE.captures(args) {
                    self.eval_context.add_dep(
                        &captures[1],
                        &captures.get(3).map_or("\"*\"", |m| m.as_str()),
                    )?;
                    Ok(EvalOutputs::new())
                } else {
                    bail!("Invalid :dep command. Expected: name = ... or just name");
                }
            }
            ":last_compile_dir" => {
                text_output(format!("{:?}", self.eval_context.last_compile_dir()))
            }
            ":opt" => {
                let new_level = if let Some(n) = args {
                    &n
                } else if self.eval_context.opt_level() == "2" {
                    "0"
                } else {
                    "2"
                };
                self.eval_context.set_opt_level(new_level)?;
                text_output(format!("Optimization: {}", self.eval_context.opt_level()))
            }
            ":fmt" => {
                let new_format = if let Some(f) = args { f } else { "{:?}" };
                self.eval_context.set_output_format(new_format.to_owned());
                text_output(format!(
                    "Output format: {}",
                    self.eval_context.output_format()
                ))
            }
            ":efmt" => {
                if let Some(f) = args {
                    self.eval_context.set_error_format(f)?;
                }
                text_output(format!(
                    "Error format: {} (errors must implement {})",
                    self.eval_context.error_format(),
                    self.eval_context.error_format_trait()
                ))
            }
            ":quit" => std::process::exit(0),
            ":timing" => {
                self.print_timings = !self.print_timings;
                text_output(format!("Timing: {}", self.print_timings))
            }
            ":time_passes" => {
                self.eval_context
                    .set_time_passes(!self.eval_context.time_passes());
                text_output(format!("Time passes: {}", self.eval_context.time_passes()))
            }
            ":sccache" => {
                self.eval_context.set_sccache(args != Some("0"))?;
                text_output(format!("sccache: {}", self.eval_context.sccache()))
            }
            ":linker" => {
                if let Some(linker) = args {
                    self.eval_context.set_linker(linker.to_owned());
                }
                text_output(format!("linker: {}", self.eval_context.linker()))
            }
            ":explain" => {
                if self.last_errors.is_empty() {
                    bail!("No last error to explain");
                } else {
                    let mut all_explanations = String::new();
                    for error in &self.last_errors {
                        if let Some(explanation) = error.explanation() {
                            all_explanations.push_str(explanation);
                        } else {
                            bail!("Sorry, last error has no explanation");
                        }
                    }
                    text_output(all_explanations)
                }
            }
            ":last_error_json" => {
                let mut errors_out = String::new();
                for error in &self.last_errors {
                    use std::fmt::Write;
                    write!(&mut errors_out, "{}", error.json)?;
                    errors_out.push('\n');
                }
                bail!(errors_out);
            }
            ":help" => text_output(
                ":vars             List bound variables and their types\n\
                 :opt [level]      Toggle/set optimization level\n\
                 :fmt [format]     Set output formatter (default: {:?}). \n\
                 :efmt [format]    Set the formatter for errors returned by ?\n\
                 :explain          Print explanation of last error\n\
                 :clear            Clear all state, keeping compilation cache\n\
                 :dep              Add dependency. e.g. :dep regex = \"1.0\"\n\
                 :sccache [0|1]    Set whether to use sccache.\n\
                 :linker [linker]  Set/print linker. Supported: system, lld\n\
                 :version          Print Evcxr version\n\
                 :quit             Quit evaluation and exit\n\
                 :preserve_vars_on_panic [0|1]  Try to keep vars on panic\n\n\
                 Mostly for development / debugging purposes:\n\
                 :last_compile_dir Print the directory in which we last compiled\n\
                 :timing           Toggle printing of how long evaluations take\n\
                 :last_error_json  Print the last compilation error as JSON (for debugging)\n\
                 :time_passes      Toggle printing of rustc pass times (requires nightly)\n\
                 :internal_debug   Toggle various internal debugging code",
            ),
            _ => bail!("Unrecognised command {}", command),
        }
    }

    fn vars_as_text(&self) -> String {
        let mut out = String::new();
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str(var);
            out.push_str(": ");
            out.push_str(ty);
            out.push_str("\n");
        }
        out
    }

    fn vars_as_html(&self) -> String {
        let mut out = String::new();
        out.push_str("

Variable	Type
");
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str("
");
            html_escape(var, &mut out);
            out.push_str("	");
            html_escape(ty, &mut out);
            out.push_str("
");
        }
        out.push_str("
");
        out
    }
}

fn html_escape(input: &str, out: &mut String) {
    for ch in input.chars() {
        match ch {
            '<' => out.push_str("<"),
            '>' => out.push_str(">"),
            x => out.push(x),
        }
    }
}

fn text_output<T: Into<String>>(text: T) -> Result<EvalOutputs, Error> {
    let mut outputs = EvalOutputs::new();
    let mut content = text.into();
    content.push('\n');
    outputs
        .content_by_mime_type
        .insert("text/plain".to_owned(), content);
    Ok(outputs)
}
<|endoftext|>


<commit_before>//! Implements a command for managing releases.
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::collections::HashSet;

use clap::{App, AppSettings, Arg, ArgMatches};
use walkdir::WalkDir;

use prelude::*;
use api::{Api, NewRelease};
use config::Config;
use utils::make_subcommand;
use sourcemaps::SourceMapValidator;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
            .about("Create a new release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version identifier for this release"))
            .arg(Arg::with_name("ref")
                 .long("ref")
                 .value_name("REF")
                 .help("Optional commit reference (commit hash)"))
            .arg(Arg::with_name("url")
                 .long("url")
                 .value_name("URL")
                 .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
            .about("Delete a release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version to delete")))
        .subcommand(make_subcommand("list")
            .about("list the most recent releases"))
        .subcommand(make_subcommand("files")
            .about("manage release artifact files")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The release to manage the files of"))
            .subcommand(make_subcommand("list")
                .about("List all release files"))
            .subcommand(make_subcommand("delete")
                .about("Delete a release file")
                .arg(Arg::with_name("all")
                     .short("A")
                     .long("all")
                     .help("deletes all files"))
                .arg(Arg::with_name("names")
                     .value_name("NAMES")
                     .index(1)
                     .multiple(true)
                     .help("a list of filenames to delete.")))
            .subcommand(make_subcommand("upload")
                .about("Uploads a file for a given release")
                .arg(Arg::with_name("path")
                     .value_name("PATH")
                     .index(1)
                     .required(true)
                     .help("The file to upload"))
                .arg(Arg::with_name("name")
                     .index(2)
                     .value_name("NAME")
                     .help("The name of the file on the server.")))
            .subcommand(make_subcommand("upload-sourcemaps")
                .about("Uploads sourcemap information for a given release")
                .arg(Arg::with_name("paths")
                     .value_name("PATHS")
                     .index(1)
                     .required(true)
                     .multiple(true)
                     .help("The files to upload"))
                .arg(Arg::with_name("url_prefix")
                     .short("u")
                     .long("url-prefix")
                     .value_name("PREFIX")
                     .help("The URL prefix to prepend to all filenames"))
                .arg(Arg::with_name("validate")
                     .long("validate")
                     .help("Enable basic sourcemap validation"))
                .arg(Arg::with_name("verbose")
                     .long("verbose")
                     .short("verbose")
                     .help("Enable verbose mode"))
                .arg(Arg::with_name("extensions")
                     .long("ext")
                     .short("x")
                     .value_name("EXT")
                     .multiple(true)
                     .help("Add a file extension to the list of files to upload."))))
}

fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                   org: &str, project: &str) -> Result<()> {
    let info_rv = Api::new(config).new_release(org, project, &NewRelease {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    })?;
    println!("Created release {}.", info_rv.version);
    Ok(())
}

fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                      org: &str, project: &str) -> Result<()> {
    let version = matches.value_of("version").unwrap();
    if Api::new(config).delete_release(org, project, version)? {
        println!("Deleted release {}!", version);
    } else {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    }
    Ok(())
}

fn execute_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                    org: &str, project: &str) -> Result<()> {
    for info in Api::new(config).list_releases(org, project)? {
        println!("[{}] {}: {} ({} new groups)",
                 info.date_released.unwrap_or("              unreleased".into()),
                 info.version,
                 info.reference.unwrap_or("-".into()),
                 info.new_groups);
    }
    Ok(())
}

fn execute_files_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str, release: &str) -> Result<()> {
    for artifact in Api::new(config).list_release_files(org, project, release)? {
        println!("{}  ({} bytes)", artifact.name, artifact.size);
    }
    Ok(())
}

fn execute_files_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, release: &str) -> Result<()> {
    let files : HashSet<String> = match matches.values_of("names") {
        Some(paths) => paths.map(|x| x.into()).collect(),
        None => HashSet::new(),
    };
    let api = Api::new(config);
    for file in api.list_release_files(org, project, release)? {
        if !(matches.is_present("all") || files.contains(&file.name)) {
            continue;
        }
        if api.delete_release_file(org, project, release, &file.id)? {
            println!("D {}", file.name);
        }
    }
    Ok(())
}

fn execute_files_upload<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, version: &str) -> Result<()> {
    let path = Path::new(matches.value_of("path").unwrap());
    let name = match matches.value_of("name") {
        Some(name) => name,
        None => Path::new(path).file_name()
            .and_then(|x| x.to_str()).ok_or("No filename provided.")?,
    };
    if let Some(artifact) = Api::new(config).upload_release_file(
        org, project, &version, &path, &name)? {
        println!("A {}  ({} bytes)", artifact.sha1, artifact.size);
    } else {
        fail!("File already present!");
    }
    Ok(())
}

fn execute_files_upload_sourcemaps<'a>(matches: &ArgMatches<'a>, config: &Config,
                                       org: &str, project: &str, version: &str) -> Result<()> {
    let api = Api::new(config);
    let release = api.get_release(org, project, version)?.ok_or("release not found")?;
    let url_prefix = matches.value_of("url_prefix").unwrap_or("~").trim_right_matches("/");
    let paths = matches.values_of("paths").unwrap();
    let extensions = match matches.values_of("extensions") {
        Some(matches) => matches.map(|ext| OsStr::new(ext.trim_left_matches("."))).collect(),
        None => vec![OsStr::new("js"), OsStr::new("map")],
    };

    let mut to_process = vec![];

    for path in paths {
        // if we start walking over something that is an actual file then
        // the directory iterator yields that path and terminates.  We
        // handle that case here specifically to figure out what the path is
        // we should strip off.
        let walk_path = PathBuf::from(&path);
        let (base_path, skip_ext_test) = if walk_path.is_file() {
            (walk_path.parent().unwrap(), true)
        } else {
            (walk_path.as_path(), false)
        };

        for dent in WalkDir::new(&walk_path) {
            let dent = dent?;
            if !skip_ext_test {
                let extension = dent.path().extension();
                if !extensions.iter().any(|ext| Some(*ext) == extension) {
                    continue;
                }
            }
            debug!("found: {} ({} bytes)", dent.path().display(), dent.metadata().unwrap().len());
            let local_path = dent.path().strip_prefix(&base_path).unwrap();
            let url = format!("{}/{}", url_prefix, local_path.display());
            to_process.push((url, local_path.to_path_buf(),
                             dent.path().to_path_buf()));
        }
    }

    if matches.is_present("validate") {
        println!("Running with sourcemap validation");
        let mut validator = SourceMapValidator::new(matches.is_present("verbose"));
        for &(ref url, _, ref path) in to_process.iter() {
            validator.consider_file(path, url);
        }
        validator.validate_sources()?;
    }

    println!("Uploading sourcemaps for release {}", release.version);
    for (url, local_path, path) in to_process {
        println!("{} -> {}", local_path.display(), url);
        if let Some(artifact) = api.upload_release_file(
            org, project, &release.version, &path, &url)? {
            println!("  {}  ({} bytes)", artifact.sha1, artifact.size);
        } else {
            println!("  already present");
        }
    }

    Ok(())
}

fn execute_files<'a>(matches: &ArgMatches<'a>, config: &Config,
                     org: &str, project: &str) -> Result<()> {
    let release = matches.value_of("version").unwrap();
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        return execute_files_list(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        return execute_files_delete(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload") {
        return execute_files_upload(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload-sourcemaps") {
        return execute_files_upload_sourcemaps(sub_matches, config, org, project, release);
    }
    unreachable!();
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_delete(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_list(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("files") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_files(sub_matches, config, &org, &project);
    }
    unreachable!();
}
<commit_msg>Added bundle to extensions<commit_after>//! Implements a command for managing releases.
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::collections::HashSet;

use clap::{App, AppSettings, Arg, ArgMatches};
use walkdir::WalkDir;

use prelude::*;
use api::{Api, NewRelease};
use config::Config;
use utils::make_subcommand;
use sourcemaps::SourceMapValidator;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
            .about("Create a new release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version identifier for this release"))
            .arg(Arg::with_name("ref")
                 .long("ref")
                 .value_name("REF")
                 .help("Optional commit reference (commit hash)"))
            .arg(Arg::with_name("url")
                 .long("url")
                 .value_name("URL")
                 .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
            .about("Delete a release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version to delete")))
        .subcommand(make_subcommand("list")
            .about("list the most recent releases"))
        .subcommand(make_subcommand("files")
            .about("manage release artifact files")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The release to manage the files of"))
            .subcommand(make_subcommand("list")
                .about("List all release files"))
            .subcommand(make_subcommand("delete")
                .about("Delete a release file")
                .arg(Arg::with_name("all")
                     .short("A")
                     .long("all")
                     .help("deletes all files"))
                .arg(Arg::with_name("names")
                     .value_name("NAMES")
                     .index(1)
                     .multiple(true)
                     .help("a list of filenames to delete.")))
            .subcommand(make_subcommand("upload")
                .about("Uploads a file for a given release")
                .arg(Arg::with_name("path")
                     .value_name("PATH")
                     .index(1)
                     .required(true)
                     .help("The file to upload"))
                .arg(Arg::with_name("name")
                     .index(2)
                     .value_name("NAME")
                     .help("The name of the file on the server.")))
            .subcommand(make_subcommand("upload-sourcemaps")
                .about("Uploads sourcemap information for a given release")
                .arg(Arg::with_name("paths")
                     .value_name("PATHS")
                     .index(1)
                     .required(true)
                     .multiple(true)
                     .help("The files to upload"))
                .arg(Arg::with_name("url_prefix")
                     .short("u")
                     .long("url-prefix")
                     .value_name("PREFIX")
                     .help("The URL prefix to prepend to all filenames"))
                .arg(Arg::with_name("validate")
                     .long("validate")
                     .help("Enable basic sourcemap validation"))
                .arg(Arg::with_name("verbose")
                     .long("verbose")
                     .short("verbose")
                     .help("Enable verbose mode"))
                .arg(Arg::with_name("extensions")
                     .long("ext")
                     .short("x")
                     .value_name("EXT")
                     .multiple(true)
                     .help("Add a file extension to the list of files to upload."))))
}

fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                   org: &str, project: &str) -> Result<()> {
    let info_rv = Api::new(config).new_release(org, project, &NewRelease {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    })?;
    println!("Created release {}.", info_rv.version);
    Ok(())
}

fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                      org: &str, project: &str) -> Result<()> {
    let version = matches.value_of("version").unwrap();
    if Api::new(config).delete_release(org, project, version)? {
        println!("Deleted release {}!", version);
    } else {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    }
    Ok(())
}

fn execute_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                    org: &str, project: &str) -> Result<()> {
    for info in Api::new(config).list_releases(org, project)? {
        println!("[{}] {}: {} ({} new groups)",
                 info.date_released.unwrap_or("              unreleased".into()),
                 info.version,
                 info.reference.unwrap_or("-".into()),
                 info.new_groups);
    }
    Ok(())
}

fn execute_files_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str, release: &str) -> Result<()> {
    for artifact in Api::new(config).list_release_files(org, project, release)? {
        println!("{}  ({} bytes)", artifact.name, artifact.size);
    }
    Ok(())
}

fn execute_files_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, release: &str) -> Result<()> {
    let files : HashSet<String> = match matches.values_of("names") {
        Some(paths) => paths.map(|x| x.into()).collect(),
        None => HashSet::new(),
    };
    let api = Api::new(config);
    for file in api.list_release_files(org, project, release)? {
        if !(matches.is_present("all") || files.contains(&file.name)) {
            continue;
        }
        if api.delete_release_file(org, project, release, &file.id)? {
            println!("D {}", file.name);
        }
    }
    Ok(())
}

fn execute_files_upload<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, version: &str) -> Result<()> {
    let path = Path::new(matches.value_of("path").unwrap());
    let name = match matches.value_of("name") {
        Some(name) => name,
        None => Path::new(path).file_name()
            .and_then(|x| x.to_str()).ok_or("No filename provided.")?,
    };
    if let Some(artifact) = Api::new(config).upload_release_file(
        org, project, &version, &path, &name)? {
        println!("A {}  ({} bytes)", artifact.sha1, artifact.size);
    } else {
        fail!("File already present!");
    }
    Ok(())
}

fn execute_files_upload_sourcemaps<'a>(matches: &ArgMatches<'a>, config: &Config,
                                       org: &str, project: &str, version: &str) -> Result<()> {
    let api = Api::new(config);
    let release = api.get_release(org, project, version)?.ok_or("release not found")?;
    let url_prefix = matches.value_of("url_prefix").unwrap_or("~").trim_right_matches("/");
    let paths = matches.values_of("paths").unwrap();
    let extensions = match matches.values_of("extensions") {
        Some(matches) => matches.map(|ext| OsStr::new(ext.trim_left_matches("."))).collect(),
        None => vec![OsStr::new("js"), OsStr::new("map"), OsStr::new("bundle")],
    };

    let mut to_process = vec![];

    for path in paths {
        // if we start walking over something that is an actual file then
        // the directory iterator yields that path and terminates.  We
        // handle that case here specifically to figure out what the path is
        // we should strip off.
        let walk_path = PathBuf::from(&path);
        let (base_path, skip_ext_test) = if walk_path.is_file() {
            (walk_path.parent().unwrap(), true)
        } else {
            (walk_path.as_path(), false)
        };

        for dent in WalkDir::new(&walk_path) {
            let dent = dent?;
            if !skip_ext_test {
                let extension = dent.path().extension();
                if !extensions.iter().any(|ext| Some(*ext) == extension) {
                    continue;
                }
            }
            debug!("found: {} ({} bytes)", dent.path().display(), dent.metadata().unwrap().len());
            let local_path = dent.path().strip_prefix(&base_path).unwrap();
            let url = format!("{}/{}", url_prefix, local_path.display());
            to_process.push((url, local_path.to_path_buf(),
                             dent.path().to_path_buf()));
        }
    }

    if matches.is_present("validate") {
        println!("Running with sourcemap validation");
        let mut validator = SourceMapValidator::new(matches.is_present("verbose"));
        for &(ref url, _, ref path) in to_process.iter() {
            validator.consider_file(path, url);
        }
        validator.validate_sources()?;
    }

    println!("Uploading sourcemaps for release {}", release.version);
    for (url, local_path, path) in to_process {
        println!("{} -> {}", local_path.display(), url);
        if let Some(artifact) = api.upload_release_file(
            org, project, &release.version, &path, &url)? {
            println!("  {}  ({} bytes)", artifact.sha1, artifact.size);
        } else {
            println!("  already present");
        }
    }

    Ok(())
}

fn execute_files<'a>(matches: &ArgMatches<'a>, config: &Config,
                     org: &str, project: &str) -> Result<()> {
    let release = matches.value_of("version").unwrap();
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        return execute_files_list(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        return execute_files_delete(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload") {
        return execute_files_upload(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload-sourcemaps") {
        return execute_files_upload_sourcemaps(sub_matches, config, org, project, release);
    }
    unreachable!();
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_delete(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_list(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("files") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_files(sub_matches, config, &org, &project);
    }
    unreachable!();
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use specs;
use specs::{ReadStorage, WriteStorage};
use gfx_app::mouse_controls::MouseInputState;
use graphics::camera::CameraInputState;
use graphics::orientation::Orientation;

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub x_movement: f32,
  pub y_movement: f32,
  pub orientation: Orientation,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      x_movement: 0.0,
      y_movement: 0.0,
      orientation: Orientation::Still,
    }
  }
}

impl specs::Component for CharacterInputState {
  type Storage = specs::HashMapStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: mpsc::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, mpsc::Sender<CharacterControl>) {
    let (tx, rx) = mpsc::channel();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>, ReadStorage<'a, MouseInputState>, WriteStorage<'a, CameraInputState>);

  fn run(&mut self, (mut character_input, mouse_input, mut camera_input): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CharacterControl::Up => self.y_move = Some(-0.9),
        CharacterControl::Down => self.y_move = Some(0.9),
        CharacterControl::YMoveStop => self.y_move = None,
        CharacterControl::Right => self.x_move = Some(-1.0),
        CharacterControl::Left => self.x_move = Some(1.0),
        CharacterControl::XMoveStop => self.x_move = None,
      }
    }

    if self.y_move.is_none() && self.x_move.is_none() {
      for (ci, mi) in (&mut character_input, &mouse_input).join() {
        if mi.left_click_point.is_none() {
          ci.orientation = Orientation::Still;
        }
      }
    } else if self.x_move.is_none() {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.y_movement += y;
            camera.y_pos -= y;
            ci.orientation =
              if y < 0.0 { Orientation::Up } else if y > 0.0 { Orientation::Down } else { Orientation::Still };
          }
        }
      }
    } else if let Some(x) = self.x_move {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x / 1.5;
            ci.y_movement += y / 1.5;
            camera.x_pos += x / 1.5;
            camera.y_pos -= y / 1.5;

            ci.orientation = match (x, y) {
              (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
              (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
              (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
              (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
              _ => Orientation::Still,
            };
          }
        }
      } else if self.y_move.is_none() {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x;
            camera.x_pos += x;
            ci.orientation =
              if x < 0.0 { Orientation::Right } else if x > 0.0 { Orientation::Left } else { Orientation::Still };
          }
        }
      }
    }
  }
}
<commit_msg>Reformat if else branches in character controls<commit_after>use std::sync::mpsc;
use specs;
use specs::{ReadStorage, WriteStorage};
use gfx_app::mouse_controls::MouseInputState;
use graphics::camera::CameraInputState;
use graphics::orientation::Orientation;

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub x_movement: f32,
  pub y_movement: f32,
  pub orientation: Orientation,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      x_movement: 0.0,
      y_movement: 0.0,
      orientation: Orientation::Still,
    }
  }
}

impl specs::Component for CharacterInputState {
  type Storage = specs::HashMapStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: mpsc::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, mpsc::Sender<CharacterControl>) {
    let (tx, rx) = mpsc::channel();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>, ReadStorage<'a, MouseInputState>, WriteStorage<'a, CameraInputState>);

  fn run(&mut self, (mut character_input, mouse_input, mut camera_input): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CharacterControl::Up => self.y_move = Some(-0.9),
        CharacterControl::Down => self.y_move = Some(0.9),
        CharacterControl::YMoveStop => self.y_move = None,
        CharacterControl::Right => self.x_move = Some(-1.0),
        CharacterControl::Left => self.x_move = Some(1.0),
        CharacterControl::XMoveStop => self.x_move = None,
      }
    }

    if self.y_move.is_none() && self.x_move.is_none() {
      for (ci, mi) in (&mut character_input, &mouse_input).join() {
        if mi.left_click_point.is_none() {
          ci.orientation = Orientation::Still;
        }
      }
    } else if self.x_move.is_none() {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.y_movement += y;
            camera.y_pos -= y;
            ci.orientation =
              if y < 0.0 { Orientation::Up }
              else if y > 0.0 { Orientation::Down }
              else { Orientation::Still };
          }
        }
      }
    } else if let Some(x) = self.x_move {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x / 1.5;
            ci.y_movement += y / 1.5;
            camera.x_pos += x / 1.5;
            camera.y_pos -= y / 1.5;

            ci.orientation = match (x, y) {
              (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
              (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
              (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
              (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
              _ => Orientation::Still,
            };
          }
        }
      } else if self.y_move.is_none() {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x;
            camera.x_pos += x;
            ci.orientation =
              if x < 0.0 { Orientation::Right }
              else if x > 0.0 { Orientation::Left }
              else { Orientation::Still };
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use kbdgen::{
    m17n_mim::*,
    models::{DesktopModes, MobileModes},
    Load, ProjectBundle,
};
use log::{debug, log_enabled};
use snafu::{ResultExt, Snafu};
use snafu_cli_debug::SnafuCliDebug;
use std::{collections::BTreeMap, convert::TryFrom, fs::File, io::BufWriter, path::PathBuf};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Cli {
    #[structopt(parse(from_os_str))]
    input: PathBuf,

    #[structopt(parse(from_os_str))]
    output: PathBuf,

    #[structopt(flatten)]
    verbose: clap_verbosity_flag::Verbosity,
}

pub fn kbdgen_to_mim(opts: &Cli) -> Result<(), Error> {
    let _ = opts.verbose.setup_env_logger("kbdgen-cli");

    let bundle = ProjectBundle::load(&opts.input).context(CannotLoad)?;
    if log_enabled!(log::Level::Debug) {
        debug!("Bundle `{}` loaded", opts.input.display());
        let locales = bundle
            .project
            .locales
            .values()
            .map(|l| l.name.as_str())
            .collect::<Vec<_>>();
        debug!("Bundle contains these locales: {:?}", locales);
    }

    bundle
        .layouts
        .iter()
        .map(|(name, layout)| (name, layout_to_mim(&name, layout, &bundle)))
        .try_for_each(|(name, keyboards)| {
            for (platform, keyboard) in keyboards? {
                let path = &opts.output.join(name).join(platform).with_extension("mim");
                std::fs::create_dir_all(path.parent().unwrap())
                    .context(CannotCreateFile { path })?;
                let file = File::create(path).context(CannotCreateFile { path })?;
                debug!("Created file `{}`", path.display());
                let mut writer = BufWriter::new(file);
                keyboard
                    .write_mim(&mut writer)
                    .context(CannotSerializeMim)?;
                log::info!("Wrote to file `{}`", path.display());
            }
            Ok(())
        })
        .context(CannotBeSaved)?;

    Ok(())
}

fn layout_to_mim(
    name: &str,
    layout: &kbdgen::models::Layout,
    _project: &kbdgen::ProjectBundle,
) -> Result<Vec<(String, Root)>, SavingError> {
    log::debug!("to cldr with you, {}!", name);

    let mut res = vec![];

    macro_rules! mode {
        (desktop: $name:ident) => {
            mode!(desktop_mode_to_keyboard -> $name)
        };
        ($fn:ident -> $name:ident) => {
            if let Some(a) = layout.modes.$name.as_ref() {
                log::debug!("{}: check", stringify!($name));
                res.push((
                    String::from(stringify!($name)),
                    $fn(name, stringify!($name), a, layout)?,
                ));
            }
        };
    }

    mode!(desktop: win);
    mode!(desktop: mac);
    mode!(desktop: chrome);
    mode!(desktop: x11);
    mode!(desktop: desktop);

    Ok(res)
}

fn desktop_mode_to_keyboard(
    name: &str,
    target: &str,
    desktop: &DesktopModes,
    layout: &kbdgen::models::Layout,
) -> Result<Root, SavingError> {
    let mut maps = vec![];

    for (key_combo, mapping) in desktop {
        let mut rules = vec![];
        let key_combo = if key_combo == "default" {
            vec![]
        } else {
            Modifier::parse_keycombo(key_combo).context(CannotSerializeKeyCombo)?
        };

        for (iso_key, key_val) in mapping.iter() {
            let key_code = KeyDef::CharacterCode(
                Integer::try_from(format!("{:#x}", iso_key.to_character_code()))
                    .context(InvalidCharacterCodeIndex)?,
            );

            let keyseq = KeySeq::KeyCombo(KeyCombo {
                modifiers: key_combo.clone(),
                key: key_code,
            });

            if let Some(key) = key_val.0.as_ref() {
                rules.push(Rule {
                    keyseq,
                    action: MapAction::Insert(Insert::Character(
                        Text::try_from(key.to_string()).context(CannotSerializeSymbol)?,
                    )),
                });
            }
        }

        maps.push(Map {
            name: Symbol::try_from(String::from("mapping")).context(CannotSerializeSymbol)?,
            rules,
        });
    }

    // TODO: Add more maps for transforms based on dead keys
    // TODO: Add map for space transforms

    Ok(Root {
        input_method: InputMethod {
            language: Symbol::try_from(name.to_string()).context(CannotSerializeSymbol)?,
            name: Symbol::try_from(name.to_string()).context(CannotSerializeSymbol)?,
            extra_id: None,
            version: None,
        },
        title: Text::try_from(name.to_string()).context(CannotSerializeSymbol)?,
        description: Some(
            Text::try_from(format!("{} ({})", name, target)).context(CannotSerializeSymbol)?,
        ),
        maps,
        states: vec![],
    })
}

fn pick_name_from_display_names(names: &BTreeMap<String, String>) -> String {
    names
        .get("en")
        .or_else(|| names.values().next())
        .cloned()
        .unwrap_or_default()
}

#[derive(Snafu, SnafuCliDebug)]
pub enum Error {
    #[snafu(display("Could not load kbdgen bundle"))]
    CannotLoad {
        source: kbdgen::LoadError,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could not write CLDR file"))]
    CannotBeSaved {
        source: SavingError,
        backtrace: snafu::Backtrace,
    },
}

#[derive(Snafu, Debug)]
pub enum SavingError {
    #[snafu(display("Could not create file `{}`", path.display()))]
    CannotCreateFile {
        path: PathBuf,
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could transform to MIM"))]
    CannotSerializeMim {
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could serialize MIM symbol"))]
    CannotSerializeSymbol {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could serialize key combo"))]
    CannotSerializeKeyCombo {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Invalid character code index"))]
    InvalidCharacterCodeIndex {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
}
<commit_msg>MIM: Output transforms as well<commit_after>use kbdgen::{m17n_mim::*, models::DesktopModes, Load, ProjectBundle};
use log::{debug, log_enabled};
use snafu::{ResultExt, Snafu};
use snafu_cli_debug::SnafuCliDebug;
use std::{collections::BTreeMap, convert::TryFrom, fs::File, io::BufWriter, path::PathBuf};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Cli {
    #[structopt(parse(from_os_str))]
    input: PathBuf,

    #[structopt(parse(from_os_str))]
    output: PathBuf,

    #[structopt(flatten)]
    verbose: clap_verbosity_flag::Verbosity,
}

pub fn kbdgen_to_mim(opts: &Cli) -> Result<(), Error> {
    let _ = opts.verbose.setup_env_logger("kbdgen-cli");

    let bundle = ProjectBundle::load(&opts.input).context(CannotLoad)?;
    if log_enabled!(log::Level::Debug) {
        debug!("Bundle `{}` loaded", opts.input.display());
        let locales = bundle
            .project
            .locales
            .values()
            .map(|l| l.name.as_str())
            .collect::<Vec<_>>();
        debug!("Bundle contains these locales: {:?}", locales);
    }

    bundle
        .layouts
        .iter()
        .map(|(name, layout)| (name, layout_to_mim(&name, layout, &bundle)))
        .try_for_each(|(name, keyboards)| {
            for (platform, keyboard) in keyboards? {
                let path = &opts.output.join(name).join(platform).with_extension("mim");
                std::fs::create_dir_all(path.parent().unwrap())
                    .context(CannotCreateFile { path })?;
                let file = File::create(path).context(CannotCreateFile { path })?;
                debug!("Created file `{}`", path.display());
                let mut writer = BufWriter::new(file);
                keyboard
                    .write_mim(&mut writer)
                    .context(CannotSerializeMim)?;
                log::info!("Wrote to file `{}`", path.display());
            }
            Ok(())
        })
        .context(CannotBeSaved)?;

    Ok(())
}

fn layout_to_mim(
    name: &str,
    layout: &kbdgen::models::Layout,
    _project: &kbdgen::ProjectBundle,
) -> Result<Vec<(String, Root)>, SavingError> {
    log::debug!("to mim with you, {}!", name);

    let mut res = vec![];

    macro_rules! mode {
        (desktop: $platform:ident) => {
            mode!(desktop_mode_to_keyboard -> $platform)
        };
        ($fn:ident -> $platform:ident) => {
            if let Some(a) = layout.modes.$platform.as_ref() {
                log::debug!("{}: check", stringify!($platform));
                let dead_key_rules = dead_key_transforms(&layout, stringify!($platform))
                    .context(CannotCreateTransformMap)?;

                res.push((
                    String::from(stringify!($platform)),
                    $fn(name, stringify!($platform), a, dead_key_rules)?,
                ));
            }
        };
    }

    mode!(desktop: win);
    mode!(desktop: mac);
    mode!(desktop: chrome);
    mode!(desktop: x11);
    mode!(desktop: desktop);

    Ok(res)
}

fn desktop_mode_to_keyboard(
    name: &str,
    target: &str,
    desktop: &DesktopModes,
    dead_key_transforms: Vec<Rule>,
) -> Result<Root, SavingError> {
    let mut rules = vec![];

    for (key_combo, mapping) in desktop {
        let key_combo = if key_combo == "default" {
            vec![]
        } else {
            Modifier::parse_keycombo(key_combo).context(CannotSerializeKeyCombo)?
        };

        for (iso_key, key_val) in mapping.iter() {
            let key_code = KeyDef::CharacterCode(
                Integer::try_from(format!("{:#x}", iso_key.to_character_code()))
                    .context(InvalidCharacterCodeIndex)?,
            );

            let keyseq = KeySeq::KeyCombo(KeyCombo {
                modifiers: key_combo.clone(),
                key: key_code,
            });

            if let Some(key) = key_val.0.as_ref() {
                rules.push(Rule {
                    keyseq,
                    action: MapAction::Insert(Insert::Character(
                        Text::try_from(key.to_string()).context(CannotSerializeSymbol)?,
                    )),
                });
            }
        }
    }

    // TODO: Add map for space transforms
    rules.extend(dead_key_transforms);

    Ok(Root {
        input_method: InputMethod {
            language: Symbol::try_from(name.to_string()).context(CannotSerializeSymbol)?,
            name: Symbol::try_from(name.to_string()).context(CannotSerializeSymbol)?,
            extra_id: None,
            version: None,
        },
        title: Text::try_from(name.to_string()).context(CannotSerializeSymbol)?,
        description: Some(
            Text::try_from(format!("{} ({})", name, target)).context(CannotSerializeSymbol)?,
        ),
        maps: vec![Map {
            name: Symbol::try_from(String::from("mapping")).context(CannotSerializeSymbol)?,
            rules,
        }],
        // (state (init (mapping)))
        states: vec![State {
            name: Symbol::try_from("init".to_string()).context(CannotSerializeSymbol)?,
            title: None,
            branches: vec![Branch {
                map_name: Symbol::try_from("mapping".to_string()).context(CannotSerializeSymbol)?,
            }],
        }],
    })
}

/// Combine dead keys with transforms
///
/// Generates MIM rules in the style of `(("´" "a") "á")`.
fn dead_key_transforms(
    layout: &kbdgen::models::Layout,
    platform: &str,
) -> Result<Vec<Rule>, MimConversion> {
    let mut rules = vec![];

    let empty_dead_keys = BTreeMap::new();
    let empty_transforms = BTreeMap::new();

    let dead_key_map = layout
        .dead_keys
        .as_ref()
        .and_then(|dead_keys| dead_keys.get(platform))
        .unwrap_or_else(|| &empty_dead_keys);
    let transforms = layout
        .transforms
        .as_ref()
        .unwrap_or_else(|| &empty_transforms);

    let dead_keys = dead_key_map.iter().flat_map(|(_modifier, keys)| keys);

    for first_key in dead_keys {
        let mapping = match transforms.get(first_key) {
            Some(map) => map,
            None => {
                log::warn!(
                    "dead key map for `{}` contains `{}` but no transforms found",
                    platform,
                    first_key
                );
                continue;
            }
        };

        for (second_key, transformed_char) in mapping {
            rules.push(Rule {
                keyseq: KeySeq::Character(Text::try_from(format!("{}{}", first_key, second_key))?),
                action: MapAction::Insert(Insert::Character(Text::try_from(
                    transformed_char.to_string(),
                )?)),
            });
        }
    }

    Ok(rules)
}

#[derive(Snafu, SnafuCliDebug)]
pub enum Error {
    #[snafu(display("Could not load kbdgen bundle"))]
    CannotLoad {
        source: kbdgen::LoadError,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could not write CLDR file"))]
    CannotBeSaved {
        source: SavingError,
        backtrace: snafu::Backtrace,
    },
}

#[derive(Snafu, Debug)]
pub enum SavingError {
    #[snafu(display("Could not create file `{}`", path.display()))]
    CannotCreateFile {
        path: PathBuf,
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could transform to MIM"))]
    CannotSerializeMim {
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could serialize MIM symbol"))]
    CannotSerializeSymbol {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could serialize key combo"))]
    CannotSerializeKeyCombo {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Invalid character code index"))]
    InvalidCharacterCodeIndex {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Cannot create transform map"))]
    CannotCreateTransformMap {
        source: MimConversion,
        backtrace: snafu::Backtrace,
    },
}
<|endoftext|>


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

use crate::{BusAccessInfo, BusDevice, BusResumeDevice};
use acpi_tables::{aml, aml::Aml};
use base::{error, warn, Event};

/// ACPI PM resource for handling OS suspend/resume request
pub struct ACPIPMResource {
    suspend_evt: Event,
    exit_evt: Event,
    pm1_status: u16,
    pm1_enable: u16,
    pm1_control: u16,
    sleep_control: u8,
    sleep_status: u8,
}

impl ACPIPMResource {
    /// Constructs ACPI Power Management Resouce.
    pub fn new(suspend_evt: Event, exit_evt: Event) -> ACPIPMResource {
        ACPIPMResource {
            suspend_evt,
            exit_evt,
            pm1_status: 0,
            pm1_enable: 0,
            pm1_control: 0,
            sleep_control: 0,
            sleep_status: 0,
        }
    }
}

/// the ACPI PM register length.
pub const ACPIPM_RESOURCE_LEN: u8 = 8;
pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;

/// ACPI PM register value definations
const PM1_STATUS: u16 = 0;
const PM1_ENABLE: u16 = 2;
const PM1_CONTROL: u16 = 4;
const SLEEP_CONTROL: u16 = 6;
const SLEEP_STATUS: u16 = 7;
const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
const BITMASK_SLEEPCNT_SLEEP_ENABLE: u8 = 0x20;
const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
const BITMASK_SLEEPCNT_WAKE_STATUS: u8 = 0x80;

const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
const SLEEP_TYPE_S5: u16 = 0;

impl BusDevice for ACPIPMResource {
    fn debug_label(&self) -> String {
        "ACPIPMResource".to_owned()
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        let val = match info.offset as u16 {
            PM1_STATUS => self.pm1_status,
            PM1_ENABLE => self.pm1_enable,
            PM1_CONTROL => self.pm1_control,
            SLEEP_CONTROL => self.sleep_control as u16,
            SLEEP_STATUS => self.sleep_status as u16,
            _ => {
                warn!("ACPIPM: Bad read from {}", info);
                return;
            }
        };

        let val_arr = val.to_ne_bytes();
        for i in 0..std::mem::size_of::<u16>() {
            if i < data.len() {
                data[i] = val_arr[i];
            }
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        let max_bytes = std::mem::size_of::<u16>();

        // only allow maximum max_bytes to write
        if data.len() > max_bytes {
            warn!("ACPIPM: bad write size: {}", data.len());
            return;
        }

        let mut val_arr = u16::to_ne_bytes(0u16);
        for i in 0..std::mem::size_of::<u16>() {
            if i < data.len() {
                val_arr[i] = data[i];
            }
        }
        let val = u16::from_ne_bytes(val_arr);

        match info.offset as u16 {
            PM1_STATUS => self.pm1_status &= !val,
            PM1_ENABLE => self.pm1_enable = val,
            PM1_CONTROL => {
                if (val & BITMASK_PM1CNT_SLEEP_ENABLE) == BITMASK_PM1CNT_SLEEP_ENABLE {
                    if val & BITMASK_PM1CNT_SLEEP_TYPE == SLEEP_TYPE_S5 {
                        if let Err(e) = self.exit_evt.write(1) {
                            error!("ACPIPM: failed to trigger exit event: {}", e);
                        }
                    } else {
                        if let Err(e) = self.suspend_evt.write(1) {
                            error!("ACPIPM: failed to trigger suspend event: {}", e);
                        }
                    }
                }
                self.pm1_control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
            }
            SLEEP_CONTROL => {
                let sleep_control = val as u8;
                if (sleep_control & BITMASK_SLEEPCNT_SLEEP_ENABLE) == BITMASK_SLEEPCNT_SLEEP_ENABLE
                {
                    if let Err(e) = self.suspend_evt.write(1) {
                        error!("ACPIPM: failed to trigger suspend event: {}", e);
                    }
                }
                self.sleep_control = sleep_control as u8 & !BITMASK_SLEEPCNT_SLEEP_ENABLE;
            }
            SLEEP_STATUS => self.sleep_status &= !val as u8,
            _ => {
                warn!("ACPIPM: Bad write to {}", info);
            }
        };
    }
}

impl BusResumeDevice for ACPIPMResource {
    fn resume_imminent(&mut self) {
        let val = self.pm1_status;
        self.pm1_status = val | BITMASK_PM1CNT_WAKE_STATUS;

        let val = self.sleep_status;
        self.sleep_status = val | BITMASK_SLEEPCNT_WAKE_STATUS;
    }
}

impl Aml for ACPIPMResource {
    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
        // S1
        aml::Name::new(
            "_S1_".into(),
            &aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
        )
        .to_aml_bytes(bytes);

        // S5
        aml::Name::new(
            "_S5_".into(),
            &aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
        )
        .to_aml_bytes(bytes);
    }
}
<commit_msg>devices: acpi: collapsed nested if inside else<commit_after>// Copyright 2019 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.

use crate::{BusAccessInfo, BusDevice, BusResumeDevice};
use acpi_tables::{aml, aml::Aml};
use base::{error, warn, Event};

/// ACPI PM resource for handling OS suspend/resume request
pub struct ACPIPMResource {
    suspend_evt: Event,
    exit_evt: Event,
    pm1_status: u16,
    pm1_enable: u16,
    pm1_control: u16,
    sleep_control: u8,
    sleep_status: u8,
}

impl ACPIPMResource {
    /// Constructs ACPI Power Management Resouce.
    pub fn new(suspend_evt: Event, exit_evt: Event) -> ACPIPMResource {
        ACPIPMResource {
            suspend_evt,
            exit_evt,
            pm1_status: 0,
            pm1_enable: 0,
            pm1_control: 0,
            sleep_control: 0,
            sleep_status: 0,
        }
    }
}

/// the ACPI PM register length.
pub const ACPIPM_RESOURCE_LEN: u8 = 8;
pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;

/// ACPI PM register value definations
const PM1_STATUS: u16 = 0;
const PM1_ENABLE: u16 = 2;
const PM1_CONTROL: u16 = 4;
const SLEEP_CONTROL: u16 = 6;
const SLEEP_STATUS: u16 = 7;
const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
const BITMASK_SLEEPCNT_SLEEP_ENABLE: u8 = 0x20;
const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
const BITMASK_SLEEPCNT_WAKE_STATUS: u8 = 0x80;

const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
const SLEEP_TYPE_S5: u16 = 0;

impl BusDevice for ACPIPMResource {
    fn debug_label(&self) -> String {
        "ACPIPMResource".to_owned()
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        let val = match info.offset as u16 {
            PM1_STATUS => self.pm1_status,
            PM1_ENABLE => self.pm1_enable,
            PM1_CONTROL => self.pm1_control,
            SLEEP_CONTROL => self.sleep_control as u16,
            SLEEP_STATUS => self.sleep_status as u16,
            _ => {
                warn!("ACPIPM: Bad read from {}", info);
                return;
            }
        };

        let val_arr = val.to_ne_bytes();
        for i in 0..std::mem::size_of::<u16>() {
            if i < data.len() {
                data[i] = val_arr[i];
            }
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        let max_bytes = std::mem::size_of::<u16>();

        // only allow maximum max_bytes to write
        if data.len() > max_bytes {
            warn!("ACPIPM: bad write size: {}", data.len());
            return;
        }

        let mut val_arr = u16::to_ne_bytes(0u16);
        for i in 0..std::mem::size_of::<u16>() {
            if i < data.len() {
                val_arr[i] = data[i];
            }
        }
        let val = u16::from_ne_bytes(val_arr);

        match info.offset as u16 {
            PM1_STATUS => self.pm1_status &= !val,
            PM1_ENABLE => self.pm1_enable = val,
            PM1_CONTROL => {
                if (val & BITMASK_PM1CNT_SLEEP_ENABLE) == BITMASK_PM1CNT_SLEEP_ENABLE {
                    if val & BITMASK_PM1CNT_SLEEP_TYPE == SLEEP_TYPE_S5 {
                        if let Err(e) = self.exit_evt.write(1) {
                            error!("ACPIPM: failed to trigger exit event: {}", e);
                        }
                    } else if let Err(e) = self.suspend_evt.write(1) {
                        error!("ACPIPM: failed to trigger suspend event: {}", e);
                    }
                }
                self.pm1_control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
            }
            SLEEP_CONTROL => {
                let sleep_control = val as u8;
                if (sleep_control & BITMASK_SLEEPCNT_SLEEP_ENABLE) == BITMASK_SLEEPCNT_SLEEP_ENABLE
                {
                    if let Err(e) = self.suspend_evt.write(1) {
                        error!("ACPIPM: failed to trigger suspend event: {}", e);
                    }
                }
                self.sleep_control = sleep_control as u8 & !BITMASK_SLEEPCNT_SLEEP_ENABLE;
            }
            SLEEP_STATUS => self.sleep_status &= !val as u8,
            _ => {
                warn!("ACPIPM: Bad write to {}", info);
            }
        };
    }
}

impl BusResumeDevice for ACPIPMResource {
    fn resume_imminent(&mut self) {
        let val = self.pm1_status;
        self.pm1_status = val | BITMASK_PM1CNT_WAKE_STATUS;

        let val = self.sleep_status;
        self.sleep_status = val | BITMASK_SLEEPCNT_WAKE_STATUS;
    }
}

impl Aml for ACPIPMResource {
    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
        // S1
        aml::Name::new(
            "_S1_".into(),
            &aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
        )
        .to_aml_bytes(bytes);

        // S5
        aml::Name::new(
            "_S5_".into(),
            &aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
        )
        .to_aml_bytes(bytes);
    }
}
<|endoftext|>