<commit_before>//#![feature(macro_rules)]
//use std::any::{Any, TypeId};
use std::cmp::{Ordering, PartialOrd};
use std::collections::{HashMap, HashSet};
use std::ops::{Add, Deref, Sub};

/*
{start: {to: {distance, path}}}
 */
type Detail<Value> = (Value, Vec<&'static str>);
type Matrix<Value> = HashMap<&'static str, HashMap<&'static str, Detail<Value>>>;

/*
impl<T> Deref for Detail<T> {
    type Target = (T, Vec<&'static str>);

    fn deref(&self) -> &Self {
        &(*self.0, *self.1)
    }
}*/

struct DistanceMatrix<T> {
    length: usize,
    inner_max: Matrix<T>,
}

impl<T> DistanceMatrix<T>
where
    T: Add<Output = T> + Sub + Ord + Copy,
{
    fn new(input: Matrix<T>) -> Self {
        DistanceMatrix {
            length: input.len(),
            inner_max: input,
        }
    }

    fn path(&mut self, start: &'static str, to: &'static str) -> Option<Vec<&'static str>> {
        match self.inner_max.get(start) {
            Some(data) => match data.get(to) {
                Some((_, p)) => return Some(p.clone()),
                None => return None,
            },
            None => return None,
        }
    }

    fn val_between(&mut self, start: &'static str, to: &'static str) -> Option<T> {
        match self.inner_max.get(start) {
            Some(data) => match data.get(to) {
                Some((v, _)) => return Some(*v),
                None => return None,
            },
            None => return None,
        }
    }

    fn new_dijkstra_on(&mut self, start: &'static str) {
        let mut all_notes = self
            .inner_max
            .keys()
            .map(|x| *x)
            .collect::<HashSet<&'static str>>();
        all_notes.remove(start);

        let mut smallest_nodes_connected: (&'static str, Detail<T>);
        {
            let this_nodes_data = match self.inner_max.get(start) {
                Some(data) => data.clone(),
                None => {
                    println!("{}", "do not have this node");
                    return;
                }
            };

            // find shortest node of start
            let (a, b) = this_nodes_data
                .iter()
                .map(|x| x)
                .min_by_key(|(_, v)| v.0)
                .unwrap();
            smallest_nodes_connected = (*a, b.clone());
        }

        all_notes.remove(smallest_nodes_connected.0);

        let mut distance_to_now: T;
        let mut path_to_now: Vec<&'static str>;

        println!("{:?}", smallest_nodes_connected.0);
        while (!all_notes.is_empty()) {
            let distance_to_now: T;
            let path_to_now: Vec<&'static str>;

            {
                distance_to_now = self.val_between(start, smallest_nodes_connected.0).unwrap();
                path_to_now = self.path(start, smallest_nodes_connected.0).unwrap();
            }

            let this_nodes_data = match { self.inner_max.get_mut(smallest_nodes_connected.0) } {
                Some(data) => data.clone(),
                None => {
                    println!("{}", "do not have this node");
                    return;
                }
            };

            //update start node
            for (k, v) in this_nodes_data.iter() {
                if let Some(v_old) = self.val_between(start, k) {
                    if (distance_to_now + v.0) < { v_old } {
                        let mut new_path = path_to_now.clone();
                        new_path.push(k);
                        self.inner_max
                            .get_mut(start)
                            .unwrap()
                            .insert(k, (distance_to_now + v.0, new_path));
                    }
                } else {
                    let mut new_path = path_to_now.clone();
                    new_path.push(k);
                    self.inner_max
                        .get_mut(start)
                        .unwrap()
                        .insert(k, (distance_to_now + v.0, new_path));
                }
            }

            all_notes.remove(smallest_nodes_connected.0);
        }
    }
}

//struct nil;
// type check function template
/*
fn is_nil<T: ?Sized + Any>(o: &T) -> bool {
    TypeId::of::<i32>() == TypeId::of::<T>()
}*/

// new_distance_matrix!()
// cannot check type in macro body. so do not need this macro
/*
macro_rules! new_distance_matrix {
    ($([$($x:expr),*]),*) => {{
        vec![$(vec![$(
            if is_nil($x) {
                None
            }else{
                Some($x)
            }
        ),*]),*]
    }};
    ($($x:expr),*) => {{

    }};
}*/

fn main() {
    //let test0: Matrix<u32>;
    //println!("{:?}", test0);
    //println!("{:?}", new_distance_matrix![[1, 2, 3], [4, 5, 6], [7, 8]]);

    let mut testcaseM1: Matrix<u32> = HashMap::new();
    testcaseM1.insert(
        "a",
        [("b", (6 as u32, vec![])), ("c", (3 as u32, vec![]))]
            .iter()
            .cloned()
            .collect(),
    );
    testcaseM1.insert(
        "b",
        [
            ("a", (6 as u32, vec![])),
            ("c", (2 as u32, vec![])),
            ("d", (5 as u32, vec![])),
        ]
            .iter()
            .cloned()
            .collect(),
    );
    println!("{:?}", testcaseM1);

    let mut testcase1: DistanceMatrix<u32>;
    testcase1 = DistanceMatrix {
        length: 4,
        inner_max: testcaseM1,
    };

    //Option<(&&str, &(u32, std::vec::Vec<u32>))>
    println!("{:?}", testcase1.new_dijkstra_on("a"));
}
<commit_msg>finish, but I need write a macro<commit_after>//#![feature(macro_rules)]
//use std::any::{Any, TypeId};
use std::cmp::{Ordering, PartialOrd};
use std::collections::{HashMap, HashSet};
use std::ops::{Add, Deref, Sub};

/*
{start: {to: {distance, path}}}
 */
type Detail<Value> = (Value, Vec<&'static str>);
type Matrix<Value> = HashMap<&'static str, HashMap<&'static str, Detail<Value>>>;

/*
impl<T> Deref for Detail<T> {
    type Target = (T, Vec<&'static str>);

    fn deref(&self) -> &Self {
        &(*self.0, *self.1)
    }
}*/

struct DistanceMatrix<T> {
    length: usize,
    inner_max: Matrix<T>,
}

impl<T> DistanceMatrix<T>
where
    T: Add<Output = T> + Sub + Ord + Copy,
{
    fn new(input: Matrix<T>) -> Self {
        DistanceMatrix {
            length: input.len(),
            inner_max: input,
        }
    }

    fn path(&mut self, start: &'static str, to: &'static str) -> Option<Vec<&'static str>> {
        match self.inner_max.get(start) {
            Some(data) => match data.get(to) {
                Some((_, p)) => return Some(p.clone()),
                None => return None,
            },
            None => return None,
        }
    }

    fn val_between(&mut self, start: &'static str, to: &'static str) -> Option<T> {
        match self.inner_max.get(start) {
            Some(data) => match data.get(to) {
                Some((v, _)) => return Some(*v),
                None => return None,
            },
            None => return None,
        }
    }

    fn new_dijkstra_on(&mut self, start: &'static str) {
        // all nodes set
        let mut all_notes = self
            .inner_max
            .keys()
            .map(|x| *x)
            .collect::<HashSet<&'static str>>();
        all_notes.remove(start);

        let mut smallest_nodes_connected: &'static str;
        {
            let this_nodes_data = match self.inner_max.get(start) {
                Some(data) => data.clone(), // need clone here
                None => {
                    println!("{}", "do not have this node");
                    return;
                }
            };

            // find smallest node
            let (a, _) = this_nodes_data
                .iter()
                .map(|x| x)
                .filter(|x| all_notes.contains(x.0)) // must nodes in all nodes.
                .min_by_key(|(_, v)| v.0)
                .unwrap();
            smallest_nodes_connected = *a;
        }

        //all_notes.remove(smallest_nodes_connected);

        //println!("{:?}", smallest_nodes_connected);
        while (!all_notes.is_empty()) {
            let distance_to_now: T;
            let path_to_now: Vec<&'static str>;

            all_notes.remove(smallest_nodes_connected);
            {
                distance_to_now = self.val_between(start, smallest_nodes_connected).unwrap();
                path_to_now = self.path(start, smallest_nodes_connected).unwrap();
            }

            let this_nodes_data = match { self.inner_max.get_mut(smallest_nodes_connected) } {
                Some(data) => data.clone(),
                None => {
                    println!("{}", "do not have this node");
                    return;
                }
            };

            //update start node
            let mut this_round_result: Vec<(&'static str, T)> = vec![];
            for (k, v) in this_nodes_data.iter() {
                // cannot be start node
                if *k == start {
                    continue;
                }

                if let Some(v_old) = self.val_between(start, k) {
                    if (distance_to_now + v.0) < v_old {
                        let mut new_path = path_to_now.clone();
                        new_path.push(k);
                        self.inner_max
                            .get_mut(start)
                            .unwrap()
                            .insert(k, (distance_to_now + v.0, new_path));
                        this_round_result.push((*k, distance_to_now + v.0));
                    } else {
                        // if old value is smaller one, dont change path
                        // but push result in this_round_result
                        this_round_result.push((*k, v_old));
                    }
                } else {
                    let mut new_path = path_to_now.clone();
                    new_path.push(k);
                    self.inner_max
                        .get_mut(start)
                        .unwrap()
                        .insert(k, (distance_to_now + v.0, new_path));
                    this_round_result.push((*k, distance_to_now + v.0));
                }
            }

            // next smallest node
            smallest_nodes_connected = if let Some(a) = this_round_result
                .iter()
                .filter(|x| all_notes.contains(x.0))
                .min_by_key(|(_, v)| v)
            {
                a.0
            } else {
                ""
            };

            //println!("{:?}", smallest_nodes_connected);
        }
    }
}

//struct nil;
// type check function template
/*
fn is_nil<T: ?Sized + Any>(o: &T) -> bool {
    TypeId::of::<i32>() == TypeId::of::<T>()
}*/

// new_distance_matrix!()
// cannot check type in macro body. so do not need this macro
/*
macro_rules! new_distance_matrix {
    ($([$($x:expr),*]),*) => {{
        vec![$(vec![$(
            if is_nil($x) {
                None
            }else{
                Some($x)
            }
        ),*]),*]
    }};
    ($($x:expr),*) => {{

    }};
}*/

fn main() {
    //let test0: Matrix<u32>;
    //println!("{:?}", test0);
    //println!("{:?}", new_distance_matrix![[1, 2, 3], [4, 5, 6], [7, 8]]);

    let mut test_caseM1: Matrix<u32> = HashMap::new();
    test_caseM1.insert(
        "a",
        [
            ("b", (6 as u32, vec!["a", "b"])),
            ("c", (3 as u32, vec!["a", "c"])),
        ]
            .iter()
            .cloned()
            .collect(),
    );
    test_caseM1.insert(
        "b",
        [
            ("a", (6 as u32, vec!["b", "a"])),
            ("c", (2 as u32, vec!["b", "c"])),
            ("d", (5 as u32, vec!["b", "d"])),
        ]
            .iter()
            .cloned()
            .collect(),
    );
    test_caseM1.insert(
        "c",
        [
            ("a", (3 as u32, vec!["c", "a"])),
            ("d", (3 as u32, vec!["c", "d"])),
            ("b", (2 as u32, vec!["c", "b"])),
            ("e", (4 as u32, vec!["c", "e"])),
        ]
            .iter()
            .cloned()
            .collect(),
    );
    test_caseM1.insert(
        "d",
        [
            ("b", (5 as u32, vec!["d", "b"])),
            ("e", (2 as u32, vec!["d", "e"])),
            ("c", (3 as u32, vec!["d", "c"])),
            ("f", (3 as u32, vec!["d", "f"])),
        ]
            .iter()
            .cloned()
            .collect(),
    );
    test_caseM1.insert(
        "e",
        [
            ("c", (4 as u32, vec!["e", "c"])),
            ("d", (2 as u32, vec!["e", "d"])),
            ("f", (5 as u32, vec!["e", "f"])),
        ]
            .iter()
            .cloned()
            .collect(),
    );
    test_caseM1.insert(
        "f",
        [
            ("e", (5 as u32, vec!["f", "e"])),
            ("d", (3 as u32, vec!["f", "e"])),
        ]
            .iter()
            .cloned()
            .collect(),
    );

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

    let mut test_case1: DistanceMatrix<u32>;
    test_case1 = DistanceMatrix {
        length: 4,
        inner_max: test_caseM1,
    };

    //Option<(&&str, &(u32, std::vec::Vec<u32>))>
    println!("{:?}", test_case1.new_dijkstra_on("a"));
    println!("{:?}", test_case1.inner_max.get("a"));
}
<|endoftext|>


<commit_before>extern crate libloading;
extern crate rand;
extern crate test_server;

use libloading::{Library, Symbol};
use std::fs;
use std::path::Path;
use std::str;
use test_server::futures::{Future, Stream};
use test_server::hyper;

#[cfg(target_os = "windows")]
const LOG_FILE_PATH: &str = "ctehxk2.log";
#[cfg(not(target_os = "windows"))]
const LOG_FILE_PATH: &str = "libctehxk2.log";

#[cfg(target_os = "windows")]
const LIB_PATH: &str = "../../target/debug/ctehxk2.dll";
#[cfg(target_os = "linux")]
const LIB_PATH: &str = "../../target/debug/libctehxk2.so";
#[cfg(target_os = "macos")]
const LIB_PATH: &str = "../../target/debug/libctehxk2.dylib";

#[test]
fn with_config_file() {
    unsafe {
        match Library::new(LIB_PATH) {
            Ok(lib) => {
                let init: Symbol<unsafe extern "system" fn(u16, u16) -> i8> =
                    lib.get(b"CT_init").unwrap();

                let server = test_server::serve(Some(String::from("127.0.0.1:65432")));
                server.reply().status(hyper::Ok).body("0");

                let ctn = rand::random::<u16>();
                let pn = rand::random::<u16>();

                assert_eq!(0, init(ctn, pn));

                let (method, uri, _version, _headers, body) =
                    server.request().unwrap().deconstruct();

                assert_eq!(hyper::Method::Post, method);
                assert_eq!("/yaml/ct_init/17/321", uri.path());
                assert!(body.concat2().wait().unwrap().is_empty());

                assert!(Path::new(LOG_FILE_PATH).exists());

                let metadata = fs::metadata(LOG_FILE_PATH).unwrap();

                assert!(metadata.len() > 0);
            }
            _ => assert!(false, format!("loading library from {}", LIB_PATH)),
        }
    }
}
<commit_msg>use dlopen in settings-file example<commit_after>#[macro_use]
extern crate const_cstr;
extern crate dlopen;
extern crate rand;
extern crate test_server;

use dlopen::raw::Library;
use std::fs;
use std::path::Path;
use std::str;
use test_server::http::{Method, StatusCode};

#[cfg(target_os = "windows")]
const LOG_FILE_PATH: &str = "ctehxk2.log";
#[cfg(not(target_os = "windows"))]
const LOG_FILE_PATH: &str = "libctehxk2.log";

#[cfg(target_os = "windows")]
const LIB_PATH: &str = "../../target/debug/ctehxk2.dll";
#[cfg(target_os = "linux")]
const LIB_PATH: &str = "../../target/debug/libctehxk2.so";
#[cfg(target_os = "macos")]
const LIB_PATH: &str = "../../target/debug/libctehxk2.dylib";

#[test]
fn with_config_file() {
    let lib = Library::open(LIB_PATH).expect("Could not open library");

    let init: unsafe extern "system" fn(u16, u16) -> i8 =
        unsafe { lib.symbol_cstr(const_cstr!("CT_init").as_cstr()) }.unwrap();

    let server = test_server::serve(Some(String::from("127.0.0.1:65432")));
    server.reply().status(StatusCode::OK).body("0");

    let ctn = rand::random::<u16>();
    let pn = rand::random::<u16>();

    assert_eq!(0, unsafe { init(ctn, pn) });

    let (parts, body) = server.request().unwrap().into_parts();
    assert_eq!(body, String::from(""));
    assert_eq!(parts.method, Method::POST);
    assert_eq!(parts.uri, "/yaml/ct_init/17/321");

    assert!(Path::new(LOG_FILE_PATH).exists());

    let metadata = fs::metadata(LOG_FILE_PATH).unwrap();

    assert!(metadata.len() > 0);
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::cmp;
use std::mem;

use js_types::js_type::{JsVar, JsType};
use uuid::Uuid;

// Initial Arena size in bytes
const INITIAL_SIZE: usize = 1024;
// Minimum Arena capacity is at least 1 byte
const MIN_CAP: usize = 1;

pub struct Scope {
    parent: Option<Box<Scope>>,
    children: Vec<Box<Scope>>,
    black_set: HashMap<Uuid, RefCell<JsVar>>,
    grey_set: HashMap<Uuid, RefCell<JsVar>>,
    white_set: HashMap<Uuid, RefCell<JsVar>>,
    get_roots: Box<Fn() -> HashSet<Uuid>>,
}

impl Scope {
    pub fn new<F>(get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: None,
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn as_child<F>(parent: Box<Scope>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: Some(parent),
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn set_parent(&mut self, parent: Box<Scope>) {
        self.parent = Some(parent);
    }

    pub fn add_child(&mut self, child: Box<Scope>) {
        self.children.push(child);
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        let uuid = var.uuid;
        self.white_set.insert(uuid, RefCell::new(var));
        uuid
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        if let Some(_) = self.white_set.remove(uuid) { true } else { false }
    }

    pub fn get_var_copy(&self, uuid: &Uuid) -> Option<JsVar> {
        if let Some(var) = self.black_set.get(uuid) {
            Some(var.clone().into_inner())
        } else if let Some(var) = self.grey_set.get(uuid) {
            Some(var.clone().into_inner())
        } else if let Some(var) = self.white_set.get(uuid) {
            Some(var.clone().into_inner())
        } else { None }
    }

    pub fn update_var(&mut self, var: JsVar) -> bool {
        unimplemented!()
    }

    /// TODO Compute the roots of the current scope-- any variable that is
    /// directly referenced or declared within the scope. This might just be the
    /// key set of the uuid map(?) Not necessarily, I think. What if you do
    /// something like this:
    /// var x = {}
    /// var y = { 1: x }
    /// y = x
    /// y would be a root by the definition above, but is no longer reachable at
    /// the end of the scope because it now aliases x. A better definition would
    /// be "Any variable that is declared or referenced directly, but a direct
    /// reference (variable usage) supercedes a declaration." The above example
    /// demonstrates why this is necessary.
    pub fn compute_roots(&self) -> HashSet<Uuid> {
        unimplemented!();
    }

    /// Roots always get marked as Black, since they're always reachable from
    /// the current scope.
    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks.iter() {
            if let Some(jst) = self.white_set.remove(mark) {
                let uuid = jst.borrow().uuid;
                self.black_set.insert(uuid, jst);
                // TODO mark child references as grey
            }
        }
    }

    pub fn mark_phase(&mut self) {
        // TODO mark object as black, mark all white objs it refs as grey
        for (_, v) in self.grey_set.drain() {
            match (*v.borrow()).t {
                JsType::JsPtr(ref ptr) => unimplemented!(),
                _ => ()
            }
        }
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use js_types::js_type::{JsVar, JsType, Marking};

    #[test]
    fn test_new_scope() {
        let test_jst0 = JsVar::new(JsType::JsNum(0.0));
        let test_jst1 = JsVar::new(JsType::JsNum(1.0));

        let mut test_scope = Scope::new("test");
        let uuid0 = test_scope.alloc(test_jst0);
        test_scope.mark_uuid(&uuid0, Marking::Black);
        let uuid1 = test_scope.alloc(test_jst1);
        test_scope.mark_uuid(&uuid1, Marking::White);
        assert_eq!(test_scope.get_jst_copy(&uuid0).unwrap().gc_flag, Marking::Black);
        assert_eq!(test_scope.get_jst_copy(&uuid1).unwrap().gc_flag, Marking::White);
    }
}
<commit_msg>Implement basic tri-color GC marking phase, TODO testing<commit_after>use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::cmp;
use std::mem;

use js_types::js_type::{JsVar, JsType, JsPtrEnum};
use uuid::Uuid;

// Initial Arena size in bytes
const INITIAL_SIZE: usize = 1024;
// Minimum Arena capacity is at least 1 byte
const MIN_CAP: usize = 1;

pub struct Scope {
    parent: Option<Box<Scope>>,
    children: Vec<Box<Scope>>,
    black_set: HashMap<Uuid, RefCell<JsVar>>,
    grey_set: HashMap<Uuid, RefCell<JsVar>>,
    white_set: HashMap<Uuid, RefCell<JsVar>>,
    get_roots: Box<Fn() -> HashSet<Uuid>>,
}

impl Scope {
    pub fn new<F>(get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: None,
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn as_child<F>(parent: Box<Scope>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: Some(parent),
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn set_parent(&mut self, parent: Box<Scope>) {
        self.parent = Some(parent);
    }

    pub fn add_child(&mut self, child: Box<Scope>) {
        self.children.push(child);
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        let uuid = var.uuid;
        self.white_set.insert(uuid, RefCell::new(var));
        uuid
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        if let Some(_) = self.white_set.remove(uuid) { true } else { false }
    }

    pub fn get_var_copy(&self, uuid: &Uuid) -> Option<JsVar> {
        if let Some(var) = self.black_set.get(uuid) {
            Some(var.clone().into_inner())
        } else if let Some(var) = self.grey_set.get(uuid) {
            Some(var.clone().into_inner())
        } else if let Some(var) = self.white_set.get(uuid) {
            Some(var.clone().into_inner())
        } else { None }
    }

    pub fn update_var(&mut self, var: JsVar) -> bool {
        unimplemented!()
    }

    /// TODO Compute the roots of the current scope-- any variable that is
    /// directly referenced or declared within the scope. This might just be the
    /// key set of the uuid map(?) Not necessarily, I think. What if you do
    /// something like this:
    /// var x = {}
    /// var y = { 1: x }
    /// y = x
    /// y would be a root by the definition above, but is no longer reachable at
    /// the end of the scope because it now aliases x. A better definition would
    /// be "Any variable that is declared or referenced directly, but a direct
    /// reference (variable usage) supercedes a declaration." The above example
    /// demonstrates why this is necessary.
    /// This should come from the interpreter, so I shouldn't actually have to
    /// care about getting the root set myself.

    //pub fn compute_roots(&self) -> HashSet<Uuid> {
    //    self.get_roots();
    //}

    /// Roots always get marked as Black, since they're always reachable from
    /// the current scope. NB that this assumes all root references are actually
    /// valid reference types, i.e. they're not numbers, etc.
    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks.iter() {
            if let Some(var) = self.white_set.remove(mark) {
                let uuid = var.borrow().uuid;
                // Get all child references
                let child_ids = self.get_var_children(&var);
                self.black_set.insert(uuid, var);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_phase(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        while let Some(&uuid) = self.grey_set.keys().take(1).next() {
            if let Some(var) = self.grey_set.remove(&uuid) {
                let child_ids = self.get_var_children(&var);
                self.black_set.insert(uuid, var);
                for child_id in child_ids.into_iter() {
                    if let Some(var) = self.white_set.remove(&child_id) {
                        self.grey_set.insert(child_id, var);
                    }
                }
            }
        }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.into_iter() {
            if let Some(var) = self.white_set.remove(&child_id) {
                self.grey_set.insert(child_id, var);
            }
        }
    }

    fn get_var_children(&self, var: &RefCell<JsVar>) -> HashSet<Uuid> {
        if let JsType::JsPtr(ref ptr) = (*var.borrow()).t {
            match ptr {
                &JsPtrEnum::JsObj(ref obj) => obj.get_children(),
                _ => HashSet::new(),
            }
        } else { HashSet::new() }
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use js_types::js_type::{JsVar, JsType, Marking};

    #[test]
    fn test_new_scope() {
        let test_jst0 = JsVar::new(JsType::JsNum(0.0));
        let test_jst1 = JsVar::new(JsType::JsNum(1.0));

        let mut test_scope = Scope::new("test");
        let uuid0 = test_scope.alloc(test_jst0);
        test_scope.mark_uuid(&uuid0, Marking::Black);
        let uuid1 = test_scope.alloc(test_jst1);
        test_scope.mark_uuid(&uuid1, Marking::White);
        assert_eq!(test_scope.get_jst_copy(&uuid0).unwrap().gc_flag, Marking::Black);
        assert_eq!(test_scope.get_jst_copy(&uuid1).unwrap().gc_flag, Marking::White);
    }
}
<|endoftext|>


<commit_before>use super::Compat;
use futures::{
    executor::{
        self as executor01, Notify as Notify01, NotifyHandle as NotifyHandle01,
        UnsafeNotify as UnsafeNotify01,
    },
    Async as Async01, Future as Future01, Stream as Stream01,
};
use futures_core::{task as task03, Future as Future03, Stream as Stream03};
use std::mem::PinMut;

impl<Fut: Future01> Future03 for Compat<Fut, ()> {
    type Output = Result<Fut::Item, Fut::Error>;

    fn poll(self: PinMut<Self>, cx: &mut task03::Context) -> task03::Poll<Self::Output> {
        let notify = &WakerToHandle(cx.waker());

        executor01::with_notify(notify, 0, move || unsafe {
            match PinMut::get_mut_unchecked(self).inner.poll() {
                Ok(Async01::Ready(t)) => task03::Poll::Ready(Ok(t)),
                Ok(Async01::NotReady) => task03::Poll::Pending,
                Err(e) => task03::Poll::Ready(Err(e)),
            }
        })
    }
}

impl<St: Stream01> Stream03 for Compat<St, ()> {
    type Item = Result<St::Item, St::Error>;

    fn poll_next(self: PinMut<Self>, cx: &mut task03::Context) -> task03::Poll<Option<Self::Item>> {
        let notify = &WakerToHandle(cx.waker());

        executor01::with_notify(notify, 0, move || unsafe {
            match PinMut::get_mut_unchecked(self).inner.poll() {
                Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
                Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
                Ok(Async01::NotReady) => task03::Poll::Pending,
                Err(e) => task03::Poll::Ready(Some(Err(e))),
            }
        })
    }
}

struct NotifyWaker(task03::Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl<'a> From<WakerToHandle<'a>> for NotifyHandle01 {
    fn from(handle: WakerToHandle<'a>) -> NotifyHandle01 {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle01::new(Box::into_raw(ptr)) }
    }
}

impl Notify01 for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake();
    }
}

unsafe impl UnsafeNotify01 for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle01 {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify01 = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify01));
    }
}
<commit_msg>Reduce unsafe scope<commit_after>use super::Compat;
use futures::{
    executor::{
        self as executor01, Notify as Notify01, NotifyHandle as NotifyHandle01,
        UnsafeNotify as UnsafeNotify01,
    },
    Async as Async01, Future as Future01, Stream as Stream01,
};
use futures_core::{task as task03, Future as Future03, Stream as Stream03};
use std::mem::PinMut;

impl<Fut: Future01> Future03 for Compat<Fut, ()> {
    type Output = Result<Fut::Item, Fut::Error>;

    fn poll(self: PinMut<Self>, cx: &mut task03::Context) -> task03::Poll<Self::Output> {
        let notify = &WakerToHandle(cx.waker());

        executor01::with_notify(notify, 0, move || {
            match unsafe { PinMut::get_mut_unchecked(self) }.inner.poll() {
                Ok(Async01::Ready(t)) => task03::Poll::Ready(Ok(t)),
                Ok(Async01::NotReady) => task03::Poll::Pending,
                Err(e) => task03::Poll::Ready(Err(e)),
            }
        })
    }
}

impl<St: Stream01> Stream03 for Compat<St, ()> {
    type Item = Result<St::Item, St::Error>;

    fn poll_next(self: PinMut<Self>, cx: &mut task03::Context) -> task03::Poll<Option<Self::Item>> {
        let notify = &WakerToHandle(cx.waker());

        executor01::with_notify(notify, 0, move || {
            match unsafe { PinMut::get_mut_unchecked(self) }.inner.poll() {
                Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
                Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
                Ok(Async01::NotReady) => task03::Poll::Pending,
                Err(e) => task03::Poll::Ready(Some(Err(e))),
            }
        })
    }
}

struct NotifyWaker(task03::Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl<'a> From<WakerToHandle<'a>> for NotifyHandle01 {
    fn from(handle: WakerToHandle<'a>) -> NotifyHandle01 {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle01::new(Box::into_raw(ptr)) }
    }
}

impl Notify01 for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake();
    }
}

unsafe impl UnsafeNotify01 for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle01 {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify01 = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify01));
    }
}
<|endoftext|>


<commit_before>use crate::{
    backend::Backend,
    buffer::Cell,
    layout::Rect,
    style::{Color, Modifier},
};
use crossterm::{
    cursor::{Hide, MoveTo, Show},
    execute, queue,
    style::{
        Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
        SetForegroundColor,
    },
    terminal::{self, Clear, ClearType},
};
use std::{
    fmt,
    io::{self, Write},
};

pub struct CrosstermBackend<W: Write> {
    buffer: W,
}

impl<W> CrosstermBackend<W>
where
    W: Write,
{
    pub fn new(buffer: W) -> CrosstermBackend<W> {
        CrosstermBackend { buffer }
    }
}

impl<W> Write for CrosstermBackend<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buffer.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buffer.flush()
    }
}

impl<W> Backend for CrosstermBackend<W>
where
    W: Write,
{
    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        use fmt::Write;

        let mut string = String::with_capacity(content.size_hint().0 * 3);
        let mut fg = Color::Reset;
        let mut bg = Color::Reset;
        let mut modifier = Modifier::empty();
        let mut last_pos: Option<(u16, u16)> = None;
        for (x, y, cell) in content {
            // Move the cursor if the previous location was not (x - 1, y)
            if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {
                map_error(queue!(string, MoveTo(x, y)))?;
            }
            last_pos = Some((x, y));
            if cell.modifier != modifier {
                let diff = ModifierDiff {
                    from: modifier,
                    to: cell.modifier,
                };
                diff.queue(&mut string)?;
                modifier = cell.modifier;
            }
            if cell.fg != fg {
                let color = CColor::from(cell.fg);
                map_error(queue!(string, SetForegroundColor(color)))?;
                fg = cell.fg;
            }
            if cell.bg != bg {
                let color = CColor::from(cell.bg);
                map_error(queue!(string, SetBackgroundColor(color)))?;
                bg = cell.bg;
            }

            string.push_str(&cell.symbol);
        }

        map_error(queue!(
            self.buffer,
            Print(string),
            SetForegroundColor(CColor::Reset),
            SetBackgroundColor(CColor::Reset),
            SetAttribute(CAttribute::Reset)
        ))
    }

    fn hide_cursor(&mut self) -> io::Result<()> {
        map_error(execute!(self.buffer, Hide))
    }

    fn show_cursor(&mut self) -> io::Result<()> {
        map_error(execute!(self.buffer, Show))
    }

    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
        crossterm::cursor::position()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
    }

    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
        map_error(execute!(self.buffer, MoveTo(x, y)))
    }

    fn clear(&mut self) -> io::Result<()> {
        map_error(execute!(self.buffer, Clear(ClearType::All)))
    }

    fn size(&self) -> io::Result<Rect> {
        let (width, height) =
            terminal::size().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;

        Ok(Rect::new(0, 0, width, height))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buffer.flush()
    }
}

fn map_error(error: crossterm::Result<()>) -> io::Result<()> {
    error.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
}

impl From<Color> for CColor {
    fn from(color: Color) -> Self {
        match color {
            Color::Reset => CColor::Reset,
            Color::Black => CColor::Black,
            Color::Red => CColor::DarkRed,
            Color::Green => CColor::DarkGreen,
            Color::Yellow => CColor::DarkYellow,
            Color::Blue => CColor::DarkBlue,
            Color::Magenta => CColor::DarkMagenta,
            Color::Cyan => CColor::DarkCyan,
            Color::Gray => CColor::Grey,
            Color::DarkGray => CColor::DarkGrey,
            Color::LightRed => CColor::Red,
            Color::LightGreen => CColor::Green,
            Color::LightBlue => CColor::Blue,
            Color::LightYellow => CColor::Yellow,
            Color::LightMagenta => CColor::Magenta,
            Color::LightCyan => CColor::Cyan,
            Color::White => CColor::White,
            Color::Indexed(i) => CColor::AnsiValue(i),
            Color::Rgb(r, g, b) => CColor::Rgb { r, g, b },
        }
    }
}

#[derive(Debug)]
struct ModifierDiff {
    pub from: Modifier,
    pub to: Modifier,
}

#[cfg(unix)]
impl ModifierDiff {
    fn queue<W>(&self, mut w: W) -> io::Result<()>
    where
        W: fmt::Write,
    {
        //use crossterm::Attribute;
        let removed = self.from - self.to;
        if removed.contains(Modifier::REVERSED) {
            map_error(queue!(w, SetAttribute(CAttribute::NoReverse)))?;
        }
        if removed.contains(Modifier::BOLD) {
            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
            if self.to.contains(Modifier::DIM) {
                map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;
            }
        }
        if removed.contains(Modifier::ITALIC) {
            map_error(queue!(w, SetAttribute(CAttribute::NoItalic)))?;
        }
        if removed.contains(Modifier::UNDERLINED) {
            map_error(queue!(w, SetAttribute(CAttribute::NoUnderline)))?;
        }
        if removed.contains(Modifier::DIM) {
            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
        }
        if removed.contains(Modifier::CROSSED_OUT) {
            map_error(queue!(w, SetAttribute(CAttribute::NotCrossedOut)))?;
        }
        if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) {
            map_error(queue!(w, SetAttribute(CAttribute::NoBlink)))?;
        }

        let added = self.to - self.from;
        if added.contains(Modifier::REVERSED) {
            map_error(queue!(w, SetAttribute(CAttribute::Reverse)))?;
        }
        if added.contains(Modifier::BOLD) {
            map_error(queue!(w, SetAttribute(CAttribute::Bold)))?;
        }
        if added.contains(Modifier::ITALIC) {
            map_error(queue!(w, SetAttribute(CAttribute::Italic)))?;
        }
        if added.contains(Modifier::UNDERLINED) {
            map_error(queue!(w, SetAttribute(CAttribute::Underlined)))?;
        }
        if added.contains(Modifier::DIM) {
            map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;
        }
        if added.contains(Modifier::CROSSED_OUT) {
            map_error(queue!(w, SetAttribute(CAttribute::CrossedOut)))?;
        }
        if added.contains(Modifier::SLOW_BLINK) {
            map_error(queue!(w, SetAttribute(CAttribute::SlowBlink)))?;
        }
        if added.contains(Modifier::RAPID_BLINK) {
            map_error(queue!(w, SetAttribute(CAttribute::RapidBlink)))?;
        }

        Ok(())
    }
}

#[cfg(windows)]
impl ModifierDiff {
    fn queue<W>(&self, mut w: W) -> io::Result<()>
    where
        W: fmt::Write,
    {
        let removed = self.from - self.to;
        if removed.contains(Modifier::BOLD) {
            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
        }
        if removed.contains(Modifier::UNDERLINED) {
            map_error(queue!(w, SetAttribute(CAttribute::NoUnderline)))?;
        }

        let added = self.to - self.from;
        if added.contains(Modifier::BOLD) {
            map_error(queue!(w, SetAttribute(CAttribute::Bold)))?;
        }
        if added.contains(Modifier::UNDERLINED) {
            map_error(queue!(w, SetAttribute(CAttribute::Underlined)))?;
        }
        Ok(())
    }
}
<commit_msg>refactor(backend/crossterm): support more style modifiers on Windows and fix build with Crossterm 0.17.8 (#368)<commit_after>use crate::{
    backend::Backend,
    buffer::Cell,
    layout::Rect,
    style::{Color, Modifier},
};
use crossterm::{
    cursor::{Hide, MoveTo, Show},
    execute, queue,
    style::{
        Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
        SetForegroundColor,
    },
    terminal::{self, Clear, ClearType},
};
use std::io::{self, Write};

pub struct CrosstermBackend<W: Write> {
    buffer: W,
}

impl<W> CrosstermBackend<W>
where
    W: Write,
{
    pub fn new(buffer: W) -> CrosstermBackend<W> {
        CrosstermBackend { buffer }
    }
}

impl<W> Write for CrosstermBackend<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buffer.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buffer.flush()
    }
}

impl<W> Backend for CrosstermBackend<W>
where
    W: Write,
{
    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut fg = Color::Reset;
        let mut bg = Color::Reset;
        let mut modifier = Modifier::empty();
        let mut last_pos: Option<(u16, u16)> = None;
        for (x, y, cell) in content {
            // Move the cursor if the previous location was not (x - 1, y)
            if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {
                map_error(queue!(self.buffer, MoveTo(x, y)))?;
            }
            last_pos = Some((x, y));
            if cell.modifier != modifier {
                let diff = ModifierDiff {
                    from: modifier,
                    to: cell.modifier,
                };
                diff.queue(&mut self.buffer)?;
                modifier = cell.modifier;
            }
            if cell.fg != fg {
                let color = CColor::from(cell.fg);
                map_error(queue!(self.buffer, SetForegroundColor(color)))?;
                fg = cell.fg;
            }
            if cell.bg != bg {
                let color = CColor::from(cell.bg);
                map_error(queue!(self.buffer, SetBackgroundColor(color)))?;
                bg = cell.bg;
            }

            map_error(queue!(self.buffer, Print(&cell.symbol)))?;
        }

        map_error(queue!(
            self.buffer,
            SetForegroundColor(CColor::Reset),
            SetBackgroundColor(CColor::Reset),
            SetAttribute(CAttribute::Reset)
        ))
    }

    fn hide_cursor(&mut self) -> io::Result<()> {
        map_error(execute!(self.buffer, Hide))
    }

    fn show_cursor(&mut self) -> io::Result<()> {
        map_error(execute!(self.buffer, Show))
    }

    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
        crossterm::cursor::position()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
    }

    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
        map_error(execute!(self.buffer, MoveTo(x, y)))
    }

    fn clear(&mut self) -> io::Result<()> {
        map_error(execute!(self.buffer, Clear(ClearType::All)))
    }

    fn size(&self) -> io::Result<Rect> {
        let (width, height) =
            terminal::size().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;

        Ok(Rect::new(0, 0, width, height))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buffer.flush()
    }
}

fn map_error(error: crossterm::Result<()>) -> io::Result<()> {
    error.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
}

impl From<Color> for CColor {
    fn from(color: Color) -> Self {
        match color {
            Color::Reset => CColor::Reset,
            Color::Black => CColor::Black,
            Color::Red => CColor::DarkRed,
            Color::Green => CColor::DarkGreen,
            Color::Yellow => CColor::DarkYellow,
            Color::Blue => CColor::DarkBlue,
            Color::Magenta => CColor::DarkMagenta,
            Color::Cyan => CColor::DarkCyan,
            Color::Gray => CColor::Grey,
            Color::DarkGray => CColor::DarkGrey,
            Color::LightRed => CColor::Red,
            Color::LightGreen => CColor::Green,
            Color::LightBlue => CColor::Blue,
            Color::LightYellow => CColor::Yellow,
            Color::LightMagenta => CColor::Magenta,
            Color::LightCyan => CColor::Cyan,
            Color::White => CColor::White,
            Color::Indexed(i) => CColor::AnsiValue(i),
            Color::Rgb(r, g, b) => CColor::Rgb { r, g, b },
        }
    }
}

#[derive(Debug)]
struct ModifierDiff {
    pub from: Modifier,
    pub to: Modifier,
}

impl ModifierDiff {
    fn queue<W>(&self, mut w: W) -> io::Result<()>
    where
        W: io::Write,
    {
        //use crossterm::Attribute;
        let removed = self.from - self.to;
        if removed.contains(Modifier::REVERSED) {
            map_error(queue!(w, SetAttribute(CAttribute::NoReverse)))?;
        }
        if removed.contains(Modifier::BOLD) {
            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
            if self.to.contains(Modifier::DIM) {
                map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;
            }
        }
        if removed.contains(Modifier::ITALIC) {
            map_error(queue!(w, SetAttribute(CAttribute::NoItalic)))?;
        }
        if removed.contains(Modifier::UNDERLINED) {
            map_error(queue!(w, SetAttribute(CAttribute::NoUnderline)))?;
        }
        if removed.contains(Modifier::DIM) {
            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
        }
        if removed.contains(Modifier::CROSSED_OUT) {
            map_error(queue!(w, SetAttribute(CAttribute::NotCrossedOut)))?;
        }
        if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) {
            map_error(queue!(w, SetAttribute(CAttribute::NoBlink)))?;
        }

        let added = self.to - self.from;
        if added.contains(Modifier::REVERSED) {
            map_error(queue!(w, SetAttribute(CAttribute::Reverse)))?;
        }
        if added.contains(Modifier::BOLD) {
            map_error(queue!(w, SetAttribute(CAttribute::Bold)))?;
        }
        if added.contains(Modifier::ITALIC) {
            map_error(queue!(w, SetAttribute(CAttribute::Italic)))?;
        }
        if added.contains(Modifier::UNDERLINED) {
            map_error(queue!(w, SetAttribute(CAttribute::Underlined)))?;
        }
        if added.contains(Modifier::DIM) {
            map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;
        }
        if added.contains(Modifier::CROSSED_OUT) {
            map_error(queue!(w, SetAttribute(CAttribute::CrossedOut)))?;
        }
        if added.contains(Modifier::SLOW_BLINK) {
            map_error(queue!(w, SetAttribute(CAttribute::SlowBlink)))?;
        }
        if added.contains(Modifier::RAPID_BLINK) {
            map_error(queue!(w, SetAttribute(CAttribute::RapidBlink)))?;
        }

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


<commit_before>extern crate rustc_serialize;
extern crate libc;
extern crate nix;
extern crate env_logger;
extern crate regex;
extern crate argparse;
extern crate quire;
#[macro_use] extern crate log;
extern crate lithos;

use std::env;
use std::io::{stderr, Read, Write};
use std::process::exit;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::fs::{File};
use std::fs::{copy, rename};
use std::default::Default;
use std::process::{Command, Stdio};

use argparse::{ArgumentParser, Parse, StoreTrue, Print};
use quire::parse_config;
use nix::sys::signal::{SIGQUIT, kill};

use lithos::master_config::MasterConfig;
use lithos::sandbox_config::SandboxConfig;

fn switch_config(master_cfg: &Path, sandbox_name: String, config_file: &Path)
    -> Result<(), String>
{
    match Command::new(env::current_exe().unwrap()
                       .parent().unwrap().join("lithos_check"))
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .arg("--config")
        .arg(&master_cfg)
        .arg("--sandbox")
        .arg(&sandbox_name)
        .arg("--alternate-config")
        .arg(&config_file)
        .output()
    {
        Ok(ref po) if po.status.code() == Some(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let sandbox_fn = master_cfg.parent().unwrap()
        .join(&master.sandboxes_dir)
        .join(&(sandbox_name.clone() + ".yaml"));
    let sandbox: SandboxConfig = match parse_config(&sandbox_fn,
        &SandboxConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse sandbox config: {}", e));
        }
    };

    let target_fn = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(sandbox.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(sandbox_name.clone() + ".yaml"))));
    debug!("Target filename {:?}", target_fn);
    let tmp_filename = target_fn.with_file_name(
        &format!(".tmp.{}", sandbox_name));
    try!(copy(&config_file, &tmp_filename)
        .map_err(|e| format!("Error copying: {}", e)));
    try!(rename(&tmp_filename, &target_fn)
        .map_err(|e| format!("Error replacing file: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    let mut buf = String::with_capacity(50);
    let read = File::open(&pid_file)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .ok();
    match read.and_then(|_| FromStr::from_str(buf[..].trim()).ok()) {
        Some(pid) if kill(pid, 0).is_ok() => {
            kill(pid, SIGQUIT)
            .map_err(|e| error!("Error sending QUIT to master: {:?}", e)).ok();
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init().unwrap();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut verbose = false;
    let mut config_file = PathBuf::from("");
    let mut sandbox_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
                (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(&["-v", "--verbose"], StoreTrue,
            "Verbose configuration");
        ap.refer(&mut sandbox_name)
          .add_argument("sandbox", Parse,
            "Name of the sandbox which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_file)
          .add_argument("new_config", Parse, "
            Name of the configuration file to this sandbox switch to.
            The file is copied over current config after configuration is
            validated and just before sending a signal to lithos_tree.")
          .metavar("FILE")
          .required();
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match switch_config(&master_config, sandbox_name, &config_file)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).unwrap();
            exit(1);
        }
    }
}
<commit_msg>More refinements to description of lithos_switch<commit_after>extern crate rustc_serialize;
extern crate libc;
extern crate nix;
extern crate env_logger;
extern crate regex;
extern crate argparse;
extern crate quire;
#[macro_use] extern crate log;
extern crate lithos;

use std::env;
use std::io::{stderr, Read, Write};
use std::process::exit;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::fs::{File};
use std::fs::{copy, rename};
use std::default::Default;
use std::process::{Command, Stdio};

use argparse::{ArgumentParser, Parse, StoreTrue, Print};
use quire::parse_config;
use nix::sys::signal::{SIGQUIT, kill};

use lithos::master_config::MasterConfig;
use lithos::sandbox_config::SandboxConfig;

fn switch_config(master_cfg: &Path, sandbox_name: String, config_file: &Path)
    -> Result<(), String>
{
    match Command::new(env::current_exe().unwrap()
                       .parent().unwrap().join("lithos_check"))
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .arg("--config")
        .arg(&master_cfg)
        .arg("--sandbox")
        .arg(&sandbox_name)
        .arg("--alternate-config")
        .arg(&config_file)
        .output()
    {
        Ok(ref po) if po.status.code() == Some(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let sandbox_fn = master_cfg.parent().unwrap()
        .join(&master.sandboxes_dir)
        .join(&(sandbox_name.clone() + ".yaml"));
    let sandbox: SandboxConfig = match parse_config(&sandbox_fn,
        &SandboxConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse sandbox config: {}", e));
        }
    };

    let target_fn = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(sandbox.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(sandbox_name.clone() + ".yaml"))));
    debug!("Target filename {:?}", target_fn);
    let tmp_filename = target_fn.with_file_name(
        &format!(".tmp.{}", sandbox_name));
    try!(copy(&config_file, &tmp_filename)
        .map_err(|e| format!("Error copying: {}", e)));
    try!(rename(&tmp_filename, &target_fn)
        .map_err(|e| format!("Error replacing file: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    let mut buf = String::with_capacity(50);
    let read = File::open(&pid_file)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .ok();
    match read.and_then(|_| FromStr::from_str(buf[..].trim()).ok()) {
        Some(pid) if kill(pid, 0).is_ok() => {
            kill(pid, SIGQUIT)
            .map_err(|e| error!("Error sending QUIT to master: {:?}", e)).ok();
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init().unwrap();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut verbose = false;
    let mut config_file = PathBuf::from("");
    let mut sandbox_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
                (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(&["-v", "--verbose"], StoreTrue,
            "Verbose configuration");
        ap.refer(&mut sandbox_name)
          .add_argument("sandbox", Parse,
            "Name of the sandbox which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_file)
          .add_argument("new_config", Parse, "
            Name of the process configuration file for this sandbox to switch
            to. The file is copied over current config after configuration is
            validated and just before sending a signal to lithos_tree.")
          .metavar("FILE")
          .required();
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match switch_config(&master_config, sandbox_name, &config_file)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).unwrap();
            exit(1);
        }
    }
}
<|endoftext|>


<commit_before>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::config::{Config, TargetSelection};

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: TargetSelection) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}

pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host));
}

pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<TargetSelection>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::create_dir_all(p)
            .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
        fs::canonicalize(p)
            .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = &builder.config.bindir;
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host.triple)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        if let Component::Normal(s) = part {
            ret.push(s)
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: TargetSelection,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "library/std", true, only_hosts: true, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target });
        install_rust_analyzer(builder, self.compiler.stage, self.target);
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
        install_clippy(builder, self.compiler.stage, self.target);
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            // Find the actual compiler (handling the full bootstrap option) which
            // produced the save-analysis data because that data isn't copied
            // through the sysroot uplifting.
            compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target),
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: builder.compiler(builder.top_stage, self.target),
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<commit_msg>Install std for non-host targets<commit_after>//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::Command;

use build_helper::t;

use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
use crate::Compiler;

use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::config::{Config, TargetSelection};

pub fn install_docs(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_std(builder: &Builder<'_>, stage: u32, target: TargetSelection) {
    install_sh(builder, "std", "rust-std", stage, Some(target));
}

pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_rls(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rls", "rls", stage, Some(host));
}

pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host));
}

pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "clippy", "clippy", stage, Some(host));
}
pub fn install_miri(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "miri", "miri", stage, Some(host));
}

pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
}

pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_src(builder: &Builder<'_>, stage: u32) {
    install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
    install_sh(builder, "rustc", "rustc", stage, Some(host));
}

fn install_sh(
    builder: &Builder<'_>,
    package: &str,
    name: &str,
    stage: u32,
    host: Option<TargetSelection>,
) {
    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));

    let prefix_default = PathBuf::from("/usr/local");
    let sysconfdir_default = PathBuf::from("/etc");
    let datadir_default = PathBuf::from("share");
    let docdir_default = datadir_default.join("doc/rust");
    let libdir_default = PathBuf::from("lib");
    let mandir_default = datadir_default.join("man");
    let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
        fs::create_dir_all(p)
            .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
        fs::canonicalize(p)
            .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
    });
    let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
    let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
    let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
    let bindir = &builder.config.bindir;
    let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);

    let sysconfdir = prefix.join(sysconfdir);
    let datadir = prefix.join(datadir);
    let docdir = prefix.join(docdir);
    let bindir = prefix.join(bindir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let sysconfdir = add_destdir(&sysconfdir, &destdir);
    let datadir = add_destdir(&datadir, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let bindir = add_destdir(&bindir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = builder.out.join("tmp/empty_dir");

    t!(fs::create_dir_all(&empty_dir));
    let package_name = if let Some(host) = host {
        format!("{}-{}", pkgname(builder, name), host.triple)
    } else {
        pkgname(builder, name)
    };

    let mut cmd = Command::new("sh");
    cmd.current_dir(&empty_dir)
        .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
        .arg(format!("--prefix={}", sanitize_sh(&prefix)))
        .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
        .arg(format!("--datadir={}", sanitize_sh(&datadir)))
        .arg(format!("--docdir={}", sanitize_sh(&docdir)))
        .arg(format!("--bindir={}", sanitize_sh(&bindir)))
        .arg(format!("--libdir={}", sanitize_sh(&libdir)))
        .arg(format!("--mandir={}", sanitize_sh(&mandir)))
        .arg("--disable-ldconfig");
    builder.run(&mut cmd);
    t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        if let Component::Normal(s) = part {
            ret.push(s)
        }
    }
    ret
}

macro_rules! install {
    (($sel:ident, $builder:ident, $_config:ident),
       $($name:ident,
       $path:expr,
       $default_cond:expr,
       only_hosts: $only_hosts:expr,
       $run_item:block $(, $c:ident)*;)+) => {
        $(
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
            pub compiler: Compiler,
            pub target: TargetSelection,
        }

        impl $name {
            #[allow(dead_code)]
            fn should_build(config: &Config) -> bool {
                config.extended && config.tools.as_ref()
                    .map_or(true, |t| t.contains($path))
            }
        }

        impl Step for $name {
            type Output = ();
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = $only_hosts;
            $(const $c: bool = true;)*

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                let $_config = &run.builder.config;
                run.path($path).default_condition($default_cond)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name {
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
                    target: run.target,
                });
            }

            fn run($sel, $builder: &Builder<'_>) {
                $run_item
            }
        })+
    }
}

install!((self, builder, _config),
    Docs, "src/doc", _config.docs, only_hosts: false, {
        builder.ensure(dist::Docs { host: self.target });
        install_docs(builder, self.compiler.stage, self.target);
    };
    Std, "library/std", true, only_hosts: false, {
        for target in &builder.targets {
            builder.ensure(dist::Std {
                compiler: self.compiler,
                target: *target
            });
            install_std(builder, self.compiler.stage, *target);
        }
    };
    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target });
        install_cargo(builder, self.compiler.stage, self.target);
    };
    Rls, "rls", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() {
            install_rls(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target });
        install_rust_analyzer(builder, self.compiler.stage, self.target);
    };
    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
        builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
        install_clippy(builder, self.compiler.stage, self.target);
    };
    Miri, "miri", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() {
            install_miri(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
        if builder.ensure(dist::Rustfmt {
            compiler: self.compiler,
            target: self.target
        }).is_some() {
            install_rustfmt(builder, self.compiler.stage, self.target);
        } else {
            builder.info(
                &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
            );
        }
    };
    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
        builder.ensure(dist::Analysis {
            // Find the actual compiler (handling the full bootstrap option) which
            // produced the save-analysis data because that data isn't copied
            // through the sysroot uplifting.
            compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target),
            target: self.target
        });
        install_analysis(builder, self.compiler.stage, self.target);
    };
    Rustc, "src/librustc", true, only_hosts: true, {
        builder.ensure(dist::Rustc {
            compiler: builder.compiler(builder.top_stage, self.target),
        });
        install_rustc(builder, self.compiler.stage, self.target);
    };
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Src {
    pub stage: u32,
}

impl Step for Src {
    type Output = ();
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        let config = &run.builder.config;
        let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
        run.path("src").default_condition(cond)
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Src { stage: run.builder.top_stage });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.ensure(dist::Src);
        install_src(builder, self.stage);
    }
}
<|endoftext|>


<commit_before>use std::{
    cmp::Ordering,
    path::{Path, PathBuf},
};

use indexmap::IndexMap;
use serde::{Deserialize, Serialize};

#[nova::newtype(serde)]
pub type ObjectId = String;

impl ObjectId {
    pub fn new_random() -> Self {
        use rand::Rng;
        const CHARSET: &[u8] = b"0123456789ABCDEF";
        const LEN: usize = 24;
        let mut rng = rand::thread_rng();

        let id: String = (0..LEN)
            .map(|_| {
                let idx = rng.gen_range(0..CHARSET.len());
                CHARSET[idx] as char
            })
            .collect();

        ObjectId(id)
    }

    pub fn add_ref_to_group() {
        println!("ADD_REF_TO_GROUP");
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Pbxproj {
    pub classes: serde_json::Value,
    pub object_version: String,
    pub archive_version: String,
    pub objects: IndexMap<ObjectId, Object>,
    pub mainGroup: IndexMap<String, String>,
}

#[derive(Serialize, Deserialize)]
pub struct PlistFile {
    #[serde(rename = "lastKnownFileType")]
    last_known_file_type: String,
    name: String,
    path: String,
    #[serde(rename = "sourceTree")]
    source_tree: String,
}

#[derive(Serialize, Deserialize)]
pub struct PbxGroup {
    children: Vec<String>,
    isa: String,
    path: String,
    #[serde(rename = "sourceTree")]
    source_tree: String,
}

impl Pbxproj {
    pub fn from_path(path: &PathBuf) -> Self {
        convert_pbxproj_to_json(path)
    }

    pub fn create_plist_file(&mut self, relative_plist_path: &PathBuf) -> ObjectId {
        let temp = PlistFile {
            last_known_file_type: "text.plist.xml".to_string(),
            name: relative_plist_path
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string(),
            path: relative_plist_path.to_str().unwrap().to_string(),
            source_tree: "<group>".to_string(),
        };

        let object = ObjectId::new_random();

        self.objects.insert(
            object.clone(),
            Object::FileReference(serde_json::json!(temp)),
        );

        return object;
    }

    // WTF IS HAPPENING IN THE PYTHON?
    // create a self.main_group??
    pub fn add_path(&self, path: &PathBuf) {
        println!("ADD_PATH: {:?}", path);
        let path_list: Vec<String> = path
            .to_str()
            .unwrap()
            .to_string()
            .split("/")
            .map(|x| x.to_string())
            .collect();

        // let mut target = self.mainGroup;

        // for path_name in path_list {
        //     for child in target.children {
        //         if child.get("path").cmp(&path_name) == Ordering::Equal {
        //             target = child;
        //             break;
        //         } else {
        //             let key = ObjectId::new_random();

        //             let value = PbxGroup {
        //                 children: vec![],
        //                 isa: "PBXGroup".to_string(),
        //                 path: path_name,
        //                 source_tree: "<group>".to_string(),
        //             };

        //             self.objects.insert(key, Object::Group(serde_json::json!(value)));
        //             target["children"].push(serde_json::json!(key));
        //             target = self.objects.get(&key);
        //         }
        //     }
        // }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "isa")]
pub enum Object {
    #[serde(rename = "PBXBuildFile")]
    BuildFile(BuildFile),

    #[serde(rename = "PBXFileReference")]
    FileReference(serde_json::Value),

    #[serde(rename = "PBXCopyFilesBuildPhase")]
    CopyFilesBuildPhase(serde_json::Value),

    #[serde(rename = "PBXGroup")]
    Group(serde_json::Value),

    #[serde(rename = "PBXProject")]
    Project(serde_json::Value),

    #[serde(rename = "XCConfigurationList")]
    ConfigurationList(serde_json::Value),

    #[serde(rename = "PBXSourcesBuildPhase")]
    SourcesBuildPhase(serde_json::Value),

    #[serde(rename = "PBXFrameworksBuildPhase")]
    FrameworksBuildPhase(serde_json::Value),

    #[serde(rename = "PBXResourcesBuildPhase")]
    ResourcesBuildPhase(serde_json::Value),

    #[serde(rename = "PBXTargetDependency")]
    TargetDependency(serde_json::Value),

    #[serde(rename = "PBXVariantGroup")]
    VariantGroup(serde_json::Value),

    #[serde(rename = "PBXShellScriptBuildPhase")]
    ShellScriptBuildPhase(serde_json::Value),

    #[serde(rename = "PBXHeadersBuildPhase")]
    HeadersBuildPhase(serde_json::Value),

    #[serde(rename = "PBXNativeTarget")]
    NativeTarget(serde_json::Value),

    #[serde(rename = "XCBuildConfiguration")]
    BuildConfiguration(serde_json::Value),

    #[serde(rename = "PBXContainerItemProxy")]
    ContainerItemProxy(serde_json::Value),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BuildFile {
    pub file_ref: ObjectId,
}

pub fn convert_pbxproj_to_json(path: &Path) -> Pbxproj {
    let tempdir = tempfile::tempdir().unwrap();
    let pbxproj_path = tempdir.path().join("tmp.pbxproj");
    std::fs::copy(path, &pbxproj_path).unwrap();

    std::process::Command::new("plutil")
        .args(["-convert", "json"])
        .arg(&pbxproj_path)
        .status()
        .unwrap();

    let reader = std::fs::File::open(pbxproj_path).unwrap();
    serde_json::from_reader(reader).unwrap()
}
<commit_msg>add path references to pbxproj<commit_after>use std::{
    cmp::Ordering,
    path::{Path, PathBuf},
};

use indexmap::IndexMap;
use serde::{Deserialize, Serialize};

#[nova::newtype(serde)]
pub type ObjectId = String;

impl ObjectId {
    pub fn new_random() -> Self {
        use rand::Rng;
        const CHARSET: &[u8] = b"0123456789ABCDEF";
        const LEN: usize = 24;
        let mut rng = rand::thread_rng();

        let id: String = (0..LEN)
            .map(|_| {
                let idx = rng.gen_range(0..CHARSET.len());
                CHARSET[idx] as char
            })
            .collect();

        ObjectId(id)
    }

    pub fn add_ref_to_group() {
        println!("ADD_REF_TO_GROUP");
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PbxProject {
    attributes: serde_json::Value,
    build_configuration_list: ObjectId,
    compatibility_version: String,
    development_region: String,
    has_scanned_for_encodings: String,
    known_regions: serde_json::Value,
    main_group: ObjectId,
    product_ref_group: ObjectId,
    project_dir_path: String,
    project_root: String,
    targets: Vec<ObjectId>,
}

#[derive(Serialize, Deserialize)]
pub struct PlistFile {
    #[serde(rename = "lastKnownFileType")]
    last_known_file_type: String,
    name: String,
    path: String,
    #[serde(rename = "sourceTree")]
    source_tree: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PbxGroup {
    children: Vec<ObjectId>,
    #[serde(rename = "sourceTree")]
    source_tree: String,
    path: Option<String>,
}

impl PbxGroup {
    pub fn add_child_ref(&mut self) {}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Pbxproj {
    pub classes: serde_json::Value,
    pub object_version: String,
    pub archive_version: String,
    pub objects: IndexMap<ObjectId, Object>,
}

impl Pbxproj {
    pub fn from_path(path: &PathBuf) -> Self {
        convert_pbxproj_to_json(path)
    }

    pub fn project(&self) -> Option<PbxProject> {
        for object in self.objects.values() {
            if let Object::Project(project) = object {
                return Some(project.clone());
            }
        }
        None
    }

    pub fn group(&self, object_id: &ObjectId) -> Option<&PbxGroup> {
        if let Some(Object::Group(main_group)) = self.objects.get(object_id) {
            return Some(main_group);
        }
        return None;
    }

    pub fn group_mut(&mut self, object_id: &ObjectId) -> Option<&mut PbxGroup> {
        if let Some(Object::Group(main_group)) = self.objects.get_mut(object_id) {
            return Some(main_group);
        }
        return None;
    }

    pub fn create_plist_file(&mut self, relative_plist_path: &PathBuf) -> ObjectId {
        let temp = PlistFile {
            last_known_file_type: "text.plist.xml".to_string(),
            name: relative_plist_path
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string(),
            path: relative_plist_path.to_str().unwrap().to_string(),
            source_tree: "<group>".to_string(),
        };

        let object = ObjectId::new_random();

        self.objects.insert(
            object.clone(),
            Object::FileReference(serde_json::json!(temp)),
        );

        return object;
    }

    pub fn add_path(&mut self, path: &PathBuf) {
        let path_names: Vec<String> = path
            .components()
            .map(|x| x.as_os_str().to_str().unwrap().to_string())
            .collect();

        let mut target = self.project().unwrap().main_group;

        'boop: for path_name in path_names {
            let children_references = &self.group(&target).unwrap().children;

            for child_reference in children_references {
                if let Some(child_group) = self.group(child_reference) {
                    if let Some(path) = &child_group.path {
                        if path == &path_name {
                            target = child_reference.clone();
                            continue 'boop;
                        }
                    }
                }
            }

            println!("Nothing exists create here");

            let id = ObjectId::new_random();

            let new_child = PbxGroup {
                children: vec![],
                path: Some(path_name.clone()),
                source_tree: "<group>".to_string(),
            };

            self.objects.insert(id.clone(), Object::Group(new_child));
            self.group_mut(&target).unwrap().children.push(id.clone());

            target = id;
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "isa")]
pub enum Object {
    #[serde(rename = "PBXBuildFile")]
    BuildFile(BuildFile),

    #[serde(rename = "PBXFileReference")]
    FileReference(serde_json::Value),

    #[serde(rename = "PBXCopyFilesBuildPhase")]
    CopyFilesBuildPhase(serde_json::Value),

    #[serde(rename = "PBXGroup")]
    Group(PbxGroup),

    #[serde(rename = "PBXProject")]
    Project(PbxProject),

    #[serde(rename = "XCConfigurationList")]
    ConfigurationList(serde_json::Value),

    #[serde(rename = "PBXSourcesBuildPhase")]
    SourcesBuildPhase(serde_json::Value),

    #[serde(rename = "PBXFrameworksBuildPhase")]
    FrameworksBuildPhase(serde_json::Value),

    #[serde(rename = "PBXResourcesBuildPhase")]
    ResourcesBuildPhase(serde_json::Value),

    #[serde(rename = "PBXTargetDependency")]
    TargetDependency(serde_json::Value),

    #[serde(rename = "PBXVariantGroup")]
    VariantGroup(serde_json::Value),

    #[serde(rename = "PBXShellScriptBuildPhase")]
    ShellScriptBuildPhase(serde_json::Value),

    #[serde(rename = "PBXHeadersBuildPhase")]
    HeadersBuildPhase(serde_json::Value),

    #[serde(rename = "PBXNativeTarget")]
    NativeTarget(serde_json::Value),

    #[serde(rename = "XCBuildConfiguration")]
    BuildConfiguration(serde_json::Value),

    #[serde(rename = "PBXContainerItemProxy")]
    ContainerItemProxy(serde_json::Value),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BuildFile {
    pub file_ref: ObjectId,
}

pub fn convert_pbxproj_to_json(path: &Path) -> Pbxproj {
    let tempdir = tempfile::tempdir().unwrap();
    let pbxproj_path = tempdir.path().join("tmp.pbxproj");
    std::fs::copy(path, &pbxproj_path).unwrap();

    std::process::Command::new("plutil")
        .args(["-convert", "json"])
        .arg(&pbxproj_path)
        .status()
        .unwrap();

    let reader = std::fs::File::open(pbxproj_path).unwrap();
    serde_json::from_reader(reader).unwrap()
}
<|endoftext|>