<commit_before>use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::str;
use std::time::Duration;
use std::collections::HashMap;

use futures::prelude::*;
use futures::future::Either;
use futures::{Future, Stream};

use hyper::Client;

use tokio::prelude::FutureExt;
use tokio::net::UdpSocket;

use bytes::Bytes;

use async::Gateway;
use common::{messages, parsing};
use errors::SearchError;

const MAX_RESPONSE_SIZE: usize = 1500;

/// Gateway search configuration
/// SearchOptions::default() should suffice for most situations
pub struct SearchOptions {
    /// Bind address for UDP socket (defaults to all interfaces)
    pub bind_addr: SocketAddr,
    /// Broadcast address for discovery packets
    pub broadcast_address: SocketAddr,
    /// Timeout for a search iteration
    pub timeout: Option<Duration>,
}

impl Default for SearchOptions {
    fn default() -> Self {
        Self {
            bind_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
            broadcast_address: "239.255.255.250:1900".parse().unwrap(),
            timeout: Some(Duration::from_secs(3)),
        }
    }
}

/// Search for a gateway with the provided options
pub fn search_gateway(options: SearchOptions) -> impl Future<Item=Gateway, Error=SearchError> {

    // Create socket for future calls
    let socket = UdpSocket::bind(&options.bind_addr).unwrap();

    // Create future and issue request
    match options.timeout {
        Some(t) => Either::A(SearchFuture::search(socket, options.broadcast_address)
            .and_then(|search| search ).timeout(t).map_err(|e| SearchError::from(e) )),
        _ => Either::B(SearchFuture::search(socket, options.broadcast_address).and_then(|search| search )),
    }
}

pub struct SearchFuture {
    socket: UdpSocket,
    pending: HashMap<SocketAddr, SearchState>,
}

enum SearchState {
    Connecting(Box<Future<Item=Bytes, Error=SearchError> + Send>),
    Done(String),
    Error,
}

impl SearchFuture {
    // Create a new search
    fn search(socket: UdpSocket, addr: SocketAddr) -> impl Future<Item=SearchFuture, Error=SearchError> {
        debug!("sending broadcast request to: {} on interface: {:?}", addr, socket.local_addr());

        socket.send_dgram(messages::SEARCH_REQUEST.as_bytes(), &addr)
            .map(|(socket, _n)| SearchFuture{socket, pending: HashMap::new() })
            .map_err(|e| SearchError::from(e) )
    }

    // Handle a UDP response message
    fn handle_broadcast_resp(from: SocketAddr, data: &[u8]) -> Result<(SocketAddr, String), SearchError> {
        debug!("handling broadcast response from: {}, data: {:?}", from, data);

        // Convert response to text
        let text = str::from_utf8(&data)
            .map_err(|e| SearchError::from(e))?;

        // Parse socket address and path
        let (addr, path) = parsing::parse_search_result(text)?;

        Ok((SocketAddr::V4(addr), path))
    }

    // Issue a control URL request over HTTP using the provided
    fn request_control_url(addr: SocketAddr, path: String) -> Result<Box<Future<Item=Bytes, Error=SearchError> + Send>, SearchError> {
        let client = Client::new();

        let uri = match format!("http://{}{}", addr, path).parse() {
            Ok(uri) => uri,
            Err(err) => return Err(SearchError::from(err)),
        };

        debug!("requesting control url from: {}", uri);

        Ok(Box::new(client.get(uri)
            .and_then(|resp| resp.into_body().concat2() )
            .map(|chunk| chunk.into_bytes() )
            .map_err(|e| SearchError::from(e) )
        ))
    }

    // Process a control response to extract the control URL
    fn handle_control_resp(addr: SocketAddr, resp: Bytes) -> Result<String, SearchError> {
        debug!("handling control response from: {}, data: {:?}", addr, resp);

        // Create a cursor over the response data
        let c = std::io::Cursor::new(&resp);

        // Parse control URL out of body
        let url = parsing::parse_control_url(c)?;

        Ok(url)
    }
}

impl Future for SearchFuture {
    type Item=Gateway;
    type Error=SearchError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {

        // Poll for (and handle) incoming messages
        let mut buff = [0u8; MAX_RESPONSE_SIZE];
        if let Async::Ready((n, from)) = self.socket.poll_recv_from(&mut buff)? {
            // Try handle response messages
            if let Ok((addr, path)) = Self::handle_broadcast_resp(from, &buff[0..n]) {
                if !self.pending.contains_key(&addr) {
                    debug!("received broadcast response from: {}", from);

                    // Issue control request
                    let req = Self::request_control_url(addr, path)?;
                    // Store pending requests
                    self.pending.insert(addr, SearchState::Connecting(req));
                } else {
                    debug!("received duplicate broadcast response from: {}, dropping", from);
                }
            }
        }

        // Poll on any outstanding control requests
        for (addr, state) in &mut self.pending {
            // Poll if we're in the connecting state
            let resp = {
                let c = match state {
                    SearchState::Connecting(c) => c,
                    _ => continue,
                };

                match c.poll()? {
                    Async::Ready(resp) => resp,
                    _ => continue,
                }
            };

            // Handle any responses
            if let Ok(url) = Self::handle_control_resp(*addr, resp) {
                debug!("received control url from: {} (url: {})", addr, url);
                *state = SearchState::Done(url.clone());

                match addr {
                    SocketAddr::V4(a) => {
                        let g = Gateway::new(*a, url);
                        return Ok(Async::Ready(g));
                    }
                    _ => warn!("unsupported IPv6 gateway response from addr: {}", addr),
                }

            } else {
                *state = SearchState::Error;
            }
        }

        Ok(Async::NotReady)
    }
}
<commit_msg>cleaned up debug logging info<commit_after>use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::str;
use std::time::Duration;
use std::collections::HashMap;

use futures::prelude::*;
use futures::future::Either;
use futures::{Future, Stream};

use hyper::Client;

use tokio::prelude::FutureExt;
use tokio::net::UdpSocket;

use bytes::Bytes;

use async::Gateway;
use common::{messages, parsing};
use errors::SearchError;

const MAX_RESPONSE_SIZE: usize = 1500;

/// Gateway search configuration
/// SearchOptions::default() should suffice for most situations
pub struct SearchOptions {
    /// Bind address for UDP socket (defaults to all interfaces)
    pub bind_addr: SocketAddr,
    /// Broadcast address for discovery packets
    pub broadcast_address: SocketAddr,
    /// Timeout for a search iteration
    pub timeout: Option<Duration>,
}

impl Default for SearchOptions {
    fn default() -> Self {
        Self {
            bind_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
            broadcast_address: "239.255.255.250:1900".parse().unwrap(),
            timeout: Some(Duration::from_secs(10)),
        }
    }
}

/// Search for a gateway with the provided options
pub fn search_gateway(options: SearchOptions) -> impl Future<Item=Gateway, Error=SearchError> {

    // Create socket for future calls
    let socket = UdpSocket::bind(&options.bind_addr).unwrap();

    // Create future and issue request
    match options.timeout {
        Some(t) => Either::A(SearchFuture::search(socket, options.broadcast_address)
            .and_then(|search| search ).timeout(t).map_err(|e| SearchError::from(e) )),
        _ => Either::B(SearchFuture::search(socket, options.broadcast_address).and_then(|search| search )),
    }
}

pub struct SearchFuture {
    socket: UdpSocket,
    pending: HashMap<SocketAddr, SearchState>,
}

enum SearchState {
    Connecting(Box<Future<Item=Bytes, Error=SearchError> + Send>),
    Done(String),
    Error,
}

impl SearchFuture {
    // Create a new search
    fn search(socket: UdpSocket, addr: SocketAddr) -> impl Future<Item=SearchFuture, Error=SearchError> {
        debug!("sending broadcast request to: {} on interface: {:?}", addr, socket.local_addr());

        socket.send_dgram(messages::SEARCH_REQUEST.as_bytes(), &addr)
            .map(|(socket, _n)| SearchFuture{socket, pending: HashMap::new() })
            .map_err(|e| SearchError::from(e) )
    }

    // Handle a UDP response message
    fn handle_broadcast_resp(from: SocketAddr, data: &[u8]) -> Result<(SocketAddr, String), SearchError> {
        debug!("handling broadcast response from: {}", from);

        // Convert response to text
        let text = str::from_utf8(&data)
            .map_err(|e| SearchError::from(e))?;

        // Parse socket address and path
        let (addr, path) = parsing::parse_search_result(text)?;

        Ok((SocketAddr::V4(addr), path))
    }

    // Issue a control URL request over HTTP using the provided
    fn request_control_url(addr: SocketAddr, path: String) -> Result<Box<Future<Item=Bytes, Error=SearchError> + Send>, SearchError> {
        let client = Client::new();

        let uri = match format!("http://{}{}", addr, path).parse() {
            Ok(uri) => uri,
            Err(err) => return Err(SearchError::from(err)),
        };

        debug!("requesting control url from: {}", uri);

        Ok(Box::new(client.get(uri)
            .and_then(|resp| resp.into_body().concat2() )
            .map(|chunk| chunk.into_bytes() )
            .map_err(|e| SearchError::from(e) )
        ))
    }

    // Process a control response to extract the control URL
    fn handle_control_resp(addr: SocketAddr, resp: Bytes) -> Result<String, SearchError> {
        debug!("handling control response from: {}", addr);

        // Create a cursor over the response data
        let c = std::io::Cursor::new(&resp);

        // Parse control URL out of body
        let url = parsing::parse_control_url(c)?;

        Ok(url)
    }
}

impl Future for SearchFuture {
    type Item=Gateway;
    type Error=SearchError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {

        // Poll for (and handle) incoming messages
        let mut buff = [0u8; MAX_RESPONSE_SIZE];
        if let Async::Ready((n, from)) = self.socket.poll_recv_from(&mut buff)? {
            // Try handle response messages
            if let Ok((addr, path)) = Self::handle_broadcast_resp(from, &buff[0..n]) {
                if !self.pending.contains_key(&addr) {
                    debug!("received broadcast response from: {}", from);

                    // Issue control request
                    let req = Self::request_control_url(addr, path)?;
                    // Store pending requests
                    self.pending.insert(addr, SearchState::Connecting(req));
                } else {
                    debug!("received duplicate broadcast response from: {}, dropping", from);
                }
            }
        }

        // Poll on any outstanding control requests
        for (addr, state) in &mut self.pending {
            // Poll if we're in the connecting state
            let resp = {
                let c = match state {
                    SearchState::Connecting(c) => c,
                    _ => continue,
                };

                match c.poll()? {
                    Async::Ready(resp) => resp,
                    _ => continue,
                }
            };

            // Handle any responses
            if let Ok(url) = Self::handle_control_resp(*addr, resp) {
                debug!("received control url from: {} (url: {})", addr, url);
                *state = SearchState::Done(url.clone());

                match addr {
                    SocketAddr::V4(a) => {
                        let g = Gateway::new(*a, url);
                        return Ok(Async::Ready(g));
                    }
                    _ => warn!("unsupported IPv6 gateway response from addr: {}", addr),
                }

            } else {
                *state = SearchState::Error;
            }
        }

        Ok(Async::NotReady)
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::fmt;
use std::path::Path;
use std::io::BufReader;
use std::borrow::Cow;

use plist::serde::deserialize;
use walkdir::WalkDir;
#[cfg(target_os="macos")]
use osascript;
#[cfg(target_os="macos")]
use unix_daemonize::{daemonize_redirect, ChdirMode};
use regex::Regex;

use prelude::*;
use utils::{TempFile, expand_vars};

#[derive(Deserialize, Debug)]
pub struct InfoPlist {
    #[serde(rename="CFBundleName")]
    name: String,
    #[serde(rename="CFBundleIdentifier")]
    bundle_id: String,
    #[serde(rename="CFBundleShortVersionString")]
    version: String,
    #[serde(rename="CFBundleVersion")]
    build: String,
}

impl fmt::Display for InfoPlist {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.name(), &self.version)
    }
}

fn var_from_env(name: &str) -> String {
    env::var(name).unwrap_or("".into())
}

pub fn expand_xcodevars<'a, F: Fn(&str) -> String>(s: &'a str, f: F) -> Cow<'a, str> {
    lazy_static! {
        static ref SEP_RE: Regex = Regex::new(r"[\s/]+").unwrap();
    }
    expand_vars(s, |key| {
        if key == "" {
            return "".into();
        }
        let mut iter = key.splitn(2, ':');
        let value = f(iter.next().unwrap());
        match iter.next() {
            Some("rfc1034identifier") => {
                SEP_RE.replace_all(&value, "-").into_owned()
            },
            Some("identifier") => {
                SEP_RE.replace_all(&value, "_").into_owned()
            },
            None | Some(_) => value
        }
    })
}

impl InfoPlist {

    pub fn discover_from_path<P: AsRef<Path>>(path: P) -> Result<Option<InfoPlist>> {
        let fpl_fn = Some("info.plist".to_string());
        for dent_res in WalkDir::new(path.as_ref()) {
            let dent = dent_res?;
            if dent.file_name().to_str().map(|x| x.to_lowercase()) == fpl_fn {
                let md = dent.metadata()?;
                if md.is_file() {
                    return Ok(Some(InfoPlist::from_path(dent.path())?));
                }
            }
        }
        Ok(None)
    }

    pub fn discover_from_env() -> Result<Option<InfoPlist>> {
        if let Ok(path) = env::var("INFOPLIST_FILE") {
            Ok(Some(InfoPlist::from_path(path)?))
        } else {
            Ok(None)
        }
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<InfoPlist> {
        let f = fs::File::open(path.as_ref()).chain_err(||
            Error::from("Could not open Info.plist file"))?;
        let mut rdr = BufReader::new(f);
        Ok(deserialize(&mut rdr).chain_err(||
            Error::from("Could not parse Info.plist file"))?)
    }

    pub fn version(&self) -> &str {
        &self.version
    }

    pub fn build(&self) -> &str {
        &self.build
    }

    pub fn name<'a>(&'a self) -> Cow<'a, str> {
        expand_xcodevars(&self.name, var_from_env)
    }

    pub fn bundle_id<'a>(&'a self) -> Cow<'a, str> {
        expand_xcodevars(&self.bundle_id, var_from_env)
    }

    /// This is similar to `bundle_id` but the product name that might be
    /// referenced is explicitly passed in instead of being picked up
    /// from the environment if missing there.  The reason for this is that
    /// in some cases (react-native with code push) we are not run from an
    /// xcode build step so that information might not be available.
    pub fn derived_bundle_id<'a>(&'a self, product: &str) -> Cow<'a, str> {
        let f = |var: &str| -> String {
            let rv = var_from_env(var);
            if rv.is_empty() && (var == "PRODUCT_NAME" || var == "TARGET_NAME") {
                product.to_string()
            } else {
                rv
            }
        };
        expand_xcodevars(&self.bundle_id, f)
    }
}

/// Helper struct that allows the current execution to detach from
/// the xcode console and continue in the background.  This becomes
/// a dummy shim for non xcode runs or platforms.
pub struct MayDetach<'a> {
    output_file: Option<TempFile>,
    #[allow(dead_code)]
    task_name: &'a str,
}

impl<'a> MayDetach<'a> {
    fn new(task_name: &'a str) -> MayDetach<'a> {
        MayDetach {
            output_file: None,
            task_name: task_name,
        }
    }

    /// Returns true if we are deteached from xcode
    pub fn is_detached(&self) -> bool {
        self.output_file.is_some()
    }

    /// If we are launched from xcode this detaches us from the xcode console
    /// and continues execution in the background.  From this moment on output
    /// is captured and the user is notified with notifications.
    #[cfg(target_os="macos")]
    pub fn may_detach(&mut self) -> Result<bool> {
        if !launched_from_xcode() {
            return Ok(false);
        }

        println!("Continuing in background.");
        show_notification("Sentry", &format!("{} starting", self.task_name))?;
        let output_file = TempFile::new()?;
        daemonize_redirect(Some(output_file.path()),
                           Some(output_file.path()),
                           ChdirMode::NoChdir).unwrap();
        self.output_file = Some(output_file);
        Ok(true)
    }

    /// For non mac platforms this just never detaches.
    #[cfg(not(target_os="macos"))]
    pub fn may_detach(&mut self) -> Result<bool> {
        Ok(false)
    }

    /// Wraps the execution of a code block.  Does not detach until someone
    /// calls into `may_detach`.
    #[cfg(target_os="macos")]
    pub fn wrap<T, F: FnOnce(&mut MayDetach) -> Result<T>>(task_name: &'a str, f: F) -> Result<T> {
        use std::time::Duration;
        use std::thread;
        use open;
        use utils::print_error;

        let mut md = MayDetach::new(task_name);
        match f(&mut md) {
            Ok(x) => {
                md.show_done()?;
                Ok(x)
            }
            Err(err) => {
                if let Some(ref output_file) = md.output_file {
                    print_error(&err);
                    if md.show_critical_info()? {
                        open::that(&output_file.path())?;
                        thread::sleep(Duration::from_millis(5000));
                    }
                }
                Err(err)
            }
        }
    }

    /// Dummy wrap call that never detaches for non mac platforms.
    #[cfg(not(target_os="macos"))]
    pub fn wrap<T, F: FnOnce(&mut MayDetach) -> Result<T>>(task_name: &'a str, f: F) -> Result<T> {
        f(&mut MayDetach::new(task_name))
    }

    #[cfg(target_os="macos")]
    fn show_critical_info(&self) -> Result<bool> {
        show_critical_info(
            &format!("{} failed", self.task_name),
            "The Sentry build step failed while running in the background. \
             You can ignore this error or view details to attempt to resolve \
             it. Ignoring it might cause your crashes not to be handled \
             properly.")
    }

    #[cfg(target_os="macos")]
    fn show_done(&self) -> Result<()> {
        if self.is_detached() {
            show_notification("Sentry", &format!("{} finished", self.task_name))?;
        }
        Ok(())
    }
}

/// Returns true if we were invoked from xcode
#[cfg(target_os="macos")]
pub fn launched_from_xcode() -> bool {
    env::var("XCODE_VERSION_ACTUAL").is_ok() && env::var("TERM").is_err()
}

/// Shows a dialog in xcode and blocks.  The dialog will have a title and a
/// message as well as the buttons "Show details" and "Ignore".  Returns
/// `true` if the `show details` button has been pressed.
#[cfg(target_os="macos")]
pub fn show_critical_info(title: &str, msg: &str) -> Result<bool> {
    lazy_static! {
        static ref SCRIPT: osascript::JavaScript = osascript::JavaScript::new("
            var App = Application('XCode');
            App.includeStandardAdditions = true;
            return App.displayAlert($params.title, {
                message: $params.message,
                as: \"critical\",
                buttons: [\"Show details\", \"Ignore\"]
            });
        ");
    }

    #[derive(Serialize)]
    struct AlertParams<'a> {
        title: &'a str,
        message: &'a str,
    }

    #[derive(Debug, Deserialize)]
    struct AlertResult {
        #[serde(rename="buttonReturned")]
        button: String,
    }

    let rv: AlertResult = SCRIPT.execute_with_params(AlertParams {
        title: title,
        message: msg,
    }).chain_err(|| "Failed to display Xcode dialog")?;

    Ok(&rv.button != "Ignore")
}

/// Shows a notification in xcode
#[cfg(target_os="macos")]
pub fn show_notification(title: &str, msg: &str) -> Result<()> {
    lazy_static! {
        static ref SCRIPT: osascript::JavaScript = osascript::JavaScript::new("
            var App = Application.currentApplication();
            App.includeStandardAdditions = true;
            App.displayNotification($params.message, {
                withTitle: $params.title
            });
        ");
    }

    #[derive(Serialize)]
    struct NotificationParams<'a> {
        title: &'a str,
        message: &'a str,
    }

    Ok(SCRIPT.execute_with_params(NotificationParams {
        title: title,
        message: msg,
    }).chain_err(|| "Failed to display Xcode notification")?)
}

#[test]
fn test_expansion() {
    fn f(name: &str) -> String {
        if name == "FOO_BAR" {
            "foo bar baz / blah".into()
        } else {
            "".into()
        }
    }
    assert_eq!(expand_xcodevars("A$(FOO_BAR:rfc1034identifier)B", f).to_string(),
               "Afoo-bar-baz-blahB".to_string());
    assert_eq!(expand_xcodevars("A$(FOO_BAR:identifier)B", f).to_string(),
               "Afoo_bar_baz_blahB".to_string());
    assert_eq!(expand_xcodevars("A${FOO_BAR:identifier}B", f).to_string(),
               "Afoo_bar_baz_blahB".to_string());
}
<commit_msg>Killed unused info.plist detection code path<commit_after>use std::fs;
use std::env;
use std::fmt;
use std::path::Path;
use std::io::BufReader;
use std::borrow::Cow;

use plist::serde::deserialize;
#[cfg(target_os="macos")]
use osascript;
#[cfg(target_os="macos")]
use unix_daemonize::{daemonize_redirect, ChdirMode};
use regex::Regex;

use prelude::*;
use utils::{TempFile, expand_vars};

#[derive(Deserialize, Debug)]
pub struct InfoPlist {
    #[serde(rename="CFBundleName")]
    name: String,
    #[serde(rename="CFBundleIdentifier")]
    bundle_id: String,
    #[serde(rename="CFBundleShortVersionString")]
    version: String,
    #[serde(rename="CFBundleVersion")]
    build: String,
}

impl fmt::Display for InfoPlist {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.name(), &self.version)
    }
}

fn var_from_env(name: &str) -> String {
    env::var(name).unwrap_or("".into())
}

pub fn expand_xcodevars<'a, F: Fn(&str) -> String>(s: &'a str, f: F) -> Cow<'a, str> {
    lazy_static! {
        static ref SEP_RE: Regex = Regex::new(r"[\s/]+").unwrap();
    }
    expand_vars(s, |key| {
        if key == "" {
            return "".into();
        }
        let mut iter = key.splitn(2, ':');
        let value = f(iter.next().unwrap());
        match iter.next() {
            Some("rfc1034identifier") => {
                SEP_RE.replace_all(&value, "-").into_owned()
            },
            Some("identifier") => {
                SEP_RE.replace_all(&value, "_").into_owned()
            },
            None | Some(_) => value
        }
    })
}

impl InfoPlist {

    pub fn discover_from_env() -> Result<Option<InfoPlist>> {
        if let Ok(path) = env::var("INFOPLIST_FILE") {
            Ok(Some(InfoPlist::from_path(path)?))
        } else {
            Ok(None)
        }
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<InfoPlist> {
        let f = fs::File::open(path.as_ref()).chain_err(||
            Error::from("Could not open Info.plist file"))?;
        let mut rdr = BufReader::new(f);
        Ok(deserialize(&mut rdr).chain_err(||
            Error::from("Could not parse Info.plist file"))?)
    }

    pub fn version(&self) -> &str {
        &self.version
    }

    pub fn build(&self) -> &str {
        &self.build
    }

    pub fn name<'a>(&'a self) -> Cow<'a, str> {
        expand_xcodevars(&self.name, var_from_env)
    }

    pub fn bundle_id<'a>(&'a self) -> Cow<'a, str> {
        expand_xcodevars(&self.bundle_id, var_from_env)
    }

    /// This is similar to `bundle_id` but the product name that might be
    /// referenced is explicitly passed in instead of being picked up
    /// from the environment if missing there.  The reason for this is that
    /// in some cases (react-native with code push) we are not run from an
    /// xcode build step so that information might not be available.
    pub fn derived_bundle_id<'a>(&'a self, product: &str) -> Cow<'a, str> {
        let f = |var: &str| -> String {
            let rv = var_from_env(var);
            if rv.is_empty() && (var == "PRODUCT_NAME" || var == "TARGET_NAME") {
                product.to_string()
            } else {
                rv
            }
        };
        expand_xcodevars(&self.bundle_id, f)
    }
}

/// Helper struct that allows the current execution to detach from
/// the xcode console and continue in the background.  This becomes
/// a dummy shim for non xcode runs or platforms.
pub struct MayDetach<'a> {
    output_file: Option<TempFile>,
    #[allow(dead_code)]
    task_name: &'a str,
}

impl<'a> MayDetach<'a> {
    fn new(task_name: &'a str) -> MayDetach<'a> {
        MayDetach {
            output_file: None,
            task_name: task_name,
        }
    }

    /// Returns true if we are deteached from xcode
    pub fn is_detached(&self) -> bool {
        self.output_file.is_some()
    }

    /// If we are launched from xcode this detaches us from the xcode console
    /// and continues execution in the background.  From this moment on output
    /// is captured and the user is notified with notifications.
    #[cfg(target_os="macos")]
    pub fn may_detach(&mut self) -> Result<bool> {
        if !launched_from_xcode() {
            return Ok(false);
        }

        println!("Continuing in background.");
        show_notification("Sentry", &format!("{} starting", self.task_name))?;
        let output_file = TempFile::new()?;
        daemonize_redirect(Some(output_file.path()),
                           Some(output_file.path()),
                           ChdirMode::NoChdir).unwrap();
        self.output_file = Some(output_file);
        Ok(true)
    }

    /// For non mac platforms this just never detaches.
    #[cfg(not(target_os="macos"))]
    pub fn may_detach(&mut self) -> Result<bool> {
        Ok(false)
    }

    /// Wraps the execution of a code block.  Does not detach until someone
    /// calls into `may_detach`.
    #[cfg(target_os="macos")]
    pub fn wrap<T, F: FnOnce(&mut MayDetach) -> Result<T>>(task_name: &'a str, f: F) -> Result<T> {
        use std::time::Duration;
        use std::thread;
        use open;
        use utils::print_error;

        let mut md = MayDetach::new(task_name);
        match f(&mut md) {
            Ok(x) => {
                md.show_done()?;
                Ok(x)
            }
            Err(err) => {
                if let Some(ref output_file) = md.output_file {
                    print_error(&err);
                    if md.show_critical_info()? {
                        open::that(&output_file.path())?;
                        thread::sleep(Duration::from_millis(5000));
                    }
                }
                Err(err)
            }
        }
    }

    /// Dummy wrap call that never detaches for non mac platforms.
    #[cfg(not(target_os="macos"))]
    pub fn wrap<T, F: FnOnce(&mut MayDetach) -> Result<T>>(task_name: &'a str, f: F) -> Result<T> {
        f(&mut MayDetach::new(task_name))
    }

    #[cfg(target_os="macos")]
    fn show_critical_info(&self) -> Result<bool> {
        show_critical_info(
            &format!("{} failed", self.task_name),
            "The Sentry build step failed while running in the background. \
             You can ignore this error or view details to attempt to resolve \
             it. Ignoring it might cause your crashes not to be handled \
             properly.")
    }

    #[cfg(target_os="macos")]
    fn show_done(&self) -> Result<()> {
        if self.is_detached() {
            show_notification("Sentry", &format!("{} finished", self.task_name))?;
        }
        Ok(())
    }
}

/// Returns true if we were invoked from xcode
#[cfg(target_os="macos")]
pub fn launched_from_xcode() -> bool {
    env::var("XCODE_VERSION_ACTUAL").is_ok() && env::var("TERM").is_err()
}

/// Shows a dialog in xcode and blocks.  The dialog will have a title and a
/// message as well as the buttons "Show details" and "Ignore".  Returns
/// `true` if the `show details` button has been pressed.
#[cfg(target_os="macos")]
pub fn show_critical_info(title: &str, msg: &str) -> Result<bool> {
    lazy_static! {
        static ref SCRIPT: osascript::JavaScript = osascript::JavaScript::new("
            var App = Application('XCode');
            App.includeStandardAdditions = true;
            return App.displayAlert($params.title, {
                message: $params.message,
                as: \"critical\",
                buttons: [\"Show details\", \"Ignore\"]
            });
        ");
    }

    #[derive(Serialize)]
    struct AlertParams<'a> {
        title: &'a str,
        message: &'a str,
    }

    #[derive(Debug, Deserialize)]
    struct AlertResult {
        #[serde(rename="buttonReturned")]
        button: String,
    }

    let rv: AlertResult = SCRIPT.execute_with_params(AlertParams {
        title: title,
        message: msg,
    }).chain_err(|| "Failed to display Xcode dialog")?;

    Ok(&rv.button != "Ignore")
}

/// Shows a notification in xcode
#[cfg(target_os="macos")]
pub fn show_notification(title: &str, msg: &str) -> Result<()> {
    lazy_static! {
        static ref SCRIPT: osascript::JavaScript = osascript::JavaScript::new("
            var App = Application.currentApplication();
            App.includeStandardAdditions = true;
            App.displayNotification($params.message, {
                withTitle: $params.title
            });
        ");
    }

    #[derive(Serialize)]
    struct NotificationParams<'a> {
        title: &'a str,
        message: &'a str,
    }

    Ok(SCRIPT.execute_with_params(NotificationParams {
        title: title,
        message: msg,
    }).chain_err(|| "Failed to display Xcode notification")?)
}

#[test]
fn test_expansion() {
    fn f(name: &str) -> String {
        if name == "FOO_BAR" {
            "foo bar baz / blah".into()
        } else {
            "".into()
        }
    }
    assert_eq!(expand_xcodevars("A$(FOO_BAR:rfc1034identifier)B", f).to_string(),
               "Afoo-bar-baz-blahB".to_string());
    assert_eq!(expand_xcodevars("A$(FOO_BAR:identifier)B", f).to_string(),
               "Afoo_bar_baz_blahB".to_string());
    assert_eq!(expand_xcodevars("A${FOO_BAR:identifier}B", f).to_string(),
               "Afoo_bar_baz_blahB".to_string());
}
<|endoftext|>


<commit_before>pub mod source;
pub mod variables;
pub mod functions;
pub mod calc;

mod conditionals;
mod job_control;
mod test;
mod echo;
mod set;
mod exists;
mod ion;

use self::conditionals::{contains, ends_with, starts_with};
use self::echo::echo;
use self::exists::exists;
use self::functions::fn_;
use self::ion::ion_docs;
use self::source::source;
use self::test::test;
use self::variables::{alias, drop_alias, drop_array, drop_variable};

use fnv::FnvHashMap;
use std::error::Error;
use std::io::{self, Write};

use parser::QuoteTerminator;
use shell::{self, FlowLogic, Shell, ShellHistory};
use shell::job_control::{JobControl, ProcessState};
use shell::status::*;
use sys;

/// Structure which represents a Terminal's command.
/// This command structure contains a name, and the code which run the
/// functionnality associated to this one, with zero, one or several argument(s).
pub struct Builtin {
    pub name: &'static str,
    pub help: &'static str,
    pub main: fn(&[&str], &mut Shell) -> i32,
}

impl Builtin {
    /// Return the map from command names to commands
    pub fn map() -> FnvHashMap<&'static str, Self> {
        let mut commands: FnvHashMap<&str, Self> =
            FnvHashMap::with_capacity_and_hasher(32, Default::default());

        // Quick and clean way to insert a builtin, define a function named as the builtin
        // for example:
        // fn builtin_not (args: &[&str], shell: &mut Shell) -> i32 {
        // let cmd = args[1..].join(" ");
        // shell.on_command(&cmd);
        // match shell.previous_status {
        // SUCCESS => FAILURE,
        // FAILURE => SUCCESS,
        // _ => shell.previous_status
        // }
        // }
        //
        // insert_builtin!("not", builtin_not, "Reverses the exit status value of the given
        // command.");
        //

        macro_rules! insert_builtin {
            ($name:expr, $func:ident, $help:expr) => {
                commands.insert(
                    $name,
                    Builtin {
                        name: $name,
                        help: $help,
                        main: $func,
                    }
                );
            }
        }

        // Directories
        insert_builtin!("cd", builtin_cd, "Change the current directory\n    cd <path>");

        insert_builtin!("dirs", builtin_dirs, "Display the current directory stack");
        insert_builtin!("pushd", builtin_pushd, "Push a directory to the stack");
        insert_builtin!("popd", builtin_popd, "Pop a directory from the stack");

        // Aliases
        insert_builtin!("alias", builtin_alias, "View, set or unset aliases");
        insert_builtin!("unalias", builtin_unalias, "Delete an alias");

        // Variables
        insert_builtin!("fn", builtin_fn, "Print list of functions");
        insert_builtin!("read", builtin_read, "Read some variables\n    read <variable>");
        insert_builtin!("drop", builtin_drop, "Delete a variable");

        // Misc
        insert_builtin!("matches", builtin_matches, "Checks if a string matches a given regex");
        insert_builtin!("not", builtin_not, "Reverses the exit status value of the given command.");
        insert_builtin!(
            "set",
            builtin_set,
            "Set or unset values of shell options and positional parameters."
        );
        insert_builtin!("eval", builtin_eval, "evaluates the evaluated expression");
        insert_builtin!("exit", builtin_exit, "Exits the current session");
        insert_builtin!(
            "wait",
            builtin_wait,
            "Waits until all running background processes have completed"
        );
        insert_builtin!(
            "jobs",
            builtin_jobs,
            "Displays all jobs that are attached to the background"
        );
        insert_builtin!("bg", builtin_bg, "Resumes a stopped background process");
        insert_builtin!(
            "fg",
            builtin_fg,
            "Resumes and sets a background process as the active process"
        );
        insert_builtin!("suspend", builtin_suspend, "Suspends the shell with a SIGTSTOP signal");
        insert_builtin!(
            "disown",
            builtin_disown,
            "Disowning a process removes that process from the shell's background process table."
        );
        insert_builtin!(
            "history",
            builtin_history,
            "Display a log of all commands previously executed"
        );
        insert_builtin!(
            "source",
            builtin_source,
            "Evaluate the file following the command or re-initialize the init file"
        );
        insert_builtin!("echo", builtin_echo, "Display a line of text");
        insert_builtin!("test", builtin_test, "Performs tests on files and text");
        insert_builtin!("calc", builtin_calc, "Calculate a mathematical expression");
        insert_builtin!("true", builtin_true, "Do nothing, successfully");
        insert_builtin!("false", builtin_false, "Do nothing, unsuccessfully");
        insert_builtin!(
            "help",
            builtin_help,
            "Display helpful information about a given command or list commands if none \
             specified\n    help <command>"
        );
        insert_builtin!(
            "and",
            builtin_and,
            "Execute the command if the shell's previous status is success"
        );
        insert_builtin!(
            "or",
            builtin_or,
            "Execute the command if the shell's previous status is failure"
        );
        insert_builtin!(
            "starts-with",
            starts_with,
            "Evaluates if the supplied argument starts with a given string"
        );
        insert_builtin!(
            "ends-with",
            ends_with,
            "Evaluates if the supplied argument ends with a given string"
        );
        insert_builtin!(
            "contains",
            contains,
            "Evaluates if the supplied argument contains a given string"
        );
        insert_builtin!("exists", builtin_exists, "Performs tests on files and text");
        insert_builtin!("ion-docs", ion_docs, "Opens the Ion manual");

        commands
    }
}

// Definitions of simple builtins go here

fn builtin_cd(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.directory_stack.cd(args, &shell.variables) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_dirs(args: &[&str], shell: &mut Shell) -> i32 { shell.directory_stack.dirs(args) }

fn builtin_pushd(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.directory_stack.pushd(args, &shell.variables) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_popd(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.directory_stack.popd(args) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_alias(args: &[&str], shell: &mut Shell) -> i32 {
    let args_str = args[1..].join(" ");
    alias(&mut shell.variables, &args_str)
}

fn builtin_unalias(args: &[&str], shell: &mut Shell) -> i32 {
    drop_alias(&mut shell.variables, args)
}

fn builtin_fn(_: &[&str], shell: &mut Shell) -> i32 { fn_(&mut shell.functions) }

fn builtin_read(args: &[&str], shell: &mut Shell) -> i32 { shell.variables.read(args) }

fn builtin_drop(args: &[&str], shell: &mut Shell) -> i32 {
    if args.len() >= 2 && args[1] == "-a" {
        drop_array(&mut shell.variables, args)
    } else {
        drop_variable(&mut shell.variables, args)
    }
}

fn builtin_not(args: &[&str], shell: &mut Shell) -> i32 {
    let cmd = args[1..].join(" ");
    shell.on_command(&cmd);
    match shell.previous_status {
        SUCCESS => FAILURE,
        FAILURE => SUCCESS,
        _ => shell.previous_status,
    }
}

fn builtin_set(args: &[&str], shell: &mut Shell) -> i32 { set::set(args, shell) }
fn builtin_eval(args: &[&str], shell: &mut Shell) -> i32 {
    let evaluated_command = args[1..].join(" ");
    let mut buffer = QuoteTerminator::new(evaluated_command);
    if buffer.check_termination() {
        shell.on_command(&buffer.consume());
        shell.previous_status
    } else {
        let stderr = io::stderr();
        let mut stderr = stderr.lock();
        let _ = writeln!(stderr, "ion: supplied eval expression was not terminted");
        FAILURE
    }
}
fn builtin_history(args: &[&str], shell: &mut Shell) -> i32 { shell.print_history(args) }

fn builtin_source(args: &[&str], shell: &mut Shell) -> i32 {
    match source(shell, args) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_echo(args: &[&str], _: &mut Shell) -> i32 {
    match echo(args) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.description().as_bytes());
            FAILURE
        }
    }
}

fn builtin_test(args: &[&str], _: &mut Shell) -> i32 {
    match test(args) {
        Ok(true) => SUCCESS,
        Ok(false) => FAILURE,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(stderr, "{}", why);
            FAILURE
        }
    }
}

fn builtin_calc(args: &[&str], _: &mut Shell) -> i32 {
    match calc::calc(&args[1..]) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(stderr, "{}", why);
            FAILURE
        }
    }
}

fn builtin_true(_: &[&str], _: &mut Shell) -> i32 { SUCCESS }

fn builtin_false(_: &[&str], _: &mut Shell) -> i32 { FAILURE }

fn builtin_wait(_: &[&str], shell: &mut Shell) -> i32 {
    shell.wait_for_background();
    SUCCESS
}

fn builtin_jobs(_: &[&str], shell: &mut Shell) -> i32 {
    job_control::jobs(shell);
    SUCCESS
}

fn builtin_bg(args: &[&str], shell: &mut Shell) -> i32 { job_control::bg(shell, &args[1..]) }

fn builtin_fg(args: &[&str], shell: &mut Shell) -> i32 { job_control::fg(shell, &args[1..]) }

fn builtin_suspend(_: &[&str], _: &mut Shell) -> i32 {
    shell::signals::suspend(0);
    SUCCESS
}

fn builtin_disown(args: &[&str], shell: &mut Shell) -> i32 {
    job_control::disown(shell, &args[1..])
}

fn builtin_help(args: &[&str], shell: &mut Shell) -> i32 {
    let builtins = shell.builtins;
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    if let Some(command) = args.get(1) {
        if builtins.contains_key(command) {
            if let Some(bltin) = builtins.get(command) {
                let _ = stdout.write_all(bltin.help.as_bytes());
                let _ = stdout.write_all(b"\n");
            }
        } else {
            let _ = stdout.write_all(b"Command helper not found [run 'help']...");
            let _ = stdout.write_all(b"\n");
        }
    } else {
        let mut commands = builtins.keys().cloned().collect::<Vec<&str>>();
        commands.sort();

        let mut buffer: Vec<u8> = Vec::new();
        for command in commands {
            let _ = writeln!(buffer, "{}", command);
        }
        let _ = stdout.write_all(&buffer);
    }
    SUCCESS
}

fn builtin_exit(args: &[&str], shell: &mut Shell) -> i32 {
    // Kill all active background tasks before exiting the shell.
    for process in shell.background.lock().unwrap().iter() {
        if process.state != ProcessState::Empty {
            let _ = sys::kill(process.pid, sys::SIGTERM);
        }
    }
    let previous_status = shell.previous_status;
    shell.exit(args.get(1).and_then(|status| status.parse::<i32>().ok()).unwrap_or(previous_status))
}

use regex::Regex;
fn builtin_matches(args: &[&str], _: &mut Shell) -> i32 {
    if args[1..].len() != 2 {
        let stderr = io::stderr();
        let mut stderr = stderr.lock();
        let _ = stderr.write_all(b"match takes two arguments\n");
        return BAD_ARG;
    }
    let input = args[1];
    let re = match Regex::new(args[2]) {
        Ok(r) => r,
        Err(e) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr
                .write_all(format!("couldn't compile input regex {}: {}\n", args[2], e).as_bytes());
            return FAILURE;
        }
    };

    if re.is_match(input) {
        SUCCESS
    } else {
        FAILURE
    }
}

fn builtin_and(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.previous_status {
        SUCCESS => {
            let cmd = args[1..].join(" ");
            shell.on_command(&cmd);
            shell.previous_status
        }
        _ => shell.previous_status,
    }
}

fn builtin_or(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.previous_status {
        FAILURE => {
            let cmd = args[1..].join(" ");
            shell.on_command(&cmd);
            shell.previous_status
        }
        _ => shell.previous_status,
    }
}

fn builtin_exists(args: &[&str], shell: &mut Shell) -> i32 {
    match exists(args, shell) {
        Ok(true) => SUCCESS,
        Ok(false) => FAILURE,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(stderr, "{}", why);
            FAILURE
        }
    }
}
<commit_msg>Let builtin prints variables<commit_after>pub mod source;
pub mod variables;
pub mod functions;
pub mod calc;

mod conditionals;
mod job_control;
mod test;
mod echo;
mod set;
mod exists;
mod ion;

use self::conditionals::{contains, ends_with, starts_with};
use self::echo::echo;
use self::exists::exists;
use self::functions::fn_;
use self::ion::ion_docs;
use self::source::source;
use self::test::test;
use self::variables::{alias, drop_alias, drop_array, drop_variable};

use fnv::FnvHashMap;
use std::error::Error;
use std::io::{self, Write};

use parser::QuoteTerminator;
use shell::{self, FlowLogic, Shell, ShellHistory};
use shell::job_control::{JobControl, ProcessState};
use shell::status::*;
use sys;

/// Structure which represents a Terminal's command.
/// This command structure contains a name, and the code which run the
/// functionnality associated to this one, with zero, one or several argument(s).
pub struct Builtin {
    pub name: &'static str,
    pub help: &'static str,
    pub main: fn(&[&str], &mut Shell) -> i32,
}

impl Builtin {
    /// Return the map from command names to commands
    pub fn map() -> FnvHashMap<&'static str, Self> {
        let mut commands: FnvHashMap<&str, Self> =
            FnvHashMap::with_capacity_and_hasher(32, Default::default());

        // Quick and clean way to insert a builtin, define a function named as the builtin
        // for example:
        // fn builtin_not (args: &[&str], shell: &mut Shell) -> i32 {
        // let cmd = args[1..].join(" ");
        // shell.on_command(&cmd);
        // match shell.previous_status {
        // SUCCESS => FAILURE,
        // FAILURE => SUCCESS,
        // _ => shell.previous_status
        // }
        // }
        //
        // insert_builtin!("not", builtin_not, "Reverses the exit status value of the given
        // command.");
        //

        macro_rules! insert_builtin {
            ($name:expr, $func:ident, $help:expr) => {
                commands.insert(
                    $name,
                    Builtin {
                        name: $name,
                        help: $help,
                        main: $func,
                    }
                );
            }
        }

        // Directories
        insert_builtin!("cd", builtin_cd, "Change the current directory\n    cd <path>");

        insert_builtin!("dirs", builtin_dirs, "Display the current directory stack");
        insert_builtin!("pushd", builtin_pushd, "Push a directory to the stack");
        insert_builtin!("popd", builtin_popd, "Pop a directory from the stack");

        // Aliases
        insert_builtin!("alias", builtin_alias, "View, set or unset aliases");
        insert_builtin!("unalias", builtin_unalias, "Delete an alias");

        // Variables
        insert_builtin!("fn", builtin_fn, "Print list of functions");
        insert_builtin!("read", builtin_read, "Read some variables\n    read <variable>");
        insert_builtin!("drop", builtin_drop, "Delete a variable");

        // Misc
        insert_builtin!("matches", builtin_matches, "Checks if a string matches a given regex");
        insert_builtin!("not", builtin_not, "Reverses the exit status value of the given command.");
        insert_builtin!(
            "set",
            builtin_set,
            "Set or unset values of shell options and positional parameters."
        );
        insert_builtin!("eval", builtin_eval, "evaluates the evaluated expression");
        insert_builtin!("exit", builtin_exit, "Exits the current session");
        insert_builtin!(
            "wait",
            builtin_wait,
            "Waits until all running background processes have completed"
        );
        insert_builtin!(
            "jobs",
            builtin_jobs,
            "Displays all jobs that are attached to the background"
        );
        insert_builtin!("bg", builtin_bg, "Resumes a stopped background process");
        insert_builtin!(
            "fg",
            builtin_fg,
            "Resumes and sets a background process as the active process"
        );
        insert_builtin!("suspend", builtin_suspend, "Suspends the shell with a SIGTSTOP signal");
        insert_builtin!(
            "disown",
            builtin_disown,
            "Disowning a process removes that process from the shell's background process table."
        );
        insert_builtin!(
            "history",
            builtin_history,
            "Display a log of all commands previously executed"
        );
        insert_builtin!(
            "source",
            builtin_source,
            "Evaluate the file following the command or re-initialize the init file"
        );
        insert_builtin!("echo", builtin_echo, "Display a line of text");
        insert_builtin!("test", builtin_test, "Performs tests on files and text");
        insert_builtin!("calc", builtin_calc, "Calculate a mathematical expression");
        insert_builtin!("true", builtin_true, "Do nothing, successfully");
        insert_builtin!("false", builtin_false, "Do nothing, unsuccessfully");
        insert_builtin!(
            "help",
            builtin_help,
            "Display helpful information about a given command or list commands if none \
             specified\n    help <command>"
        );
        insert_builtin!(
            "and",
            builtin_and,
            "Execute the command if the shell's previous status is success"
        );
        insert_builtin!(
            "or",
            builtin_or,
            "Execute the command if the shell's previous status is failure"
        );
        insert_builtin!(
            "starts-with",
            starts_with,
            "Evaluates if the supplied argument starts with a given string"
        );
        insert_builtin!(
            "ends-with",
            ends_with,
            "Evaluates if the supplied argument ends with a given string"
        );
        insert_builtin!(
            "contains",
            contains,
            "Evaluates if the supplied argument contains a given string"
        );
        insert_builtin!("exists", builtin_exists, "Performs tests on files and text");
        insert_builtin!("ion-docs", ion_docs, "Opens the Ion manual");
        insert_builtin!("let", list_vars, "Displays a list of local variables");
        commands
    }
}

// Definitions of simple builtins go here

fn list_vars(_: &[&str], shell: &mut Shell) -> i32 {
    shell.variables.variables.iter().for_each(
        |(key, val)| println!("{} = {}", key, val)
    );
    SUCCESS
}

fn builtin_cd(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.directory_stack.cd(args, &shell.variables) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_dirs(args: &[&str], shell: &mut Shell) -> i32 { shell.directory_stack.dirs(args) }

fn builtin_pushd(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.directory_stack.pushd(args, &shell.variables) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_popd(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.directory_stack.popd(args) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_alias(args: &[&str], shell: &mut Shell) -> i32 {
    let args_str = args[1..].join(" ");
    alias(&mut shell.variables, &args_str)
}

fn builtin_unalias(args: &[&str], shell: &mut Shell) -> i32 {
    drop_alias(&mut shell.variables, args)
}

fn builtin_fn(_: &[&str], shell: &mut Shell) -> i32 { fn_(&mut shell.functions) }

fn builtin_read(args: &[&str], shell: &mut Shell) -> i32 { shell.variables.read(args) }

fn builtin_drop(args: &[&str], shell: &mut Shell) -> i32 {
    if args.len() >= 2 && args[1] == "-a" {
        drop_array(&mut shell.variables, args)
    } else {
        drop_variable(&mut shell.variables, args)
    }
}

fn builtin_not(args: &[&str], shell: &mut Shell) -> i32 {
    let cmd = args[1..].join(" ");
    shell.on_command(&cmd);
    match shell.previous_status {
        SUCCESS => FAILURE,
        FAILURE => SUCCESS,
        _ => shell.previous_status,
    }
}

fn builtin_set(args: &[&str], shell: &mut Shell) -> i32 { set::set(args, shell) }
fn builtin_eval(args: &[&str], shell: &mut Shell) -> i32 {
    let evaluated_command = args[1..].join(" ");
    let mut buffer = QuoteTerminator::new(evaluated_command);
    if buffer.check_termination() {
        shell.on_command(&buffer.consume());
        shell.previous_status
    } else {
        let stderr = io::stderr();
        let mut stderr = stderr.lock();
        let _ = writeln!(stderr, "ion: supplied eval expression was not terminted");
        FAILURE
    }
}
fn builtin_history(args: &[&str], shell: &mut Shell) -> i32 { shell.print_history(args) }

fn builtin_source(args: &[&str], shell: &mut Shell) -> i32 {
    match source(shell, args) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.as_bytes());
            FAILURE
        }
    }
}

fn builtin_echo(args: &[&str], _: &mut Shell) -> i32 {
    match echo(args) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr.write_all(why.description().as_bytes());
            FAILURE
        }
    }
}

fn builtin_test(args: &[&str], _: &mut Shell) -> i32 {
    match test(args) {
        Ok(true) => SUCCESS,
        Ok(false) => FAILURE,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(stderr, "{}", why);
            FAILURE
        }
    }
}

fn builtin_calc(args: &[&str], _: &mut Shell) -> i32 {
    match calc::calc(&args[1..]) {
        Ok(()) => SUCCESS,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(stderr, "{}", why);
            FAILURE
        }
    }
}

fn builtin_true(_: &[&str], _: &mut Shell) -> i32 { SUCCESS }

fn builtin_false(_: &[&str], _: &mut Shell) -> i32 { FAILURE }

fn builtin_wait(_: &[&str], shell: &mut Shell) -> i32 {
    shell.wait_for_background();
    SUCCESS
}

fn builtin_jobs(_: &[&str], shell: &mut Shell) -> i32 {
    job_control::jobs(shell);
    SUCCESS
}

fn builtin_bg(args: &[&str], shell: &mut Shell) -> i32 { job_control::bg(shell, &args[1..]) }

fn builtin_fg(args: &[&str], shell: &mut Shell) -> i32 { job_control::fg(shell, &args[1..]) }

fn builtin_suspend(_: &[&str], _: &mut Shell) -> i32 {
    shell::signals::suspend(0);
    SUCCESS
}

fn builtin_disown(args: &[&str], shell: &mut Shell) -> i32 {
    job_control::disown(shell, &args[1..])
}

fn builtin_help(args: &[&str], shell: &mut Shell) -> i32 {
    let builtins = shell.builtins;
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    if let Some(command) = args.get(1) {
        if builtins.contains_key(command) {
            if let Some(bltin) = builtins.get(command) {
                let _ = stdout.write_all(bltin.help.as_bytes());
                let _ = stdout.write_all(b"\n");
            }
        } else {
            let _ = stdout.write_all(b"Command helper not found [run 'help']...");
            let _ = stdout.write_all(b"\n");
        }
    } else {
        let mut commands = builtins.keys().cloned().collect::<Vec<&str>>();
        commands.sort();

        let mut buffer: Vec<u8> = Vec::new();
        for command in commands {
            let _ = writeln!(buffer, "{}", command);
        }
        let _ = stdout.write_all(&buffer);
    }
    SUCCESS
}

fn builtin_exit(args: &[&str], shell: &mut Shell) -> i32 {
    // Kill all active background tasks before exiting the shell.
    for process in shell.background.lock().unwrap().iter() {
        if process.state != ProcessState::Empty {
            let _ = sys::kill(process.pid, sys::SIGTERM);
        }
    }
    let previous_status = shell.previous_status;
    shell.exit(args.get(1).and_then(|status| status.parse::<i32>().ok()).unwrap_or(previous_status))
}

use regex::Regex;
fn builtin_matches(args: &[&str], _: &mut Shell) -> i32 {
    if args[1..].len() != 2 {
        let stderr = io::stderr();
        let mut stderr = stderr.lock();
        let _ = stderr.write_all(b"match takes two arguments\n");
        return BAD_ARG;
    }
    let input = args[1];
    let re = match Regex::new(args[2]) {
        Ok(r) => r,
        Err(e) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = stderr
                .write_all(format!("couldn't compile input regex {}: {}\n", args[2], e).as_bytes());
            return FAILURE;
        }
    };

    if re.is_match(input) {
        SUCCESS
    } else {
        FAILURE
    }
}

fn builtin_and(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.previous_status {
        SUCCESS => {
            let cmd = args[1..].join(" ");
            shell.on_command(&cmd);
            shell.previous_status
        }
        _ => shell.previous_status,
    }
}

fn builtin_or(args: &[&str], shell: &mut Shell) -> i32 {
    match shell.previous_status {
        FAILURE => {
            let cmd = args[1..].join(" ");
            shell.on_command(&cmd);
            shell.previous_status
        }
        _ => shell.previous_status,
    }
}

fn builtin_exists(args: &[&str], shell: &mut Shell) -> i32 {
    match exists(args, shell) {
        Ok(true) => SUCCESS,
        Ok(false) => FAILURE,
        Err(why) => {
            let stderr = io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(stderr, "{}", why);
            FAILURE
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::raw;

pub trait VertexData: Copy { }

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<Self> {
                data: self,
                len: mem::size_of::<Self>()
            })
        }
    }
}
<commit_msg>Add `vertex_data!` macro<commit_after>use std::mem;
use std::raw;

pub trait VertexData: Copy { }

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<Self> {
                data: self,
                len: mem::size_of::<Self>()
            })
        }
    }
}

#[macro_export]
macro_rules! vertex_data {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty),*
    }) => {
        #[repr(C)]
        #[derive(Debug, Clone, Copy)]
        struct $name {
            $($field_name: $field_type),*
        }

        impl $crate::VertexData for $name { }
    }
}
<|endoftext|>


<commit_before>//! VM Runtime
use util::bigint::M256;
use util::gas::Gas;
use util::address::Address;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas};

mod cost;
mod run;
mod check;
mod util;
mod lifecycle;
mod precompiled;

/// A VM state without PC.
pub struct State<M> {
    /// Memory of this runtime.
    pub memory: M,
    /// Stack of this runtime.
    pub stack: Stack,

    /// Context.
    pub context: Context,
    /// Block header.
    pub block: BlockHeader,
    /// Patch that is used by this runtime.
    pub patch: &'static Patch,

    /// The current out value.
    pub out: Vec<u8>,

    /// The current memory cost. Note that this is different from
    /// memory gas.
    pub memory_cost: Gas,
    /// Used gas excluding memory gas.
    pub used_gas: Gas,
    /// Refunded gas.
    pub refunded_gas: Gas,

    /// The current account commitment states.
    pub account_state: AccountState,
    /// The current blockhash commitment states.
    pub blockhash_state: BlockhashState,
    /// Logs appended.
    pub logs: Vec<Log>,
    /// Removed accounts using the SUICIDE opcode.
    pub removed: Vec<Address>,

    /// Depth of this runtime.
    pub depth: usize,
}

impl<M> State<M> {
    /// Memory gas, part of total used gas.
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    /// Available gas at this moment.
    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }

    /// Total used gas including the memory gas.
    pub fn total_used_gas(&self) -> Gas {
        self.memory_gas() + self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    /// Create a new runtime with the given states.
    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice(), patch),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),
                removed: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice(), self.state.patch),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),
                removed: self.state.removed.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.as_usize()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);

        let all_gas_cost = memory_gas + self.state.used_gas + gas_cost - gas_stipend;
        if self.state.context.gas_limit < all_gas_cost {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let after_gas = self.state.context.gas_limit - all_gas_cost;
        {
            use vm::Instruction;
            if instruction == Instruction::CALL || instruction == Instruction::CALLCODE ||
                instruction == Instruction::CREATE || instruction == Instruction::SUICIDE ||
                instruction == Instruction::DELEGATECALL
            // if true
            {
                let gas_cost_dis: u64 = (self.state.available_gas() - after_gas).into();
                let total_gas_dis: u64 = all_gas_cost.into();
                let after_gas_dis: u64 = after_gas.into();
                println!("{:?}, cost: {}, total: {}, after: {}", instruction,
                         gas_cost_dis, total_gas_dis, after_gas_dis);
            }
        }

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.as_usize()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<commit_msg>Remove debug println<commit_after>//! VM Runtime
use util::bigint::M256;
use util::gas::Gas;
use util::address::Address;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas};

mod cost;
mod run;
mod check;
mod util;
mod lifecycle;
mod precompiled;

/// A VM state without PC.
pub struct State<M> {
    /// Memory of this runtime.
    pub memory: M,
    /// Stack of this runtime.
    pub stack: Stack,

    /// Context.
    pub context: Context,
    /// Block header.
    pub block: BlockHeader,
    /// Patch that is used by this runtime.
    pub patch: &'static Patch,

    /// The current out value.
    pub out: Vec<u8>,

    /// The current memory cost. Note that this is different from
    /// memory gas.
    pub memory_cost: Gas,
    /// Used gas excluding memory gas.
    pub used_gas: Gas,
    /// Refunded gas.
    pub refunded_gas: Gas,

    /// The current account commitment states.
    pub account_state: AccountState,
    /// The current blockhash commitment states.
    pub blockhash_state: BlockhashState,
    /// Logs appended.
    pub logs: Vec<Log>,
    /// Removed accounts using the SUICIDE opcode.
    pub removed: Vec<Address>,

    /// Depth of this runtime.
    pub depth: usize,
}

impl<M> State<M> {
    /// Memory gas, part of total used gas.
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    /// Available gas at this moment.
    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }

    /// Total used gas including the memory gas.
    pub fn total_used_gas(&self) -> Gas {
        self.memory_gas() + self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    /// Create a new runtime with the given states.
    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice(), patch),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),
                removed: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice(), self.state.patch),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),
                removed: self.state.removed.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.as_usize()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);

        let all_gas_cost = memory_gas + self.state.used_gas + gas_cost - gas_stipend;
        if self.state.context.gas_limit < all_gas_cost {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let after_gas = self.state.context.gas_limit - all_gas_cost;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.as_usize()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<|endoftext|>


<commit_before>#![crate_id = "codegen"]

#![feature(macro_rules)]

extern crate collections;

use std::io::{File, Truncate, Write};
use std::os;

pub mod branchify;
pub mod status;
pub mod read_method;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println!("usage: codegen [read_method|status].rs <output-dir>");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = Path::new(args[2].as_slice());

            match args[1].as_slice() {
                "read_method.rs" => read_method::generate(&output_dir).unwrap(),
                "status.rs" => status::generate(&output_dir).unwrap(),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [read_method|status].rs <output-dir>", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~Writer {
    let mut output_file = output_dir.clone();
    output_file.push(filename);
    match File::open_mode(&output_file, Truncate, Write) {
        Ok(writer) => ~writer as ~Writer,
        Err(e) => fail!("Unable to write file: {}", e.desc),
    }
}
<commit_msg>Update to remove ~<commit_after>#![crate_id = "codegen"]

#![feature(macro_rules)]

extern crate collections;

use std::io::{File, Truncate, Write};
use std::os;

pub mod branchify;
pub mod status;
pub mod read_method;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println!("usage: codegen [read_method|status].rs <output-dir>");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = Path::new(args[2].as_slice());

            match args[1].as_slice() {
                "read_method.rs" => read_method::generate(&output_dir).unwrap(),
                "status.rs" => status::generate(&output_dir).unwrap(),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [read_method|status].rs <output-dir>", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> Box<Writer> {
    let mut output_file = output_dir.clone();
    output_file.push(filename);
    match File::open_mode(&output_file, Truncate, Write) {
        Ok(writer) => box writer as Box<Writer>,
        Err(e) => fail!("Unable to write file: {}", e.desc),
    }
}
<|endoftext|>


<commit_before>//! This module implements the root command of the CLI tool.

use std::io;
use std::io::Write;
use std::env;
use std::process;

use log;
use clap::{Arg, App, AppSettings};

use prelude::*;
use constants::VERSION;
use utils::{make_subcommand, Logger};
use config::{Config, Auth};

const ABOUT: &'static str = "
Command line utility for Sentry.

This tool helps you managing remote resources on a Sentry server like
sourcemaps, debug symbols, releases or similar.  Use `--help` on the
subcommands to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dsym);
        $mac!(releases);
        $mac!(issues);
        $mac!(update);
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        #[cfg(target_os="macos")]
        $mac!(react_native_xcode);
    }
}

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod upload_dsym;
pub mod releases;
pub mod issues;
pub mod update;
pub mod uninstall;
pub mod info;
pub mod login;
pub mod send_event;

#[cfg(target_os="macos")]
pub mod react_native_xcode;

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: Vec<String>, config: &mut Config) -> Result<()> {
    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
        env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
        if &val == "1" {
            return react_native_xcode::wrap_call();
        }
    }

    let mut app = App::new("sentry-cli")
        .version(VERSION)
        .about(ABOUT)
        .max_term_width(100)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("url")
            .value_name("URL")
            .long("url")
            .help("The sentry API URL{n}defaults to https://sentry.io/"))
        .arg(Arg::with_name("auth_token")
            .value_name("AUTH_TOKEN")
            .long("auth-token")
            .help("The sentry auth token to use"))
        .arg(Arg::with_name("api_key")
            .value_name("API_KEY")
            .long("api-key")
            .help("The sentry API key to use"))
        .arg(Arg::with_name("log_level")
            .value_name("LOG_LEVEL")
            .long("log-level")
            .help("The log level for sentry-cli{n}\
                   (valid levels: TRACE, DEBUG, INFO, WARN, ERROR)"));

    macro_rules! add_subcommand {
        ($name:ident) => {{
            app = app.subcommand($name::make_app(
                make_subcommand(&stringify!($name).replace("_", "-"))));
        }}
    }
    each_subcommand!(add_subcommand);

    let matches = app.get_matches_from_safe(args)?;

    if let Some(url) = matches.value_of("url") {
        config.url = url.to_owned();
    }
    if let Some(api_key) = matches.value_of("api_key") {
        config.auth = Some(Auth::Key(api_key.to_owned()));
    }
    if let Some(auth_token) = matches.value_of("auth_token") {
        config.auth = Some(Auth::Token(auth_token.to_owned()));
    }
    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.log_level = level;
            }
            Err(_) => {
                fail!("Unknown log level: {}", level_str);
            }
        }
    }

    log::set_logger(|max_log_level| {
            max_log_level.set(config.log_level);
            Box::new(Logger)
        })
        .ok();

    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(cmd) {
                return Ok($name::execute(&sub_matches, &config)?);
            }
        }}
    }
    each_subcommand!(execute_subcommand);
    unreachable!();
}

fn run() -> Result<()> {
    execute(env::args().collect(), &mut Config::from_cli_config()?)
}

/// Executes the command line application and exists the process.
pub fn main() {
    match run() {
        Ok(()) => process::exit(0),
        Err(err) => {
            if let &ErrorKind::Clap(ref clap_err) = err.kind() {
                clap_err.exit();
            }

            writeln!(&mut io::stderr(), "error: {}", err).ok();

            if env::var("RUST_BACKTRACE") == Ok("1".into()) {
                writeln!(&mut io::stderr(), "").ok();
                writeln!(&mut io::stderr(), "{:?}", err.backtrace()).ok();
            }

            process::exit(1);
        }
    }
}
<commit_msg>Fixed preexecute hook for non osx<commit_after>//! This module implements the root command of the CLI tool.

use std::io;
use std::io::Write;
use std::env;
use std::process;

use log;
use clap::{Arg, App, AppSettings};

use prelude::*;
use constants::VERSION;
use utils::{make_subcommand, Logger};
use config::{Config, Auth};

const ABOUT: &'static str = "
Command line utility for Sentry.

This tool helps you managing remote resources on a Sentry server like
sourcemaps, debug symbols, releases or similar.  Use `--help` on the
subcommands to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dsym);
        $mac!(releases);
        $mac!(issues);
        $mac!(update);
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        #[cfg(target_os="macos")]
        $mac!(react_native_xcode);
    }
}

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod upload_dsym;
pub mod releases;
pub mod issues;
pub mod update;
pub mod uninstall;
pub mod info;
pub mod login;
pub mod send_event;

#[cfg(target_os="macos")]
pub mod react_native_xcode;

fn preexecute_hooks() -> Result<()> {
    sentry_react_native_xcode_wrap()?;

    return Ok(());

    #[cfg(target_os="macos")]
    fn sentry_react_native_xcode_wrap() -> Result<()> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                return react_native_xcode::wrap_call();
            }
        }
        Ok(())
    }

    #[cfg(not(target_os="macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<()> {
        Ok(())
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: Vec<String>, config: &mut Config) -> Result<()> {
    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    preexecute_hooks()?;

    let mut app = App::new("sentry-cli")
        .version(VERSION)
        .about(ABOUT)
        .max_term_width(100)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("url")
            .value_name("URL")
            .long("url")
            .help("The sentry API URL{n}defaults to https://sentry.io/"))
        .arg(Arg::with_name("auth_token")
            .value_name("AUTH_TOKEN")
            .long("auth-token")
            .help("The sentry auth token to use"))
        .arg(Arg::with_name("api_key")
            .value_name("API_KEY")
            .long("api-key")
            .help("The sentry API key to use"))
        .arg(Arg::with_name("log_level")
            .value_name("LOG_LEVEL")
            .long("log-level")
            .help("The log level for sentry-cli{n}\
                   (valid levels: TRACE, DEBUG, INFO, WARN, ERROR)"));

    macro_rules! add_subcommand {
        ($name:ident) => {{
            app = app.subcommand($name::make_app(
                make_subcommand(&stringify!($name).replace("_", "-"))));
        }}
    }
    each_subcommand!(add_subcommand);

    let matches = app.get_matches_from_safe(args)?;

    if let Some(url) = matches.value_of("url") {
        config.url = url.to_owned();
    }
    if let Some(api_key) = matches.value_of("api_key") {
        config.auth = Some(Auth::Key(api_key.to_owned()));
    }
    if let Some(auth_token) = matches.value_of("auth_token") {
        config.auth = Some(Auth::Token(auth_token.to_owned()));
    }
    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.log_level = level;
            }
            Err(_) => {
                fail!("Unknown log level: {}", level_str);
            }
        }
    }

    log::set_logger(|max_log_level| {
            max_log_level.set(config.log_level);
            Box::new(Logger)
        })
        .ok();

    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(cmd) {
                return Ok($name::execute(&sub_matches, &config)?);
            }
        }}
    }
    each_subcommand!(execute_subcommand);
    unreachable!();
}

fn run() -> Result<()> {
    execute(env::args().collect(), &mut Config::from_cli_config()?)
}

/// Executes the command line application and exists the process.
pub fn main() {
    match run() {
        Ok(()) => process::exit(0),
        Err(err) => {
            if let &ErrorKind::Clap(ref clap_err) = err.kind() {
                clap_err.exit();
            }

            writeln!(&mut io::stderr(), "error: {}", err).ok();

            if env::var("RUST_BACKTRACE") == Ok("1".into()) {
                writeln!(&mut io::stderr(), "").ok();
                writeln!(&mut io::stderr(), "{:?}", err.backtrace()).ok();
            }

            process::exit(1);
        }
    }
}
<|endoftext|>