<commit_before>use crate::convert::From;
use crate::fmt;
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, DispatchFromDyn};

// ignore-tidy-undocumented-unsafe

/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
/// of this wrapper owns the referent. Useful for building abstractions like
/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
///
/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
/// the kind of strong aliasing guarantees an instance of `T` can expect:
/// the referent of the pointer should not be modified without a unique path to
/// its owning Unique.
///
/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
/// consider using `NonNull`, which has weaker semantics.
///
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
/// is never dereferenced. This is so that enums may use this forbidden value
/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
/// However the pointer may still dangle if it isn't dereferenced.
///
/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
/// for any type which upholds Unique's aliasing requirements.
#[unstable(
    feature = "ptr_internals",
    issue = "none",
    reason = "use `NonNull` instead and consider `PhantomData<T>` \
              (if you also use `#[may_dangle]`), `Send`, and/or `Sync`"
)]
#[doc(hidden)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
pub struct Unique<T: ?Sized> {
    pointer: *const T,
    // NOTE: this marker has no consequences for variance, but is necessary
    // for dropck to understand that we logically own a `T`.
    //
    // For details, see:
    // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
    _marker: PhantomData<T>,
}

/// `Unique` pointers are `Send` if `T` is `Send` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
#[unstable(feature = "ptr_internals", issue = "none")]
unsafe impl<T: Send + ?Sized> Send for Unique<T> {}

/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
#[unstable(feature = "ptr_internals", issue = "none")]
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: Sized> Unique<T> {
    /// Creates a new `Unique` that is dangling, but well-aligned.
    ///
    /// This is useful for initializing types which lazily allocate, like
    /// `Vec::new` does.
    ///
    /// Note that the pointer value may potentially represent a valid pointer to
    /// a `T`, which means this must not be used as a "not yet initialized"
    /// sentinel value. Types that lazily allocate must track initialization by
    /// some other means.
    #[inline]
    pub const fn dangling() -> Self {
        // SAFETY: mem::align_of() returns a valid, non-null pointer. The
        // conditions to call new_unchecked() are thus respected.
        unsafe { Unique::new_unchecked(mem::align_of::<T>() as *mut T) }
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> Unique<T> {
    /// Creates a new `Unique`.
    ///
    /// # Safety
    ///
    /// `ptr` must be non-null.
    #[inline]
    pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
        // SAFETY: the caller must guarantee that `ptr` is non-null.
        unsafe { Unique { pointer: ptr as _, _marker: PhantomData } }
    }

    /// Creates a new `Unique` if `ptr` is non-null.
    #[inline]
    pub fn new(ptr: *mut T) -> Option<Self> {
        if !ptr.is_null() {
            // SAFETY: The pointer has already been checked and is not null.
            Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } })
        } else {
            None
        }
    }

    /// Acquires the underlying `*mut` pointer.
    #[inline]
    pub const fn as_ptr(self) -> *mut T {
        self.pointer as *mut T
    }

    /// Dereferences the content.
    ///
    /// The resulting lifetime is bound to self so this behaves "as if"
    /// it were actually an instance of T that is getting borrowed. If a longer
    /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
    #[inline]
    pub unsafe fn as_ref(&self) -> &T {
        // SAFETY: the caller must guarantee that `self` meets all the
        // requirements for a reference.
        unsafe { &*self.as_ptr() }
    }

    /// Mutably dereferences the content.
    ///
    /// The resulting lifetime is bound to self so this behaves "as if"
    /// it were actually an instance of T that is getting borrowed. If a longer
    /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
    #[inline]
    pub unsafe fn as_mut(&mut self) -> &mut T {
        // SAFETY: the caller must guarantee that `self` meets all the
        // requirements for a mutable reference.
        unsafe { &mut *self.as_ptr() }
    }

    /// Casts to a pointer of another type.
    #[inline]
    pub const fn cast<U>(self) -> Unique<U> {
        // SAFETY: Unique::new_unchecked() creates a new unique and needs
        // the given pointer to not be null.
        // Since we are passing self as a pointer, it cannot be null.
        unsafe { Unique::new_unchecked(self.as_ptr() as *mut U) }
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> Clone for Unique<T> {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> Copy for Unique<T> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> fmt::Debug for Unique<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Pointer::fmt(&self.as_ptr(), f)
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> fmt::Pointer for Unique<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Pointer::fmt(&self.as_ptr(), f)
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> From<&mut T> for Unique<T> {
    #[inline]
    fn from(reference: &mut T) -> Self {
        // SAFETY: A mutable reference cannot be null
        unsafe { Unique { pointer: reference as *mut T, _marker: PhantomData } }
    }
}
<commit_msg>Rollup merge of #76493 - moonheart08:unique-quick, r=jyn514<commit_after>use crate::convert::From;
use crate::fmt;
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, DispatchFromDyn};

/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
/// of this wrapper owns the referent. Useful for building abstractions like
/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
///
/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
/// the kind of strong aliasing guarantees an instance of `T` can expect:
/// the referent of the pointer should not be modified without a unique path to
/// its owning Unique.
///
/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
/// consider using `NonNull`, which has weaker semantics.
///
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
/// is never dereferenced. This is so that enums may use this forbidden value
/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
/// However the pointer may still dangle if it isn't dereferenced.
///
/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
/// for any type which upholds Unique's aliasing requirements.
#[unstable(
    feature = "ptr_internals",
    issue = "none",
    reason = "use `NonNull` instead and consider `PhantomData<T>` \
              (if you also use `#[may_dangle]`), `Send`, and/or `Sync`"
)]
#[doc(hidden)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
pub struct Unique<T: ?Sized> {
    pointer: *const T,
    // NOTE: this marker has no consequences for variance, but is necessary
    // for dropck to understand that we logically own a `T`.
    //
    // For details, see:
    // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
    _marker: PhantomData<T>,
}

/// `Unique` pointers are `Send` if `T` is `Send` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
#[unstable(feature = "ptr_internals", issue = "none")]
unsafe impl<T: Send + ?Sized> Send for Unique<T> {}

/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
#[unstable(feature = "ptr_internals", issue = "none")]
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: Sized> Unique<T> {
    /// Creates a new `Unique` that is dangling, but well-aligned.
    ///
    /// This is useful for initializing types which lazily allocate, like
    /// `Vec::new` does.
    ///
    /// Note that the pointer value may potentially represent a valid pointer to
    /// a `T`, which means this must not be used as a "not yet initialized"
    /// sentinel value. Types that lazily allocate must track initialization by
    /// some other means.
    #[inline]
    pub const fn dangling() -> Self {
        // SAFETY: mem::align_of() returns a valid, non-null pointer. The
        // conditions to call new_unchecked() are thus respected.
        unsafe { Unique::new_unchecked(mem::align_of::<T>() as *mut T) }
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> Unique<T> {
    /// Creates a new `Unique`.
    ///
    /// # Safety
    ///
    /// `ptr` must be non-null.
    #[inline]
    pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
        // SAFETY: the caller must guarantee that `ptr` is non-null.
        unsafe { Unique { pointer: ptr as _, _marker: PhantomData } }
    }

    /// Creates a new `Unique` if `ptr` is non-null.
    #[inline]
    pub fn new(ptr: *mut T) -> Option<Self> {
        if !ptr.is_null() {
            // SAFETY: The pointer has already been checked and is not null.
            Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } })
        } else {
            None
        }
    }

    /// Acquires the underlying `*mut` pointer.
    #[inline]
    pub const fn as_ptr(self) -> *mut T {
        self.pointer as *mut T
    }

    /// Dereferences the content.
    ///
    /// The resulting lifetime is bound to self so this behaves "as if"
    /// it were actually an instance of T that is getting borrowed. If a longer
    /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
    #[inline]
    pub unsafe fn as_ref(&self) -> &T {
        // SAFETY: the caller must guarantee that `self` meets all the
        // requirements for a reference.
        unsafe { &*self.as_ptr() }
    }

    /// Mutably dereferences the content.
    ///
    /// The resulting lifetime is bound to self so this behaves "as if"
    /// it were actually an instance of T that is getting borrowed. If a longer
    /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
    #[inline]
    pub unsafe fn as_mut(&mut self) -> &mut T {
        // SAFETY: the caller must guarantee that `self` meets all the
        // requirements for a mutable reference.
        unsafe { &mut *self.as_ptr() }
    }

    /// Casts to a pointer of another type.
    #[inline]
    pub const fn cast<U>(self) -> Unique<U> {
        // SAFETY: Unique::new_unchecked() creates a new unique and needs
        // the given pointer to not be null.
        // Since we are passing self as a pointer, it cannot be null.
        unsafe { Unique::new_unchecked(self.as_ptr() as *mut U) }
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> Clone for Unique<T> {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> Copy for Unique<T> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> fmt::Debug for Unique<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Pointer::fmt(&self.as_ptr(), f)
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> fmt::Pointer for Unique<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Pointer::fmt(&self.as_ptr(), f)
    }
}

#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> From<&mut T> for Unique<T> {
    #[inline]
    fn from(reference: &mut T) -> Self {
        // SAFETY: A mutable reference cannot be null
        unsafe { Unique { pointer: reference as *mut T, _marker: PhantomData } }
    }
}
<|endoftext|>


<commit_before><commit_msg>Updated alloc API usage<commit_after><|endoftext|>


<commit_before><commit_msg>Little cleanup<commit_after><|endoftext|>


<commit_before><commit_msg>more general float parser<commit_after><|endoftext|>


<commit_before><commit_msg>Resolve an overflow on left-shift cdef_dist_wxh_8x8<commit_after><|endoftext|>


<commit_before><commit_msg>Speed up sum of squared errors function<commit_after><|endoftext|>


<commit_before><commit_msg>unlock all the tests<commit_after><|endoftext|>


<commit_before><commit_msg>uci: fix sending wrong default values<commit_after><|endoftext|>


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

use maplit::hashset;
use std::{
    collections::{HashMap, HashSet},
    io::{BufRead, BufReader},
    path::{Path, PathBuf},
    process::Command,
};

use crate::{
    files::*,
    internal::{CargoManifest, Scope},
};

#[derive(Debug)]
pub struct ModifiedContent {
    /// List of modified files.
    pub files: Option<Vec<String>>,
}

impl ModifiedContent {
    pub fn contains(&self, file_name: &str) -> bool {
        self.files.is_none()
            || self
                .files
                .as_ref()
                .unwrap()
                .contains(&file_name.to_string())
    }
}

/// Get all the files that have been modified in the given `scope`. If the scope is `Scope::All`
/// returns `None` as the list of files in `ModifiedContent`. For `Scope::Commits` and
/// `Scope::DiffToMain` the returned files include tracked files with unstaged changes, but do
/// not include new files that are not tracked (i.e., not added to git yet). For
/// `Scope::Commits(N)`, a positive number of commits must be given. In case of zero or
/// a negative number, only the last commit will be considered for finding the modified files.
pub fn modified_files(scope: &Scope) -> ModifiedContent {
    let args = match scope {
        Scope::All => None,
        Scope::Commits(commits) => Some(format!("HEAD~{}", std::cmp::max(1, *commits))),
        // TODO(#2491): Use `--merge-base` when we have a newer version of Git in the docker image.
        Scope::DiffToMain => Some("main".to_owned()),
    };

    let files: Option<Vec<String>> = args.map(|args| {
        let vec = Command::new("git")
            .args(spread!["diff".to_owned(), "--name-only".to_owned(), args,])
            .output()
            .expect("could not get modified files")
            .stdout;

        // Extract the file names from the git output
        String::from_utf8(vec)
            .expect("could not convert to string")
            .split('\n')
            .map(|s| format!("./{}", s))
            .collect()
    });

    // If something is changed in a Dockerfile, we'd want to run all CI steps, so set `files` to
    // `None` in `ModifiedContent`.
    if let Some(ref paths) = files {
        if paths.iter().any(|path| path.contains("Dockerfile")) {
            return ModifiedContent { files: None };
        }
    }

    ModifiedContent { files }
}

/// Returns the list of paths to `Cargo.toml` files for all crates that include at least one of the
/// given modified files.
pub fn directly_modified_crates(files: &ModifiedContent) -> ModifiedContent {
    let files = files.files.as_ref().map(|modified_files| {
        let mut crates = hashset![];
        for str_path in modified_files {
            if let Some(crate_path) = find_crate_toml_file(str_path.clone()) {
                crates.insert(crate_path);
            }
        }
        crates.iter().cloned().collect()
    });
    ModifiedContent { files }
}

fn find_crate_toml_file(str_path: String) -> Option<String> {
    if str_path.ends_with("Cargo.toml") {
        return Some(str_path);
    } else if str_path.ends_with(".rs") || str_path.ends_with(".lock") {
        let mut path = PathBuf::from(&str_path);
        while path.parent().is_some() {
            path.pop();
            let crate_path = path.join("Cargo.toml");
            let crate_path = crate_path.as_path();
            if crate_path.exists() {
                return Some(crate_path.to_str().unwrap().to_string());
            }
        }
    }
    None
}

/// Returns the list of paths to all `.proto` files affected by the given list of modified files.
fn affected_protos(files: &ModifiedContent) -> Vec<String> {
    files
        .files
        .as_ref()
        .map(|modified_files| {
            let mut affected_protos: Vec<String> = modified_files
                .iter()
                .filter(|p| p.ends_with(".proto"))
                .cloned()
                .collect();

            if !affected_protos.is_empty() {
                let all_protos = source_files()
                    .map(to_string)
                    .map(|s| s.replace("./", ""))
                    .filter(|p| p.ends_with(".proto"));

                for proto in all_protos {
                    add_affected_protos(proto, &mut affected_protos);
                }
            }

            affected_protos
        })
        .unwrap_or_else(Vec::new)
}

/// Adds `proto_path` to the list of `affected_protos` if `proto_path` or any of its imported protos
/// imports any of the proto files in `affected_protos`.
fn add_affected_protos(proto_path: String, affected_protos: &mut Vec<String>) {
    if affected_protos.contains(&proto_path) {
        return;
    }

    let imported_proto_files = imported_proto_files(proto_path.clone());
    for imported_proto_file in imported_proto_files {
        if !affected_protos.contains(&imported_proto_file) {
            add_affected_protos(imported_proto_file.clone(), affected_protos);
        }

        if affected_protos.contains(&imported_proto_file) {
            affected_protos.push(proto_path);
            return;
        }
    }
}

/// Returns paths to all `.proto` files that `proto_file_path` imports.
fn imported_proto_files(proto_file_path: String) -> Vec<String> {
    let mut imported_protos = vec![];
    if let Ok(file) = std::fs::File::open(proto_file_path) {
        let lines = BufReader::new(file).lines();
        let re = regex::Regex::new(r#"import "(.*)";"#).unwrap();

        // Scan the lines in the file line by line to find all the imports.
        for line in lines {
            let line = line.expect("could not read line");
            if let Some(imported) = re.captures(&line).map(|c| c[1].to_string()) {
                imported_protos.push(imported);
            }
        }
    }

    imported_protos
}

/// Path to the `Cargo.toml` files for all crates that are either directly modified or have a
/// dependency to a modified crate.
pub fn all_affected_crates(scope: &Scope) -> ModifiedContent {
    crates_affected_by_files(&modified_files(scope))
}

fn crates_affected_by_files(files: &ModifiedContent) -> ModifiedContent {
    let modified_crates = directly_modified_crates(files);
    let files = modified_crates.files.map(|modified_files| {
        let crate_manifest_files = crate_manifest_files();
        // A map of `Cargo.toml` files visited by the algorithm. If the value associated with a
        // key is `true`, the crate is affected by the changes and should be included in the
        // result.
        let mut affected_crates: HashMap<String, bool> = modified_files
            .into_iter()
            .map(|path| (path, true))
            .collect();

        crates_affected_by_protos(&affected_protos(files))
            .iter()
            .fold(&mut affected_crates, |affected_crates, toml_path| {
                affected_crates.insert(toml_path.clone(), true);
                affected_crates
            });

        for crate_path in crate_manifest_files {
            add_affected_crates(crate_path, &mut affected_crates);
        }

        // Return `Cargo.toml` files of the crates that are affected by the changes
        affected_crates
            .iter()
            .filter(|(_key, value)| **value)
            .map(|(key, _value)| key.clone())
            .collect()
    });

    ModifiedContent { files }
}

/// Returns the paths to `Cargo.toml` files of crates affected by the changed proto files.
fn crates_affected_by_protos(affected_protos: &[String]) -> HashSet<String> {
    source_files()
        .filter(|path| to_string(path.clone()).ends_with("build.rs"))
        .filter(|path| {
            for proto in affected_protos {
                if file_contains(path, &proto.replace("./", "")) {
                    return true;
                }
            }
            false
        })
        .map(to_string)
        .map(|build_path| find_crate_toml_file(build_path).unwrap())
        .collect()
}

/// Checks if `crate_toml_path` has a direct or indirect dependency to any of the affected crates in
/// `affected_crates_toml_path`. If so, adds `crate_toml_path` and any of its affected dependencies
/// to `affected_crates_toml_path`.
///
/// Keys in `affected_crates_toml_path` are paths to visited `Cargo.toml` files. If the value
/// associated with a key is `true`, then the corresponding crate is affected by the changes.
fn add_affected_crates(
    crate_toml_path: PathBuf,
    affected_crates_toml_path: &mut HashMap<String, bool>,
) {
    // Return immediately, if the `crate_toml_path` is already visited.
    if affected_crates_toml_path.contains_key(&to_string(crate_toml_path.clone())) {
        return;
    }
    affected_crates_toml_path.insert(to_string(crate_toml_path.clone()), false);
    let deps = get_local_dependencies(&crate_toml_path);
    for dep in deps {
        // If the dependency is not visited, visit it and its dependencies
        if !affected_crates_toml_path.contains_key(&dep) {
            let dep_path = PathBuf::from(dep.clone());
            add_affected_crates(dep_path.clone(), affected_crates_toml_path)
        }
        if *affected_crates_toml_path.get(&dep).unwrap_or(&false) {
            affected_crates_toml_path.insert(to_string(crate_toml_path), true);
            return;
        }
    }
}

/// Returns paths to `Cargo.toml` files of local crates (crates belonging to the Oak repo) that the
/// given crate has a dependency to. Converts the relative dependency paths in `Cargo.toml` into
/// paths relative to the repo's root.
fn get_local_dependencies(toml_path: &Path) -> Vec<String> {
    let cargo_manifest: CargoManifest =
        toml::from_str(&read_file(toml_path)).unwrap_or_else(|err| {
            panic!(
                "could not parse crate manifest file {:?}: {}",
                toml_path, err
            )
        });

    let mut dependency_toml_paths = vec![];
    cargo_manifest
        .all_dependencies_with_toml_path()
        .iter()
        .fold(&mut dependency_toml_paths, |paths, dep_path_str| {
            let dep_path = PathBuf::from(dep_path_str);
            let dep_path = dep_path.as_path();
            let mut canonical_dep_toml_path = toml_path.to_path_buf();
            canonical_dep_toml_path.pop();
            // Change the path to be relative to the repo's root.
            for dir in dep_path.components() {
                if dir == std::path::Component::ParentDir {
                    canonical_dep_toml_path.pop();
                } else {
                    canonical_dep_toml_path.push(dir);
                }
            }
            paths.push(to_string(canonical_dep_toml_path));
            paths
        });

    dependency_toml_paths
}
<commit_msg>Run xtask command for the entire repo if diff fails (#2616)<commit_after>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use maplit::hashset;
use std::{
    collections::{HashMap, HashSet},
    io::{BufRead, BufReader},
    path::{Path, PathBuf},
    process::Command,
};

use crate::{
    files::*,
    internal::{CargoManifest, Scope},
};

#[derive(Debug)]
pub struct ModifiedContent {
    /// List of modified files.
    pub files: Option<Vec<String>>,
}

impl ModifiedContent {
    pub fn contains(&self, file_name: &str) -> bool {
        self.files.is_none()
            || self
                .files
                .as_ref()
                .unwrap()
                .contains(&file_name.to_string())
    }
}

/// Get all the files that have been modified in the given `scope`. If the scope is `Scope::All`
/// returns `None` as the list of files in `ModifiedContent`. For `Scope::Commits` and
/// `Scope::DiffToMain` the returned files include tracked files with unstaged changes, but do
/// not include new files that are not tracked (i.e., not added to git yet). For
/// `Scope::Commits(N)`, a positive number of commits must be given. In case of zero or
/// a negative number, only the last commit will be considered for finding the modified files.
pub fn modified_files(scope: &Scope) -> ModifiedContent {
    let args = match scope {
        Scope::All => None,
        Scope::Commits(commits) => Some(format!("HEAD~{}", std::cmp::max(1, *commits))),
        // TODO(#2491): Use `--merge-base` when we have a newer version of Git in the docker image.
        Scope::DiffToMain => Some("main".to_owned()),
    };

    let files: Option<Vec<String>> = args
        .and_then(|args| {
            let output = Command::new("git")
                .args(spread!["diff".to_owned(), "--name-only".to_owned(), args,])
                .output()
                .expect("could not get modified files");

            if output.status.success() {
                let vec = output.stdout;

                // Extract the file names from the git output
                Some(
                    String::from_utf8(vec)
                        .expect("could not convert to string")
                        .split('\n')
                        .map(|s| format!("./{}", s))
                        .collect(),
                )
            } else {
                eprintln!(
                    "WARN: git diff failed with error ({}), running the command for the entire code base.",
                    output.status
                );
                None
            }
        });

    // If something is changed in a Dockerfile, we'd want to run all CI steps, so set `files` to
    // `None` in `ModifiedContent`.
    if let Some(ref paths) = files {
        if paths.iter().any(|path| path.contains("Dockerfile")) {
            return ModifiedContent { files: None };
        }
    }

    ModifiedContent { files }
}

/// Returns the list of paths to `Cargo.toml` files for all crates that include at least one of the
/// given modified files.
pub fn directly_modified_crates(files: &ModifiedContent) -> ModifiedContent {
    let files = files.files.as_ref().map(|modified_files| {
        let mut crates = hashset![];
        for str_path in modified_files {
            if let Some(crate_path) = find_crate_toml_file(str_path.clone()) {
                crates.insert(crate_path);
            }
        }
        crates.iter().cloned().collect()
    });
    ModifiedContent { files }
}

fn find_crate_toml_file(str_path: String) -> Option<String> {
    if str_path.ends_with("Cargo.toml") {
        return Some(str_path);
    } else if str_path.ends_with(".rs") || str_path.ends_with(".lock") {
        let mut path = PathBuf::from(&str_path);
        while path.parent().is_some() {
            path.pop();
            let crate_path = path.join("Cargo.toml");
            let crate_path = crate_path.as_path();
            if crate_path.exists() {
                return Some(crate_path.to_str().unwrap().to_string());
            }
        }
    }
    None
}

/// Returns the list of paths to all `.proto` files affected by the given list of modified files.
fn affected_protos(files: &ModifiedContent) -> Vec<String> {
    files
        .files
        .as_ref()
        .map(|modified_files| {
            let mut affected_protos: Vec<String> = modified_files
                .iter()
                .filter(|p| p.ends_with(".proto"))
                .cloned()
                .collect();

            if !affected_protos.is_empty() {
                let all_protos = source_files()
                    .map(to_string)
                    .map(|s| s.replace("./", ""))
                    .filter(|p| p.ends_with(".proto"));

                for proto in all_protos {
                    add_affected_protos(proto, &mut affected_protos);
                }
            }

            affected_protos
        })
        .unwrap_or_else(Vec::new)
}

/// Adds `proto_path` to the list of `affected_protos` if `proto_path` or any of its imported protos
/// imports any of the proto files in `affected_protos`.
fn add_affected_protos(proto_path: String, affected_protos: &mut Vec<String>) {
    if affected_protos.contains(&proto_path) {
        return;
    }

    let imported_proto_files = imported_proto_files(proto_path.clone());
    for imported_proto_file in imported_proto_files {
        if !affected_protos.contains(&imported_proto_file) {
            add_affected_protos(imported_proto_file.clone(), affected_protos);
        }

        if affected_protos.contains(&imported_proto_file) {
            affected_protos.push(proto_path);
            return;
        }
    }
}

/// Returns paths to all `.proto` files that `proto_file_path` imports.
fn imported_proto_files(proto_file_path: String) -> Vec<String> {
    let mut imported_protos = vec![];
    if let Ok(file) = std::fs::File::open(proto_file_path) {
        let lines = BufReader::new(file).lines();
        let re = regex::Regex::new(r#"import "(.*)";"#).unwrap();

        // Scan the lines in the file line by line to find all the imports.
        for line in lines {
            let line = line.expect("could not read line");
            if let Some(imported) = re.captures(&line).map(|c| c[1].to_string()) {
                imported_protos.push(imported);
            }
        }
    }

    imported_protos
}

/// Path to the `Cargo.toml` files for all crates that are either directly modified or have a
/// dependency to a modified crate.
pub fn all_affected_crates(scope: &Scope) -> ModifiedContent {
    crates_affected_by_files(&modified_files(scope))
}

fn crates_affected_by_files(files: &ModifiedContent) -> ModifiedContent {
    let modified_crates = directly_modified_crates(files);
    let files = modified_crates.files.map(|modified_files| {
        let crate_manifest_files = crate_manifest_files();
        // A map of `Cargo.toml` files visited by the algorithm. If the value associated with a
        // key is `true`, the crate is affected by the changes and should be included in the
        // result.
        let mut affected_crates: HashMap<String, bool> = modified_files
            .into_iter()
            .map(|path| (path, true))
            .collect();

        crates_affected_by_protos(&affected_protos(files))
            .iter()
            .fold(&mut affected_crates, |affected_crates, toml_path| {
                affected_crates.insert(toml_path.clone(), true);
                affected_crates
            });

        for crate_path in crate_manifest_files {
            add_affected_crates(crate_path, &mut affected_crates);
        }

        // Return `Cargo.toml` files of the crates that are affected by the changes
        affected_crates
            .iter()
            .filter(|(_key, value)| **value)
            .map(|(key, _value)| key.clone())
            .collect()
    });

    ModifiedContent { files }
}

/// Returns the paths to `Cargo.toml` files of crates affected by the changed proto files.
fn crates_affected_by_protos(affected_protos: &[String]) -> HashSet<String> {
    source_files()
        .filter(|path| to_string(path.clone()).ends_with("build.rs"))
        .filter(|path| {
            for proto in affected_protos {
                if file_contains(path, &proto.replace("./", "")) {
                    return true;
                }
            }
            false
        })
        .map(to_string)
        .map(|build_path| find_crate_toml_file(build_path).unwrap())
        .collect()
}

/// Checks if `crate_toml_path` has a direct or indirect dependency to any of the affected crates in
/// `affected_crates_toml_path`. If so, adds `crate_toml_path` and any of its affected dependencies
/// to `affected_crates_toml_path`.
///
/// Keys in `affected_crates_toml_path` are paths to visited `Cargo.toml` files. If the value
/// associated with a key is `true`, then the corresponding crate is affected by the changes.
fn add_affected_crates(
    crate_toml_path: PathBuf,
    affected_crates_toml_path: &mut HashMap<String, bool>,
) {
    // Return immediately, if the `crate_toml_path` is already visited.
    if affected_crates_toml_path.contains_key(&to_string(crate_toml_path.clone())) {
        return;
    }
    affected_crates_toml_path.insert(to_string(crate_toml_path.clone()), false);
    let deps = get_local_dependencies(&crate_toml_path);
    for dep in deps {
        // If the dependency is not visited, visit it and its dependencies
        if !affected_crates_toml_path.contains_key(&dep) {
            let dep_path = PathBuf::from(dep.clone());
            add_affected_crates(dep_path.clone(), affected_crates_toml_path)
        }
        if *affected_crates_toml_path.get(&dep).unwrap_or(&false) {
            affected_crates_toml_path.insert(to_string(crate_toml_path), true);
            return;
        }
    }
}

/// Returns paths to `Cargo.toml` files of local crates (crates belonging to the Oak repo) that the
/// given crate has a dependency to. Converts the relative dependency paths in `Cargo.toml` into
/// paths relative to the repo's root.
fn get_local_dependencies(toml_path: &Path) -> Vec<String> {
    let cargo_manifest: CargoManifest =
        toml::from_str(&read_file(toml_path)).unwrap_or_else(|err| {
            panic!(
                "could not parse crate manifest file {:?}: {}",
                toml_path, err
            )
        });

    let mut dependency_toml_paths = vec![];
    cargo_manifest
        .all_dependencies_with_toml_path()
        .iter()
        .fold(&mut dependency_toml_paths, |paths, dep_path_str| {
            let dep_path = PathBuf::from(dep_path_str);
            let dep_path = dep_path.as_path();
            let mut canonical_dep_toml_path = toml_path.to_path_buf();
            canonical_dep_toml_path.pop();
            // Change the path to be relative to the repo's root.
            for dir in dep_path.components() {
                if dir == std::path::Component::ParentDir {
                    canonical_dep_toml_path.pop();
                } else {
                    canonical_dep_toml_path.push(dir);
                }
            }
            paths.push(to_string(canonical_dep_toml_path));
            paths
        });

    dependency_toml_paths
}
<|endoftext|>


<commit_before><commit_msg>Solution for 3,4, the rest of 2 if that hasn't been committed yet, and part of 5.<commit_after><|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use js_types::js_type::JsPtrEnum;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    white_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        self.white_set.insert(uuid, Rc::new(RefCell::new(ptr)));
        uuid
    }

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

    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks {
            // FIXME? Could a root be grey already?
            if let Some(ptr) = self.white_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.clone();
        self.grey_set = HashMap::new();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(uuid).or(
            self.grey_set.get(uuid).or(
                self.black_set.get(uuid)))
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            true
        } else { false }
    }

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

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Uuid> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }
}
<commit_msg>Check for grey roots when marking roots<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use js_types::js_type::JsPtrEnum;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    white_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        // TODO validate that `uuid` isn't already in the map
        self.white_set.insert(uuid, Rc::new(RefCell::new(ptr)));
        uuid
    }

    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks {
            if let Some(ptr) = self.white_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            } else if let Some(ptr) = self.grey_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.clone();
        self.grey_set = HashMap::new();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(uuid).or(
            self.grey_set.get(uuid).or(
                self.black_set.get(uuid)))
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            true
        } else { false }
    }

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

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Uuid> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(unix, feature(fs_ext))]

extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>add search to help<commit_after>#![cfg_attr(unix, feature(fs_ext))]

extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search crates from host of a registry

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![crate_type = "bin"]
extern crate script;
extern crate test;
extern crate collections;
use script::lexer::Lexer;
use script::parser::Parser;
use script::exec::{Executor, Interpreter};
use script::ast::{Token, TComment};
use script::js::value::{Value, ResultValue, to_value, from_value};
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
fn find_attr(tokens: Vec<Token>, attr:~str) -> Option<~str> {
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let comm = comm.clone();
				let desc_loc = comm.find_str("@" + attr);
				if desc_loc.is_some() {
					return Some(comm.slice_from(desc_loc.unwrap() + attr.len() + 2).split('\n').next().unwrap().to_owned());
				}
			},
			_ => ()
		}
	}
	None
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let val : bool = from_value(*args.get(0)).unwrap();
	if val {
		Ok(to_value(true))
	} else {
		Err(to_value(false))
	}
}
fn main() {
	for file in walk_dir(&Path::new("../tests/")).unwrap() {
		let file_name = file.to_c_str().as_str().unwrap().to_owned();
		if file_name.ends_with(".js") {
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_name, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_maybe_owned(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(v) => println!("{}: {}", file_name, v.borrow()),
				Err(v) => fail!("{}: Failed with {}", file_name, v.borrow())
			}
		}
	}
}<commit_msg>Remove unneccessary extern crates<commit_after>#![feature(globs)]
#![crate_type = "bin"]
extern crate script;
use script::lexer::Lexer;
use script::parser::Parser;
use script::exec::{Executor, Interpreter};
use script::ast::{Token, TComment};
use script::js::value::{Value, ResultValue, to_value, from_value};
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
fn find_attr(tokens: Vec<Token>, attr:~str) -> Option<~str> {
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let comm = comm.clone();
				let desc_loc = comm.find_str("@" + attr);
				if desc_loc.is_some() {
					return Some(comm.slice_from(desc_loc.unwrap() + attr.len() + 2).split('\n').next().unwrap().to_owned());
				}
			},
			_ => ()
		}
	}
	None
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let val : bool = from_value(*args.get(0)).unwrap();
	if val {
		Ok(to_value(true))
	} else {
		Err(to_value(false))
	}
}
fn main() {
	for file in walk_dir(&Path::new("../tests/")).unwrap() {
		let file_name = file.to_c_str().as_str().unwrap().to_owned();
		if file_name.ends_with(".js") {
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_name, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_maybe_owned(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(v) => println!("{}: {}", file_name, v.borrow()),
				Err(v) => fail!("{}: Failed with {}", file_name, v.borrow())
			}
		}
	}
}<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::net::TcpStream;
use std::{io, thread};
use std::os::unix::io::{AsRawFd};
use std::sync::mpsc::{channel, Sender};

use pty;
use libc;
use libc_ext;
use nix::sys::signal;
use termios::*;

use pty_spawn;
use winsize;
use message;

pub fn execute(host: String, port: i32, channel_name: String) {
    let mut stream         = TcpStream::connect(&format!("{}:{}", host, port)[..]).unwrap();
    let (child, termios)   = pty_spawn::pty_spawn();
    let (sender, receiver) = channel();

    let request = message::JoinRequest::Broadcast(channel_name.clone());
    request.send(&mut stream).unwrap();
    message::JoinResponse::receive(&stream).unwrap();

    InputHandler::spawn(io::stdin(), &child);
    OutputHandler::spawn(io::stdout(), &child, &sender);
    ResizeHandler::spawn(&child, &sender);
    NotificationHandler::spawn(&stream, &sender);

    sender.send(build_winsize_notification()).unwrap();

    for message in receiver {
        match message {
            Some(notification) => notification.send(&mut stream).unwrap(),
            None => break
        };
    }

    child.wait().unwrap();
    tcsetattr(libc::STDIN_FILENO, TCSANOW, &termios).unwrap();
}

fn build_winsize_notification() -> Option<message::Notification> {
    let winsize      = winsize::from_fd(libc::STDIN_FILENO).unwrap();
    let notification = message::Notification::Output(format!("\x1b[8;{};{}t", winsize.ws_row, winsize.ws_col));

    Some(notification)
}

static mut sigwinch_count: i32 = 0;
extern fn handle_sigwinch(_: i32) {
    unsafe { sigwinch_count += 1; };
}

struct InputHandler {
    input: io::Stdin,
    child: pty::Child,
}

struct OutputHandler {
    output: io::Stdout,
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct ResizeHandler {
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct NotificationHandler {
    stream: TcpStream,
    sender: Sender<Option<message::Notification>>,
}

impl InputHandler {
    fn spawn(input: io::Stdin, child: &pty::Child) {
        let mut handler = InputHandler { input: input, child: child.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();
        let mut buf = [0; 128];

        loop {
            let nread = self.input.read(&mut buf).unwrap();

            pty.write(&buf[..nread]).unwrap();
        }
    }
}

impl OutputHandler {
    fn spawn(output: io::Stdout, child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let mut handler = OutputHandler { output: output, child: child.clone(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();
        let mut buf = [0; 128];

        loop {
            let nread = pty.read(&mut buf).unwrap();

            if nread <= 0 {
                break;
            } else {
                let string = String::from_utf8_lossy(&buf[..nread]).into_owned();

                self.handle_output(string);
            }
        }

        self.handle_terminate();
    }

    fn handle_output(&mut self, string: String) {
        print!("{}", string);
        self.output.flush().unwrap();

        self.sender.send(Some(message::Notification::Output(string))).unwrap();
    }

    fn handle_terminate(&self) {
        self.sender.send(None).unwrap();
    }
}

impl ResizeHandler {
    fn spawn(child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let handler = ResizeHandler { child: child.clone(), sender: sender.clone() };

        Self::register_sigwinch_handler();

        thread::spawn(move || {
            handler.process();
        });
    }

    fn register_sigwinch_handler() {
        let sig_action = signal::SigAction::new(
            handle_sigwinch,
            signal::signal::SA_RESTART,
            signal::SigSet::empty()
        );

        unsafe { signal::sigaction(signal::SIGWINCH, &sig_action).unwrap(); };
    }

    fn process(&self) {
        let mut count = unsafe { sigwinch_count };

        loop {
            let last_count = unsafe { sigwinch_count };

            if last_count > count {
                let winsize = winsize::from_fd(libc::STDIN_FILENO).unwrap();

                self.handle_resize(&winsize);

                count = last_count;
            }

            thread::sleep_ms(1000);
        }
    }

    fn handle_resize(&self, winsize: &libc_ext::Winsize) {
        let pty = self.child.pty().unwrap();

        self.sender.send(build_winsize_notification()).unwrap();
        winsize::set(pty.as_raw_fd(), winsize);
    }
}

impl NotificationHandler {
    fn spawn(stream: &TcpStream, sender: &Sender<Option<message::Notification>>) {
        let mut handler = NotificationHandler { stream: stream.try_clone().unwrap(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        loop {
            let notification = message::Notification::receive(&self.stream).unwrap();

            match notification {
                message::Notification::Closed(reason) => {
                    self.handle_closed(&reason);

                    break;
                },
                message::Notification::WatcherJoined(_) => {
                    self.sender.send(build_winsize_notification()).unwrap();
                },
                _ => ()
            }
        }
    }

    fn handle_closed(&self, reason: &String) {
        self.sender.send(None).unwrap();

        println!("Broadcast has stopped: {}", reason);
    }
}
<commit_msg>Ignore SendError due to takeover<commit_after>use std::io::{Read, Write};
use std::net::TcpStream;
use std::{io, thread};
use std::os::unix::io::{AsRawFd};
use std::sync::mpsc::{channel, Sender};

use pty;
use libc;
use libc_ext;
use nix::sys::signal;
use termios::*;

use pty_spawn;
use winsize;
use message;

pub fn execute(host: String, port: i32, channel_name: String) {
    let mut stream         = TcpStream::connect(&format!("{}:{}", host, port)[..]).unwrap();
    let (child, termios)   = pty_spawn::pty_spawn();
    let (sender, receiver) = channel();

    let request = message::JoinRequest::Broadcast(channel_name.clone());
    request.send(&mut stream).unwrap();
    message::JoinResponse::receive(&stream).unwrap();

    InputHandler::spawn(io::stdin(), &child);
    OutputHandler::spawn(io::stdout(), &child, &sender);
    ResizeHandler::spawn(&child, &sender);
    NotificationHandler::spawn(&stream, &sender);

    sender.send(build_winsize_notification()).unwrap();

    for message in receiver {
        match message {
            Some(notification) => notification.send(&mut stream).unwrap(),
            None => break
        };
    }

    child.wait().unwrap();
    tcsetattr(libc::STDIN_FILENO, TCSANOW, &termios).unwrap();
}

fn build_winsize_notification() -> Option<message::Notification> {
    let winsize      = winsize::from_fd(libc::STDIN_FILENO).unwrap();
    let notification = message::Notification::Output(format!("\x1b[8;{};{}t", winsize.ws_row, winsize.ws_col));

    Some(notification)
}

static mut sigwinch_count: i32 = 0;
extern fn handle_sigwinch(_: i32) {
    unsafe { sigwinch_count += 1; };
}

struct InputHandler {
    input: io::Stdin,
    child: pty::Child,
}

struct OutputHandler {
    output: io::Stdout,
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct ResizeHandler {
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct NotificationHandler {
    stream: TcpStream,
    sender: Sender<Option<message::Notification>>,
}

impl InputHandler {
    fn spawn(input: io::Stdin, child: &pty::Child) {
        let mut handler = InputHandler { input: input, child: child.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();
        let mut buf = [0; 128];

        loop {
            let nread = self.input.read(&mut buf).unwrap();

            pty.write(&buf[..nread]).unwrap();
        }
    }
}

impl OutputHandler {
    fn spawn(output: io::Stdout, child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let mut handler = OutputHandler { output: output, child: child.clone(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();
        let mut buf = [0; 128];

        loop {
            let nread = pty.read(&mut buf).unwrap_or(0);

            if nread <= 0 {
                break;
            } else {
                let string = String::from_utf8_lossy(&buf[..nread]).into_owned();

                self.handle_output(string);
            }
        }

        self.handle_terminate();
    }

    fn handle_output(&mut self, string: String) {
        print!("{}", string);
        self.output.flush().unwrap();

        let _ = self.sender.send(Some(message::Notification::Output(string)));
    }

    fn handle_terminate(&self) {
        let _ = self.sender.send(None);
    }
}

impl ResizeHandler {
    fn spawn(child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let handler = ResizeHandler { child: child.clone(), sender: sender.clone() };

        Self::register_sigwinch_handler();

        thread::spawn(move || {
            handler.process();
        });
    }

    fn register_sigwinch_handler() {
        let sig_action = signal::SigAction::new(
            handle_sigwinch,
            signal::signal::SA_RESTART,
            signal::SigSet::empty()
        );

        unsafe { signal::sigaction(signal::SIGWINCH, &sig_action).unwrap(); };
    }

    fn process(&self) {
        let mut count = unsafe { sigwinch_count };

        loop {
            let last_count = unsafe { sigwinch_count };

            if last_count > count {
                let winsize = winsize::from_fd(libc::STDIN_FILENO).unwrap();

                self.handle_resize(&winsize);

                count = last_count;
            }

            thread::sleep_ms(1000);
        }
    }

    fn handle_resize(&self, winsize: &libc_ext::Winsize) {
        let pty = self.child.pty().unwrap();

        self.sender.send(build_winsize_notification()).unwrap();
        winsize::set(pty.as_raw_fd(), winsize);
    }
}

impl NotificationHandler {
    fn spawn(stream: &TcpStream, sender: &Sender<Option<message::Notification>>) {
        let mut handler = NotificationHandler { stream: stream.try_clone().unwrap(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        loop {
            let notification = message::Notification::receive(&self.stream).unwrap();

            match notification {
                message::Notification::Closed(reason) => {
                    self.handle_closed(&reason);

                    break;
                },
                message::Notification::WatcherJoined(_) => {
                    self.sender.send(build_winsize_notification()).unwrap();
                },
                _ => ()
            }
        }
    }

    fn handle_closed(&self, reason: &String) {
        self.sender.send(None).unwrap();

        println!("Broadcast has stopped: {}", reason);
    }
}
<|endoftext|>