<commit_before>//! Content interface
use std::fmt;
use std::ops;

use data_encoding::BASE64;
use serde::de::{self, Visitor};
use serde::{Deserialize, Serialize};

use crate::repo_commits::CommitDetails;
use crate::utils::{percent_encode, PATH};
use crate::{Future, Github, Stream};

/// Provides access to the content information for a repository
pub struct Content {
    github: Github,
    owner: String,
    repo: String,
}

impl Content {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Content {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, location: &str, ref_: &str) -> String {
        // Handle files with spaces and other characters that can mess up the
        // final URL.
        let location = percent_encode(location.as_ref(), PATH);
        let mut path = format!("/repos/{}/{}/contents{}", self.owner, self.repo, location);
        if !ref_.is_empty() {
            path += &format!("?ref={}", ref_);
        }
        path
    }

    /// Gets the contents of the location. This could be a file, symlink, or
    /// submodule. To list the contents of a directory, use `iter`.
    pub fn get(&self, location: &str, ref_: &str) -> Future<Contents> {
        self.github.get(&self.path(location, ref_))
    }

    /// Information on a single file.
    ///
    /// GitHub only supports downloading files up to 1 megabyte in size. If you
    /// need to retrieve larger files, the Git Data API must be used instead.
    pub fn file(&self, location: &str, ref_: &str) -> Future<File> {
        self.github.get(&self.path(location, ref_))
    }

    /// List the root directory.
    pub fn root(&self, ref_: &str) -> Stream<DirectoryItem> {
        self.iter("/", ref_)
    }

    /// Provides a stream over the directory items in `location`.
    ///
    /// GitHub limits the number of items returned to 1000 for this API. If you
    /// need to retrieve more items, the Git Data API must be used instead.
    pub fn iter(&self, location: &str, ref_: &str) -> Stream<DirectoryItem> {
        self.github.get_stream(&self.path(location, ref_))
    }

    /// Creates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn create(&self, location: &str, content: &[u8], message: &str) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(content),
            message: message.to_string(),
            sha: None,
        };
        self.github.put(&self.path(location, ""), json!(file))
    }

    /// Updates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn update(
        &self,
        location: &str,
        content: &[u8],
        message: &str,
        sha: &str,
    ) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(content),
            message: message.to_string(),
            sha: Some(sha.to_string()),
        };
        self.github.put(&self.path(location, ""), json!(file))
    }
}

/// Contents of a path in a repository.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Contents {
    File(File),
    Symlink(Symlink),
    Submodule(Submodule),
}

/// The type of content encoding.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Encoding {
    Base64,
    // Are there actually any other encoding types?
}

#[derive(Debug, Serialize)]
pub struct NewFile {
    pub content: String,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sha: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct NewFileResponse {
    pub commit: CommitDetails,
}

#[derive(Debug, Deserialize)]
pub struct File {
    pub encoding: Encoding,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub content: DecodedContents,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct DirectoryItem {
    #[serde(rename = "type")]
    pub _type: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Symlink {
    pub target: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Submodule {
    pub submodule_git_url: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Links {
    pub git: String,
    #[serde(rename = "self")]
    pub _self: String,
    pub html: String,
}

/// Decoded file contents.
#[derive(Debug)]
pub struct DecodedContents(Vec<u8>);

impl Into<Vec<u8>> for DecodedContents {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

impl AsRef<[u8]> for DecodedContents {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl ops::Deref for DecodedContents {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'de> Deserialize<'de> for DecodedContents {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct DecodedContentsVisitor;

        impl<'de> Visitor<'de> for DecodedContentsVisitor {
            type Value = DecodedContents;

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "base64 string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                // GitHub wraps the base64 to column 60. The base64 crate
                // doesn't handle whitespace, nor does it take a reader, so we
                // must unfortunately allocate again and remove all new lines.
                let v = v.replace("\n", "");

                let decoded = base64::decode_config(&v, base64::STANDARD).map_err(|e| match e {
                    base64::DecodeError::InvalidLength => {
                        E::invalid_length(v.len(), &"invalid base64 length")
                    }
                    base64::DecodeError::InvalidByte(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid base64 character at offset {}", offset).as_str(),
                    ),
                    base64::DecodeError::InvalidLastSymbol(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid last base64 character at offset {}", offset).as_str(),
                    ),
                })?;

                Ok(DecodedContents(decoded))
            }
        }

        deserializer.deserialize_str(DecodedContentsVisitor)
    }
}
<commit_msg>add delete functionality to contents<commit_after>//! Content interface
use std::fmt;
use std::ops;

use data_encoding::BASE64;
use serde::de::{self, Visitor};
use serde::{Deserialize, Serialize};

use crate::repo_commits::CommitDetails;
use crate::utils::{percent_encode, PATH};
use crate::{Future, Github, Stream};

/// Provides access to the content information for a repository
pub struct Content {
    github: Github,
    owner: String,
    repo: String,
}

impl Content {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Content {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, location: &str, ref_: &str) -> String {
        // Handle files with spaces and other characters that can mess up the
        // final URL.
        let location = percent_encode(location.as_ref(), PATH);
        let mut path = format!("/repos/{}/{}/contents{}", self.owner, self.repo, location);
        if !ref_.is_empty() {
            path += &format!("?ref={}", ref_);
        }
        path
    }

    /// Gets the contents of the location. This could be a file, symlink, or
    /// submodule. To list the contents of a directory, use `iter`.
    pub fn get(&self, location: &str, ref_: &str) -> Future<Contents> {
        self.github.get(&self.path(location, ref_))
    }

    /// Information on a single file.
    ///
    /// GitHub only supports downloading files up to 1 megabyte in size. If you
    /// need to retrieve larger files, the Git Data API must be used instead.
    pub fn file(&self, location: &str, ref_: &str) -> Future<File> {
        self.github.get(&self.path(location, ref_))
    }

    /// List the root directory.
    pub fn root(&self, ref_: &str) -> Stream<DirectoryItem> {
        self.iter("/", ref_)
    }

    /// Provides a stream over the directory items in `location`.
    ///
    /// GitHub limits the number of items returned to 1000 for this API. If you
    /// need to retrieve more items, the Git Data API must be used instead.
    pub fn iter(&self, location: &str, ref_: &str) -> Stream<DirectoryItem> {
        self.github.get_stream(&self.path(location, ref_))
    }

    /// Creates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn create(&self, location: &str, content: &[u8], message: &str) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(content),
            message: message.to_string(),
            sha: None,
        };
        self.github.put(&self.path(location, ""), json!(file))
    }

    /// Updates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn update(
        &self,
        location: &str,
        content: &[u8],
        message: &str,
        sha: &str,
    ) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(content),
            message: message.to_string(),
            sha: Some(sha.to_string()),
        };
        self.github.put(&self.path(location, ""), json!(file))
    }

    /// Deletes a file.
    pub fn delete(&self, location: &str, message: &str, sha: &str) -> Future<()> {
        let file = &NewFile {
            content: "".to_string(),
            message: message.to_string(),
            sha: Some(sha.to_string()),
        };
        self.github
            .delete_message(&self.path(location, ""), json!(file))
    }
}

/// Contents of a path in a repository.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Contents {
    File(File),
    Symlink(Symlink),
    Submodule(Submodule),
}

/// The type of content encoding.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Encoding {
    Base64,
    // Are there actually any other encoding types?
}

#[derive(Debug, Serialize)]
pub struct NewFile {
    #[serde(skip_serializing_if = "String::is_empty")]
    pub content: String,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sha: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct NewFileResponse {
    pub commit: CommitDetails,
}

#[derive(Debug, Deserialize)]
pub struct File {
    pub encoding: Encoding,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub content: DecodedContents,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct DirectoryItem {
    #[serde(rename = "type")]
    pub _type: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Symlink {
    pub target: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Submodule {
    pub submodule_git_url: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Links {
    pub git: String,
    #[serde(rename = "self")]
    pub _self: String,
    pub html: String,
}

/// Decoded file contents.
#[derive(Debug)]
pub struct DecodedContents(Vec<u8>);

impl Into<Vec<u8>> for DecodedContents {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

impl AsRef<[u8]> for DecodedContents {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl ops::Deref for DecodedContents {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'de> Deserialize<'de> for DecodedContents {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct DecodedContentsVisitor;

        impl<'de> Visitor<'de> for DecodedContentsVisitor {
            type Value = DecodedContents;

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "base64 string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                // GitHub wraps the base64 to column 60. The base64 crate
                // doesn't handle whitespace, nor does it take a reader, so we
                // must unfortunately allocate again and remove all new lines.
                let v = v.replace("\n", "");

                let decoded = base64::decode_config(&v, base64::STANDARD).map_err(|e| match e {
                    base64::DecodeError::InvalidLength => {
                        E::invalid_length(v.len(), &"invalid base64 length")
                    }
                    base64::DecodeError::InvalidByte(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid base64 character at offset {}", offset).as_str(),
                    ),
                    base64::DecodeError::InvalidLastSymbol(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid last base64 character at offset {}", offset).as_str(),
                    ),
                })?;

                Ok(DecodedContents(decoded))
            }
        }

        deserializer.deserialize_str(DecodedContentsVisitor)
    }
}
<|endoftext|>


<commit_before>//! This module contains the configuration of the application.
//!
//! All options are passed individually to each function and are not bundled together.
//!
//! # Examples
//!
//! ```no_run
//! # use https::Options;
//! let options = Options::parse();
//! println!("Directory to host: {}", options.hosted_directory.0);
//! ```

use clap::{AppSettings, Arg};
use std::path::PathBuf;
use std::env::temp_dir;
use std::str::FromStr;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// The directory to host.
    pub hosted_directory: (String, PathBuf),
    /// The port to host on. Default: first free port from 8000 up
    pub port: Option<u16>,
    /// Whether to allow symlinks to be requested. Default: true
    pub follow_symlinks: bool,
    /// The temp directory to write to before copying to hosted directory. Default: `None`
    pub temp_directory: Option<(String, PathBuf)>,
    /// Whether to check for index files in served directories before serving a listing. Default: true
    pub check_indices: bool,
    /// Whether to allow write operations. Default: false
    pub allow_writes: bool,
    /// Whether to encode filesystem files. Default: true
    pub encode_fs: bool,
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = app_from_crate!()
            .setting(AppSettings::ColoredHelp)
            .arg(Arg::from_usage("[DIR] 'Directory to host. Default: current working directory'")
                .validator(|s| Options::filesystem_dir_validator(s, "Directory to host")))
            .arg(Arg::from_usage("-p --port [port] 'Port to use. Default: first free port from 8000 up'").validator(Options::u16_validator))
            .arg(Arg::from_usage("-t --temp-dir [temp] 'Temporary directory. Default: $TEMP'")
                .validator(|s| Options::filesystem_dir_validator(s, "Temporary directory")))
            .arg(Arg::from_usage("-s --no-follow-symlinks 'Don't follow symlinks. Default: false'"))
            .arg(Arg::from_usage("-w --allow-write 'Allow for write operations. Default: false'"))
            .arg(Arg::from_usage("-i --no-indices 'Always generate dir listings even if index files are available. Default: false'"))
            .arg(Arg::from_usage("-e --no-encode 'Do not encode filesystem files. Default: false'"))
            .get_matches();

        let w = matches.is_present("allow-write");
        let e = !matches.is_present("no-encode");
        let dir = matches.value_of("DIR").unwrap_or(".");
        let dir_pb = fs::canonicalize(dir).unwrap();
        Options {
            hosted_directory: (dir.to_string(), dir_pb.clone()),
            port: matches.value_of("port").map(u16::from_str).map(Result::unwrap),
            follow_symlinks: !matches.is_present("no-follow-symlinks"),
            temp_directory: if w || e {
                let (temp_s, temp_pb) = if let Some(tmpdir) = matches.value_of("temp-dir") {
                    (tmpdir.to_string(), fs::canonicalize(tmpdir).unwrap())
                } else {
                    ("$TEMP".to_string(), temp_dir())
                };
                let suffix = format!("http-{}",
                                     dir_pb.into_os_string().to_str().unwrap().replace(r"\\?\", "").replace(':', "").replace('\\', "/").replace('/', "-"));

                Some((format!("{}{}{}",
                              temp_s,
                              if temp_s.ends_with("/") || temp_s.ends_with(r"\") {
                                  ""
                              } else {
                                  "/"
                              },
                              suffix),
                      temp_pb.join(suffix)))
            } else {
                None
            },
            check_indices: !matches.is_present("no-indices"),
            allow_writes: w,
            encode_fs: e,
        }
    }

    fn filesystem_dir_validator(s: String, prefix: &str) -> Result<(), String> {
        fs::canonicalize(&s).map_err(|_| format!("{} \"{}\" not found", prefix, s)).and_then(|f| if f.is_dir() {
            Ok(())
        } else {
            Err(format!("{} \"{}\" not actualy a directory", prefix, s))
        })
    }

    fn u16_validator(s: String) -> Result<(), String> {
        u16::from_str(&s).map(|_| ()).map_err(|_| format!("{} is not a valid port number", s))
    }
}
<commit_msg>Fix double dash in temp folder on Linux<commit_after>//! This module contains the configuration of the application.
//!
//! All options are passed individually to each function and are not bundled together.
//!
//! # Examples
//!
//! ```no_run
//! # use https::Options;
//! let options = Options::parse();
//! println!("Directory to host: {}", options.hosted_directory.0);
//! ```

use clap::{AppSettings, Arg};
use std::path::PathBuf;
use std::env::temp_dir;
use std::str::FromStr;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// The directory to host.
    pub hosted_directory: (String, PathBuf),
    /// The port to host on. Default: first free port from 8000 up
    pub port: Option<u16>,
    /// Whether to allow symlinks to be requested. Default: true
    pub follow_symlinks: bool,
    /// The temp directory to write to before copying to hosted directory. Default: `None`
    pub temp_directory: Option<(String, PathBuf)>,
    /// Whether to check for index files in served directories before serving a listing. Default: true
    pub check_indices: bool,
    /// Whether to allow write operations. Default: false
    pub allow_writes: bool,
    /// Whether to encode filesystem files. Default: true
    pub encode_fs: bool,
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = app_from_crate!()
            .setting(AppSettings::ColoredHelp)
            .arg(Arg::from_usage("[DIR] 'Directory to host. Default: current working directory'")
                .validator(|s| Options::filesystem_dir_validator(s, "Directory to host")))
            .arg(Arg::from_usage("-p --port [port] 'Port to use. Default: first free port from 8000 up'").validator(Options::u16_validator))
            .arg(Arg::from_usage("-t --temp-dir [temp] 'Temporary directory. Default: $TEMP'")
                .validator(|s| Options::filesystem_dir_validator(s, "Temporary directory")))
            .arg(Arg::from_usage("-s --no-follow-symlinks 'Don't follow symlinks. Default: false'"))
            .arg(Arg::from_usage("-w --allow-write 'Allow for write operations. Default: false'"))
            .arg(Arg::from_usage("-i --no-indices 'Always generate dir listings even if index files are available. Default: false'"))
            .arg(Arg::from_usage("-e --no-encode 'Do not encode filesystem files. Default: false'"))
            .get_matches();

        let w = matches.is_present("allow-write");
        let e = !matches.is_present("no-encode");
        let dir = matches.value_of("DIR").unwrap_or(".");
        let dir_pb = fs::canonicalize(dir).unwrap();
        Options {
            hosted_directory: (dir.to_string(), dir_pb.clone()),
            port: matches.value_of("port").map(u16::from_str).map(Result::unwrap),
            follow_symlinks: !matches.is_present("no-follow-symlinks"),
            temp_directory: if w || e {
                let (temp_s, temp_pb) = if let Some(tmpdir) = matches.value_of("temp-dir") {
                    (tmpdir.to_string(), fs::canonicalize(tmpdir).unwrap())
                } else {
                    ("$TEMP".to_string(), temp_dir())
                };
                let suffix = dir_pb.into_os_string().to_str().unwrap().replace(r"\\?\", "").replace(':', "").replace('\\', "/").replace('/', "-");
                let suffix = format!("http{}{}", if suffix.starts_with('-') { "" } else { "-" }, suffix);

                Some((format!("{}{}{}",
                              temp_s,
                              if temp_s.ends_with("/") || temp_s.ends_with(r"\") {
                                  ""
                              } else {
                                  "/"
                              },
                              suffix),
                      temp_pb.join(suffix)))
            } else {
                None
            },
            check_indices: !matches.is_present("no-indices"),
            allow_writes: w,
            encode_fs: e,
        }
    }

    fn filesystem_dir_validator(s: String, prefix: &str) -> Result<(), String> {
        fs::canonicalize(&s).map_err(|_| format!("{} \"{}\" not found", prefix, s)).and_then(|f| if f.is_dir() {
            Ok(())
        } else {
            Err(format!("{} \"{}\" not actualy a directory", prefix, s))
        })
    }

    fn u16_validator(s: String) -> Result<(), String> {
        u16::from_str(&s).map(|_| ()).map_err(|_| format!("{} is not a valid port number", s))
    }
}
<|endoftext|>


<commit_before>// In pythons secretstorage, this is dhcrypto.py
//
// This module implements Secret Service Session,
// including crypto
//
// rand to get integer with 1024 random bits

//use crypto::digest::Digest;
//use crypto::sha2::Sha256;

use ss::{
    SS_DBUS_NAME,
    SS_PATH,
    SS_INTERFACE_SERVICE,
    ALGORITHM_PLAIN,
};

use dbus::{
    Connection,
    Message,
    Path,
    Error,
};
use dbus::MessageItem::{
    Variant,
    Str,
    ObjectPath,
};
use std::rc::Rc;

// helper enum
pub enum EncryptionType {
    Plain,
    Dh,
}

#[derive(Debug)]
pub struct Session {
    // TODO: Should session store encryption?
    // TODO: method for getting path
    pub object_path: Path,
    server_public_key: Option<Vec<u8>>,
    aes_key: Option<Vec<u8>>,
    encrypted: bool,
    my_private_key: Vec<u8>,
    my_public_key: Vec<u8>,
}

impl Session {
    pub fn new(bus: Rc<Connection>, encryption: EncryptionType) -> Result<Self, Error> {
        // Forming message, should not fail unless bug
        let m = match encryption {
            EncryptionType::Plain => {
                Message::new_method_call(
                    SS_DBUS_NAME,
                    SS_PATH,
                    SS_INTERFACE_SERVICE,
                    "OpenSession"
                ).unwrap()
                .append(Str(ALGORITHM_PLAIN.to_owned()))
                // this argument should be input for algorithm
                .append(Variant(Box::new(Str("".to_owned()))))
            },
            EncryptionType::Dh => {
                // TODO: Change this to encrypted!
                Message::new_method_call(
                    SS_DBUS_NAME,
                    SS_PATH,
                    SS_INTERFACE_SERVICE,
                    "OpenSession"
                ).unwrap()
                .append(Str(ALGORITHM_PLAIN.to_owned()))
                // this argument should be input for algorithm
                .append(Variant(Box::new(Str("".to_owned()))))
            },
        };

        let r = try!(bus.send_with_reply_and_block(m, 2000));

        let items = r.get_items();

        // check session output
        match items.get(0) {
            Some(o) if *o == Variant(Box::new(Str("".to_owned()))) => (),
            Some(_) => {
                return Err(Error::new_custom("SSError", "Error negotiating algorithm"));
            },
            _ => {
                return Err(Error::new_custom("SSError",  "Error: no output fromOpenSession"));
            },
        };

        let object_path = match items.get(1) {
            Some(&ObjectPath(ref path)) => path.clone(),
            _ => {
                return Err(Error::new_custom("SSError",  "Error: no output fromOpenSession"));
            },
        };

        Ok(Session {
            object_path: object_path,
            server_public_key: None,
            aes_key: None,
            encrypted: false,
            my_private_key: vec![],
            my_public_key: vec![],
        })
    }

//    pub fn set_server_public_key(&mut self, server_public_key: &[u8]) {
//        ()
//    }
//
//    pub fn set_object_path(&mut self, object_path: ObjectPath) {
//        self.object_path = object_path;
//    }
}

#[cfg(test)]
mod test {
    use std::rc::Rc;
    use super::*;
    use dbus::{Connection, BusType};

    #[test]
    fn should_create_plain_session() {
        let bus = Connection::get_private(BusType::Session).unwrap();
        Session::new(Rc::new(bus), EncryptionType::Plain).unwrap();
    }

    #[test]
    fn should_create_encrypted_session() {
        let bus = Connection::get_private(BusType::Session).unwrap();
        Session::new(Rc::new(bus), EncryptionType::Dh).unwrap();
    }
}
<commit_msg>Session handling<commit_after>// In pythons secretstorage, this is dhcrypto.py
//
// This module implements Secret Service Session,
// including crypto
//
// rand to get integer with 1024 random bits

//use crypto::digest::Digest;
//use crypto::sha2::Sha256;

use ss::{
    SS_DBUS_NAME,
    SS_PATH,
    SS_INTERFACE_SERVICE,
    ALGORITHM_PLAIN,
};

use dbus::{
    Connection,
    Message,
    MessageItem,
    Path,
    Error,
};
use dbus::MessageItem::{
    Variant,
    Str,
};
use std::rc::Rc;

// helper enum
#[derive(Debug, PartialEq)]
pub enum EncryptionType {
    Plain,
    Dh,
}

#[derive(Debug)]
pub struct Session {
    // TODO: Should session store encryption? As bool or EncryptionType? also getter/setter
    pub object_path: Path,
    server_public_key: Option<Vec<u8>>,
    aes_key: Option<Vec<u8>>,
    encrypted: bool,
    my_private_key: Vec<u8>,
    my_public_key: Vec<u8>,
}

impl Session {
    pub fn new(bus: Rc<Connection>, encryption: EncryptionType) -> Result<Self, Error> {
        // Forming message, should not fail unless bug
        let m = match encryption {
            EncryptionType::Plain => {
                Message::new_method_call(
                    SS_DBUS_NAME,
                    SS_PATH,
                    SS_INTERFACE_SERVICE,
                    "OpenSession"
                ).unwrap()
                .append(Str(ALGORITHM_PLAIN.to_owned()))
                // this argument should be input for algorithm
                .append(Variant(Box::new(Str("".to_owned()))))
            },
            EncryptionType::Dh => {
                // TODO: Change this to encrypted!
                Message::new_method_call(
                    SS_DBUS_NAME,
                    SS_PATH,
                    SS_INTERFACE_SERVICE,
                    "OpenSession"
                ).unwrap()
                .append(Str(ALGORITHM_PLAIN.to_owned()))
                // this argument should be input for algorithm
                .append(Variant(Box::new(Str("".to_owned()))))
            },
        };

        let r = try!(bus.send_with_reply_and_block(m, 2000));
        let items = r.get_items();

        // check session output
        // Should this always be a Variant String?
        let session_output_dbus = try!(items
            .get(0)
            .ok_or(Error::new_custom("SSError",  "Error: no output from OpenSession"))
        );
        let session_output_variant_dbus: &MessageItem = session_output_dbus.inner().unwrap();

        let session_output = if encryption == EncryptionType::Plain {
            // plain encryption negotiation should result in empty string
            match session_output_variant_dbus.inner::<&str>().unwrap() {
                "" => vec![],
                _ => return Err(Error::new_custom("SSError", "Error negotiating algorithm")),
            }
        } else {
            // If not plain, Variant should be a vector of bytes
            let session_output_array_dbus: &Vec<_> = session_output_variant_dbus
                .inner()
                .expect("SSError, Algorithm negotiation expected Array");

            session_output_array_dbus
                .iter()
                .map(|byte_dbus| byte_dbus.inner::<u8>().unwrap())
                .collect::<Vec<_>>()
        };

        println!("{:?}", session_output);

        // get session path
        let object_path_dbus = try!(items
            .get(1)
            .ok_or(Error::new_custom("SSError",  "Error: no output from OpenSession"))
        );
        let object_path: &Path = object_path_dbus.inner().unwrap();

        Ok(Session {
            object_path: object_path.clone(),
            server_public_key: None,
            aes_key: None,
            encrypted: false,
            my_private_key: vec![],
            my_public_key: vec![],
        })
    }

    pub fn is_encrypted(&self) -> bool {
        self.encrypted
    }

//    pub fn set_server_public_key(&mut self, server_public_key: &[u8]) {
//        ()
//    }
//
//    pub fn set_object_path(&mut self, object_path: ObjectPath) {
//        self.object_path = object_path;
//    }
}

#[cfg(test)]
mod test {
    use std::rc::Rc;
    use super::*;
    use dbus::{Connection, BusType};

    #[test]
    fn should_create_plain_session() {
        let bus = Connection::get_private(BusType::Session).unwrap();
        let session = Session::new(Rc::new(bus), EncryptionType::Plain).unwrap();
        assert!(!session.is_encrypted());
    }

    #[test]
    fn should_create_encrypted_session() {
        let bus = Connection::get_private(BusType::Session).unwrap();
        let session = Session::new(Rc::new(bus), EncryptionType::Dh).unwrap();
        assert!(session.is_encrypted());
    }
}
<|endoftext|>


<commit_before>//! Transformation context

use draw_state::DrawState;
use default_draw_state;
use math::{
    abs_transform,
    identity,
    get_scale,
    Matrix2d,
    Scalar,
    Vec2d,
};

/// View transform property
#[derive(Copy, Clone)]
pub struct ViewTransform(pub Matrix2d);

/// Drawing 2d context.
#[derive(Copy, Clone)]
pub struct Context {
    /// View transformation.
    pub view: Matrix2d,
    /// Current transformation.
    pub transform: Matrix2d,
    /// Current draw state settings.
    pub draw_state: DrawState,
}

impl Context {
    /// Creates a new drawing context.
    #[inline(always)]
    pub fn new() -> Context {
        Context {
            view: identity(),
            transform: identity(),
            draw_state: *default_draw_state(),
        }
    }

    /// Creates a new drawing context in absolute coordinates.
    ///
    /// This function assumes the default coordinate system
    /// being centered with x axis pointing to the right
    /// and y axis pointing up.
    ///
    /// Returns a drawing context
    /// with origin in the upper left corner
    /// and x axis pointing to the right
    /// and y axis pointing down.
    #[inline(always)]
    pub fn abs(w: Scalar, h: Scalar) -> Context {
        let mat = abs_transform(w, h);
        Context {
            view: mat,
            transform: mat,
            draw_state: *default_draw_state(),
        }
    }

    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    pub fn view(mut self) -> Self {
        self.transform = self.view;
        self
    }

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    #[inline(always)]
    pub fn reset(mut self) -> Self {
        self.transform = identity();
        self
    }

    /// Stores the current transform as new view.
    #[inline(always)]
    pub fn store_view(mut self) -> Self {
        self.view = self.transform;
        self
    }

    /// Computes the current view size.
    #[inline(always)]
    pub fn get_view_size(&self) -> Vec2d {
        let scale = get_scale(self.view);
        [2.0 / scale[0], 2.0 / scale[1]]
    }
}

#[cfg(test)]
mod test {
    use super::Context;
    use std::num::Float;

    #[test]
    fn test_context() {
        use RelativeTransform;

        let c = Context::new();
        {
            let d = c.trans(20.0, 40.0);
            let d = d.trans(10.0, 10.0);
            let transform = d.transform;
            assert_eq!(transform[0][2], 30.0);
            assert_eq!(transform[1][2], 50.0);
        }

        let transform = c.transform;
        assert_eq!(transform[0][2], 0.0);
        assert_eq!(transform[1][2], 0.0);

        let c = c.rot_deg(90.0);
        let transform = c.transform;
        assert!((transform[0][0] - 0.0).abs() < 0.00001);
        assert!((transform[0][1] + 1.0).abs() < 0.00001);
    }

    #[test]
    fn test_scale() {
        use RelativeTransform;

        let c = Context::new();
        let c = c.scale(2.0, 3.0);
        let transform = c.transform;
        assert!((transform[0][0] - 2.0).abs() < 0.00001);
        assert!((transform[1][1] - 3.0).abs() < 0.00001);
    }
}
<commit_msg>Deleted `ViewTransform` property type<commit_after>//! Transformation context

use draw_state::DrawState;
use default_draw_state;
use math::{
    abs_transform,
    identity,
    get_scale,
    Matrix2d,
    Scalar,
    Vec2d,
};

/// Drawing 2d context.
#[derive(Copy, Clone)]
pub struct Context {
    /// View transformation.
    pub view: Matrix2d,
    /// Current transformation.
    pub transform: Matrix2d,
    /// Current draw state settings.
    pub draw_state: DrawState,
}

impl Context {
    /// Creates a new drawing context.
    #[inline(always)]
    pub fn new() -> Context {
        Context {
            view: identity(),
            transform: identity(),
            draw_state: *default_draw_state(),
        }
    }

    /// Creates a new drawing context in absolute coordinates.
    ///
    /// This function assumes the default coordinate system
    /// being centered with x axis pointing to the right
    /// and y axis pointing up.
    ///
    /// Returns a drawing context
    /// with origin in the upper left corner
    /// and x axis pointing to the right
    /// and y axis pointing down.
    #[inline(always)]
    pub fn abs(w: Scalar, h: Scalar) -> Context {
        let mat = abs_transform(w, h);
        Context {
            view: mat,
            transform: mat,
            draw_state: *default_draw_state(),
        }
    }

    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    pub fn view(mut self) -> Self {
        self.transform = self.view;
        self
    }

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    #[inline(always)]
    pub fn reset(mut self) -> Self {
        self.transform = identity();
        self
    }

    /// Stores the current transform as new view.
    #[inline(always)]
    pub fn store_view(mut self) -> Self {
        self.view = self.transform;
        self
    }

    /// Computes the current view size.
    #[inline(always)]
    pub fn get_view_size(&self) -> Vec2d {
        let scale = get_scale(self.view);
        [2.0 / scale[0], 2.0 / scale[1]]
    }
}

#[cfg(test)]
mod test {
    use super::Context;
    use std::num::Float;

    #[test]
    fn test_context() {
        use RelativeTransform;

        let c = Context::new();
        {
            let d = c.trans(20.0, 40.0);
            let d = d.trans(10.0, 10.0);
            let transform = d.transform;
            assert_eq!(transform[0][2], 30.0);
            assert_eq!(transform[1][2], 50.0);
        }

        let transform = c.transform;
        assert_eq!(transform[0][2], 0.0);
        assert_eq!(transform[1][2], 0.0);

        let c = c.rot_deg(90.0);
        let transform = c.transform;
        assert!((transform[0][0] - 0.0).abs() < 0.00001);
        assert!((transform[0][1] + 1.0).abs() < 0.00001);
    }

    #[test]
    fn test_scale() {
        use RelativeTransform;

        let c = Context::new();
        let c = c.scale(2.0, 3.0);
        let transform = c.transform;
        assert!((transform[0][0] - 2.0).abs() < 0.00001);
        assert!((transform[1][1] - 3.0).abs() < 0.00001);
    }
}
<|endoftext|>


<commit_before>//! Option parsing and management.
//!
//! Use the `Options::parse()` function to get the program's configuration,
//! as parsed from the commandline.
//!
//! # Examples
//!
//! ```no_run
//! # use cargo_update::Options;
//! let opts = Options::parse();
//! println!("{:#?}", opts);
//! ```

use clap::{self, AppSettings, SubCommand, App, Arg};
use self::super::ops::ConfigOperation;
use std::env::{self, home_dir};
use array_tool::vec::Uniq;
use std::path::PathBuf;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// Packages to update. Default: `None`
    ///
    /// If empty - update all.
    pub to_update: Vec<String>,
    /// Whether to update packages or just list them. Default: `true`
    pub update: bool,
    /// Whether to allow for just installing packages. Default: `false`
    pub install: bool,
    /// Update all packages. Default: `false`
    pub force: bool,
    /// The `cargo` home directory. Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// The `cargo` home directory. Default: `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub cargo_dir: (String, PathBuf),
}

/// Representation of the config application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ConfigOptions {
    /// The `config` file in the `cargo` home directory.
    /// Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// Crate to modify config for
    pub package: String,
    /// What to do to the config, or display with empty
    pub ops: Vec<ConfigOperation>,
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = App::new("cargo-install-update")
            .bin_name("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .validator(cargo_dir_validator),
                        Arg::from_usage("-a --all 'Update all packages'").conflicts_with("PACKAGE"),
                        Arg::from_usage("-l --list 'Don't update packages, only list and check if they need an update'"),
                        Arg::from_usage("-f --force 'Update all packages regardless if they need updating'"),
                        Arg::from_usage("-i --allow-no-update 'Allow for fresh-installing packages'"),
                        Arg::from_usage("<PACKAGE>... 'Packages to update'").conflicts_with("all").empty_values(false).min_values(1)]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update").unwrap();

        let cdir = cargo_dir();
        Options {
            to_update: if matches.is_present("all") {
                vec![]
            } else {
                let packages: Vec<_> = matches.values_of("PACKAGE").unwrap().map(String::from).collect();
                packages.unique()
            },
            update: !matches.is_present("list"),
            install: matches.is_present("allow-no-update"),
            force: matches.is_present("force"),
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            cargo_dir: cdir,
        }
    }
}

impl ConfigOptions {
    /// Parse `env`-wide command-line arguments into a `ConfigOptions` instance
    pub fn parse() -> ConfigOptions {
        let matches = App::new("cargo-install-update-config")
            .bin_name("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update-config")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables -- configuration")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .validator(cargo_dir_validator),
                        Arg::from_usage("-t --toolchain=[TOOLCHAIN] 'Toolchain to use or empty for default'"),
                        Arg::from_usage("-f --feature=[FEATURE]... 'Feature to enable'"),
                        Arg::from_usage("-n --no-feature=[DISABLED_FEATURE]... 'Feature to disable'"),
                        Arg::from_usage("-d --default-features=[DEFAULT_FEATURES] 'Whether to allow default features'")
                            .possible_values(&["1", "yes", "true", "0", "no", "false"])
                            .hide_possible_values(true),
                        Arg::from_usage("<PACKAGE> 'Package to configure'").empty_values(false)]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update-config").unwrap();

        let cdir = cargo_dir();
        ConfigOptions {
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            package: matches.value_of("PACKAGE").unwrap().to_string(),
            ops: matches.value_of("toolchain")
                .map(|t| if t.is_empty() {
                    ConfigOperation::RemoveToolchain
                } else {
                    ConfigOperation::SetToolchain(t.to_string())
                })
                .into_iter()
                .chain(matches.values_of("feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::AddFeature))
                .chain(matches.values_of("no-feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::RemoveFeature))
                .chain(matches.value_of("default-features").map(|d| ["1", "yes", "true"].contains(&d)).map(ConfigOperation::DefaultFeatures).into_iter())
                .collect(),
        }
    }
}

fn cargo_dir() -> (String, PathBuf) {
    match env::var("CARGO_HOME").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
        Ok(ch) => ("$CARGO_HOME".to_string(), ch),
        Err(()) =>
                match home_dir().and_then(|hd| hd.canonicalize().ok()) {
                    Some(mut hd) => {
                        hd.push(".cargo");

                        fs::create_dir_all(&hd).unwrap();
                        ("$HOME/.cargo".to_string(), hd)
                    }
                    None => {
                        clap::Error {
                                message: "$CARGO_HOME and home directory invalid, please specify the cargo home directory with the -c option".to_string(),
                                kind: clap::ErrorKind::MissingRequiredArgument,
                                info: None,
                            }
                            .exit()
                    }
                },
    }
}

fn cargo_dir_validator(s: String) -> Result<(), String> {
    fs::canonicalize(&s).map(|_| ()).map_err(|_| format!("Cargo directory \"{}\" not found", s))
}
<commit_msg>Alias --root to --cargo-dir<commit_after>//! Option parsing and management.
//!
//! Use the `Options::parse()` function to get the program's configuration,
//! as parsed from the commandline.
//!
//! # Examples
//!
//! ```no_run
//! # use cargo_update::Options;
//! let opts = Options::parse();
//! println!("{:#?}", opts);
//! ```

use clap::{self, AppSettings, SubCommand, App, Arg};
use self::super::ops::ConfigOperation;
use std::env::{self, home_dir};
use array_tool::vec::Uniq;
use std::path::PathBuf;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// Packages to update. Default: `None`
    ///
    /// If empty - update all.
    pub to_update: Vec<String>,
    /// Whether to update packages or just list them. Default: `true`
    pub update: bool,
    /// Whether to allow for just installing packages. Default: `false`
    pub install: bool,
    /// Update all packages. Default: `false`
    pub force: bool,
    /// The `cargo` home directory. Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// The `cargo` home directory. Default: `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub cargo_dir: (String, PathBuf),
}

/// Representation of the config application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ConfigOptions {
    /// The `config` file in the `cargo` home directory.
    /// Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// Crate to modify config for
    pub package: String,
    /// What to do to the config, or display with empty
    pub ops: Vec<ConfigOperation>,
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = App::new("cargo-install-update")
            .bin_name("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .visible_alias("root")
                            .validator(cargo_dir_validator),
                        Arg::from_usage("-a --all 'Update all packages'").conflicts_with("PACKAGE"),
                        Arg::from_usage("-l --list 'Don't update packages, only list and check if they need an update'"),
                        Arg::from_usage("-f --force 'Update all packages regardless if they need updating'"),
                        Arg::from_usage("-i --allow-no-update 'Allow for fresh-installing packages'"),
                        Arg::from_usage("<PACKAGE>... 'Packages to update'").conflicts_with("all").empty_values(false).min_values(1)]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update").unwrap();

        let cdir = cargo_dir();
        Options {
            to_update: if matches.is_present("all") {
                vec![]
            } else {
                let packages: Vec<_> = matches.values_of("PACKAGE").unwrap().map(String::from).collect();
                packages.unique()
            },
            update: !matches.is_present("list"),
            install: matches.is_present("allow-no-update"),
            force: matches.is_present("force"),
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            cargo_dir: cdir,
        }
    }
}

impl ConfigOptions {
    /// Parse `env`-wide command-line arguments into a `ConfigOptions` instance
    pub fn parse() -> ConfigOptions {
        let matches = App::new("cargo-install-update-config")
            .bin_name("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update-config")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables -- configuration")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .validator(cargo_dir_validator),
                        Arg::from_usage("-t --toolchain=[TOOLCHAIN] 'Toolchain to use or empty for default'"),
                        Arg::from_usage("-f --feature=[FEATURE]... 'Feature to enable'"),
                        Arg::from_usage("-n --no-feature=[DISABLED_FEATURE]... 'Feature to disable'"),
                        Arg::from_usage("-d --default-features=[DEFAULT_FEATURES] 'Whether to allow default features'")
                            .possible_values(&["1", "yes", "true", "0", "no", "false"])
                            .hide_possible_values(true),
                        Arg::from_usage("<PACKAGE> 'Package to configure'").empty_values(false)]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update-config").unwrap();

        let cdir = cargo_dir();
        ConfigOptions {
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            package: matches.value_of("PACKAGE").unwrap().to_string(),
            ops: matches.value_of("toolchain")
                .map(|t| if t.is_empty() {
                    ConfigOperation::RemoveToolchain
                } else {
                    ConfigOperation::SetToolchain(t.to_string())
                })
                .into_iter()
                .chain(matches.values_of("feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::AddFeature))
                .chain(matches.values_of("no-feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::RemoveFeature))
                .chain(matches.value_of("default-features").map(|d| ["1", "yes", "true"].contains(&d)).map(ConfigOperation::DefaultFeatures).into_iter())
                .collect(),
        }
    }
}

fn cargo_dir() -> (String, PathBuf) {
    match env::var("CARGO_HOME").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
        Ok(ch) => ("$CARGO_HOME".to_string(), ch),
        Err(()) =>
                match home_dir().and_then(|hd| hd.canonicalize().ok()) {
                    Some(mut hd) => {
                        hd.push(".cargo");

                        fs::create_dir_all(&hd).unwrap();
                        ("$HOME/.cargo".to_string(), hd)
                    }
                    None => {
                        clap::Error {
                                message: "$CARGO_HOME and home directory invalid, please specify the cargo home directory with the -c option".to_string(),
                                kind: clap::ErrorKind::MissingRequiredArgument,
                                info: None,
                            }
                            .exit()
                    }
                },
    }
}

fn cargo_dir_validator(s: String) -> Result<(), String> {
    fs::canonicalize(&s).map(|_| ()).map_err(|_| format!("Cargo directory \"{}\" not found", s))
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::BTreeMap;

use serde::ser::Serialize;
use serde_json::value::{to_value, Map, Value};

use crate::errors::{Error, Result as TeraResult};

/// The struct that holds the context of a template rendering.
///
/// Light wrapper around a `BTreeMap` for easier insertions of Serializable
/// values
#[derive(Debug, Clone, PartialEq)]
pub struct Context {
    data: BTreeMap<String, Value>,
}

impl Context {
    /// Initializes an empty context
    pub fn new() -> Self {
        Context { data: BTreeMap::new() }
    }

    /// Converts the `val` parameter to `Value` and insert it into the context
    ///
    /// ```rust,ignore
    /// let mut context = Context::new();
    /// // user is an instance of a struct implementing `Serialize`
    /// context.insert("number_users", 42);
    /// ```
    pub fn insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) {
        self.data.insert(key.into(), to_value(val).unwrap());
    }

    /// Appends the data of the `source` parameter to `self`, overwriting existing keys.
    /// The source context will be dropped.
    ///
    /// ```rust,ignore
    /// let mut target = Context::new();
    /// target.insert("a", 1);
    /// target.insert("b", 2);
    /// let mut source = Context::new();
    /// source.insert("b", 3);
    /// source.insert("d", 4);
    /// target.extend(source);
    /// ```
    pub fn extend(&mut self, mut source: Context) {
        self.data.append(&mut source.data);
    }

    /// Converts the context to a `serde_json::Value` consuming the context
    pub fn into_json(self) -> Value {
        let mut m = Map::new();
        for (key, value) in self.data {
            m.insert(key, value);
        }
        Value::Object(m)
    }

    /// Takes a serde-json `Value` and convert it into a `Context` with no overhead/cloning
    pub fn from_value(obj: Value) -> TeraResult<Self> {
        match obj {
            Value::Object(m) => {
                let mut data = BTreeMap::new();
                for (key, value) in m {
                    data.insert(key, value);
                }
                Ok(Context { data })
            }
            _ => Err(Error::msg(
                "Creating a Context from a Value/Serialize requires it being a JSON object",
            )),
        }
    }

    /// Takes something that impl Serialize and create a context with it.
    /// Meant to be used if you have a hashmap or a struct and don't want to insert values
    /// one by one in the context
    pub fn from_serialize(value: impl Serialize) -> TeraResult<Self> {
        let obj = to_value(value).map_err(Error::json)?;
        Context::from_value(obj)
    }

    /// Returns the value at a given key index.
    pub fn get(&self, index: &str) -> Option<&Value> {
        self.data.get(index)
    }

    /// Checks if a value exists at a specific index.
    pub fn contains_key(&self, index: &str) -> bool {
        self.data.contains_key(index)
    }
}

impl Default for Context {
    fn default() -> Context {
        Context::new()
    }
}

pub trait ValueRender {
    fn render(&self) -> Cow<str>;
}

// Convert serde Value to String
impl ValueRender for Value {
    fn render(&self) -> Cow<str> {
        match *self {
            Value::String(ref s) => Cow::Borrowed(s),
            Value::Number(ref i) => Cow::Owned(i.to_string()),
            Value::Bool(i) => Cow::Owned(i.to_string()),
            Value::Null => Cow::Owned(String::new()),
            Value::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    if buf.len() > 1 {
                        buf.push_str(", ");
                    }
                    buf.push_str(i.render().as_ref());
                }
                buf.push(']');
                Cow::Owned(buf)
            }
            Value::Object(_) => Cow::Borrowed("[object]"),
        }
    }
}

pub trait ValueNumber {
    fn to_number(&self) -> Result<f64, ()>;
}
// Needed for all the maths
// Convert everything to f64, seems like a terrible idea
impl ValueNumber for Value {
    fn to_number(&self) -> Result<f64, ()> {
        match *self {
            Value::Number(ref i) => Ok(i.as_f64().unwrap()),
            _ => Err(()),
        }
    }
}

// From handlebars-rust
pub trait ValueTruthy {
    fn is_truthy(&self) -> bool;
}

impl ValueTruthy for Value {
    fn is_truthy(&self) -> bool {
        match *self {
            Value::Number(ref i) => {
                if i.is_i64() {
                    return i.as_i64().unwrap() != 0;
                }
                if i.is_u64() {
                    return i.as_u64().unwrap() != 0;
                }
                let f = i.as_f64().unwrap();
                f != 0.0 && !f.is_nan()
            }
            Value::Bool(ref i) => *i,
            Value::Null => false,
            Value::String(ref i) => !i.is_empty(),
            Value::Array(ref i) => !i.is_empty(),
            Value::Object(ref i) => !i.is_empty(),
        }
    }
}

/// Converts a dotted path to a json pointer one
#[inline]
pub fn get_json_pointer(key: &str) -> String {
    ["/", &key.replace(".", "/")].join("")
}

#[cfg(test)]
mod tests {
    use super::*;

    use serde_json::json;
    use std::collections::HashMap;

    #[test]
    fn can_extend_context() {
        let mut target = Context::new();
        target.insert("a", &1);
        target.insert("b", &2);
        let mut source = Context::new();
        source.insert("b", &3);
        source.insert("c", &4);
        target.extend(source);
        assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
        assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
        assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
    }

    #[test]
    fn can_create_context_from_value() {
        let obj = json!({
            "name": "bob",
            "age": 25
        });
        let context_from_value = Context::from_value(obj).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("age", &25);
        assert_eq!(context_from_value, context);
    }

    #[test]
    fn can_create_context_from_impl_serialize() {
        let mut map = HashMap::new();
        map.insert("name", "bob");
        map.insert("last_name", "something");
        let context_from_serialize = Context::from_serialize(&map).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("last_name", "something");
        assert_eq!(context_from_serialize, context);
    }
}
<commit_msg>Add “Context::try_insert” − Update some “Context” doc tests (#577)<commit_after>use std::borrow::Cow;
use std::collections::BTreeMap;

use serde::ser::Serialize;
use serde_json::value::{to_value, Map, Value};

use crate::errors::{Error, Result as TeraResult};

/// The struct that holds the context of a template rendering.
///
/// Light wrapper around a `BTreeMap` for easier insertions of Serializable
/// values
#[derive(Debug, Clone, PartialEq)]
pub struct Context {
    data: BTreeMap<String, Value>,
}

impl Context {
    /// Initializes an empty context
    pub fn new() -> Self {
        Context { data: BTreeMap::new() }
    }

    /// Converts the `val` parameter to `Value` and insert it into the context.
    ///
    /// Panics if the serialization fails.
    ///
    /// ```rust
    /// # use tera::Context;
    /// let mut context = tera::Context::new();
    /// context.insert("number_users", &42);
    /// ```
    pub fn insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) {
        self.data.insert(key.into(), to_value(val).unwrap());
    }

    /// Converts the `val` parameter to `Value` and insert it into the context.
    ///
    /// Returns an error if the serialization fails.
    ///
    /// ```rust
    /// # use tera::Context;
    /// # struct CannotBeSerialized;
    /// # impl serde::Serialize for CannotBeSerialized {
    /// #     fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
    /// #         Err(serde::ser::Error::custom("Error"))
    /// #     }
    /// # }
    /// # let user = CannotBeSerialized;
    /// let mut context = Context::new();
    /// // user is an instance of a struct implementing `Serialize`
    /// if let Err(_) = context.try_insert("number_users", &user) {
    ///     // Serialization failed
    /// }
    /// ```
    pub fn try_insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) -> TeraResult<()> {
        self.data.insert(key.into(), to_value(val)?);

        Ok(())
    }

    /// Appends the data of the `source` parameter to `self`, overwriting existing keys.
    /// The source context will be dropped.
    ///
    /// ```rust
    /// # use tera::Context;
    /// let mut target = Context::new();
    /// target.insert("a", &1);
    /// target.insert("b", &2);
    /// let mut source = Context::new();
    /// source.insert("b", &3);
    /// source.insert("d", &4);
    /// target.extend(source);
    /// ```
    pub fn extend(&mut self, mut source: Context) {
        self.data.append(&mut source.data);
    }

    /// Converts the context to a `serde_json::Value` consuming the context.
    pub fn into_json(self) -> Value {
        let mut m = Map::new();
        for (key, value) in self.data {
            m.insert(key, value);
        }
        Value::Object(m)
    }

    /// Takes a serde-json `Value` and convert it into a `Context` with no overhead/cloning.
    pub fn from_value(obj: Value) -> TeraResult<Self> {
        match obj {
            Value::Object(m) => {
                let mut data = BTreeMap::new();
                for (key, value) in m {
                    data.insert(key, value);
                }
                Ok(Context { data })
            }
            _ => Err(Error::msg(
                "Creating a Context from a Value/Serialize requires it being a JSON object",
            )),
        }
    }

    /// Takes something that impl Serialize and create a context with it.
    /// Meant to be used if you have a hashmap or a struct and don't want to insert values
    /// one by one in the context.
    pub fn from_serialize(value: impl Serialize) -> TeraResult<Self> {
        let obj = to_value(value).map_err(Error::json)?;
        Context::from_value(obj)
    }

    /// Returns the value at a given key index.
    pub fn get(&self, index: &str) -> Option<&Value> {
        self.data.get(index)
    }

    /// Checks if a value exists at a specific index.
    pub fn contains_key(&self, index: &str) -> bool {
        self.data.contains_key(index)
    }
}

impl Default for Context {
    fn default() -> Context {
        Context::new()
    }
}

pub trait ValueRender {
    fn render(&self) -> Cow<str>;
}

// Convert serde Value to String.
impl ValueRender for Value {
    fn render(&self) -> Cow<str> {
        match *self {
            Value::String(ref s) => Cow::Borrowed(s),
            Value::Number(ref i) => Cow::Owned(i.to_string()),
            Value::Bool(i) => Cow::Owned(i.to_string()),
            Value::Null => Cow::Owned(String::new()),
            Value::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    if buf.len() > 1 {
                        buf.push_str(", ");
                    }
                    buf.push_str(i.render().as_ref());
                }
                buf.push(']');
                Cow::Owned(buf)
            }
            Value::Object(_) => Cow::Borrowed("[object]"),
        }
    }
}

pub trait ValueNumber {
    fn to_number(&self) -> Result<f64, ()>;
}
// Needed for all the maths
// Convert everything to f64, seems like a terrible idea
impl ValueNumber for Value {
    fn to_number(&self) -> Result<f64, ()> {
        match *self {
            Value::Number(ref i) => Ok(i.as_f64().unwrap()),
            _ => Err(()),
        }
    }
}

// From handlebars-rust
pub trait ValueTruthy {
    fn is_truthy(&self) -> bool;
}

impl ValueTruthy for Value {
    fn is_truthy(&self) -> bool {
        match *self {
            Value::Number(ref i) => {
                if i.is_i64() {
                    return i.as_i64().unwrap() != 0;
                }
                if i.is_u64() {
                    return i.as_u64().unwrap() != 0;
                }
                let f = i.as_f64().unwrap();
                f != 0.0 && !f.is_nan()
            }
            Value::Bool(ref i) => *i,
            Value::Null => false,
            Value::String(ref i) => !i.is_empty(),
            Value::Array(ref i) => !i.is_empty(),
            Value::Object(ref i) => !i.is_empty(),
        }
    }
}

/// Converts a dotted path to a json pointer one
#[inline]
pub fn get_json_pointer(key: &str) -> String {
    ["/", &key.replace(".", "/")].join("")
}

#[cfg(test)]
mod tests {
    use super::*;

    use serde_json::json;
    use std::collections::HashMap;

    #[test]
    fn can_extend_context() {
        let mut target = Context::new();
        target.insert("a", &1);
        target.insert("b", &2);
        let mut source = Context::new();
        source.insert("b", &3);
        source.insert("c", &4);
        target.extend(source);
        assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
        assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
        assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
    }

    #[test]
    fn can_create_context_from_value() {
        let obj = json!({
            "name": "bob",
            "age": 25
        });
        let context_from_value = Context::from_value(obj).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("age", &25);
        assert_eq!(context_from_value, context);
    }

    #[test]
    fn can_create_context_from_impl_serialize() {
        let mut map = HashMap::new();
        map.insert("name", "bob");
        map.insert("last_name", "something");
        let context_from_serialize = Context::from_serialize(&map).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("last_name", "something");
        assert_eq!(context_from_serialize, context);
    }
}
<|endoftext|>


<commit_before>use Query;
use Token;

use std::collections::{HashMap, BTreeMap};

/// Result of a query
pub struct QueryReturn {
    text: String,
    condition: Option<bool>,
}

/// Trait describing an object that can be queried for variables
pub trait Queryable {
    fn query(&self, key: &str) -> Option<String>;
}

/// Trait describing an object that contains a dictionary of functions
pub trait Context {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>>;
}

/// Errors found while evaluating query
#[derive(Debug)]
pub enum EvalError {
    /// Function used is not in the current context
    /// String passed is the function name
    FunctionNotFound(String),
}

pub type EvalResult<T> = Result<T, EvalError>;

/// The General function signature for formatting function calls
/// > note: very likely to change
pub type EvalFunc = (Fn(&Vec<Token>) -> EvalResult<QueryReturn>);

impl Query {
    /// Evaluate the query with a queryable object to be based off and a
    /// context
    pub fn eval(&self, queryable: &Queryable, context: &Context) -> EvalResult<String> {
        let mut output = String::new();
        for token in &self.tokens {
            let result = match eval_token(token, queryable, context) {
                Ok(txt) => txt,
                Err(err) => return Err(err),
            };
            output.push_str(&result.text);
        }
        Ok(output)
    }
}

fn eval_token(token: &Token, queryable: &Queryable, context: &Context) -> EvalResult<QueryReturn> {
    match token {
        &Token::Text(ref t) => {
            Ok(QueryReturn {
                text: t.to_owned(),
                condition: None,
            })
        }
        &Token::Variable(ref v) => {
            match queryable.query(v) {
                Some(r) => {
                    Ok(QueryReturn {
                        text: r,
                        condition: Some(true),
                    })
                }
                None => {
                    Ok(QueryReturn {
                        text: String::new(),
                        condition: Some(false),
                    })
                }
            }
        }
        &Token::Function(ref f, ref arg) => {
            match context.get_func(f) {
                Some(func) => func(arg),
                None => {
                    return Err(EvalError::FunctionNotFound(f.to_owned()));
                }
            }
        }
    }
}

// Example Implementation for Queryable and Context

impl Queryable for HashMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for HashMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

impl Queryable for BTreeMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for BTreeMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use Query;
    use Token;
    use std::collections::HashMap;

    #[test]
    fn test_run() {

        let mut map = HashMap::new();
        map.insert("name".to_owned(), "Dave".to_owned());

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello Dave".to_owned(), result);
    }

    #[test]
    fn test_run_func() {

        let map = HashMap::new();

        let mut func = HashMap::<String, Box<EvalFunc>>::new();
        func.insert("hi".to_owned(),
                    Box::new(|_| {
                        Ok(QueryReturn {
                            text: "hi!".to_owned(),
                            condition: None,
                        })
                    }));

        let result = Query::parse("Hello $hi()".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello hi!".to_owned(), result);
    }
}
<commit_msg>test: add tests for failure in context<commit_after>use Query;
use Token;

use std::collections::{HashMap, BTreeMap};

/// Result of a query
pub struct QueryReturn {
    text: String,
    condition: Option<bool>,
}

/// Trait describing an object that can be queried for variables
pub trait Queryable {
    fn query(&self, key: &str) -> Option<String>;
}

/// Trait describing an object that contains a dictionary of functions
pub trait Context {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>>;
}

/// Errors found while evaluating query
#[derive(Debug)]
pub enum EvalError {
    /// Function used is not in the current context
    /// String passed is the function name
    FunctionNotFound(String),
}

pub type EvalResult<T> = Result<T, EvalError>;

/// The General function signature for formatting function calls
/// > note: very likely to change
pub type EvalFunc = (Fn(&Vec<Token>) -> EvalResult<QueryReturn>);

impl Query {
    /// Evaluate the query with a queryable object to be based off and a
    /// context
    pub fn eval(&self, queryable: &Queryable, context: &Context) -> EvalResult<String> {
        let mut output = String::new();
        for token in &self.tokens {
            let result = match eval_token(token, queryable, context) {
                Ok(txt) => txt,
                Err(err) => return Err(err),
            };
            output.push_str(&result.text);
        }
        Ok(output)
    }
}

fn eval_token(token: &Token, queryable: &Queryable, context: &Context) -> EvalResult<QueryReturn> {
    match token {
        &Token::Text(ref t) => {
            Ok(QueryReturn {
                text: t.to_owned(),
                condition: None,
            })
        }
        &Token::Variable(ref v) => {
            match queryable.query(v) {
                Some(r) => {
                    Ok(QueryReturn {
                        text: r,
                        condition: Some(true),
                    })
                }
                None => {
                    Ok(QueryReturn {
                        text: String::new(),
                        condition: Some(false),
                    })
                }
            }
        }
        &Token::Function(ref f, ref arg) => {
            match context.get_func(f) {
                Some(func) => func(arg),
                None => {
                    return Err(EvalError::FunctionNotFound(f.to_owned()));
                }
            }
        }
    }
}

// Example Implementation for Queryable and Context

impl Queryable for HashMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for HashMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

impl Queryable for BTreeMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for BTreeMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use Query;
    use std::collections::HashMap;

    #[test]
    fn test_run() {

        let mut map = HashMap::new();
        map.insert("name".to_owned(), "Dave".to_owned());

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%!".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello Dave!".to_owned(), result);
    }

    #[test]
    fn test_run_unknown_variable() {

        let map = HashMap::new();

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%!".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello !".to_owned(), result);
    }

    #[test]
    fn test_run_func() {

        let map = HashMap::new();

        let mut func = HashMap::<String, Box<EvalFunc>>::new();
        func.insert("hi".to_owned(),
                    Box::new(|_| {
                        Ok(QueryReturn {
                            text: "hi!".to_owned(),
                            condition: None,
                        })
                    }));

        let result = Query::parse("Hello $hi()".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello hi!".to_owned(), result);
    }

    #[test]
    fn test_run_func_does_not_exist() {

        let map = HashMap::new();

        let func = HashMap::<String, Box<EvalFunc>>::new();

        match Query::parse("Hello $hi()".to_owned())
                  .unwrap()
                  .eval(&map, &func) {
            Ok(_) => unreachable!(),
            Err(e) => {
                match e {
                    EvalError::FunctionNotFound(_) => (),
                }
            }
        }
    }
}
<|endoftext|>


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

use target::{TargetOptions, RelroLevel};
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        has_rpath: false,
        target_family: Some("unix".to_string()),
        relro_level: RelroLevel::Full,
        linker_is_gnu: true,
        no_integrated_as: true,
        .. Default::default()
    }
}
<commit_msg>haiku/librustc_back: Remove incorrect no_integrated_as<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use target::{TargetOptions, RelroLevel};
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        has_rpath: false,
        target_family: Some("unix".to_string()),
        relro_level: RelroLevel::Full,
        linker_is_gnu: true,
        .. Default::default()
    }
}
<|endoftext|>


<commit_before>// Mostly taken from, with MIT license
// https://github.com/emk/toyos-rs/blob/master/crates/pic8259_simple/src/lib.rs
// and from, public domain:
// http://wiki.osdev.org/PIC#Programming_the_PIC_chips

use spin::Mutex;
use cpuio::{Port, UnsafePort};

// PIC ports
const PIC1_COMMAND: u16 = 0x20;
const PIC2_COMMAND: u16 = 0xA0;
const PIC1_DATA:    u16 = 0x21;
const PIC2_DATA:    u16 = 0xA1;

// PIC commands
const PIC_CMD_EOI:  u8 = 0x20;
const PIC_CMD_INIT: u8 = 0x11;

struct Pic {
    offset: u8,
    command_port: UnsafePort<u8>,
    data_port: UnsafePort<u8>,
}

impl Pic {
    fn handles_interrupt(&self, interupt_id: u8) -> bool {
        self.offset <= interupt_id && interupt_id < self.offset + 8
    }
    /// Send end of interrupt signal to pic
    unsafe fn send_eoi(&mut self) {
        self.command_port.write(PIC_CMD_EOI);
    }
}

pub struct ChainedPics {
    pics: [Pic; 2],
}

impl ChainedPics {
    pub const unsafe fn new(pic1_offset: u8, pic2_offset: u8) -> ChainedPics {
        ChainedPics {
            pics: [
                Pic {
                    offset: pic1_offset,
                    command_port:   UnsafePort::new(PIC1_COMMAND),
                    data_port:      UnsafePort::new(PIC1_DATA),
                },
                Pic {
                    offset: pic2_offset,
                    command_port:   UnsafePort::new(PIC2_COMMAND),
                    data_port:      UnsafePort::new(PIC2_DATA),
                },
            ]
        }
    }
    /// Init - remap irqs (http://wiki.osdev.org/PIC#Initialisation, https://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf)
    pub unsafe fn init(&mut self) {
        // Create local IO wait function
        let mut io_wait_port: Port<u8> = Port::new(0x80);
        let mut io_wait = || { io_wait_port.write(0) };

        // Save masks
        let mask1_orig: u8 = self.pics[0].data_port.read();
        let mask2_orig: u8 = self.pics[1].data_port.read();

        // Initialization sequence
        self.pics[0].command_port.write(PIC_CMD_INIT);
        io_wait();
        self.pics[1].command_port.write(PIC_CMD_INIT);
        io_wait();

        // Set interrupt offset
        self.pics[0].data_port.write(self.pics[0].offset);
        io_wait();
        self.pics[1].data_port.write(self.pics[1].offset);
        io_wait();

        // Introduce PICs to each other
        self.pics[0].data_port.write(4);
        io_wait();
        self.pics[1].data_port.write(2);
        io_wait();

        // Use 8086/88 (MCS-80/85) mode (http://forum.osdev.org/viewtopic.php?f=1&t=12960&start=0)
        self.pics[0].data_port.write(1);
        io_wait();
        self.pics[1].data_port.write(1);
        io_wait();

        // Restore masks
        self.pics[0].data_port.write(mask1_orig);
        self.pics[1].data_port.write(mask2_orig);
    }
    pub fn handles_interrupt(&self, interrupt_id: u8) -> bool {
        self.pics.iter().any(|p| p.handles_interrupt(interrupt_id))
    }
    pub unsafe fn notify_eoi(&mut self, interrupt_id: u8) {
        if self.handles_interrupt(interrupt_id) {
            // chain
            if self.pics[1].handles_interrupt(interrupt_id) {
                self.pics[1].send_eoi();
            }
            self.pics[0].send_eoi();
        }
    }
}

pub static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) });

pub fn init() {
    unsafe {
        PICS.lock().init();
    }
}
<commit_msg>Fix PIC IRQ masks<commit_after>// Mostly taken from, with MIT license
// https://github.com/emk/toyos-rs/blob/master/crates/pic8259_simple/src/lib.rs
// and from, public domain:
// http://wiki.osdev.org/PIC#Programming_the_PIC_chips

use spin::Mutex;
use cpuio::{Port, UnsafePort};

// PIC ports
const PIC1_COMMAND: u16 = 0x20;
const PIC2_COMMAND: u16 = 0xA0;
const PIC1_DATA:    u16 = 0x21;
const PIC2_DATA:    u16 = 0xA1;

// PIC commands
const PIC_CMD_EOI:  u8 = 0x20;
const PIC_CMD_INIT: u8 = 0x11;

struct Pic {
    offset: u8,
    command_port: UnsafePort<u8>,
    data_port: UnsafePort<u8>,
}

impl Pic {
    fn handles_interrupt(&self, interupt_id: u8) -> bool {
        self.offset <= interupt_id && interupt_id < self.offset + 8
    }
    /// Send end of interrupt signal to pic
    unsafe fn send_eoi(&mut self) {
        self.command_port.write(PIC_CMD_EOI);
    }
}

pub struct ChainedPics {
    pics: [Pic; 2],
}

impl ChainedPics {
    pub const unsafe fn new(pic1_offset: u8, pic2_offset: u8) -> ChainedPics {
        ChainedPics {
            pics: [
                Pic {
                    offset: pic1_offset,
                    command_port:   UnsafePort::new(PIC1_COMMAND),
                    data_port:      UnsafePort::new(PIC1_DATA),
                },
                Pic {
                    offset: pic2_offset,
                    command_port:   UnsafePort::new(PIC2_COMMAND),
                    data_port:      UnsafePort::new(PIC2_DATA),
                },
            ]
        }
    }
    /// Init - remap irqs (http://wiki.osdev.org/PIC#Initialisation, https://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf)
    pub unsafe fn init(&mut self) {
        // Create local IO wait function
        let mut io_wait_port: Port<u8> = Port::new(0x80);
        let mut io_wait = || { io_wait_port.write(0) };

        // Save masks
        let mut mask1: u8 = self.pics[0].data_port.read();
        let mut mask2: u8 = self.pics[1].data_port.read();

        // Initialization sequence
        self.pics[0].command_port.write(PIC_CMD_INIT);
        io_wait();
        self.pics[1].command_port.write(PIC_CMD_INIT);
        io_wait();

        // Set interrupt offset
        self.pics[0].data_port.write(self.pics[0].offset);
        io_wait();
        self.pics[1].data_port.write(self.pics[1].offset);
        io_wait();

        // Introduce PICs to each other
        self.pics[0].data_port.write(4);
        io_wait();
        self.pics[1].data_port.write(2);
        io_wait();

        // Use 8086/88 (MCS-80/85) mode (http://forum.osdev.org/viewtopic.php?f=1&t=12960&start=0)
        self.pics[0].data_port.write(1);
        io_wait();
        self.pics[1].data_port.write(1);
        io_wait();

        // Modify masks
        // http://wiki.osdev.org/IRQ#Standard_ISA_IRQs
        // http://wiki.osdev.org/8259_PIC#Masking
        mask1 &= 0b11111100; // Enable PIT and Keyboard
        mask2 &= 0b11111111; // Do nothing

        // Restore / Set masks
        self.pics[0].data_port.write(mask1);
        self.pics[1].data_port.write(mask2);
    }
    pub fn handles_interrupt(&self, interrupt_id: u8) -> bool {
        self.pics.iter().any(|p| p.handles_interrupt(interrupt_id))
    }
    pub unsafe fn notify_eoi(&mut self, interrupt_id: u8) {
        if self.handles_interrupt(interrupt_id) {
            // chain
            if self.pics[1].handles_interrupt(interrupt_id) {
                self.pics[1].send_eoi();
            }
            self.pics[0].send_eoi();
        }
    }
}

pub static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) });

pub fn init() {
    unsafe {
        PICS.lock().init();
    }
}
<|endoftext|>