<commit_before>use {AsyncRead, AsyncWrite};
use futures::{Async, Poll};
use std::{fmt, io};

/// A simple wrapper type which allows types which implement only
/// implement `std::io::Read` or `std::io::Write`
/// to be used in contexts which expect an `AsyncRead` or `AsyncWrite`.
///
/// If these types issue an error with the kind `io::ErrorKind::WouldBlock`,
/// it is expected that they will notify the current task on readiness.
/// Synchronous `std` types should not issue errors of this kind and
/// are safe to use in this context. However, using these types with
/// `AllowStdIo` will cause the event loop to block, so they should be used
/// with care.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AllowStdIo<T>(T);

impl<T> AllowStdIo<T> {
    /// Creates a new `AllowStdIo` from an existing IO object.
    pub fn new(io: T) -> Self {
        AllowStdIo(io)
    }

    /// Returns a reference to the contained IO object.
    pub fn get_ref(&self) -> &T {
        &self.0
    }

    /// Returns a mutable reference to the contained IO object.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.0
    }

    /// Consumes self and returns the contained IO object.
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> io::Write for AllowStdIo<T> where T: io::Write {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.0.write_all(buf)
    }
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        self.0.write_fmt(fmt)
    }
}

impl<T> AsyncWrite for AllowStdIo<T> where T: io::Write {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(Async::Ready(()))
    }
}

impl<T> io::Read for AllowStdIo<T> where T: io::Read {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    // TODO: implement the `initializer` fn when it stabilizes.
    // See rust-lang/rust #42788
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_to_end(buf)
    }
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_to_string(buf)
    }
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        self.0.read_exact(buf)
    }
}

impl<T> AsyncRead for AllowStdIo<T> where T: io::Read {
    // TODO: override prepare_unitialized_buffer once `Read::initializer` is stable.
    // See rust-lang/rust #42788
}
<commit_msg>Fixup docs for AllowStdIo (#184)<commit_after>use {AsyncRead, AsyncWrite};
use futures::{Async, Poll};
use std::{fmt, io};

/// A simple wrapper type which allows types that only implement
/// `std::io::Read` or `std::io::Write` to be used in contexts which expect
/// an `AsyncRead` or `AsyncWrite`.
///
/// If these types issue an error with the kind `io::ErrorKind::WouldBlock`,
/// it is expected that they will notify the current task on readiness.
/// Synchronous `std` types should not issue errors of this kind and
/// are safe to use in this context. However, using these types with
/// `AllowStdIo` will cause the event loop to block, so they should be used
/// with care.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AllowStdIo<T>(T);

impl<T> AllowStdIo<T> {
    /// Creates a new `AllowStdIo` from an existing IO object.
    pub fn new(io: T) -> Self {
        AllowStdIo(io)
    }

    /// Returns a reference to the contained IO object.
    pub fn get_ref(&self) -> &T {
        &self.0
    }

    /// Returns a mutable reference to the contained IO object.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.0
    }

    /// Consumes self and returns the contained IO object.
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> io::Write for AllowStdIo<T> where T: io::Write {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.0.write_all(buf)
    }
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        self.0.write_fmt(fmt)
    }
}

impl<T> AsyncWrite for AllowStdIo<T> where T: io::Write {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(Async::Ready(()))
    }
}

impl<T> io::Read for AllowStdIo<T> where T: io::Read {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    // TODO: implement the `initializer` fn when it stabilizes.
    // See rust-lang/rust #42788
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_to_end(buf)
    }
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_to_string(buf)
    }
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        self.0.read_exact(buf)
    }
}

impl<T> AsyncRead for AllowStdIo<T> where T: io::Read {
    // TODO: override prepare_unitialized_buffer once `Read::initializer` is stable.
    // See rust-lang/rust #42788
}
<|endoftext|>


<commit_before>use action::Action;
use config;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::{
    Message,
    MessageBuilder
};

use handlebars::{
    Context,
    Handlebars,
    Template
};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
use state::State;
use self::error::Error;
use self::renderer_context::RendererContext;

mod error;
mod renderer_context;
#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = ".context.uuid";
pub const CONTEXT_NAME: &'static str = ".context.name";

pub struct MessageAction {
    sender: Rc<RefCell<Box<ResponseSender<Response>>>>,
    uuid: String,
    name: Option<String>,
    message: Template,
    values: Handlebars
}

impl MessageAction {
    pub fn new(sender: Rc<RefCell<Box<ResponseSender<Response>>>>, action: config::action::MessageAction) -> MessageAction {
        let config::action::MessageAction { uuid, name, message, values } = action;
        let mut handlebars = Handlebars::new();
        for (name, template) in values.into_iter() {
            handlebars.register_template(&name, template);
        }

        MessageAction {
            sender: sender,
            uuid: uuid,
            name: name,
            message: message,
            values: handlebars
        }
    }

    fn render_value(&self, key: &String, template_context: &Context) -> Result<String, Error> {
        let mut writer = Vec::new();
        {
            try!(self.values.renderw(key, &template_context, &mut writer));
        }
        let string = try!(String::from_utf8(writer));
        Ok(string)
    }

    fn render_values(&self, template_context: &Context) -> Result<BTreeMap<String, String>, Error> {
        let mut rendered_values = BTreeMap::new();
        for (key, _) in self.values.get_templates() {
            let rendered_value = try!(self.render_value(key, &template_context));
            rendered_values.insert(key.to_string(), rendered_value);
        }
        Ok(rendered_values)
    }

    fn render_message(&self, state: &State, context: &BaseContext) -> Result<Message, Error> {
        let template_context = {
            use handlebars::Context;
            let context = RendererContext::new(state, context);
            Context::wraps(&context)
        };

        let rendered_values = try!(self.render_values(&template_context));
        let name = self.name.as_ref().map(|name| name.borrow());
        let message = MessageBuilder::new(&self.uuid, "moricka message")
                        .name(name)
                        .values(rendered_values)
                        .build();
        Ok(message)
    }
}

#[derive(Debug)]
pub struct MessageResponse {
    message: Message,
}

impl MessageResponse {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn execute(&self, _state: &State, _context: &BaseContext) {
        trace!("MessageAction: executed");
        match self.render_message(_state, _context) {
            Ok(mut message) => {
                message.insert(".context.uuid", &_context.uuid().to_hyphenated_string());
                message.insert(".context.len", &_state.messages().len().to_string());
                if let Some(name) = _context.name() {
                    message.insert(".context.name", name);
                }
                let response = MessageResponse {
                    message: message,
                };
                self.sender.borrow_mut().send_response(Response::Message(response));
            },
            Err(error) => {
                error!("{}", error);
            }
        }
    }
}
<commit_msg>action::message::MessageAction: use the "MESSAGE" key to hold the rendered<commit_after>use action::Action;
use config;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::{
    Message,
    MessageBuilder
};

use handlebars::{
    Context,
    Handlebars,
};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
use state::State;
use self::error::Error;
use self::renderer_context::RendererContext;

mod error;
mod renderer_context;
#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = ".context.uuid";
pub const CONTEXT_NAME: &'static str = ".context.name";
const MESSAGE_KEY: &'static str = "MESSAGE";

pub struct MessageAction {
    sender: Rc<RefCell<Box<ResponseSender<Response>>>>,
    uuid: String,
    name: Option<String>,
    values: Handlebars
}

impl MessageAction {
    pub fn new(sender: Rc<RefCell<Box<ResponseSender<Response>>>>, action: config::action::MessageAction) -> MessageAction {
        let config::action::MessageAction { uuid, name, message, values } = action;
        let mut handlebars = Handlebars::new();
        for (name, template) in values.into_iter() {
            handlebars.register_template(&name, template);
        }
        handlebars.register_template(MESSAGE_KEY, message);

        MessageAction {
            sender: sender,
            uuid: uuid,
            name: name,
            values: handlebars
        }
    }

    fn render_value(&self, key: &String, template_context: &Context) -> Result<String, Error> {
        let mut writer = Vec::new();
        {
            try!(self.values.renderw(key, &template_context, &mut writer));
        }
        let string = try!(String::from_utf8(writer));
        Ok(string)
    }

    fn render_values(&self, template_context: &Context) -> Result<BTreeMap<String, String>, Error> {
        let mut rendered_values = BTreeMap::new();
        for (key, _) in self.values.get_templates() {
            let rendered_value = try!(self.render_value(key, &template_context));
            rendered_values.insert(key.to_string(), rendered_value);
        }
        Ok(rendered_values)
    }

    fn render_message(&self, state: &State, context: &BaseContext) -> Result<Message, Error> {
        let template_context = {
            use handlebars::Context;
            let context = RendererContext::new(state, context);
            Context::wraps(&context)
        };

        let mut rendered_values = try!(self.render_values(&template_context));
        let message = rendered_values.remove(MESSAGE_KEY).expect(&format!("There is no '{}' key in the renderer key-value pairs", MESSAGE_KEY));
        let name = self.name.as_ref().map(|name| name.borrow());
        let message = MessageBuilder::new(&self.uuid, message)
                        .name(name)
                        .values(rendered_values)
                        .build();
        Ok(message)
    }
}

#[derive(Debug)]
pub struct MessageResponse {
    message: Message,
}

impl MessageResponse {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn execute(&self, _state: &State, _context: &BaseContext) {
        trace!("MessageAction: executed");
        match self.render_message(_state, _context) {
            Ok(mut message) => {
                message.insert(".context.uuid", &_context.uuid().to_hyphenated_string());
                message.insert(".context.len", &_state.messages().len().to_string());
                if let Some(name) = _context.name() {
                    message.insert(".context.name", name);
                }
                let response = MessageResponse {
                    message: message,
                };
                self.sender.borrow_mut().send_response(Response::Message(response));
            },
            Err(error) => {
                error!("{}", error);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! `HashMap` based Graph's Intermediate Representation
use asm::assembler::SEQUENCES;
use data::edges::Edges;
use data::read_slice::ReadSlice;
use data::primitives::{K_SIZE, Idx};
use super::hs_gir::create_or_modify_edge;
use algorithms::builder::Build;
use data::collections::girs::gir::{GIR, Convert};
use data::collections::graphs::pt_graph::{PtGraph, NodeIndex};

use std::collections::HashMap as HM;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;

extern crate metrohash;
use self::metrohash::MetroHash;

/// `HashMap` GIR
pub type HmGIR = HM<ReadSlice, Edges, BuildHasherDefault<MetroHash>>;

impl GIR for HmGIR {}

impl Build for HmGIR {
    /// Add new reads to `HmGIR`, modify weights of existing edges.
    fn add_read(&mut self, read: &[u8]) {
        assert!(read.len() as Idx >= K_SIZE + 1, "Read is too short!");
        let mut ins_counter: Idx = 0;
        let mut index_counter = unwrap!(SEQUENCES.read(), "Global sequences poisoned :(").len() as Idx;
        let mut tmp_index_counter;
        let mut current: ReadSlice;
        let mut insert = false;
        let mut previous_node: ReadSlice = ReadSlice::new(0);
        let mut offset;
        let mut idx = self.len();
        let mut current_idx;
        for (cnt, window) in read.windows(K_SIZE as usize).enumerate() {
            let from_tmp = {
                let mut s = unwrap!(SEQUENCES.write(), "Global sequences poisoned :(");
                offset = s.len();
                // push to vector
                if ins_counter == 0 {
                    // append window to vector
                    s.extend_from_slice(window);
                    tmp_index_counter = 0;
                    ReadSlice::new(offset as Idx)
                }
                else if ins_counter > K_SIZE {
                    // append window to vector
                    s.extend_from_slice(window);
                    tmp_index_counter = K_SIZE;
                    ReadSlice::new(offset as Idx)
                }
                else {
                    // append only ins_counter last bytes of window
                    s.extend_from_slice(&window[(K_SIZE - ins_counter) as usize..]);
                    tmp_index_counter = ins_counter;
                    ReadSlice::new(offset - (K_SIZE - ins_counter) as Idx)
                }
            };
            current = {
                // get a proper key to the hashmap
                match self.entry(from_tmp) {
                    Entry::Occupied(oe) => {
                        // remove added window from SEQUENCES
                        unwrap!(SEQUENCES.write()).truncate(offset);
                        if ins_counter > 0 {
                            ins_counter += 1;
                        }
                        current_idx = oe.get().idx;
                        oe.key().clone()
                    }
                    Entry::Vacant(_) => {
                        // we cant use that VE because it is keyed with a temporary value
                        index_counter += tmp_index_counter;
                        ins_counter = 1;
                        current_idx = idx;
                        insert = true;
                        ReadSlice::new(index_counter)
                    }
                }
            };
            if cnt > 0 {
                // insert current sequence as a member of the previous
                let e: &mut Edges = unwrap!(self.get_mut(&previous_node), "Node disappeared");
                create_or_modify_edge(e, current_idx);
            }
            if insert {
                // insert new vertex
                self.entry(current.clone()).or_insert_with(|| Edges::empty(current_idx));
                idx += 1;
                insert = false;
            }
            previous_node = current;
        }
    }
}

impl Convert<HmGIR> for PtGraph {
    fn create_from(gir: HmGIR) -> Self {
        info!("Starting conversion from GIR to graph");
        // get rid of hashes -- we don't need them anymore
        let mut vec = gir.into_iter().collect::<Vec<(ReadSlice, Edges)>>();
        // sort this vector according to indicees of nodes, guaranteeing proper node creation (node
        // indices are created just like we created ours, but iterator over hashmap likely changed the
        // ordering).
        vec.sort_by(|a, b| a.1.idx.cmp(&b.1.idx));
        // create separate representations of nodes and edges
        let (nodes, edges): (Vec<ReadSlice>, Vec<Edges>) = vec.into_iter().unzip();
        let mut graph = PtGraph::default();
        // digest nodes and move them into the Graph
        for (cnt, node) in nodes.into_iter().enumerate() {
            let tmp = graph.add_node(node).index();
            assert_eq!(tmp, cnt);
        }
        for edges_ in edges.into_iter() {
            let idx = edges_.idx;
            for edge in edges_.outgoing.into_iter() {
                graph.add_edge(NodeIndex::new(idx), NodeIndex::new(edge.0), edge.1);
            }
        }
        info!("Conversion ended!");
        graph
    }
}
<commit_msg>Remove unnecessary lookup in HmGIR build<commit_after>//! `HashMap` based Graph's Intermediate Representation
use asm::assembler::SEQUENCES;
use data::edges::Edges;
use data::read_slice::ReadSlice;
use data::primitives::{K_SIZE, Idx};
use super::hs_gir::create_or_modify_edge;
use algorithms::builder::Build;
use data::collections::girs::gir::{GIR, Convert};
use data::collections::graphs::pt_graph::{PtGraph, NodeIndex};

use std::collections::HashMap as HM;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;

extern crate metrohash;
use self::metrohash::MetroHash;

/// `HashMap` GIR
pub type HmGIR = HM<ReadSlice, Edges, BuildHasherDefault<MetroHash>>;

impl GIR for HmGIR {}

impl Build for HmGIR {
    /// Add new reads to `HmGIR`, modify weights of existing edges.
    fn add_read(&mut self, read: &[u8]) {
        assert!(read.len() as Idx >= K_SIZE + 1, "Read is too short!");
        let mut ins_counter: Idx = 0;
        let mut index_counter = unwrap!(SEQUENCES.read(), "Global sequences poisoned :(").len() as Idx;
        let mut tmp_index_counter;
        let mut current: ReadSlice;
        let mut previous_node: ReadSlice = ReadSlice::new(0);
        let mut offset;
        let mut idx = self.len();
        let mut current_idx;
        for (cnt, window) in read.windows(K_SIZE as usize).enumerate() {
            let from_tmp = {
                let mut s = unwrap!(SEQUENCES.write(), "Global sequences poisoned :(");
                offset = s.len();
                // push to vector
                if ins_counter == 0 {
                    // append window to vector
                    s.extend_from_slice(window);
                    tmp_index_counter = 0;
                    ReadSlice::new(offset as Idx)
                }
                else if ins_counter > K_SIZE {
                    // append window to vector
                    s.extend_from_slice(window);
                    tmp_index_counter = K_SIZE;
                    ReadSlice::new(offset as Idx)
                }
                else {
                    // append only ins_counter last bytes of window
                    s.extend_from_slice(&window[(K_SIZE - ins_counter) as usize..]);
                    tmp_index_counter = ins_counter;
                    ReadSlice::new(offset - (K_SIZE - ins_counter) as Idx)
                }
            };
            current = {
                // get a proper key to the hashmap
                match self.entry(from_tmp) {
                    Entry::Occupied(oe) => {
                        // remove added window from SEQUENCES
                        unwrap!(SEQUENCES.write()).truncate(offset);
                        if ins_counter > 0 {
                            ins_counter += 1;
                        }
                        current_idx = oe.get().idx;
                        oe.key().clone()
                    }
                    Entry::Vacant(ve) => {
                        index_counter += tmp_index_counter;
                        ins_counter = 1;
                        current_idx = idx;
                        idx += 1;
                        ve.insert(Edges::empty(current_idx));
                        ReadSlice::new(index_counter)
                    }
                }
            };
            if cnt > 0 {
                // insert current sequence as a member of the previous
                let e: &mut Edges = unwrap!(self.get_mut(&previous_node), "Node disappeared");
                create_or_modify_edge(e, current_idx);
            }
            previous_node = current;
        }
    }
}

impl Convert<HmGIR> for PtGraph {
    fn create_from(gir: HmGIR) -> Self {
        info!("Starting conversion from GIR to graph");
        // get rid of hashes -- we don't need them anymore
        let mut vec = gir.into_iter().collect::<Vec<(ReadSlice, Edges)>>();
        // sort this vector according to indicees of nodes, guaranteeing proper node creation (node
        // indices are created just like we created ours, but iterator over hashmap likely changed the
        // ordering).
        vec.sort_by(|a, b| a.1.idx.cmp(&b.1.idx));
        // create separate representations of nodes and edges
        let (nodes, edges): (Vec<ReadSlice>, Vec<Edges>) = vec.into_iter().unzip();
        let mut graph = PtGraph::default();
        // digest nodes and move them into the Graph
        for (cnt, node) in nodes.into_iter().enumerate() {
            let tmp = graph.add_node(node).index();
            assert_eq!(tmp, cnt);
        }
        for edges_ in edges.into_iter() {
            let idx = edges_.idx;
            for edge in edges_.outgoing.into_iter() {
                graph.add_edge(NodeIndex::new(idx), NodeIndex::new(edge.0), edge.1);
            }
        }
        info!("Conversion ended!");
        graph
    }
}
<|endoftext|>


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

use std::env;
use std::ffi::OsString;

use common::ui::UI;
use hcore::crypto::CACHE_KEY_PATH_ENV_VAR;
use hcore::env as henv;
use hcore::fs::CACHE_KEY_PATH;
use hcore::os::users;

use config;
use error::Result;

pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
    try!(inner::rerun_with_sudo_if_needed(ui));

    // If the `$HAB_ORIGIN` environment variable is not present, then see if a default is set in
    // the CLI config. If so, set it as the `$HAB_ORIGIN` environment variable for the `hab-studio`
    // or `docker` execv call.
    if henv::var("HAB_ORIGIN").is_err() {
        let config = try!(config::load_with_sudo_user());
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    // If the `$HAB_CACHE_KEY_PATH` environment variable is not present, check if we are running
    // under a `sudo` invocation. If so, determine the non-root user that issued the command in
    // order to set their key cache location in the environment variable. This is done so that the
    // `hab-studio` command will find the correct key cache or so that the correct directory will
    // be volume mounted when used with Docker.
    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        if let Some(sudo_user) = henv::sudo_user() {
            if let Some(home) = users::get_home_for_user(&sudo_user) {
                let cache_key_path = home.join(format!(".{}", CACHE_KEY_PATH));
                debug!("Setting cache_key_path for SUDO_USER={} to: {}",
                       &sudo_user,
                       cache_key_path.display());
                env::set_var(CACHE_KEY_PATH_ENV_VAR, cache_key_path);
                // Prevent any inner `hab` invocations from triggering similar logic: we will be
                // operating in the context `hab-studio` which is running with rootlike privileges.
                env::remove_var("SUDO_USER");
            }
        }
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use std::env;
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use common::ui::UI;
    use hcore::crypto::{init, default_cache_key_path};
    use hcore::env as henv;
    use hcore::fs::{am_i_root, find_command};
    use hcore::os::process;
    use hcore::package::PackageIdent;

    use error::{Error, Result};
    use exec;

    const STUDIO_CMD: &'static str = "hab-studio";
    const STUDIO_CMD_ENVVAR: &'static str = "HAB_STUDIO_BINARY";
    const STUDIO_PACKAGE_IDENT: &'static str = "core/hab-studio";
    const SUDO_CMD: &'static str = "sudo";

    pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let command = match henv::var(STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let ident = try!(PackageIdent::from_str(STUDIO_PACKAGE_IDENT));
                try!(exec::command_from_pkg(ui,
                                            STUDIO_CMD,
                                            &ident,
                                            &default_cache_key_path(None),
                                            0))
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            try!(process::become_command(cmd, args));
        } else {
            return Err(Error::ExecCommandNotFound(command.to_string_lossy().into_owned()));
        }
        Ok(())
    }

    pub fn rerun_with_sudo_if_needed(ui: &mut UI) -> Result<()> {
        // If I have root permissions, early return, we are done.
        if am_i_root() {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> =
                    vec!["-p".into(), "[sudo hab-studio] password for %u: ".into(), "-E".into()];
                args.append(&mut env::args_os().collect());
                Ok(try!(process::become_command(sudo_prog, args)))
            }
            None => {
                try!(ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                     SUDO_CMD)));
                try!(ui.warn("Running Habitat Studio requires root or administrator privileges. \
                              Please retry this command as a super user or use a \
                              privilege-granting facility such as sudo."));
                try!(ui.br());
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use std::env;
    use std::ffi::OsString;
    use std::process::{Command, Stdio};

    use common::ui::UI;
    use hcore::crypto::default_cache_key_path;
    use hcore::env as henv;
    use hcore::fs::{CACHE_KEY_PATH, find_command};
    use hcore::os::process;

    use error::{Error, Result};
    use VERSION;

    const DOCKER_CMD: &'static str = "docker";
    const DOCKER_CMD_ENVVAR: &'static str = "HAB_DOCKER_BINARY";
    const DOCKER_IMAGE: &'static str = "habitat-docker-registry.bintray.io/studio";
    const DOCKER_IMAGE_ENVVAR: &'static str = "HAB_DOCKER_STUDIO_IMAGE";
    const DOCKER_OPTS: &'static str = "HAB_DOCKER_OPTS";

    pub fn start(_ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let docker = henv::var(DOCKER_CMD_ENVVAR).unwrap_or(DOCKER_CMD.to_string());

        let cmd = match find_command(&docker) {
            Some(cmd) => cmd,
            None => return Err(Error::ExecCommandNotFound(docker.to_string())),
        };

        let child = Command::new(&cmd)
            .arg("pull")
            .arg(&image_identifier())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()
            .expect("docker failed to start");

        let output = child.wait_with_output()
            .expect("failed to wait on child");

        if output.status.success() {
            debug!("Docker image is reachable. Proceeding with launching docker.");
        } else {
            debug!("Docker image is unreachable. Exit code = {:?}",
                   output.status);

            let err_output = String::from_utf8(output.stderr).unwrap();

            if err_output.contains("image") && err_output.contains("not found") {
                return Err(Error::DockerImageNotFound(image_identifier().to_string()));
            } else if err_output.contains("Cannot connect to the Docker daemon") {
                return Err(Error::DockerDaemonDown);
            } else {
                return Err(Error::DockerNetworkDown(image_identifier().to_string()));
            }
        }

        let mut cmd_args: Vec<OsString> = vec!["run".into(),
                                               "--rm".into(),
                                               "--tty".into(),
                                               "--interactive".into(),
                                               "--privileged".into()];

        // All the args already placed in `cmd_args` are things that we don't want to insert again.
        // Later args such as `--env` will overwrite any options (potentially) set mistakenly here.
        if let Ok(ops) = henv::var(DOCKER_OPTS) {
            let ops = ops.split(" ")
                .map(|v| v.into())
                // Ensure we're not passing something like `--tty` again here.
                .filter(|v| !cmd_args.contains(v))
                .collect::<Vec<_>>();
            debug!("Docker ops originating from DOCKER_OPTS = {:?}", ops);
            cmd_args.extend_from_slice(ops.as_slice());
        }

        let env_vars = vec!["HAB_DEPOT_URL", "HAB_ORIGIN", "http_proxy", "https_proxy"];
        for var in env_vars {
            if let Ok(val) = henv::var(var) {
                debug!("Propagating environment variable into container: {}={}",
                       var,
                       val);
                cmd_args.push("--env".into());
                cmd_args.push(format!("{}={}", var, val).into());
            }
        }

        cmd_args.push("--volume".into());
        cmd_args.push("/var/run/docker.sock:/var/run/docker.sock".into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/{}",
                              default_cache_key_path(None).to_string_lossy(),
                              CACHE_KEY_PATH)
            .into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/src", env::current_dir().unwrap().to_string_lossy()).into());

        cmd_args.push(image_identifier().into());
        cmd_args.extend_from_slice(args.as_slice());

        for var in vec!["http_proxy", "https_proxy"] {
            if let Ok(_) = henv::var(var) {
                debug!("Unsetting proxy environment variable '{}' before calling `{}'",
                       var,
                       docker);
                env::remove_var(var);
            }
        }

        debug!("Docker arguments = {:?}", cmd_args);
        Ok(try!(process::become_command(cmd, cmd_args)))
    }

    pub fn rerun_with_sudo_if_needed(_ui: &mut UI) -> Result<()> {
        // No sudo calls necessary here--we are calling `docker` commands instead
        Ok(())
    }

    /// Returns the Docker Studio image with tag for the desired version which corresponds to the
    /// same version (minus release) as this program.
    fn image_identifier() -> String {
        let version: Vec<&str> = VERSION.split("/").collect();
        henv::var(DOCKER_IMAGE_ENVVAR).unwrap_or(format!("{}:{}", DOCKER_IMAGE, version[0]))
    }

    #[cfg(test)]
    mod tests {
        use super::{image_identifier, DOCKER_IMAGE};
        use VERSION;

        #[test]
        fn retrieve_image_identifier() {
            assert_eq!(image_identifier(), format!("{}:{}", DOCKER_IMAGE, VERSION));
        }
    }
}
<commit_msg>corrected variable name<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::ffi::OsString;

use common::ui::UI;
use hcore::crypto::CACHE_KEY_PATH_ENV_VAR;
use hcore::env as henv;
use hcore::fs::CACHE_KEY_PATH;
use hcore::os::users;

use config;
use error::Result;

pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
    try!(inner::rerun_with_sudo_if_needed(ui));

    // If the `$HAB_ORIGIN` environment variable is not present, then see if a default is set in
    // the CLI config. If so, set it as the `$HAB_ORIGIN` environment variable for the `hab-studio`
    // or `docker` execv call.
    if henv::var("HAB_ORIGIN").is_err() {
        let config = try!(config::load_with_sudo_user());
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    // If the `$HAB_CACHE_KEY_PATH` environment variable is not present, check if we are running
    // under a `sudo` invocation. If so, determine the non-root user that issued the command in
    // order to set their key cache location in the environment variable. This is done so that the
    // `hab-studio` command will find the correct key cache or so that the correct directory will
    // be volume mounted when used with Docker.
    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        if let Some(sudo_user) = henv::sudo_user() {
            if let Some(home) = users::get_home_for_user(&sudo_user) {
                let cache_key_path = home.join(format!(".{}", CACHE_KEY_PATH));
                debug!("Setting cache_key_path for SUDO_USER={} to: {}",
                       &sudo_user,
                       cache_key_path.display());
                env::set_var(CACHE_KEY_PATH_ENV_VAR, cache_key_path);
                // Prevent any inner `hab` invocations from triggering similar logic: we will be
                // operating in the context `hab-studio` which is running with rootlike privileges.
                env::remove_var("SUDO_USER");
            }
        }
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use std::env;
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use common::ui::UI;
    use hcore::crypto::{init, default_cache_key_path};
    use hcore::env as henv;
    use hcore::fs::{am_i_root, find_command};
    use hcore::os::process;
    use hcore::package::PackageIdent;

    use error::{Error, Result};
    use exec;

    const STUDIO_CMD: &'static str = "hab-studio";
    const STUDIO_CMD_ENVVAR: &'static str = "HAB_STUDIO_BINARY";
    const STUDIO_PACKAGE_IDENT: &'static str = "core/hab-studio";
    const SUDO_CMD: &'static str = "sudo";

    pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let command = match henv::var(STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let ident = try!(PackageIdent::from_str(STUDIO_PACKAGE_IDENT));
                try!(exec::command_from_pkg(ui,
                                            STUDIO_CMD,
                                            &ident,
                                            &default_cache_key_path(None),
                                            0))
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            try!(process::become_command(cmd, args));
        } else {
            return Err(Error::ExecCommandNotFound(command.to_string_lossy().into_owned()));
        }
        Ok(())
    }

    pub fn rerun_with_sudo_if_needed(ui: &mut UI) -> Result<()> {
        // If I have root permissions, early return, we are done.
        if am_i_root() {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> =
                    vec!["-p".into(), "[sudo hab-studio] password for %u: ".into(), "-E".into()];
                args.append(&mut env::args_os().collect());
                Ok(try!(process::become_command(sudo_prog, args)))
            }
            None => {
                try!(ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                     SUDO_CMD)));
                try!(ui.warn("Running Habitat Studio requires root or administrator privileges. \
                              Please retry this command as a super user or use a \
                              privilege-granting facility such as sudo."));
                try!(ui.br());
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use std::env;
    use std::ffi::OsString;
    use std::process::{Command, Stdio};

    use common::ui::UI;
    use hcore::crypto::default_cache_key_path;
    use hcore::env as henv;
    use hcore::fs::{CACHE_KEY_PATH, find_command};
    use hcore::os::process;

    use error::{Error, Result};
    use VERSION;

    const DOCKER_CMD: &'static str = "docker";
    const DOCKER_CMD_ENVVAR: &'static str = "HAB_DOCKER_BINARY";
    const DOCKER_IMAGE: &'static str = "habitat-docker-registry.bintray.io/studio";
    const DOCKER_IMAGE_ENVVAR: &'static str = "HAB_DOCKER_STUDIO_IMAGE";
    const DOCKER_OPTS: &'static str = "HAB_DOCKER_OPTS";

    pub fn start(_ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let docker = henv::var(DOCKER_CMD_ENVVAR).unwrap_or(DOCKER_CMD.to_string());

        let cmd = match find_command(&docker) {
            Some(cmd) => cmd,
            None => return Err(Error::ExecCommandNotFound(docker.to_string())),
        };

        let child = Command::new(&cmd)
            .arg("pull")
            .arg(&image_identifier())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()
            .expect("docker failed to start");

        let output = child.wait_with_output()
            .expect("failed to wait on child");

        if output.status.success() {
            debug!("Docker image is reachable. Proceeding with launching docker.");
        } else {
            debug!("Docker image is unreachable. Exit code = {:?}",
                   output.status);

            let err_output = String::from_utf8(output.stderr).unwrap();

            if err_output.contains("image") && err_output.contains("not found") {
                return Err(Error::DockerImageNotFound(image_identifier().to_string()));
            } else if err_output.contains("Cannot connect to the Docker daemon") {
                return Err(Error::DockerDaemonDown);
            } else {
                return Err(Error::DockerNetworkDown(image_identifier().to_string()));
            }
        }

        let mut cmd_args: Vec<OsString> = vec!["run".into(),
                                               "--rm".into(),
                                               "--tty".into(),
                                               "--interactive".into(),
                                               "--privileged".into()];

        // All the args already placed in `cmd_args` are things that we don't want to insert again.
        // Later args such as `--env` will overwrite any options (potentially) set mistakenly here.
        if let Ok(opts) = henv::var(DOCKER_OPTS) {
            let opts = opts.split(" ")
                .map(|v| v.into())
                // Ensure we're not passing something like `--tty` again here.
                .filter(|v| !cmd_args.contains(v))
                .collect::<Vec<_>>();
            debug!("Docker opts originating from DOCKER_OPTS = {:?}", opts);
            cmd_args.extend_from_slice(opts.as_slice());
        }

        let env_vars = vec!["HAB_DEPOT_URL", "HAB_ORIGIN", "http_proxy", "https_proxy"];
        for var in env_vars {
            if let Ok(val) = henv::var(var) {
                debug!("Propagating environment variable into container: {}={}",
                       var,
                       val);
                cmd_args.push("--env".into());
                cmd_args.push(format!("{}={}", var, val).into());
            }
        }

        cmd_args.push("--volume".into());
        cmd_args.push("/var/run/docker.sock:/var/run/docker.sock".into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/{}",
                              default_cache_key_path(None).to_string_lossy(),
                              CACHE_KEY_PATH)
            .into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/src", env::current_dir().unwrap().to_string_lossy()).into());

        cmd_args.push(image_identifier().into());
        cmd_args.extend_from_slice(args.as_slice());

        for var in vec!["http_proxy", "https_proxy"] {
            if let Ok(_) = henv::var(var) {
                debug!("Unsetting proxy environment variable '{}' before calling `{}'",
                       var,
                       docker);
                env::remove_var(var);
            }
        }

        debug!("Docker arguments = {:?}", cmd_args);
        Ok(try!(process::become_command(cmd, cmd_args)))
    }

    pub fn rerun_with_sudo_if_needed(_ui: &mut UI) -> Result<()> {
        // No sudo calls necessary here--we are calling `docker` commands instead
        Ok(())
    }

    /// Returns the Docker Studio image with tag for the desired version which corresponds to the
    /// same version (minus release) as this program.
    fn image_identifier() -> String {
        let version: Vec<&str> = VERSION.split("/").collect();
        henv::var(DOCKER_IMAGE_ENVVAR).unwrap_or(format!("{}:{}", DOCKER_IMAGE, version[0]))
    }

    #[cfg(test)]
    mod tests {
        use super::{image_identifier, DOCKER_IMAGE};
        use VERSION;

        #[test]
        fn retrieve_image_identifier() {
            assert_eq!(image_identifier(), format!("{}:{}", DOCKER_IMAGE, VERSION));
        }
    }
}
<|endoftext|>


<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not sucessful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let cargo_download = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.output()
			.expect("could not launch cargo download");
		if !cargo_download.status.success() {
			panic!("Unable to download rusty-hermit. Is `cargo-download` installed?.");
		}
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>build.rs: Prefer Command::status over output<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not sucessful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use serde::de::{Deserialize, DeserializeSeed, Deserializer, Error};

type Id = u32;
type IdToShared<T> = HashMap<Id, T>;

#[derive(Default)]
pub struct NodeMap<T>(Rc<RefCell<IdToShared<T>>>);

pub struct SharedSeed<T>(T);

struct VariantSeed<T>(T);

fn deserialize_t<'de, D, T>(seed: &mut VariantSeed<T>,
                            deserializer: D)
                            -> Result<T::Value, D::Error>
    where D: Deserializer<'de>,
          T: DeserializeSeed<'de> + Clone
{
    seed.0.clone().deserialize(deserializer)
}

#[derive(DeserializeSeed)]
#[serde(deserialize_seed = "VariantSeed<T>")]
#[serde(bound = "T: DeserializeSeed<'de> + Clone")]
enum Variant<T> {
    Marked(Id,
           #[serde(deserialize_seed_with = "deserialize_t")]
           T),
    Plain(#[serde(deserialize_seed_with = "deserialize_t")]
          T),
    Reference(Id),
}

impl<'de, T> DeserializeSeed<'de> for SharedSeed<T>
    where T: DeserializeSeed<'de> + Deserialize<'de> + Clone,
          T: AsMut<NodeMap<<T as DeserializeSeed<'de>>::Value>>,
          T::Value: Clone
{
    type Value = T::Value;

    fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de>
    {

        match VariantSeed(self.0.clone()).deserialize(deserializer)? {
            Variant::Marked(id, node) => {
                self.0
                    .as_mut()
                    .0
                    .borrow_mut()
                    .insert(id, node.clone());
                Ok(node)
            }
            Variant::Plain(value) => Ok(value),
            Variant::Reference(id) => {
                match self.0.as_mut().0.borrow_mut().get(&id) {
                    Some(rc) => Ok(rc.clone()),
                    None => Err(D::Error::custom(format_args!("missing id {}", id))),
                }
            }
        }
    }
}
<commit_msg>Add MapSeed<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use serde::de::{Deserialize, DeserializeSeed, Deserializer, Error};

#[derive(Clone)]
pub struct MapSeed<S, F> {
    seed: S,
    map: F,
}

impl<S, F> MapSeed<S, F> {
    pub fn new(seed: S, map: F) -> MapSeed<S, F> {
        MapSeed {
            seed: seed,
            map: map,
        }
    }
}

impl<S, T, F> AsMut<T> for MapSeed<S, F>
    where S: AsMut<T>
{
    fn as_mut(&mut self) -> &mut T {
        self.seed.as_mut()
    }
}

impl<'de, S, F, R> DeserializeSeed<'de> for MapSeed<S, F>
    where S: DeserializeSeed<'de>,
          F: FnOnce(S::Value) -> R
{
    type Value = R;

    fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de>
    {
        self.seed.deserialize(deserializer).map(self.map)
    }
}

type Id = u32;
type IdToShared<T> = HashMap<Id, T>;

#[derive(Clone, Default)]
pub struct NodeMap<T>(Rc<RefCell<IdToShared<T>>>);

pub struct SharedSeed<T>(pub T);

struct VariantSeed<T>(T);

fn deserialize_t<'de, D, T>(seed: &mut VariantSeed<T>,
                            deserializer: D)
                            -> Result<T::Value, D::Error>
    where D: Deserializer<'de>,
          T: DeserializeSeed<'de> + Clone
{
    seed.0.clone().deserialize(deserializer)
}

#[derive(DeserializeSeed)]
#[serde(deserialize_seed = "VariantSeed<T>")]
#[serde(bound = "T: DeserializeSeed<'de> + Clone")]
enum Variant<T> {
    Marked(Id,
           #[serde(deserialize_seed_with = "deserialize_t")]
           T),
    Plain(#[serde(deserialize_seed_with = "deserialize_t")]
          T),
    Reference(Id),
}

impl<'de, T> DeserializeSeed<'de> for SharedSeed<T>
    where T: DeserializeSeed<'de> + Clone,
          T: AsMut<NodeMap<<T as DeserializeSeed<'de>>::Value>>,
          T::Value: Clone
{
    type Value = T::Value;

    fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de>
    {

        match VariantSeed(self.0.clone()).deserialize(deserializer)? {
            Variant::Marked(id, node) => {
                self.0
                    .as_mut()
                    .0
                    .borrow_mut()
                    .insert(id, node.clone());
                Ok(node)
            }
            Variant::Plain(value) => Ok(value),
            Variant::Reference(id) => {
                match self.0.as_mut().0.borrow_mut().get(&id) {
                    Some(rc) => Ok(rc.clone()),
                    None => Err(D::Error::custom(format_args!("missing id {}", id))),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;

use value::{Value, Field, Tuple};
use relation::{Relation, SingleSelect, Reference, MultiSelect};
use primitive::Primitive;

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<SingleSelect>,
    pub remove: Option<SingleSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<SingleSelect>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstraintOp {
    EQ,
    NEQ,
    LT,
    GT,
    LTE,
    GTE,
}

#[derive(Clone, Debug)]
pub struct Constraint {
    pub left: Reference,
    pub op: ConstraintOp,
    pub right: Reference,
}

impl Constraint {
    fn is_satisfied_by(&self, tuples: &[Tuple]) -> bool {
        let left = self.left.resolve(tuples);
        let right = self.right.resolve(tuples);
        match self.op {
            ConstraintOp::EQ => left == right,
            ConstraintOp::NEQ => left != right,
            ConstraintOp::LT => left < right,
            ConstraintOp::GT => left > right,
            ConstraintOp::LTE => left <= right,
            ConstraintOp::GTE => left >= right,
        }
    }
}

#[derive(Clone, Debug)]
pub enum JoinSource {
    Relation{
        input: usize
    },
    Primitive{
        primitive: Primitive,
        arguments: Vec<Reference>,
        fields: Vec<Field>,
        // TODO `fields` is here just to hack a Tuple in - will go away when we stop using Tuple
    },
}

#[derive(Clone, Debug)]
pub struct Join {
    pub sources: Vec<JoinSource>,
    pub constraints: Vec<Vec<Constraint>>,
    pub select: MultiSelect,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
    pub outer: SingleSelect,
    pub inner: SingleSelect,
    pub limit_from: Option<Reference>,
    pub limit_to: Option<Reference>,
    pub select: MultiSelect,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
    Aggregate(Aggregate),
}

fn join_step<'a>(join: &'a Join, inputs: &[&'a Relation], tuples: &mut Vec<Tuple<'a>>, index: &mut BTreeSet<Vec<Value>>) {
    let ix = tuples.len();
    if ix == join.sources.len() {
        index.insert(join.select.select(&tuples[..]));
    } else {
        match join.sources[ix] {
            JoinSource::Relation{input} => {
                for tuple in inputs[input].iter() {
                    tuples.push(tuple);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&tuples[..])) {
                        join_step(join, inputs, tuples, index)
                    }
                    tuples.pop();
                }
            }
            JoinSource::Primitive{ref primitive, ref arguments, ref fields} => {
                let output = {
                    let arguments = arguments.iter().map(|reference|
                        reference.resolve(&tuples[..])
                        ).collect::<Vec<_>>();
                    primitive.eval(&arguments[..])
                };
                for values in output.into_iter() {
                    let tuple = Tuple{fields: &fields[..], names: &fields[..], values: &values[..]};
                    // promise the borrow checker that we will pop `tuple` before leaving this scope
                    let tuple = unsafe{ ::std::mem::transmute::<Tuple, Tuple<'a>>(tuple) };
                    tuples.push(tuple);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&tuples[..])) {
                        join_step(join, inputs, tuples, index)
                    }
                    tuples.pop();
                }

            }
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, inputs: &[&Relation]) -> Option<Relation> {
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), inputs.len());
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                for select in union.selects.iter() {
                    for values in select.select(&inputs[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut tuples = Vec::with_capacity(join.sources.len());
                join_step(join, inputs, &mut tuples, &mut output.index);
                Some(output)
            }
            View::Aggregate(ref aggregate) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut outer = aggregate.outer.select(&inputs[..]);
                let mut inner = aggregate.inner.select(&inputs[..]);
                outer.sort();
                outer.dedup();
                inner.sort();
                let mut group_start = 0;
                for outer_values in outer.iter() {
                    let mut group_end = group_start;
                    while (group_end < inner.len())
                    && (inner[group_end][0..outer_values.len()] == outer_values[..]) {
                        group_end += 1;
                    }
                    let outer_tuple = Tuple{
                        fields: &aggregate.outer.fields[..],
                        names: &aggregate.outer.fields[..],
                        values: &outer_values[..]
                    };
                    let inputs = &[outer_tuple];
                    let limit_from = match aggregate.limit_from {
                        None => group_start,
                        Some(ref reference) => group_start + reference.resolve(inputs).as_usize(),
                    };
                    let limit_to = match aggregate.limit_to {
                        None => group_end,
                        Some(ref reference) => group_start + reference.resolve(inputs).as_usize(),
                    };
                    for inner_values in &inner[limit_from..limit_to] {
                        let inner_tuple = Tuple{
                            fields: &aggregate.inner.fields[..],
                            names: &aggregate.inner.fields[..],
                            values: &inner_values[..]
                        };
                        output.index.insert(aggregate.select.select(&[inner_tuple]));
                    }
                    group_start = group_end;
                }
                Some(output)
            }
        }
    }
}<commit_msg>Dont blow up on non-sensical limits<commit_after>use std::collections::BTreeSet;

use value::{Value, Field, Tuple};
use relation::{Relation, SingleSelect, Reference, MultiSelect};
use primitive::Primitive;

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<SingleSelect>,
    pub remove: Option<SingleSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<SingleSelect>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstraintOp {
    EQ,
    NEQ,
    LT,
    GT,
    LTE,
    GTE,
}

#[derive(Clone, Debug)]
pub struct Constraint {
    pub left: Reference,
    pub op: ConstraintOp,
    pub right: Reference,
}

impl Constraint {
    fn is_satisfied_by(&self, tuples: &[Tuple]) -> bool {
        let left = self.left.resolve(tuples);
        let right = self.right.resolve(tuples);
        match self.op {
            ConstraintOp::EQ => left == right,
            ConstraintOp::NEQ => left != right,
            ConstraintOp::LT => left < right,
            ConstraintOp::GT => left > right,
            ConstraintOp::LTE => left <= right,
            ConstraintOp::GTE => left >= right,
        }
    }
}

#[derive(Clone, Debug)]
pub enum JoinSource {
    Relation{
        input: usize
    },
    Primitive{
        primitive: Primitive,
        arguments: Vec<Reference>,
        fields: Vec<Field>,
        // TODO `fields` is here just to hack a Tuple in - will go away when we stop using Tuple
    },
}

#[derive(Clone, Debug)]
pub struct Join {
    pub sources: Vec<JoinSource>,
    pub constraints: Vec<Vec<Constraint>>,
    pub select: MultiSelect,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
    pub outer: SingleSelect,
    pub inner: SingleSelect,
    pub limit_from: Option<Reference>,
    pub limit_to: Option<Reference>,
    pub select: MultiSelect,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
    Aggregate(Aggregate),
}

fn join_step<'a>(join: &'a Join, inputs: &[&'a Relation], tuples: &mut Vec<Tuple<'a>>, index: &mut BTreeSet<Vec<Value>>) {
    let ix = tuples.len();
    if ix == join.sources.len() {
        index.insert(join.select.select(&tuples[..]));
    } else {
        match join.sources[ix] {
            JoinSource::Relation{input} => {
                for tuple in inputs[input].iter() {
                    tuples.push(tuple);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&tuples[..])) {
                        join_step(join, inputs, tuples, index)
                    }
                    tuples.pop();
                }
            }
            JoinSource::Primitive{ref primitive, ref arguments, ref fields} => {
                let output = {
                    let arguments = arguments.iter().map(|reference|
                        reference.resolve(&tuples[..])
                        ).collect::<Vec<_>>();
                    primitive.eval(&arguments[..])
                };
                for values in output.into_iter() {
                    let tuple = Tuple{fields: &fields[..], names: &fields[..], values: &values[..]};
                    // promise the borrow checker that we will pop `tuple` before leaving this scope
                    let tuple = unsafe{ ::std::mem::transmute::<Tuple, Tuple<'a>>(tuple) };
                    tuples.push(tuple);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&tuples[..])) {
                        join_step(join, inputs, tuples, index)
                    }
                    tuples.pop();
                }

            }
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, inputs: &[&Relation]) -> Option<Relation> {
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), inputs.len());
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                for select in union.selects.iter() {
                    for values in select.select(&inputs[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut tuples = Vec::with_capacity(join.sources.len());
                join_step(join, inputs, &mut tuples, &mut output.index);
                Some(output)
            }
            View::Aggregate(ref aggregate) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut outer = aggregate.outer.select(&inputs[..]);
                let mut inner = aggregate.inner.select(&inputs[..]);
                outer.sort();
                outer.dedup();
                inner.sort();
                let mut group_start = 0;
                for outer_values in outer.iter() {
                    let mut group_end = group_start;
                    while (group_end < inner.len())
                    && (inner[group_end][0..outer_values.len()] == outer_values[..]) {
                        group_end += 1;
                    }
                    let outer_tuple = Tuple{
                        fields: &aggregate.outer.fields[..],
                        names: &aggregate.outer.fields[..],
                        values: &outer_values[..]
                    };
                    let inputs = &[outer_tuple];
                    let limit_from = match aggregate.limit_from {
                        None => group_start,
                        Some(ref reference) => group_start + reference.resolve(inputs).as_usize(),
                    };
                    let limit_to = match aggregate.limit_to {
                        None => group_end,
                        Some(ref reference) => group_start + reference.resolve(inputs).as_usize(),
                    };
                    let limit_to = ::std::cmp::max(limit_to, limit_from); // the slice explodes if end < start
                    for inner_values in &inner[limit_from..limit_to] {
                        let inner_tuple = Tuple{
                            fields: &aggregate.inner.fields[..],
                            names: &aggregate.inner.fields[..],
                            values: &inner_values[..]
                        };
                        output.index.insert(aggregate.select.select(&[inner_tuple]));
                    }
                    group_start = group_end;
                }
                Some(output)
            }
        }
    }
}<|endoftext|>


<commit_before>//! List of the removed feature gates.

use super::{to_nonzero, Feature, State};
use rustc_span::symbol::sym;

macro_rules! declare_features {
    ($(
        $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr),
    )+) => {
        /// Represents unstable features which have since been removed (it was once Active)
        pub const REMOVED_FEATURES: &[Feature] = &[
            $(
                Feature {
                    state: State::Removed { reason: $reason },
                    name: sym::$feature,
                    since: $ver,
                    issue: to_nonzero($issue),
                    edition: None,
                    description: concat!($($doc,)*),
                }
            ),+
        ];
    };

    ($(
        $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None),
    )+) => {
        /// Represents stable features which have since been removed (it was once Accepted)
        pub const STABLE_REMOVED_FEATURES: &[Feature] = &[
            $(
                Feature {
                    state: State::Stabilized { reason: None },
                    name: sym::$feature,
                    since: $ver,
                    issue: to_nonzero($issue),
                    edition: None,
                    description: concat!($($doc,)*),
                }
            ),+
        ];
    };
}

#[rustfmt::skip]
declare_features! (
    // -------------------------------------------------------------------------
    // feature-group-start: removed features
    // -------------------------------------------------------------------------

    (removed, import_shadowing, "1.0.0", None, None, None),
    (removed, managed_boxes, "1.0.0", None, None, None),
    /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
    (removed, negate_unsigned, "1.0.0", Some(29645), None, None),
    (removed, reflect, "1.0.0", Some(27749), None, None),
    /// A way to temporarily opt out of opt in copy. This will *never* be accepted.
    (removed, opt_out_copy, "1.0.0", None, None, None),
    (removed, quad_precision_float, "1.0.0", None, None, None),
    (removed, struct_inherit, "1.0.0", None, None, None),
    (removed, test_removed_feature, "1.0.0", None, None, None),
    (removed, visible_private_types, "1.0.0", None, None, None),
    (removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
    /// Allows using items which are missing stability attributes
    (removed, unmarked_api, "1.0.0", None, None, None),
    (removed, allocator, "1.0.0", None, None, None),
    (removed, simd, "1.0.0", Some(27731), None,
     Some("removed in favor of `#[repr(simd)]`")),
    (removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
     Some("merged into `#![feature(slice_patterns)]`")),
    (removed, macro_reexport, "1.0.0", Some(29638), None,
     Some("subsumed by `pub use`")),
    /// Allows using custom attributes (RFC 572).
    (removed, custom_attribute, "1.0.0", Some(29642), None,
     Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
    /// Allows features specific to OIBIT (now called auto traits).
    /// Renamed to `auto_traits`.
    (removed, optin_builtin_traits, "1.0.0", Some(13231), None,
     Some("renamed to `auto_traits`")),
    (removed, pushpop_unsafe, "1.2.0", None, None, None),
    (removed, needs_allocator, "1.4.0", Some(27389), None,
     Some("subsumed by `#![feature(allocator_internals)]`")),
    /// Allows identifying crates that contain sanitizer runtimes.
    (removed, sanitizer_runtime, "1.17.0", None, None, None),
    /// Allows `#[doc(spotlight)]`.
    /// The attribute was renamed to `#[doc(notable_trait)]`
    /// and the feature to `doc_notable_trait`.
    (removed, doc_spotlight, "1.22.0", Some(45040), None,
     Some("renamed to `doc_notable_trait`")),
    (removed, proc_macro_mod, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_expr, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_non_items, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_gen, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, panic_implementation, "1.28.0", Some(44489), None,
     Some("subsumed by `#[panic_handler]`")),
    /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
    (removed, custom_derive, "1.32.0", Some(29644), None,
     Some("subsumed by `#[proc_macro_derive]`")),
    /// Paths of the form: `extern::foo::bar`
    (removed, extern_in_paths, "1.33.0", Some(55600), None,
     Some("subsumed by `::foo::bar` paths")),
    (removed, quote, "1.33.0", Some(29601), None, None),
    /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
    (removed, const_generics, "1.34.0", Some(44580), None,
     Some("removed in favor of `#![feature(adt_const_params]` and `#![feature(generic_const_exprs)]`")),
    /// Allows `[x; N]` where `x` is a constant (RFC 2203).
    (removed, const_in_array_repeat_expressions,  "1.37.0", Some(49147), None,
     Some("removed due to causing promotable bugs")),
    /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
    (removed, dropck_parametricity, "1.38.0", Some(28498), None, None),
    (removed, await_macro, "1.38.0", Some(50547), None,
     Some("subsumed by `.await` syntax")),
    /// Allows defining `existential type`s.
    (removed, existential_type, "1.38.0", Some(63063), None,
     Some("removed in favor of `#![feature(type_alias_impl_trait)]`")),
    /// Allows using the macros:
    /// + `__diagnostic_used`
    /// + `__register_diagnostic`
    /// +`__build_diagnostic_array`
    (removed, rustc_diagnostic_macros, "1.38.0", None, None, None),
    /// Allows using `#[on_unimplemented(..)]` on traits.
    /// (Moved to `rustc_attrs`.)
    (removed, on_unimplemented, "1.40.0", None, None, None),
    /// Allows overlapping impls of marker traits.
    (removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
     Some("removed in favor of `#![feature(marker_trait_attr)]`")),
    /// Allows `T: ?const Trait` syntax in bounds.
    (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
     Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
    /// Allows `#[no_debug]`.
    (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
    /// Lazily evaluate constants. This allows constants to depend on type parameters.
    (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
    /// Allows comparing raw pointers during const eval.
    (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
     Some("cannot be allowed in const eval in any meaningful way")),
    /// Allows non-trivial generic constants which have to be manually propagated upwards.
    (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
    /// Allows using the `#[link_args]` attribute.
    (removed, link_args, "1.53.0", Some(29596), None,
     Some("removed in favor of using `-C link-arg=ARG` on command line, \
           which is available from cargo build scripts with `cargo:rustc-link-arg` now")),
    /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls.
    (removed, main, "1.53.0", Some(29634), None, None),
    (removed, pub_macro_rules, "1.53.0", Some(78855), None,
     Some("removed due to being incomplete, in particular it does not work across crates")),
    /// Allows the definition of `const` functions with some advanced features.
    (removed, const_fn, "1.54.0", Some(57563), None,
     Some("split into finer-grained feature gates")),
    /// Allows using `#[plugin_registrar]` on functions.
    (removed, plugin_registrar, "1.54.0", Some(29597), None,
     Some("a __rustc_plugin_registrar symbol must now be defined instead")),

    /// Allows `#[doc(include = "some-file")]`.
    (removed, external_doc, "1.54.0", Some(44732), None,
     Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),

     /// Allows casting raw pointers to `usize` during const eval.
    (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None,
     Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),

    /// Allows `impl Trait` in bindings (`let`, `const`, `static`).
    (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None,
     Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),

    /// Allows the use of type alias impl trait in function return positions
    (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None,
     Some("removed in favor of full type_alias_impl_trait")),

    /// Allows `#[unwind(..)]`.
    ///
    /// Permits specifying whether a function should permit unwinding or abort on unwind.
    (removed, unwind_attributes, "1.56.0", Some(58760), None, Some("use the C-unwind ABI instead")),

    // -------------------------------------------------------------------------
    // feature-group-end: removed features
    // -------------------------------------------------------------------------
);

#[rustfmt::skip]
declare_features! (
    (stable_removed, no_stack_check, "1.0.0", None, None),
);
<commit_msg>Fix typo in `const_generics` replaced with `adt_const_params` note<commit_after>//! List of the removed feature gates.

use super::{to_nonzero, Feature, State};
use rustc_span::symbol::sym;

macro_rules! declare_features {
    ($(
        $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr),
    )+) => {
        /// Represents unstable features which have since been removed (it was once Active)
        pub const REMOVED_FEATURES: &[Feature] = &[
            $(
                Feature {
                    state: State::Removed { reason: $reason },
                    name: sym::$feature,
                    since: $ver,
                    issue: to_nonzero($issue),
                    edition: None,
                    description: concat!($($doc,)*),
                }
            ),+
        ];
    };

    ($(
        $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None),
    )+) => {
        /// Represents stable features which have since been removed (it was once Accepted)
        pub const STABLE_REMOVED_FEATURES: &[Feature] = &[
            $(
                Feature {
                    state: State::Stabilized { reason: None },
                    name: sym::$feature,
                    since: $ver,
                    issue: to_nonzero($issue),
                    edition: None,
                    description: concat!($($doc,)*),
                }
            ),+
        ];
    };
}

#[rustfmt::skip]
declare_features! (
    // -------------------------------------------------------------------------
    // feature-group-start: removed features
    // -------------------------------------------------------------------------

    (removed, import_shadowing, "1.0.0", None, None, None),
    (removed, managed_boxes, "1.0.0", None, None, None),
    /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
    (removed, negate_unsigned, "1.0.0", Some(29645), None, None),
    (removed, reflect, "1.0.0", Some(27749), None, None),
    /// A way to temporarily opt out of opt in copy. This will *never* be accepted.
    (removed, opt_out_copy, "1.0.0", None, None, None),
    (removed, quad_precision_float, "1.0.0", None, None, None),
    (removed, struct_inherit, "1.0.0", None, None, None),
    (removed, test_removed_feature, "1.0.0", None, None, None),
    (removed, visible_private_types, "1.0.0", None, None, None),
    (removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
    /// Allows using items which are missing stability attributes
    (removed, unmarked_api, "1.0.0", None, None, None),
    (removed, allocator, "1.0.0", None, None, None),
    (removed, simd, "1.0.0", Some(27731), None,
     Some("removed in favor of `#[repr(simd)]`")),
    (removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
     Some("merged into `#![feature(slice_patterns)]`")),
    (removed, macro_reexport, "1.0.0", Some(29638), None,
     Some("subsumed by `pub use`")),
    /// Allows using custom attributes (RFC 572).
    (removed, custom_attribute, "1.0.0", Some(29642), None,
     Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
    /// Allows features specific to OIBIT (now called auto traits).
    /// Renamed to `auto_traits`.
    (removed, optin_builtin_traits, "1.0.0", Some(13231), None,
     Some("renamed to `auto_traits`")),
    (removed, pushpop_unsafe, "1.2.0", None, None, None),
    (removed, needs_allocator, "1.4.0", Some(27389), None,
     Some("subsumed by `#![feature(allocator_internals)]`")),
    /// Allows identifying crates that contain sanitizer runtimes.
    (removed, sanitizer_runtime, "1.17.0", None, None, None),
    /// Allows `#[doc(spotlight)]`.
    /// The attribute was renamed to `#[doc(notable_trait)]`
    /// and the feature to `doc_notable_trait`.
    (removed, doc_spotlight, "1.22.0", Some(45040), None,
     Some("renamed to `doc_notable_trait`")),
    (removed, proc_macro_mod, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_expr, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_non_items, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_gen, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, panic_implementation, "1.28.0", Some(44489), None,
     Some("subsumed by `#[panic_handler]`")),
    /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
    (removed, custom_derive, "1.32.0", Some(29644), None,
     Some("subsumed by `#[proc_macro_derive]`")),
    /// Paths of the form: `extern::foo::bar`
    (removed, extern_in_paths, "1.33.0", Some(55600), None,
     Some("subsumed by `::foo::bar` paths")),
    (removed, quote, "1.33.0", Some(29601), None, None),
    /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
    (removed, const_generics, "1.34.0", Some(44580), None,
     Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")),
    /// Allows `[x; N]` where `x` is a constant (RFC 2203).
    (removed, const_in_array_repeat_expressions,  "1.37.0", Some(49147), None,
     Some("removed due to causing promotable bugs")),
    /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
    (removed, dropck_parametricity, "1.38.0", Some(28498), None, None),
    (removed, await_macro, "1.38.0", Some(50547), None,
     Some("subsumed by `.await` syntax")),
    /// Allows defining `existential type`s.
    (removed, existential_type, "1.38.0", Some(63063), None,
     Some("removed in favor of `#![feature(type_alias_impl_trait)]`")),
    /// Allows using the macros:
    /// + `__diagnostic_used`
    /// + `__register_diagnostic`
    /// +`__build_diagnostic_array`
    (removed, rustc_diagnostic_macros, "1.38.0", None, None, None),
    /// Allows using `#[on_unimplemented(..)]` on traits.
    /// (Moved to `rustc_attrs`.)
    (removed, on_unimplemented, "1.40.0", None, None, None),
    /// Allows overlapping impls of marker traits.
    (removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
     Some("removed in favor of `#![feature(marker_trait_attr)]`")),
    /// Allows `T: ?const Trait` syntax in bounds.
    (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
     Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
    /// Allows `#[no_debug]`.
    (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
    /// Lazily evaluate constants. This allows constants to depend on type parameters.
    (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
    /// Allows comparing raw pointers during const eval.
    (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
     Some("cannot be allowed in const eval in any meaningful way")),
    /// Allows non-trivial generic constants which have to be manually propagated upwards.
    (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
    /// Allows using the `#[link_args]` attribute.
    (removed, link_args, "1.53.0", Some(29596), None,
     Some("removed in favor of using `-C link-arg=ARG` on command line, \
           which is available from cargo build scripts with `cargo:rustc-link-arg` now")),
    /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls.
    (removed, main, "1.53.0", Some(29634), None, None),
    (removed, pub_macro_rules, "1.53.0", Some(78855), None,
     Some("removed due to being incomplete, in particular it does not work across crates")),
    /// Allows the definition of `const` functions with some advanced features.
    (removed, const_fn, "1.54.0", Some(57563), None,
     Some("split into finer-grained feature gates")),
    /// Allows using `#[plugin_registrar]` on functions.
    (removed, plugin_registrar, "1.54.0", Some(29597), None,
     Some("a __rustc_plugin_registrar symbol must now be defined instead")),

    /// Allows `#[doc(include = "some-file")]`.
    (removed, external_doc, "1.54.0", Some(44732), None,
     Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),

     /// Allows casting raw pointers to `usize` during const eval.
    (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None,
     Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),

    /// Allows `impl Trait` in bindings (`let`, `const`, `static`).
    (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None,
     Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),

    /// Allows the use of type alias impl trait in function return positions
    (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None,
     Some("removed in favor of full type_alias_impl_trait")),

    /// Allows `#[unwind(..)]`.
    ///
    /// Permits specifying whether a function should permit unwinding or abort on unwind.
    (removed, unwind_attributes, "1.56.0", Some(58760), None, Some("use the C-unwind ABI instead")),

    // -------------------------------------------------------------------------
    // feature-group-end: removed features
    // -------------------------------------------------------------------------
);

#[rustfmt::skip]
declare_features! (
    (stable_removed, no_stack_check, "1.0.0", None, None),
);
<|endoftext|>