<commit_before>use types::{
    CrosslinkRecord,
    Hash256,
    ValidatorRegistration,
};
use super::{
    ActiveState,
    CrystallizedState,
    BeaconChainError,
    ChainConfig,
};
use validator_induction::ValidatorInductor;
use validator_shuffling::{
    shard_and_committees_for_cycle,
    ValidatorAssignmentError,
};

pub const INITIAL_FORK_VERSION: u32 = 0;

impl From<ValidatorAssignmentError> for BeaconChainError {
    fn from(_: ValidatorAssignmentError) -> BeaconChainError {
        BeaconChainError::InvalidGenesis
    }
}

/// Initialize a new ChainHead with genesis parameters.
///
/// Used when syncing a chain from scratch.
pub fn genesis_states(config: &ChainConfig)
    -> Result<(ActiveState, CrystallizedState), ValidatorAssignmentError>
{
    /*
     * Parse the ValidatorRegistrations into ValidatorRecords and induct them.
     *
     * Ignore any records which fail proof-of-possession or are invalid.
     */
    let validators = {
        let mut inductor = ValidatorInductor::new(0, config.shard_count, vec![]);
        for registration in &config.initial_validators {
            let _ = inductor.induct(&registration);
        };
        inductor.to_vec()
    };

    /*
     * Assign the validators to shards, using all zeros as the seed.
     *
     * Crystallizedstate stores two cycles, so we simply repeat the same assignment twice.
     */
    let shard_and_committee_for_slots = {
        let mut a = shard_and_committees_for_cycle(&vec![0; 32], &validators, 0, &config)?;
        let mut b = a.clone();
        a.append(&mut b);
        a
    };

    /*
     * Set all the crosslink records to reference zero hashes.
     */
    let crosslinks = {
        let mut c = vec![];
        for _ in 0..config.shard_count {
            c.push(CrosslinkRecord {
                recently_changed: false,
                slot: 0,
                hash: Hash256::zero(),
            });
        }
        c
    };

    /*
     * Initialize a genesis `Crystallizedstate`
     */
    let crystallized_state = CrystallizedState {
        validator_set_change_slot: 0,
        validators: validators.to_vec(),
        crosslinks,
        last_state_recalculation_slot: 0,
        last_finalized_slot: 0,
        last_justified_slot: 0,
        justified_streak: 0,
        shard_and_committee_for_slots,
        deposits_penalized_in_period: vec![],
        validator_set_delta_hash_chain: Hash256::zero(),
        pre_fork_version: INITIAL_FORK_VERSION,
        post_fork_version: INITIAL_FORK_VERSION,
        fork_slot_number: 0,
    };

    /*
     * Set all recent block hashes to zero.
     */
    let recent_block_hashes = vec![Hash256::zero(); config.cycle_length as usize];

    /*
     * Create an active state.
     */
    let active_state = ActiveState {
        pending_attestations: vec![],
        pending_specials: vec![],
        recent_block_hashes,
        randao_mix: Hash256::zero(),
    };

    Ok((active_state, crystallized_state))
}

#[cfg(test)]
mod tests {
    extern crate validator_induction;
    extern crate bls;

    use super::*;
    use self::bls::{
        create_proof_of_possession,
        Keypair,
    };
    use types::{
        Hash256,
        Address,
    };

    #[test]
    fn test_genesis_no_validators() {
        let config = ChainConfig::standard();
        let (act, cry) = genesis_states(&config).unwrap();

        assert_eq!(cry.validator_set_change_slot, 0);
        assert_eq!(cry.validators.len(), 0);
        assert_eq!(cry.crosslinks.len(), config.shard_count as usize);
        for cl in cry.crosslinks {
            assert_eq!(cl.recently_changed, false);
            assert_eq!(cl.slot, 0);
            assert_eq!(cl.hash, Hash256::zero());
        }
        assert_eq!(cry.last_state_recalculation_slot, 0);
        assert_eq!(cry.last_finalized_slot, 0);
        assert_eq!(cry.last_justified_slot, 0);
        assert_eq!(cry.justified_streak, 0);
        assert_eq!(cry.shard_and_committee_for_slots.len(), (config.cycle_length as usize) * 2);
        assert_eq!(cry.deposits_penalized_in_period.len(), 0);
        assert_eq!(cry.validator_set_delta_hash_chain, Hash256::zero());
        assert_eq!(cry.pre_fork_version, INITIAL_FORK_VERSION);
        assert_eq!(cry.post_fork_version, INITIAL_FORK_VERSION);
        assert_eq!(cry.fork_slot_number, 0);

        assert_eq!(act.pending_attestations.len(), 0);
        assert_eq!(act.pending_specials.len(), 0);
        assert_eq!(act.recent_block_hashes, vec![Hash256::zero(); config.cycle_length as usize]);
        assert_eq!(act.randao_mix, Hash256::zero());
    }

    fn random_registration() -> ValidatorRegistration {
        let keypair = Keypair::random();
        ValidatorRegistration {
            pubkey: keypair.pk.clone(),
            withdrawal_shard: 0,
            withdrawal_address: Address::random(),
            randao_commitment: Hash256::random(),
            proof_of_possession: create_proof_of_possession(&keypair)
        }
    }

    #[test]
    fn test_genesis_valid_validators() {
        let mut config = ChainConfig::standard();
        let validator_count = 5;

        for _ in 0..validator_count {
            config.initial_validators.push(random_registration());
        }

        let (_, cry) = genesis_states(&config).unwrap();

        assert_eq!(cry.validators.len(), validator_count);
    }

    #[test]
    fn test_genesis_invalid_validators() {
        let mut config = ChainConfig::standard();
        let good_validator_count = 5;

        for _ in 0..good_validator_count {
            config.initial_validators.push(random_registration());
        }

        let mut bad_v = random_registration();
        let bad_kp = Keypair::random();
        bad_v.proof_of_possession =  create_proof_of_possession(&bad_kp);
        config.initial_validators.push(bad_v);

        let mut bad_v = random_registration();
        bad_v.withdrawal_shard =  config.shard_count + 1;
        config.initial_validators.push(bad_v);

        let (_, cry) = genesis_states(&config).unwrap();

        assert!(config.initial_validators.len() != good_validator_count, "test is invalid");
        assert_eq!(cry.validators.len(), good_validator_count);
    }
}
<commit_msg>Ensure genesis inducts all validators as active<commit_after>use types::{
    CrosslinkRecord,
    Hash256,
    ValidatorRegistration,
    ValidatorStatus,
};
use super::{
    ActiveState,
    CrystallizedState,
    BeaconChainError,
    ChainConfig,
};
use validator_induction::ValidatorInductor;
use validator_shuffling::{
    shard_and_committees_for_cycle,
    ValidatorAssignmentError,
};

pub const INITIAL_FORK_VERSION: u32 = 0;

impl From<ValidatorAssignmentError> for BeaconChainError {
    fn from(_: ValidatorAssignmentError) -> BeaconChainError {
        BeaconChainError::InvalidGenesis
    }
}

/// Initialize a new ChainHead with genesis parameters.
///
/// Used when syncing a chain from scratch.
pub fn genesis_states(config: &ChainConfig)
    -> Result<(ActiveState, CrystallizedState), ValidatorAssignmentError>
{
    /*
     * Parse the ValidatorRegistrations into ValidatorRecords and induct them.
     *
     * Ignore any records which fail proof-of-possession or are invalid.
     */
    let validators = {
        let mut inductor = ValidatorInductor::new(0, config.shard_count, vec![]);
        for registration in &config.initial_validators {
            let _ = inductor.induct(&registration, ValidatorStatus::Active);
        };
        inductor.to_vec()
    };

    /*
     * Assign the validators to shards, using all zeros as the seed.
     *
     * Crystallizedstate stores two cycles, so we simply repeat the same assignment twice.
     */
    let shard_and_committee_for_slots = {
        let mut a = shard_and_committees_for_cycle(&vec![0; 32], &validators, 0, &config)?;
        let mut b = a.clone();
        a.append(&mut b);
        a
    };

    /*
     * Set all the crosslink records to reference zero hashes.
     */
    let crosslinks = {
        let mut c = vec![];
        for _ in 0..config.shard_count {
            c.push(CrosslinkRecord {
                recently_changed: false,
                slot: 0,
                hash: Hash256::zero(),
            });
        }
        c
    };

    /*
     * Initialize a genesis `Crystallizedstate`
     */
    let crystallized_state = CrystallizedState {
        validator_set_change_slot: 0,
        validators: validators.to_vec(),
        crosslinks,
        last_state_recalculation_slot: 0,
        last_finalized_slot: 0,
        last_justified_slot: 0,
        justified_streak: 0,
        shard_and_committee_for_slots,
        deposits_penalized_in_period: vec![],
        validator_set_delta_hash_chain: Hash256::zero(),
        pre_fork_version: INITIAL_FORK_VERSION,
        post_fork_version: INITIAL_FORK_VERSION,
        fork_slot_number: 0,
    };

    /*
     * Set all recent block hashes to zero.
     */
    let recent_block_hashes = vec![Hash256::zero(); config.cycle_length as usize];

    /*
     * Create an active state.
     */
    let active_state = ActiveState {
        pending_attestations: vec![],
        pending_specials: vec![],
        recent_block_hashes,
        randao_mix: Hash256::zero(),
    };

    Ok((active_state, crystallized_state))
}

#[cfg(test)]
mod tests {
    extern crate validator_induction;
    extern crate bls;

    use super::*;
    use self::bls::{
        create_proof_of_possession,
        Keypair,
    };
    use types::{
        Hash256,
        Address,
    };

    #[test]
    fn test_genesis_no_validators() {
        let config = ChainConfig::standard();
        let (act, cry) = genesis_states(&config).unwrap();

        assert_eq!(cry.validator_set_change_slot, 0);
        assert_eq!(cry.validators.len(), 0);
        assert_eq!(cry.crosslinks.len(), config.shard_count as usize);
        for cl in cry.crosslinks {
            assert_eq!(cl.recently_changed, false);
            assert_eq!(cl.slot, 0);
            assert_eq!(cl.hash, Hash256::zero());
        }
        assert_eq!(cry.last_state_recalculation_slot, 0);
        assert_eq!(cry.last_finalized_slot, 0);
        assert_eq!(cry.last_justified_slot, 0);
        assert_eq!(cry.justified_streak, 0);
        assert_eq!(cry.shard_and_committee_for_slots.len(), (config.cycle_length as usize) * 2);
        assert_eq!(cry.deposits_penalized_in_period.len(), 0);
        assert_eq!(cry.validator_set_delta_hash_chain, Hash256::zero());
        assert_eq!(cry.pre_fork_version, INITIAL_FORK_VERSION);
        assert_eq!(cry.post_fork_version, INITIAL_FORK_VERSION);
        assert_eq!(cry.fork_slot_number, 0);

        assert_eq!(act.pending_attestations.len(), 0);
        assert_eq!(act.pending_specials.len(), 0);
        assert_eq!(act.recent_block_hashes, vec![Hash256::zero(); config.cycle_length as usize]);
        assert_eq!(act.randao_mix, Hash256::zero());
    }

    fn random_registration() -> ValidatorRegistration {
        let keypair = Keypair::random();
        ValidatorRegistration {
            pubkey: keypair.pk.clone(),
            withdrawal_shard: 0,
            withdrawal_address: Address::random(),
            randao_commitment: Hash256::random(),
            proof_of_possession: create_proof_of_possession(&keypair)
        }
    }

    #[test]
    fn test_genesis_valid_validators() {
        let mut config = ChainConfig::standard();
        let validator_count = 5;

        for _ in 0..validator_count {
            config.initial_validators.push(random_registration());
        }

        let (_, cry) = genesis_states(&config).unwrap();

        assert_eq!(cry.validators.len(), validator_count);
    }

    #[test]
    fn test_genesis_invalid_validators() {
        let mut config = ChainConfig::standard();
        let good_validator_count = 5;

        for _ in 0..good_validator_count {
            config.initial_validators.push(random_registration());
        }

        let mut bad_v = random_registration();
        let bad_kp = Keypair::random();
        bad_v.proof_of_possession =  create_proof_of_possession(&bad_kp);
        config.initial_validators.push(bad_v);

        let mut bad_v = random_registration();
        bad_v.withdrawal_shard =  config.shard_count + 1;
        config.initial_validators.push(bad_v);

        let (_, cry) = genesis_states(&config).unwrap();

        assert!(config.initial_validators.len() != good_validator_count, "test is invalid");
        assert_eq!(cry.validators.len(), good_validator_count);
    }
}
<|endoftext|>


<commit_before>use mio::*;
use mio::tcp::TcpStream;
use mio::channel::channel;
use mio::channel::{Sender, Receiver};
use std::collections::HashMap;
use std::net::IpAddr;
use std::net::SocketAddr;
use metainfo::MetaInfo;
use metainfo::SHA1Hash20b;
use wire::handler::{BasicHandler, PeerHandler};

const OUTSIDE_MSG: Token = Token(0);

pub struct Protocol<H: PeerHandler> {
    streams: HashMap<usize, TcpStream>,
    poll: Poll,
    sender: Sender<ChanMsg>,
    receiver: Receiver<ChanMsg>,
    info: MetaInfo,
    info_hash: SHA1Hash20b,
    handlers: Vec<Peer<H>>,
}

struct Peer<H: PeerHandler> {
    stream: TcpStream,
    handler: H,
    buffer: Vec<u8>,
}

#[derive(Debug)]
pub enum ChanMsg {
    NewPeer(IpAddr, u16),
}

impl<H: PeerHandler> Protocol<H> {
    pub fn new(info: &MetaInfo,
               hash: SHA1Hash20b)
               -> (Protocol<H>, Sender<ChanMsg>, Receiver<ChanMsg>) {
        let poll = Poll::new().unwrap();

        match (channel(), channel()) {
            ((to_inside, from_outside), (to_outside, from_inside)) => {

                poll.register(&from_outside,
                              OUTSIDE_MSG,
                              Ready::readable(),
                              PollOpt::edge())
                    .unwrap();

                let proto = Protocol {
                    streams: HashMap::new(),
                    poll: poll,
                    sender: to_outside,
                    receiver: from_outside,
                    info: info.clone(),
                    info_hash: hash,
                    handlers: Vec::new(),
                };

                (proto, to_inside, from_inside)
            }
        }
    }

    pub fn run(&mut self) {
        let mut events = Events::with_capacity(1024);
        loop {
            self.poll.poll(&mut events, None).unwrap();
            for event in events.iter() {
                match event.token() {
                    OUTSIDE_MSG => {
                        match self.receiver.try_recv() {
                            Ok(msg) => self._handle_outside_msg(msg),
                            _ => (),
                        }
                    }
                    _ => self._handle_socket_event(event),
                }
            }
        }
    }

    pub fn _handle_socket_event(&mut self, event: Event) {
        let kind = event.kind();
        if kind.is_readable() {
            // read bytes of messages
        }
        if kind.is_writable() {
            // write pending messages
        }
        if kind.is_hup() {
            // remove socket and clean up
        }
    }

    fn _handle_outside_msg(&mut self, msg: ChanMsg) {
        match msg {
            ChanMsg::NewPeer(ip, port) => self._connect_to_peer(ip, port),
        }
    }

    fn _connect_to_peer(&mut self, addr: IpAddr, port: u16) {
        let sock_addr = SocketAddr::new(addr, port);
        let sock = TcpStream::connect(&sock_addr).unwrap();
        self.poll
            .register(&sock,
                      Token(1),
                      Ready::readable() | Ready::writable(),
                      PollOpt::edge())
            .unwrap();
    }
}
<commit_msg>Add methods for handling read, write, hup<commit_after>use mio::*;
use mio::tcp::TcpStream;
use mio::channel::channel;
use mio::channel::{Sender, Receiver};
use std::collections::HashMap;
use std::net::IpAddr;
use std::net::SocketAddr;

use metainfo::MetaInfo;
use metainfo::SHA1Hash20b;

use wire::handler::{BasicHandler, PeerHandler};
use wire::data::PeerMsg;

const OUTSIDE_MSG: Token = Token(0);
type StreamId = u32;

pub struct Protocol {
    streams: HashMap<StreamId, (TcpStream, PeerStream)>,
    poll: Poll,
    sender: Sender<ChanMsg>,
    receiver: Receiver<ChanMsg>,
    info: MetaInfo,
    info_hash: SHA1Hash20b
}

struct PeerStream {
    id: StreamId,
    bytes_in: Vec<u8>,
    bytes_out: Vec<u8>
}

impl PeerStream {
    fn write_in(&mut self, bytes: &[u8]) {
        unimplemented!();
    }

    fn write_out(&mut self, bytes: &[u8]) {
        unimplemented!();
    }

    fn message(&mut self) -> Option<PeerMsg> {
        unimplemented!();
    }

    fn take(&mut self, len: usize) -> Vec<u8> {
        unimplemented!();
    }

}

#[derive(Debug)]
pub enum ChanMsg {
    NewPeer(IpAddr, u16),
}

impl Protocol {
    pub fn new(info: &MetaInfo,
               hash: SHA1Hash20b)
               -> (Protocol, Sender<ChanMsg>, Receiver<ChanMsg>) {
        let poll = Poll::new().unwrap();

        match (channel(), channel()) {
            ((to_inside, from_outside), (to_outside, from_inside)) => {

                poll.register(&from_outside,
                              OUTSIDE_MSG,
                              Ready::readable(),
                              PollOpt::edge())
                    .unwrap();

                let proto = Protocol {
                    streams: HashMap::new(),
                    poll: poll,
                    sender: to_outside,
                    receiver: from_outside,
                    info: info.clone(),
                    info_hash: hash
                };

                (proto, to_inside, from_inside)
            }
        }
    }

    pub fn run(&mut self) {
        let mut events = Events::with_capacity(1024);
        loop {
            self.poll.poll(&mut events, None).unwrap();
            for event in events.iter() {
                match event.token() {
                    OUTSIDE_MSG => {
                        match self.receiver.try_recv() {
                            Ok(msg) => self._handle_outside_msg(msg),
                            _ => (),
                        }
                    }
                    _ => self._handle_socket_event(event),
                }
            }
        }
    }

    fn _get_stream_id(&self, token: Token) -> Option<StreamId> {
        unimplemented!()
    }

    fn _handle_socket_event(&mut self, event: Event) {
        let kind = event.kind();
        let peer_id: StreamId = match self._get_stream_id(event.token()) {
            Some(p_id) => p_id,
            None => return
        };

        if let Some((mut tcp_stream, mut peer_stream)) = self.streams.remove(&peer_id) {
            if kind.is_readable() {
                // read bytes of messages
                self._handle_read(&mut tcp_stream, &mut peer_stream);
            }
            if kind.is_writable() {
                // write pending messages
                self._handle_write(&mut tcp_stream, &mut peer_stream);
            }
            if kind.is_hup() {
                // remove socket and clean up
                self._handle_hup(&mut tcp_stream,&mut  peer_stream);
            }
            self.streams.insert(peer_stream.id, (tcp_stream, peer_stream));
        }

    }

    fn _handle_read(&mut self, socket: &mut TcpStream, peer: &mut PeerStream) {

    }

    fn _handle_write(&mut self, socket: &mut TcpStream, peer: &mut PeerStream) {

    }

    fn _handle_hup(&mut self, socket: &mut TcpStream, peer: &mut PeerStream) {

    }

    fn _handle_outside_msg(&mut self, msg: ChanMsg) {
        match msg {
            ChanMsg::NewPeer(ip, port) => self._connect_to_peer(ip, port),
        }
    }

    fn _connect_to_peer(&mut self, addr: IpAddr, port: u16) {
        let sock_addr = SocketAddr::new(addr, port);
        let sock = TcpStream::connect(&sock_addr).unwrap();
        self.poll
            .register(&sock,
                      Token(1),
                      Ready::readable() | Ready::writable(),
                      PollOpt::edge())
            .unwrap();
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::{File, read_link};
use std::io::Write;
use std::ffi::OsString;
use std::io::ErrorKind::NotFound;
use std::ascii::AsciiExt;
use std::fs::{rename};
use std::fs::{remove_file, remove_dir};
use std::io::{stdout, stderr};
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::os::unix::io::FromRawFd;

use argparse::{ArgumentParser, Store, StoreTrue};
use rustc_serialize::json;
use unshare::{Command, Namespace, ExitStatus};

use container::util::clean_dir;
use container::mount::{bind_mount, unmount};
use container::uidmap::{map_users};
use config::{Container};
use config::builders::Builder as B;
use config::builders::Source as S;
use file_util::{create_dir, Lock};
use path_util::PathExt;
use process_util::{capture_fd3_status, set_uidmap, copy_env_vars};
use super::Wrapper;
use super::setup;

pub fn prepare_tmp_root_dir(path: &Path) -> Result<(), String> {
    if path.exists() {
        try!(clean_dir(path, true)
             .map_err(|x| format!("Error removing directory: {}", x)));
    }
    try_msg!(create_dir(path, true),
         "Error creating directory: {err}");
    let rootdir = path.join("root");
    try_msg!(create_dir(&rootdir, false),
         "Error creating directory: {err}");

    let tgtbase = Path::new("/vagga/container");
    try_msg!(create_dir(&tgtbase, false),
         "Error creating directory: {err}");
    try!(bind_mount(path, &tgtbase));

    let tgtroot = Path::new("/vagga/root");
    try_msg!(create_dir(&tgtroot, false),
         "Error creating directory: {err}");
    try!(bind_mount(&rootdir, &tgtroot));

    try_msg!(create_dir(&tgtroot.join("dev"), false),
         "Error creating directory: {err}");
    try_msg!(create_dir(&tgtroot.join("sys"), false),
         "Error creating directory: {err}");
    try_msg!(create_dir(&tgtroot.join("proc"), false),
         "Error creating directory: {err}");
    try_msg!(create_dir(&tgtroot.join("work"), false),
         "Error creating directory: {err}");
    return Ok(());
}

pub fn commit_root(tmp_path: &Path, final_path: &Path) -> Result<(), String> {
    let mut path_to_remove = None;
    if final_path.exists() {
        let rempath = tmp_path.with_file_name(
            // TODO(tailhook) consider these unwraps
            tmp_path.file_name().unwrap().to_str()
            .unwrap().to_string() + ".old");
        try!(rename(final_path, &rempath)
             .map_err(|x| format!("Error renaming old dir: {}", x)));
        path_to_remove = Some(rempath);
    }
    try!(rename(tmp_path, final_path)
         .map_err(|x| format!("Error renaming dir: {}", x)));
    if let Some(ref path_to_remove) = path_to_remove {
        try!(clean_dir(path_to_remove, true)
             .map_err(|x| format!("Error removing old dir: {}", x)));
    }
    return Ok(());
}

pub fn get_version_hash(container: &String, wrapper: &Wrapper)
    -> Result<Option<String>, String>
{
    let cconfig = try!(wrapper.config.containers.get(container)
        .ok_or(format!("Container {} not found", container)));
    let uid_map = try!(map_users(wrapper.settings,
        &cconfig.uids, &cconfig.gids));

    let mut cmd = Command::new("/vagga/bin/vagga");
    cmd.arg0("vagga_version");
    set_uidmap(&mut cmd, &uid_map, false);
    cmd.arg(&container);
    cmd.arg("--settings");
    cmd.arg(json::encode(wrapper.settings).unwrap());
    cmd.env_clear();
    copy_env_vars(&mut cmd, &wrapper.settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }
    match capture_fd3_status(cmd) {
        Ok((ExitStatus::Exited(0), val)) => {
            String::from_utf8(val)
                .map_err(|e| format!("Can't decode version: {}", e))
                .map(Some)
        },
        Ok((ExitStatus::Exited(29), _)) => Ok(None),
        Ok((status, _)) => return Err(format!("Versioner exited {}", status)),
        Err(e) => return Err(format!("Could not run versioner: {}", e)),
    }
}

pub fn build_container(container: &String, force: bool, wrapper: &Wrapper)
    -> Result<String, String>
{
    let cconfig = try!(wrapper.config.containers.get(container)
        .ok_or(format!("Container {} not found", container)));
    let name = try!(_build_container(cconfig, container, force, wrapper));
    let destlink = Path::new("/work/.vagga").join(&container);
    let tmplink = destlink.with_extension("tmp");
    if tmplink.exists() {
        try!(remove_file(&tmplink)
            .map_err(|e| format!("Error removing temporary link: {}", e)));
    }
    let roots = if wrapper.ext_settings.storage_dir.is_some() {
        Path::new(".lnk/.roots")
    } else {
        Path::new(".roots")
    };
    let linkval = roots.join(&name).join("root");
    if cconfig.auto_clean {
        match read_link(&destlink) {
            Ok(ref oldval) if oldval != &linkval => {
                let oldname = try!(oldval.iter().rev().nth(1)
                    .ok_or(format!("Bad link {:?} -> {:?}",
                        destlink, oldval)));
                let base = Path::new("/vagga/base/.roots");
                let dir = base.join(&oldname);
                let tmpdir = base.join({
                    let mut tmpname = OsString::from(".tmp");
                    tmpname.push(oldname);
                    tmpname
                });
                rename(&dir, &tmpdir)
                    .map_err(|e| error!("Error renaming old dir: {}", e)).ok();
                clean_dir(&tmpdir, true)
                    .map_err(|e| error!("Error removing old dir: {}", e)).ok();
            }
            Ok(_) => {}
            Err(ref e) if e.kind() == NotFound => {}
            Err(e) => {
                return Err(format!("Error reading symlin {:?}: {}",
                    destlink, e));
            }
        };
    }
    try!(symlink(&linkval, &tmplink)
         .map_err(|e| format!("Error symlinking container: {}", e)));
    try!(rename(&tmplink, &destlink)
         .map_err(|e| format!("Error renaming symlink: {}", e)));
    return Ok(name);
}

pub fn _build_container(cconfig: &Container, container: &String,
    force: bool, wrapper: &Wrapper)
    -> Result<String, String>
{
    let uid_map = try!(map_users(wrapper.settings,
        &cconfig.uids, &cconfig.gids));

    let ver = match get_version_hash(container, wrapper) {
        Ok(Some(ver)) => {
            if ver.len() == 64 && ver[..].is_ascii() {
                let name = format!("{}.{}", container, &ver[..8]);
                let finalpath = Path::new("/vagga/base/.roots")
                    .join(&name);
                debug!("Container path: {:?} (force: {}) {}", finalpath, force,
                    finalpath.exists());
                if finalpath.exists() && !force {
                    debug!("Path {} is already built",
                           finalpath.display());
                    return Ok(name);
                }
                Some(ver)
            } else {
                error!("Wrong version hash: {:?}", ver);
                None
            }
        }
        Ok(None) => None,
        Err(e) => return Err(e),
    };
    debug!("Container version: {:?}", ver);
    let tmppath = PathBuf::from(
        &format!("/vagga/base/.roots/.tmp.{}", container));

    let _lock_guard = try!(Lock::exclusive(
            &tmppath.with_file_name(format!(".tmp.{}.lock", container)))
        .map_err(|e| format!("Can't lock container build ({}). \
            Probably other process is doing build. Aborting...", e)));

    match prepare_tmp_root_dir(&tmppath) {
        Ok(()) => {}
        Err(x) => {
            return Err(format!("Error preparing root dir: {}", x));
        }
    }

    let mut cmd = Command::new("/vagga/bin/vagga");
    cmd.arg0("vagga_build");
    set_uidmap(&mut cmd, &uid_map, false);
    cmd.unshare(
        [Namespace::Mount, Namespace::Ipc, Namespace::Pid].iter().cloned());
    cmd.arg(&container);
    cmd.arg("--settings");
    cmd.arg(json::encode(wrapper.settings).unwrap());
    cmd.env_clear();
    copy_env_vars(&mut cmd, &wrapper.settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }

    let result = cmd.status();
    try!(unmount(&Path::new("/vagga/root")));
    try!(remove_dir(&Path::new("/vagga/root"))
        .map_err(|e| format!("Can't unlink root: {}", e)));
    try!(unmount(&Path::new("/vagga/container")));
    try!(remove_dir(&Path::new("/vagga/container"))
        .map_err(|e| format!("Can't unlink root: {}", e)));
    match result {
        Ok(s) if s.success() => {}
        Ok(s) => return Err(format!("Builder {}", s)),
        Err(e) => return Err(format!("Error running builder: {}", e)),
    };

    let ver = if let Some(ver) = ver { ver }
        else {
            match get_version_hash(container, wrapper) {
                Ok(Some(ver)) => {
                    if ver.len() == 64 && ver[..].is_ascii() {
                        ver
                    } else {
                        return Err(format!("Internal Error: \
                                Wrong version returned: {:?}", ver));
                    }
                }
                Ok(None) => {
                    return Err(format!("Internal Error: \
                            Can't version even after build"));
                },
                Err(e) => return Err(e),
            }
        };
    let name = format!("{}.{}", container,
        &ver[..8]);
    let finalpath = Path::new("/vagga/base/.roots").join(&name);
    debug!("Committing {} -> {}", tmppath.display(),
                                  finalpath.display());
    match commit_root(&tmppath, &finalpath) {
        Ok(()) => {}
        Err(x) => {
            return Err(format!("Error committing root dir: {}", x));
        }
    }
    return Ok(name);
}

pub fn build_container_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut name: String = "".to_string();
    let mut force: bool = false;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Internal vagga tool to setup basic system sandbox
            ");
        ap.refer(&mut name)
            .add_argument("container_name", Store,
                "Container name to build");
        ap.refer(&mut force)
            .add_option(&["--force"], StoreTrue,
                "Force build even if container is considered up to date");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(122);
            }
        }
    }
    try!(setup::setup_base_filesystem(
        wrapper.project_root, wrapper.ext_settings));

    build_wrapper(&name, force, wrapper)
    .map(|x| unsafe { File::from_raw_fd(3) }.write_all(x.as_bytes()).unwrap())
    .map(|_| 0)
}

pub fn build_wrapper(name: &String, force: bool, wrapper: &Wrapper)
    -> Result<String, String>
{
    let container = try!(wrapper.config.containers.get(name)
        .ok_or(format!("Container {:?} not found", name)));
    for step in container.setup.iter() {
        match step {
            &B::Container(ref name) => {
                try!(build_wrapper(name, force, wrapper)
                    .map(|x| debug!("Built container with name {}", x))
                    .map(|()| 0));
            }
            &B::SubConfig(ref cfg) => {
                match cfg.source {
                    S::Directory => {}
                    S::Container(ref name) => {
                        try!(build_wrapper(name, force, wrapper)
                            .map(|x| debug!("Built container with name {}", x))
                            .map(|()| 0));
                    }
                    S::Git(ref _git) => {
                        unimplemented!();
                    }
                }
            }
            _ => {}
        }
    }

    return build_container(name, force, wrapper)
}

pub fn print_version_hash_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut name: String = "".to_string();
    let mut short = false;
    let mut fd3 = false;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Prints version hash of the container without building it. If
            this command exits with code 29, then container can't be versioned
            before the build.
            ");
        ap.refer(&mut name)
            .add_argument("container_name", Store,
                "Container name to build");
        ap.refer(&mut short)
            .add_option(&["-s", "--short"], StoreTrue,
                "Print short container version, like used in directory names \
                 (8 chars)");
        ap.refer(&mut fd3)
            .add_option(&["--fd3"], StoreTrue,
                "Print into file descriptor #3 instead of stdout");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(122);
            }
        }
    }
    try!(setup::setup_base_filesystem(
        wrapper.project_root, wrapper.ext_settings));
    if let Some(hash) = try!(get_version_hash(&name, wrapper)) {
        let res = if short { &hash[..8] } else { &hash[..] };
        if fd3 {
            try!(unsafe { File::from_raw_fd(3) }.write_all(res.as_bytes())
                .map_err(|e| format!("Error writing to fd 3: {}", e)));
        } else {
            println!("{}", res);
        }
        Ok(0)
    } else {
        Ok(29)
    }
}

<commit_msg>Fix bug of replacing container build directory (fixes #115)<commit_after>use std::env;
use std::fs::{File, read_link};
use std::io::Write;
use std::ffi::OsString;
use std::io::ErrorKind::NotFound;
use std::ascii::AsciiExt;
use std::fs::{rename};
use std::fs::{remove_file, remove_dir};
use std::io::{stdout, stderr};
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::os::unix::io::FromRawFd;

use argparse::{ArgumentParser, Store, StoreTrue};
use rustc_serialize::json;
use unshare::{Command, Namespace, ExitStatus};

use container::util::clean_dir;
use container::mount::{bind_mount, unmount};
use container::uidmap::{map_users};
use config::{Container};
use config::builders::Builder as B;
use config::builders::Source as S;
use file_util::{create_dir, Lock};
use path_util::PathExt;
use process_util::{capture_fd3_status, set_uidmap, copy_env_vars};
use super::Wrapper;
use super::setup;

pub fn prepare_tmp_root_dir(path: &Path) -> Result<(), String> {
    if path.exists() {
        try!(clean_dir(path, true)
             .map_err(|x| format!("Error removing directory: {}", x)));
    }
    try_msg!(create_dir(path, true),
         "Error creating directory: {err}");
    let rootdir = path.join("root");
    try_msg!(create_dir(&rootdir, false),
         "Error creating directory: {err}");

    let tgtbase = Path::new("/vagga/container");
    try_msg!(create_dir(&tgtbase, false),
         "Error creating directory: {err}");
    try!(bind_mount(path, &tgtbase));

    let tgtroot = Path::new("/vagga/root");
    try_msg!(create_dir(&tgtroot, false),
         "Error creating directory: {err}");
    try!(bind_mount(&rootdir, &tgtroot));

    try_msg!(create_dir(&tgtroot.join("dev"), false),
         "Error creating directory: {err}");
    try_msg!(create_dir(&tgtroot.join("sys"), false),
         "Error creating directory: {err}");
    try_msg!(create_dir(&tgtroot.join("proc"), false),
         "Error creating directory: {err}");
    try_msg!(create_dir(&tgtroot.join("work"), false),
         "Error creating directory: {err}");
    return Ok(());
}

pub fn commit_root(tmp_path: &Path, final_path: &Path) -> Result<(), String> {
    let mut path_to_remove = None;
    if final_path.exists() {
        let rempath = tmp_path.with_file_name(
            // TODO(tailhook) consider these unwraps
            tmp_path.file_name().unwrap().to_str()
            .unwrap().to_string() + ".old");
        if rempath.is_dir() {
            try!(clean_dir(&rempath, true)
                 .map_err(|x| format!("Error removing old dir: {}", x)));
        }
        try!(rename(final_path, &rempath)
             .map_err(|x| format!("Error renaming old dir: {}", x)));
        path_to_remove = Some(rempath);
    }
    try!(rename(tmp_path, final_path)
         .map_err(|x| format!("Error renaming dir: {}", x)));
    if let Some(ref path_to_remove) = path_to_remove {
        try!(clean_dir(path_to_remove, true)
             .map_err(|x| format!("Error removing old dir: {}", x)));
    }
    return Ok(());
}

pub fn get_version_hash(container: &String, wrapper: &Wrapper)
    -> Result<Option<String>, String>
{
    let cconfig = try!(wrapper.config.containers.get(container)
        .ok_or(format!("Container {} not found", container)));
    let uid_map = try!(map_users(wrapper.settings,
        &cconfig.uids, &cconfig.gids));

    let mut cmd = Command::new("/vagga/bin/vagga");
    cmd.arg0("vagga_version");
    set_uidmap(&mut cmd, &uid_map, false);
    cmd.arg(&container);
    cmd.arg("--settings");
    cmd.arg(json::encode(wrapper.settings).unwrap());
    cmd.env_clear();
    copy_env_vars(&mut cmd, &wrapper.settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }
    match capture_fd3_status(cmd) {
        Ok((ExitStatus::Exited(0), val)) => {
            String::from_utf8(val)
                .map_err(|e| format!("Can't decode version: {}", e))
                .map(Some)
        },
        Ok((ExitStatus::Exited(29), _)) => Ok(None),
        Ok((status, _)) => return Err(format!("Versioner exited {}", status)),
        Err(e) => return Err(format!("Could not run versioner: {}", e)),
    }
}

pub fn build_container(container: &String, force: bool, wrapper: &Wrapper)
    -> Result<String, String>
{
    let cconfig = try!(wrapper.config.containers.get(container)
        .ok_or(format!("Container {} not found", container)));
    let name = try!(_build_container(cconfig, container, force, wrapper));
    let destlink = Path::new("/work/.vagga").join(&container);
    let tmplink = destlink.with_extension("tmp");
    if tmplink.exists() {
        try!(remove_file(&tmplink)
            .map_err(|e| format!("Error removing temporary link: {}", e)));
    }
    let roots = if wrapper.ext_settings.storage_dir.is_some() {
        Path::new(".lnk/.roots")
    } else {
        Path::new(".roots")
    };
    let linkval = roots.join(&name).join("root");
    if cconfig.auto_clean {
        match read_link(&destlink) {
            Ok(ref oldval) if oldval != &linkval => {
                let oldname = try!(oldval.iter().rev().nth(1)
                    .ok_or(format!("Bad link {:?} -> {:?}",
                        destlink, oldval)));
                let base = Path::new("/vagga/base/.roots");
                let dir = base.join(&oldname);
                let tmpdir = base.join({
                    let mut tmpname = OsString::from(".tmp");
                    tmpname.push(oldname);
                    tmpname
                });
                rename(&dir, &tmpdir)
                    .map_err(|e| error!("Error renaming old dir: {}", e)).ok();
                clean_dir(&tmpdir, true)
                    .map_err(|e| error!("Error removing old dir: {}", e)).ok();
            }
            Ok(_) => {}
            Err(ref e) if e.kind() == NotFound => {}
            Err(e) => {
                return Err(format!("Error reading symlin {:?}: {}",
                    destlink, e));
            }
        };
    }
    try!(symlink(&linkval, &tmplink)
         .map_err(|e| format!("Error symlinking container: {}", e)));
    try!(rename(&tmplink, &destlink)
         .map_err(|e| format!("Error renaming symlink: {}", e)));
    return Ok(name);
}

pub fn _build_container(cconfig: &Container, container: &String,
    force: bool, wrapper: &Wrapper)
    -> Result<String, String>
{
    let uid_map = try!(map_users(wrapper.settings,
        &cconfig.uids, &cconfig.gids));

    let ver = match get_version_hash(container, wrapper) {
        Ok(Some(ver)) => {
            if ver.len() == 64 && ver[..].is_ascii() {
                let name = format!("{}.{}", container, &ver[..8]);
                let finalpath = Path::new("/vagga/base/.roots")
                    .join(&name);
                debug!("Container path: {:?} (force: {}) {}", finalpath, force,
                    finalpath.exists());
                if finalpath.exists() && !force {
                    debug!("Path {} is already built",
                           finalpath.display());
                    return Ok(name);
                }
                Some(ver)
            } else {
                error!("Wrong version hash: {:?}", ver);
                None
            }
        }
        Ok(None) => None,
        Err(e) => return Err(e),
    };
    debug!("Container version: {:?}", ver);
    let tmppath = PathBuf::from(
        &format!("/vagga/base/.roots/.tmp.{}", container));

    let _lock_guard = try!(Lock::exclusive(
            &tmppath.with_file_name(format!(".tmp.{}.lock", container)))
        .map_err(|e| format!("Can't lock container build ({}). \
            Probably other process is doing build. Aborting...", e)));

    match prepare_tmp_root_dir(&tmppath) {
        Ok(()) => {}
        Err(x) => {
            return Err(format!("Error preparing root dir: {}", x));
        }
    }

    let mut cmd = Command::new("/vagga/bin/vagga");
    cmd.arg0("vagga_build");
    set_uidmap(&mut cmd, &uid_map, false);
    cmd.unshare(
        [Namespace::Mount, Namespace::Ipc, Namespace::Pid].iter().cloned());
    cmd.arg(&container);
    cmd.arg("--settings");
    cmd.arg(json::encode(wrapper.settings).unwrap());
    cmd.env_clear();
    copy_env_vars(&mut cmd, &wrapper.settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }

    let result = cmd.status();
    try!(unmount(&Path::new("/vagga/root")));
    try!(remove_dir(&Path::new("/vagga/root"))
        .map_err(|e| format!("Can't unlink root: {}", e)));
    try!(unmount(&Path::new("/vagga/container")));
    try!(remove_dir(&Path::new("/vagga/container"))
        .map_err(|e| format!("Can't unlink root: {}", e)));
    match result {
        Ok(s) if s.success() => {}
        Ok(s) => return Err(format!("Builder {}", s)),
        Err(e) => return Err(format!("Error running builder: {}", e)),
    };

    let ver = if let Some(ver) = ver { ver }
        else {
            match get_version_hash(container, wrapper) {
                Ok(Some(ver)) => {
                    if ver.len() == 64 && ver[..].is_ascii() {
                        ver
                    } else {
                        return Err(format!("Internal Error: \
                                Wrong version returned: {:?}", ver));
                    }
                }
                Ok(None) => {
                    return Err(format!("Internal Error: \
                            Can't version even after build"));
                },
                Err(e) => return Err(e),
            }
        };
    let name = format!("{}.{}", container,
        &ver[..8]);
    let finalpath = Path::new("/vagga/base/.roots").join(&name);
    debug!("Committing {} -> {}", tmppath.display(),
                                  finalpath.display());
    match commit_root(&tmppath, &finalpath) {
        Ok(()) => {}
        Err(x) => {
            return Err(format!("Error committing root dir: {}", x));
        }
    }
    return Ok(name);
}

pub fn build_container_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut name: String = "".to_string();
    let mut force: bool = false;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Internal vagga tool to setup basic system sandbox
            ");
        ap.refer(&mut name)
            .add_argument("container_name", Store,
                "Container name to build");
        ap.refer(&mut force)
            .add_option(&["--force"], StoreTrue,
                "Force build even if container is considered up to date");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(122);
            }
        }
    }
    try!(setup::setup_base_filesystem(
        wrapper.project_root, wrapper.ext_settings));

    build_wrapper(&name, force, wrapper)
    .map(|x| unsafe { File::from_raw_fd(3) }.write_all(x.as_bytes()).unwrap())
    .map(|_| 0)
}

pub fn build_wrapper(name: &String, force: bool, wrapper: &Wrapper)
    -> Result<String, String>
{
    let container = try!(wrapper.config.containers.get(name)
        .ok_or(format!("Container {:?} not found", name)));
    for step in container.setup.iter() {
        match step {
            &B::Container(ref name) => {
                try!(build_wrapper(name, force, wrapper)
                    .map(|x| debug!("Built container with name {}", x))
                    .map(|()| 0));
            }
            &B::SubConfig(ref cfg) => {
                match cfg.source {
                    S::Directory => {}
                    S::Container(ref name) => {
                        try!(build_wrapper(name, force, wrapper)
                            .map(|x| debug!("Built container with name {}", x))
                            .map(|()| 0));
                    }
                    S::Git(ref _git) => {
                        unimplemented!();
                    }
                }
            }
            _ => {}
        }
    }

    return build_container(name, force, wrapper)
}

pub fn print_version_hash_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut name: String = "".to_string();
    let mut short = false;
    let mut fd3 = false;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Prints version hash of the container without building it. If
            this command exits with code 29, then container can't be versioned
            before the build.
            ");
        ap.refer(&mut name)
            .add_argument("container_name", Store,
                "Container name to build");
        ap.refer(&mut short)
            .add_option(&["-s", "--short"], StoreTrue,
                "Print short container version, like used in directory names \
                 (8 chars)");
        ap.refer(&mut fd3)
            .add_option(&["--fd3"], StoreTrue,
                "Print into file descriptor #3 instead of stdout");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(122);
            }
        }
    }
    try!(setup::setup_base_filesystem(
        wrapper.project_root, wrapper.ext_settings));
    if let Some(hash) = try!(get_version_hash(&name, wrapper)) {
        let res = if short { &hash[..8] } else { &hash[..] };
        if fd3 {
            try!(unsafe { File::from_raw_fd(3) }.write_all(res.as_bytes())
                .map_err(|e| format!("Error writing to fd 3: {}", e)));
        } else {
            println!("{}", res);
        }
        Ok(0)
    } else {
        Ok(29)
    }
}

<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fs::{read_dir, read_link};
use std::io::{stdout, stderr};
use std::path::Path;
use std::str::FromStr;

use argparse::{ArgumentParser, PushConst, StoreTrue};

use super::setup;
use super::Wrapper;
use container::util::clean_dir;
use file_util::read_visible_entries;
use path_util::PathExt;

#[derive(Clone, Copy)]
enum Action {
    Temporary,
    Old,
    Everything,
    Orphans,
    Transient,
}

pub fn clean_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut global = false;
    let mut dry_run = false;
    let mut actions = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Performs various cleanup tasks
            ");
        ap.refer(&mut actions)
          .add_option(&["--tmp", "--tmp-folders"],
                PushConst(Action::Temporary),
                "Clean temporary containers (failed builds)")
          .add_option(&["--old", "--old-containers"], PushConst(Action::Old),
                "Clean old versions of containers (configurable)")
          .add_option(&["--transient"], PushConst(Action::Transient),
                "Clean unneeded transient folders (left from containers with
                 `write-mode` set to transient-something). The pid of process
                 is checked for liveness first.")
          .add_option(&["--everything"], PushConst(Action::Everything),
                "Clean whole `.vagga` folder. Useful when deleting a project.
                 With ``--global`` cleans whole storage-dir and cache-dir")
          .add_option(&["--orphans"], PushConst(Action::Orphans),
                "Without `--global` removes containers which are not in
                 vagga.yaml any more. With `--global` removes all folders
                 which have `.lnk` pointing to nowhere (i.e. project dir
                 already deleted while vagga folder is not)")
          .required();
        ap.refer(&mut global)
          .add_option(&["--global"], StoreTrue,
                "Apply cleanup command to all containers. Works only \
                if `storage-dir` is configured in settings");
        ap.refer(&mut dry_run)
          .add_option(&["-n", "--dry-run"], StoreTrue,
                "Dry run. Don't delete everything, just print");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(1);
            }
        }
    }
    if global && wrapper.ext_settings.storage_dir.is_none() {
        error!("The --global flag is only meaningful if you configure \
            storage-dir in settings");
        return Ok(2);
    }
    for action in actions.iter() {
        let res = match *action {
            Action::Temporary => clean_temporary(wrapper, global, dry_run),
            Action::Old => clean_old(wrapper, global, dry_run),
            Action::Transient => clean_transient(wrapper, global, dry_run),
            _ => unimplemented!(),
        };
        match res {
            Ok(()) => {}
            Err(err) => {
                error!("Error cleaning up: {}", err);
                return Ok(3);
            }
        }
    }
    return Ok(0);
}

fn clean_dir_wrapper(path: &Path, dry_run: bool) -> Result<(), String> {
    // TODO(tailhook) chroot to dir for removing
    if dry_run {
        println!("Would remove {:?}", path);
    } else {
        debug!("Removing {:?}", path);
        try!(clean_dir(path, true));
    }
    Ok(())
}

fn clean_temporary(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let roots = base.join(".roots");
    for entry in try_msg!(read_dir(&roots),
        "Can't read dir {r:?}: {err}", r=roots)
    {
        let entry = try_msg!(entry, "Can't read dir {r:?}: {err}", r=roots);
        if entry.file_name()[..].to_str().map(|n| n.starts_with(".tmp"))
                                         .unwrap_or(false)
        {
            try!(clean_dir_wrapper(&entry.path(), dry_run));
        }
    }

    return Ok(());
}

fn clean_old(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let useful: HashSet<String> = try_msg!(
        read_visible_entries(&wrapper.project_root.join(".vagga")),
            "Can't read vagga directory: {err}")
        .into_iter()
        .filter_map(|path| read_link(&path)
             .map_err(|e| warn!("Can't readlink {:?}: {}", path, e))
             .ok()
             .and_then(|f| {
                 // The container name is next to the last component
                 f.iter().rev().nth(1)
                 .and_then(|x| x.to_str()).map(ToString::to_string)
             }))
        .collect();
    debug!("Useful images {:?}", useful);

    let roots = base.join(".roots");
    for entry in try_msg!(read_dir(&roots),
                         "Can't read dir {dir:?}: {err}", dir=roots)
    {
        let entry = try_msg!(entry,
                             "Can't read dir {dir:?}: {err}", dir=roots);
        if entry.file_name()[..].to_str()
            .map(|n| !useful.contains(&n.to_string()))
            .unwrap_or(false)
        {
            try!(clean_dir_wrapper(&entry.path(), dry_run));
        }
    }

    return Ok(());
}

fn clean_transient(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let procfs = Path::new("/proc");
    for entry in try_msg!(read_dir(&base.join(".transient")),
                        "Can't read .vagga/.transient dir: {err}")
    {
        let entry = try_msg!(entry, "Error reading .vagga/transient: {err}");
        if let Some(fname) = entry.file_name()[..].to_str() {
            if let Some(idx) = fname.find('.') {
                if u32::from_str(&fname[idx+1..]).is_ok() &&
                    procfs.join(&fname[idx+1..]).exists()
                {
                    continue;
                }
            }
        }
        try!(clean_dir_wrapper(&entry.path(), dry_run));
    }

    return Ok(());
}
<commit_msg>Unbroken `_clean --old` (fixes #95)<commit_after>use std::collections::HashSet;
use std::fs::{read_dir, read_link, remove_file};
use std::io::{stdout, stderr};
use std::path::Path;
use std::str::FromStr;

use argparse::{ArgumentParser, PushConst, StoreTrue};

use super::setup;
use super::Wrapper;
use container::util::clean_dir;
use file_util::read_visible_entries;
use path_util::PathExt;

#[derive(Clone, Copy)]
enum Action {
    Temporary,
    Old,
    Everything,
    Orphans,
    Transient,
}

pub fn clean_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
    -> Result<i32, String>
{
    let mut global = false;
    let mut dry_run = false;
    let mut actions = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Performs various cleanup tasks
            ");
        ap.refer(&mut actions)
          .add_option(&["--tmp", "--tmp-folders"],
                PushConst(Action::Temporary),
                "Clean temporary containers (failed builds)")
          .add_option(&["--old", "--old-containers"], PushConst(Action::Old),
                "Clean old versions of containers (configurable)")
          .add_option(&["--transient"], PushConst(Action::Transient),
                "Clean unneeded transient folders (left from containers with
                 `write-mode` set to transient-something). The pid of process
                 is checked for liveness first.")
          .add_option(&["--everything"], PushConst(Action::Everything),
                "Clean whole `.vagga` folder. Useful when deleting a project.
                 With ``--global`` cleans whole storage-dir and cache-dir")
          .add_option(&["--orphans"], PushConst(Action::Orphans),
                "Without `--global` removes containers which are not in
                 vagga.yaml any more. With `--global` removes all folders
                 which have `.lnk` pointing to nowhere (i.e. project dir
                 already deleted while vagga folder is not)")
          .required();
        ap.refer(&mut global)
          .add_option(&["--global"], StoreTrue,
                "Apply cleanup command to all containers. Works only \
                if `storage-dir` is configured in settings");
        ap.refer(&mut dry_run)
          .add_option(&["-n", "--dry-run"], StoreTrue,
                "Dry run. Don't delete everything, just print");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(1);
            }
        }
    }
    if global && wrapper.ext_settings.storage_dir.is_none() {
        error!("The --global flag is only meaningful if you configure \
            storage-dir in settings");
        return Ok(2);
    }
    for action in actions.iter() {
        let res = match *action {
            Action::Temporary => clean_temporary(wrapper, global, dry_run),
            Action::Old => clean_old(wrapper, global, dry_run),
            Action::Transient => clean_transient(wrapper, global, dry_run),
            _ => unimplemented!(),
        };
        match res {
            Ok(()) => {}
            Err(err) => {
                error!("Error cleaning up: {}", err);
                return Ok(3);
            }
        }
    }
    return Ok(0);
}

fn clean_dir_wrapper(path: &Path, dry_run: bool) -> Result<(), String> {
    // TODO(tailhook) chroot to dir for removing
    if dry_run {
        println!("Would remove {:?}", path);
    } else {
        debug!("Removing {:?}", path);
        try!(clean_dir(path, true));
    }
    Ok(())
}

fn clean_temporary(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let roots = base.join(".roots");
    for entry in try_msg!(read_dir(&roots),
        "Can't read dir {r:?}: {err}", r=roots)
    {
        let entry = try_msg!(entry, "Can't read dir {r:?}: {err}", r=roots);
        let typ = try_msg!(entry.file_type(),
            "Can't stat {p:?}: {err}", p=entry.path());
        if typ.is_dir() &&
           entry.file_name()[..].to_str().map(|n| n.starts_with(".tmp"))
                                         .unwrap_or(false)
        {
            try!(clean_dir_wrapper(&entry.path(), dry_run));
        }
    }

    return Ok(());
}

fn clean_old(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let useful: HashSet<String> = try_msg!(
        read_visible_entries(&wrapper.project_root.join(".vagga")),
            "Can't read vagga directory: {err}")
        .into_iter()
        .filter_map(|path| read_link(&path)
             .map_err(|e| warn!("Can't readlink {:?}: {}", path, e))
             .ok()
             .and_then(|f| {
                 // The container name is next to the last component
                 f.iter().rev().nth(1)
                 .and_then(|x| x.to_str()).map(ToString::to_string)
             }))
        .collect();
    debug!("Useful images {:?}", useful);

    let roots = base.join(".roots");
    for entry in try_msg!(read_dir(&roots),
                         "Can't read dir {dir:?}: {err}", dir=roots)
    {
        let entry = try_msg!(entry,
                             "Can't read dir {dir:?}: {err}", dir=roots);
        let typ = try_msg!(entry.file_type(),
            "Can't stat {p:?}: {err}", p=entry.path());
        if !typ.is_dir() {
            try_msg!(remove_file(&entry.path()),
                "Can't remove file {p:?}: {err}", p=entry.path());
        } else if !typ.is_dir() || entry.file_name()[..].to_str()
            .map(|n| !useful.contains(&n.to_string()))
            .unwrap_or(false)
        {
            try!(clean_dir_wrapper(&entry.path(), dry_run));
        }
    }

    return Ok(());
}

fn clean_transient(wrapper: &Wrapper, global: bool, dry_run: bool)
    -> Result<(), String>
{
    if global {
        panic!("Global cleanup is not implemented yet");
    }
    let base = match try!(setup::get_vagga_base(
        wrapper.project_root, wrapper.ext_settings))
    {
        Some(base) => base,
        None => {
            warn!("No vagga directory exists");
            return Ok(());
        }
    };
    let procfs = Path::new("/proc");
    for entry in try_msg!(read_dir(&base.join(".transient")),
                        "Can't read .vagga/.transient dir: {err}")
    {
        let entry = try_msg!(entry, "Error reading .vagga/transient: {err}");
        if let Some(fname) = entry.file_name()[..].to_str() {
            if let Some(idx) = fname.find('.') {
                if u32::from_str(&fname[idx+1..]).is_ok() &&
                    procfs.join(&fname[idx+1..]).exists()
                {
                    continue;
                }
            }
        }
        try!(clean_dir_wrapper(&entry.path(), dry_run));
    }

    return Ok(());
}
<|endoftext|>


<commit_before>//! Definitions of integer that is known not to equal zero.

use crate::fmt;
use crate::ops::{BitOr, BitOrAssign, Div, Rem};
use crate::str::FromStr;

use super::from_str_radix;
use super::{IntErrorKind, ParseIntError};
use crate::intrinsics;

macro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        #[doc = $x]
        $($tt)*
    };
}

macro_rules! impl_nonzero_fmt {
    ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
        $(
            #[$stability]
            impl fmt::$Trait for $Ty {
                #[inline]
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    self.get().fmt(f)
                }
            }
        )+
    }
}

macro_rules! nonzero_integers {
    ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
        $(
            doc_comment! {
                concat!("An integer that is known not to equal zero.

This enables some memory layout optimization.
For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:

```rust
use std::mem::size_of;
assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
">());
```"),
                #[$stability]
                #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
                #[repr(transparent)]
                #[rustc_layout_scalar_valid_range_start(1)]
                #[rustc_nonnull_optimization_guaranteed]
                pub struct $Ty($Int);
            }

            impl $Ty {
                /// Creates a non-zero without checking the value.
                ///
                /// # Safety
                ///
                /// The value must not be zero.
                #[$stability]
                #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
                #[inline]
                pub const unsafe fn new_unchecked(n: $Int) -> Self {
                    // SAFETY: this is guaranteed to be safe by the caller.
                    unsafe { Self(n) }
                }

                /// Creates a non-zero if the given value is not zero.
                #[$stability]
                #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
                #[inline]
                pub const fn new(n: $Int) -> Option<Self> {
                    if n != 0 {
                        // SAFETY: we just checked that there's no `0`
                        Some(unsafe { Self(n) })
                    } else {
                        None
                    }
                }

                /// Returns the value as a primitive type.
                #[$stability]
                #[inline]
                #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
                pub const fn get(self) -> $Int {
                    self.0
                }

            }

            #[stable(feature = "from_nonzero", since = "1.31.0")]
            impl From<$Ty> for $Int {
                doc_comment! {
                    concat!(
"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
                    #[inline]
                    fn from(nonzero: $Ty) -> Self {
                        nonzero.0
                    }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOr for $Ty {
                type Output = Self;
                #[inline]
                fn bitor(self, rhs: Self) -> Self::Output {
                    // SAFETY: since `self` and `rhs` are both nonzero, the
                    // result of the bitwise-or will be nonzero.
                    unsafe { $Ty::new_unchecked(self.get() | rhs.get()) }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOr<$Int> for $Ty {
                type Output = Self;
                #[inline]
                fn bitor(self, rhs: $Int) -> Self::Output {
                    // SAFETY: since `self` is nonzero, the result of the
                    // bitwise-or will be nonzero regardless of the value of
                    // `rhs`.
                    unsafe { $Ty::new_unchecked(self.get() | rhs) }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOr<$Ty> for $Int {
                type Output = $Ty;
                #[inline]
                fn bitor(self, rhs: $Ty) -> Self::Output {
                    // SAFETY: since `rhs` is nonzero, the result of the
                    // bitwise-or will be nonzero regardless of the value of
                    // `self`.
                    unsafe { $Ty::new_unchecked(self | rhs.get()) }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOrAssign for $Ty {
                #[inline]
                fn bitor_assign(&mut self, rhs: Self) {
                    *self = *self | rhs;
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOrAssign<$Int> for $Ty {
                #[inline]
                fn bitor_assign(&mut self, rhs: $Int) {
                    *self = *self | rhs;
                }
            }

            impl_nonzero_fmt! {
                #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
            }
        )+
    }
}

nonzero_integers! {
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
}

macro_rules! from_str_radix_nzint_impl {
    ($($t:ty)*) => {$(
        #[stable(feature = "nonzero_parse", since = "1.35.0")]
        impl FromStr for $t {
            type Err = ParseIntError;
            fn from_str(src: &str) -> Result<Self, Self::Err> {
                Self::new(from_str_radix(src, 10)?)
                    .ok_or(ParseIntError {
                        kind: IntErrorKind::Zero
                    })
            }
        }
    )*}
}

from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }

macro_rules! nonzero_leading_trailing_zeros {
    ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
        $(
            impl $Ty {
                doc_comment! {
                    concat!("Returns the number of leading zeros in the binary representation of `self`.

On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.

# Examples

Basic usage:

```
#![feature(nonzero_leading_trailing_zeros)]
let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();

assert_eq!(n.leading_zeros(), 0);
```"),
                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[inline]
                    pub const fn leading_zeros(self) -> u32 {
                        // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
                        unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
                    }
                }

                doc_comment! {
                    concat!("Returns the number of trailing zeros in the binary representation
of `self`.

On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.

# Examples

Basic usage:

```
#![feature(nonzero_leading_trailing_zeros)]
let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();

assert_eq!(n.trailing_zeros(), 3);
```"),
                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[inline]
                    pub const fn trailing_zeros(self) -> u32 {
                        // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
                        unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
                    }
                }

            }
        )+
    }
}

nonzero_leading_trailing_zeros! {
    NonZeroU8(u8), u8::MAX;
    NonZeroU16(u16), u16::MAX;
    NonZeroU32(u32), u32::MAX;
    NonZeroU64(u64), u64::MAX;
    NonZeroU128(u128), u128::MAX;
    NonZeroUsize(usize), usize::MAX;
    NonZeroI8(u8), -1i8;
    NonZeroI16(u16), -1i16;
    NonZeroI32(u32), -1i32;
    NonZeroI64(u64), -1i64;
    NonZeroI128(u128), -1i128;
    NonZeroIsize(usize), -1isize;
}

macro_rules! nonzero_integers_div {
    ( $( $Ty: ident($Int: ty); )+ ) => {
        $(
            #[stable(feature = "nonzero_div", since = "1.50.0")]
            impl Div<$Ty> for $Int {
                type Output = $Int;
                /// This operation rounds towards zero,
                /// truncating any fractional part of the exact result, and cannot panic.
                #[inline]
                fn div(self, other: $Ty) -> $Int {
                    // SAFETY: div by zero is checked because `other` is a nonzero,
                    // and MIN/-1 is checked because `self` is an unsigned int.
                    unsafe { crate::intrinsics::unchecked_div(self, other.get()) }
                }
            }

            #[stable(feature = "nonzero_div", since = "1.50.0")]
            impl Rem<$Ty> for $Int {
                type Output = $Int;
                /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
                #[inline]
                fn rem(self, other: $Ty) -> $Int {
                    // SAFETY: rem by zero is checked because `other` is a nonzero,
                    // and MIN/-1 is checked because `self` is an unsigned int.
                    unsafe { crate::intrinsics::unchecked_rem(self, other.get()) }
                }
            }
        )+
    }
}

nonzero_integers_div! {
    NonZeroU8(u8);
    NonZeroU16(u16);
    NonZeroU32(u32);
    NonZeroU64(u64);
    NonZeroU128(u128);
    NonZeroUsize(usize);
}
<commit_msg>Bump nonzero_div feature to Rust 1.51<commit_after>//! Definitions of integer that is known not to equal zero.

use crate::fmt;
use crate::ops::{BitOr, BitOrAssign, Div, Rem};
use crate::str::FromStr;

use super::from_str_radix;
use super::{IntErrorKind, ParseIntError};
use crate::intrinsics;

macro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        #[doc = $x]
        $($tt)*
    };
}

macro_rules! impl_nonzero_fmt {
    ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
        $(
            #[$stability]
            impl fmt::$Trait for $Ty {
                #[inline]
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    self.get().fmt(f)
                }
            }
        )+
    }
}

macro_rules! nonzero_integers {
    ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
        $(
            doc_comment! {
                concat!("An integer that is known not to equal zero.

This enables some memory layout optimization.
For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:

```rust
use std::mem::size_of;
assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
">());
```"),
                #[$stability]
                #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
                #[repr(transparent)]
                #[rustc_layout_scalar_valid_range_start(1)]
                #[rustc_nonnull_optimization_guaranteed]
                pub struct $Ty($Int);
            }

            impl $Ty {
                /// Creates a non-zero without checking the value.
                ///
                /// # Safety
                ///
                /// The value must not be zero.
                #[$stability]
                #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
                #[inline]
                pub const unsafe fn new_unchecked(n: $Int) -> Self {
                    // SAFETY: this is guaranteed to be safe by the caller.
                    unsafe { Self(n) }
                }

                /// Creates a non-zero if the given value is not zero.
                #[$stability]
                #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
                #[inline]
                pub const fn new(n: $Int) -> Option<Self> {
                    if n != 0 {
                        // SAFETY: we just checked that there's no `0`
                        Some(unsafe { Self(n) })
                    } else {
                        None
                    }
                }

                /// Returns the value as a primitive type.
                #[$stability]
                #[inline]
                #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
                pub const fn get(self) -> $Int {
                    self.0
                }

            }

            #[stable(feature = "from_nonzero", since = "1.31.0")]
            impl From<$Ty> for $Int {
                doc_comment! {
                    concat!(
"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
                    #[inline]
                    fn from(nonzero: $Ty) -> Self {
                        nonzero.0
                    }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOr for $Ty {
                type Output = Self;
                #[inline]
                fn bitor(self, rhs: Self) -> Self::Output {
                    // SAFETY: since `self` and `rhs` are both nonzero, the
                    // result of the bitwise-or will be nonzero.
                    unsafe { $Ty::new_unchecked(self.get() | rhs.get()) }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOr<$Int> for $Ty {
                type Output = Self;
                #[inline]
                fn bitor(self, rhs: $Int) -> Self::Output {
                    // SAFETY: since `self` is nonzero, the result of the
                    // bitwise-or will be nonzero regardless of the value of
                    // `rhs`.
                    unsafe { $Ty::new_unchecked(self.get() | rhs) }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOr<$Ty> for $Int {
                type Output = $Ty;
                #[inline]
                fn bitor(self, rhs: $Ty) -> Self::Output {
                    // SAFETY: since `rhs` is nonzero, the result of the
                    // bitwise-or will be nonzero regardless of the value of
                    // `self`.
                    unsafe { $Ty::new_unchecked(self | rhs.get()) }
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOrAssign for $Ty {
                #[inline]
                fn bitor_assign(&mut self, rhs: Self) {
                    *self = *self | rhs;
                }
            }

            #[stable(feature = "nonzero_bitor", since = "1.45.0")]
            impl BitOrAssign<$Int> for $Ty {
                #[inline]
                fn bitor_assign(&mut self, rhs: $Int) {
                    *self = *self | rhs;
                }
            }

            impl_nonzero_fmt! {
                #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
            }
        )+
    }
}

nonzero_integers! {
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
    #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
}

macro_rules! from_str_radix_nzint_impl {
    ($($t:ty)*) => {$(
        #[stable(feature = "nonzero_parse", since = "1.35.0")]
        impl FromStr for $t {
            type Err = ParseIntError;
            fn from_str(src: &str) -> Result<Self, Self::Err> {
                Self::new(from_str_radix(src, 10)?)
                    .ok_or(ParseIntError {
                        kind: IntErrorKind::Zero
                    })
            }
        }
    )*}
}

from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }

macro_rules! nonzero_leading_trailing_zeros {
    ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
        $(
            impl $Ty {
                doc_comment! {
                    concat!("Returns the number of leading zeros in the binary representation of `self`.

On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.

# Examples

Basic usage:

```
#![feature(nonzero_leading_trailing_zeros)]
let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();

assert_eq!(n.leading_zeros(), 0);
```"),
                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[inline]
                    pub const fn leading_zeros(self) -> u32 {
                        // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
                        unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
                    }
                }

                doc_comment! {
                    concat!("Returns the number of trailing zeros in the binary representation
of `self`.

On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.

# Examples

Basic usage:

```
#![feature(nonzero_leading_trailing_zeros)]
let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();

assert_eq!(n.trailing_zeros(), 3);
```"),
                    #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
                    #[inline]
                    pub const fn trailing_zeros(self) -> u32 {
                        // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
                        unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
                    }
                }

            }
        )+
    }
}

nonzero_leading_trailing_zeros! {
    NonZeroU8(u8), u8::MAX;
    NonZeroU16(u16), u16::MAX;
    NonZeroU32(u32), u32::MAX;
    NonZeroU64(u64), u64::MAX;
    NonZeroU128(u128), u128::MAX;
    NonZeroUsize(usize), usize::MAX;
    NonZeroI8(u8), -1i8;
    NonZeroI16(u16), -1i16;
    NonZeroI32(u32), -1i32;
    NonZeroI64(u64), -1i64;
    NonZeroI128(u128), -1i128;
    NonZeroIsize(usize), -1isize;
}

macro_rules! nonzero_integers_div {
    ( $( $Ty: ident($Int: ty); )+ ) => {
        $(
            #[stable(feature = "nonzero_div", since = "1.51.0")]
            impl Div<$Ty> for $Int {
                type Output = $Int;
                /// This operation rounds towards zero,
                /// truncating any fractional part of the exact result, and cannot panic.
                #[inline]
                fn div(self, other: $Ty) -> $Int {
                    // SAFETY: div by zero is checked because `other` is a nonzero,
                    // and MIN/-1 is checked because `self` is an unsigned int.
                    unsafe { crate::intrinsics::unchecked_div(self, other.get()) }
                }
            }

            #[stable(feature = "nonzero_div", since = "1.51.0")]
            impl Rem<$Ty> for $Int {
                type Output = $Int;
                /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
                #[inline]
                fn rem(self, other: $Ty) -> $Int {
                    // SAFETY: rem by zero is checked because `other` is a nonzero,
                    // and MIN/-1 is checked because `self` is an unsigned int.
                    unsafe { crate::intrinsics::unchecked_rem(self, other.get()) }
                }
            }
        )+
    }
}

nonzero_integers_div! {
    NonZeroU8(u8);
    NonZeroU16(u16);
    NonZeroU32(u32);
    NonZeroU64(u64);
    NonZeroU128(u128);
    NonZeroUsize(usize);
}
<|endoftext|>


<commit_before>use ra_db::{FileId, LocalSyntaxPtr, Cancelable};
use ra_syntax::{
    SyntaxNode, AstNode, SmolStr, TextRange, ast,
    SyntaxKind::{self, NAME},
};
use hir::{Def, ModuleSource};

use crate::{FileSymbol, db::RootDatabase};

/// `NavigationTarget` represents and element in the editor's UI which you can
/// click on to navigate to a particular piece of code.
///
/// Typically, a `NavigationTarget` corresponds to some element in the source
/// code, like a function or a struct, but this is not strictly required.
#[derive(Debug, Clone)]
pub struct NavigationTarget {
    file_id: FileId,
    name: SmolStr,
    kind: SyntaxKind,
    full_range: TextRange,
    focus_range: Option<TextRange>,
    // Should be DefId ideally
    ptr: Option<LocalSyntaxPtr>,
}

impl NavigationTarget {
    pub fn name(&self) -> &SmolStr {
        &self.name
    }

    pub fn kind(&self) -> SyntaxKind {
        self.kind
    }

    pub fn file_id(&self) -> FileId {
        self.file_id
    }

    pub fn full_range(&self) -> TextRange {
        self.full_range
    }

    /// A "most interesting" range withing the `range_full`.
    ///
    /// Typically, `range` is the whole syntax node, including doc comments, and
    /// `focus_range` is the range of the identifier.
    pub fn focus_range(&self) -> Option<TextRange> {
        self.focus_range
    }

    pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            full_range: symbol.ptr.range(),
            focus_range: None,
            ptr: Some(symbol.ptr.clone()),
        }
    }

    pub(crate) fn from_scope_entry(
        file_id: FileId,
        entry: &hir::ScopeEntryWithSyntax,
    ) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name: entry.name().to_string().into(),
            full_range: entry.ptr().range(),
            focus_range: None,
            kind: NAME,
            ptr: None,
        }
    }

    pub(crate) fn from_module(
        db: &RootDatabase,
        module: hir::Module,
    ) -> Cancelable<NavigationTarget> {
        let (file_id, source) = module.definition_source(db)?;
        let name = module
            .name(db)?
            .map(|it| it.to_string().into())
            .unwrap_or_default();
        let res = match source {
            ModuleSource::SourceFile(node) => {
                NavigationTarget::from_syntax(file_id, name, None, node.syntax())
            }
            ModuleSource::Module(node) => {
                NavigationTarget::from_syntax(file_id, name, None, node.syntax())
            }
        };
        Ok(res)
    }

    // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
    pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
        let res = match def {
            Def::Struct(s) => {
                let (file_id, node) = s.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::Enum(e) => {
                let (file_id, node) = e.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::EnumVariant(ev) => {
                let (file_id, node) = ev.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::Function(f) => {
                let (file_id, node) = f.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::Module(m) => NavigationTarget::from_module(db, m)?,
            Def::Item => return Ok(None),
        };
        Ok(Some(res))
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        let mut buf = format!(
            "{} {:?} {:?} {:?}",
            self.name(),
            self.kind(),
            self.file_id(),
            self.full_range()
        );
        if let Some(focus_range) = self.focus_range() {
            buf.push_str(&format!(" {:?}", focus_range))
        }
        buf
    }

    fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget {
        let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
        let focus_range = node.name().map(|it| it.syntax().range());
        NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax())
    }

    fn from_syntax(
        file_id: FileId,
        name: SmolStr,
        focus_range: Option<TextRange>,
        node: &SyntaxNode,
    ) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name,
            kind: node.kind(),
            full_range: node.range(),
            focus_range,
            ptr: Some(LocalSyntaxPtr::new(node)),
        }
    }
}
<commit_msg>kill NavTarget ptr<commit_after>use ra_db::{FileId, Cancelable};
use ra_syntax::{
    SyntaxNode, AstNode, SmolStr, TextRange, ast,
    SyntaxKind::{self, NAME},
};
use hir::{Def, ModuleSource};

use crate::{FileSymbol, db::RootDatabase};

/// `NavigationTarget` represents and element in the editor's UI which you can
/// click on to navigate to a particular piece of code.
///
/// Typically, a `NavigationTarget` corresponds to some element in the source
/// code, like a function or a struct, but this is not strictly required.
#[derive(Debug, Clone)]
pub struct NavigationTarget {
    file_id: FileId,
    name: SmolStr,
    kind: SyntaxKind,
    full_range: TextRange,
    focus_range: Option<TextRange>,
}

impl NavigationTarget {
    pub fn name(&self) -> &SmolStr {
        &self.name
    }

    pub fn kind(&self) -> SyntaxKind {
        self.kind
    }

    pub fn file_id(&self) -> FileId {
        self.file_id
    }

    pub fn full_range(&self) -> TextRange {
        self.full_range
    }

    /// A "most interesting" range withing the `range_full`.
    ///
    /// Typically, `range` is the whole syntax node, including doc comments, and
    /// `focus_range` is the range of the identifier.
    pub fn focus_range(&self) -> Option<TextRange> {
        self.focus_range
    }

    pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            full_range: symbol.ptr.range(),
            focus_range: None,
        }
    }

    pub(crate) fn from_scope_entry(
        file_id: FileId,
        entry: &hir::ScopeEntryWithSyntax,
    ) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name: entry.name().to_string().into(),
            full_range: entry.ptr().range(),
            focus_range: None,
            kind: NAME,
        }
    }

    pub(crate) fn from_module(
        db: &RootDatabase,
        module: hir::Module,
    ) -> Cancelable<NavigationTarget> {
        let (file_id, source) = module.definition_source(db)?;
        let name = module
            .name(db)?
            .map(|it| it.to_string().into())
            .unwrap_or_default();
        let res = match source {
            ModuleSource::SourceFile(node) => {
                NavigationTarget::from_syntax(file_id, name, None, node.syntax())
            }
            ModuleSource::Module(node) => {
                NavigationTarget::from_syntax(file_id, name, None, node.syntax())
            }
        };
        Ok(res)
    }

    // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
    pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
        let res = match def {
            Def::Struct(s) => {
                let (file_id, node) = s.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::Enum(e) => {
                let (file_id, node) = e.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::EnumVariant(ev) => {
                let (file_id, node) = ev.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::Function(f) => {
                let (file_id, node) = f.source(db)?;
                NavigationTarget::from_named(file_id.original_file(db), &*node)
            }
            Def::Module(m) => NavigationTarget::from_module(db, m)?,
            Def::Item => return Ok(None),
        };
        Ok(Some(res))
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        let mut buf = format!(
            "{} {:?} {:?} {:?}",
            self.name(),
            self.kind(),
            self.file_id(),
            self.full_range()
        );
        if let Some(focus_range) = self.focus_range() {
            buf.push_str(&format!(" {:?}", focus_range))
        }
        buf
    }

    fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget {
        let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
        let focus_range = node.name().map(|it| it.syntax().range());
        NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax())
    }

    fn from_syntax(
        file_id: FileId,
        name: SmolStr,
        focus_range: Option<TextRange>,
        node: &SyntaxNode,
    ) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name,
            kind: node.kind(),
            full_range: node.range(),
            focus_range,
            // ptr: Some(LocalSyntaxPtr::new(node)),
        }
    }
}
<|endoftext|>