├── .gitignore ├── assets └── running-example.png ├── Cargo.toml ├── debian_bridge_core ├── resources │ └── default.ico ├── src │ ├── lib.rs │ ├── sys │ │ ├── error.rs │ │ ├── driver.rs │ │ └── mod.rs │ └── app │ │ ├── error.rs │ │ ├── deb.rs │ │ ├── config.rs │ │ ├── util.rs │ │ ├── docker.rs │ │ └── mod.rs ├── Cargo.toml └── build.rs ├── Dockerfile ├── docker-compose.yaml ├── debian_bridge_cli ├── src │ ├── lib.rs │ ├── matcher.rs │ └── starter.rs ├── Cargo.toml ├── build.rs └── config │ └── cli.yaml ├── debian_bridge ├── src │ └── bin │ │ └── debian_bridge.rs └── Cargo.toml ├── .rustfmt.toml ├── .travis.yml ├── LICENSE ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .idea 4 | -------------------------------------------------------------------------------- /assets/running-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedorenko22116/debian_bridge/HEAD/assets/running-example.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "./debian_bridge", 4 | "./debian_bridge_cli", 5 | "./debian_bridge_core", 6 | ] -------------------------------------------------------------------------------- /debian_bridge_core/resources/default.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedorenko22116/debian_bridge/HEAD/debian_bridge_core/resources/default.ico -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust 2 | 3 | RUN rustup toolchain install nightly 4 | RUN rustup component add --toolchain nightly rustfmt 5 | 6 | ENTRYPOINT ["cargo"] 7 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | cargo: 4 | build: { context: . } 5 | volumes: 6 | - .:/home/app 7 | working_dir: /home/app 8 | entrypoint: ["cargo"] 9 | -------------------------------------------------------------------------------- /debian_bridge_cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate clap; 3 | #[macro_use] 4 | extern crate log; 5 | extern crate pretty_env_logger; 6 | extern crate xdg; 7 | 8 | mod matcher; 9 | mod starter; 10 | 11 | pub use matcher::*; 12 | pub use starter::start; 13 | -------------------------------------------------------------------------------- /debian_bridge/src/bin/debian_bridge.rs: -------------------------------------------------------------------------------- 1 | extern crate debian_bridge_cli; 2 | 3 | use debian_bridge_cli::start; 4 | 5 | fn main() { 6 | start( 7 | env!("CARGO_PKG_NAME"), 8 | env!("CARGO_PKG_AUTHORS"), 9 | env!("CARGO_PKG_VERSION"), 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # [config.rs](https://github.com/rust-lang-nursery/rustfmt/blob/master/src/config.rs) 2 | # [rustfmt-configs-guide](https://github.com/regexident/rustfmt-configs-guide) 3 | format_strings = true 4 | newline_style = "Unix" 5 | reorder_imports = true 6 | imports_granularity = "Crate" 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - stable 5 | - nightly 6 | 7 | matrix: 8 | fast_finish: true 9 | 10 | before_script: 11 | - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then rustup component add rustfmt; fi 12 | 13 | script: 14 | - cargo build 15 | - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then cargo test; fi 16 | - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then cargo fmt --all -- --check; fi 17 | -------------------------------------------------------------------------------- /debian_bridge/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "debian_bridge" 3 | description = "Bridge to run .deb packages on your distribution using docker" 4 | version = "1.0.0" 5 | authors = ["victor "] 6 | edition = "2018" 7 | license = "MIT" 8 | default-run = "debian_bridge" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | debian_bridge_cli = { path = "../debian_bridge_cli" } -------------------------------------------------------------------------------- /debian_bridge_core/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(test, feature(proc_macro_hygiene))] 2 | #[cfg(test)] 3 | extern crate mocktopus; 4 | 5 | #[macro_use] 6 | pub extern crate log; 7 | 8 | extern crate colorful; 9 | extern crate dirs; 10 | extern crate dockerfile; 11 | extern crate freedesktop_desktop_entry; 12 | extern crate pipers; 13 | extern crate pretty_env_logger; 14 | extern crate regex; 15 | extern crate serde_json; 16 | extern crate shiplift; 17 | extern crate tokio; 18 | 19 | mod app; 20 | mod sys; 21 | 22 | pub use app::*; 23 | pub use shiplift::Docker; 24 | pub use sys::System; 25 | -------------------------------------------------------------------------------- /debian_bridge_core/src/sys/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub enum SystemError { 3 | DockerConnection, 4 | } 5 | 6 | impl std::error::Error for SystemError { 7 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 8 | None 9 | } 10 | } 11 | 12 | impl std::fmt::Display for SystemError { 13 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 14 | write!( 15 | f, 16 | "{}", 17 | match self { 18 | SystemError::DockerConnection => "Cannot connect to docker daemon", 19 | } 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /debian_bridge_cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "debian_bridge_cli" 3 | description = "Bridge to run .deb packages on your distribution using docker" 4 | version = "0.2.2" 5 | authors = ["victor "] 6 | edition = "2018" 7 | license = "MIT" 8 | build = "build.rs" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | debian_bridge_core = { path = "../debian_bridge_core" } 14 | clap = { version = "2.33.0", features = ["yaml"] } 15 | pretty_env_logger = "0.3.0" 16 | log = "0.4" 17 | xdg = "^2.1" 18 | dirs = "2.0.2" 19 | 20 | [dev-dependencies] 21 | mocktopus = "0.7.0" 22 | 23 | [build-dependencies] 24 | clap = { version = "2.33.0", features = ["yaml"] } 25 | xdg = "^2.1" 26 | dirs = "2.0.2" 27 | -------------------------------------------------------------------------------- /debian_bridge_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "debian_bridge_core" 3 | description = "debian_bridge core libraries" 4 | version = "0.2.2" 5 | authors = ["victor "] 6 | edition = "2018" 7 | license = "MIT" 8 | build = "build.rs" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | shiplift = "0.5" 14 | pretty_env_logger = "0.3.0" 15 | log = "0.4" 16 | tokio = "0.1.22" 17 | xdg = "^2.1" 18 | colorful = "0.2.1" 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1.0" 21 | dockerfile = "0.2.1" 22 | pipers = "1.0.1" 23 | regex = "1.2.1" 24 | freedesktop-desktop-entry = "0.1.1" 25 | dirs = "2.0.2" 26 | 27 | [dev-dependencies] 28 | mocktopus = "0.7.0" 29 | 30 | [build-dependencies] 31 | xdg = "^2.1" 32 | dirs = "2.0.2" 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Victor Fedorenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /debian_bridge_core/src/app/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub enum AppError { 3 | Docker, 4 | DockerStatus(i16), 5 | File(String), 6 | Program(String), 7 | } 8 | 9 | impl std::error::Error for AppError { 10 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 11 | None 12 | } 13 | } 14 | 15 | impl std::fmt::Display for AppError { 16 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 17 | write!( 18 | f, 19 | "{}", 20 | match self { 21 | AppError::Docker => "Cannot connect to docker daemon", 22 | AppError::DockerStatus(error) => { 23 | Box::leak(format!("Docker returned code: {}", error).into_boxed_str()) 24 | } 25 | AppError::File(error) => { 26 | Box::leak(format!("IO errors occured: {}", error).into_boxed_str()) 27 | } 28 | AppError::Program(error) => { 29 | Box::leak(format!("Program errors occured: {}", error).into_boxed_str()) 30 | } 31 | } 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /debian_bridge_cli/src/matcher.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | 3 | pub struct CommandMatcher<'a> { 4 | matches: &'a ArgMatches<'a>, 5 | } 6 | 7 | impl<'a> CommandMatcher<'a> { 8 | pub fn new(matches: &'a ArgMatches<'a>) -> Self { 9 | CommandMatcher { matches } 10 | } 11 | 12 | pub fn is_option_present(&self, command: T, option: S) -> bool 13 | where 14 | T: Into, 15 | S: Into, 16 | { 17 | let command = command.into(); 18 | let option = option.into(); 19 | 20 | self.matches 21 | .subcommand_matches(&command) 22 | .expect(format!("No command '{}' presented", command).as_str()) 23 | .is_present(option) 24 | } 25 | 26 | pub fn get_argument(&self, command: T, arg: S) -> Option 27 | where 28 | T: Into, 29 | S: Into, 30 | { 31 | let command = command.into(); 32 | let arg = arg.into(); 33 | 34 | self.matches 35 | .subcommand_matches(&command) 36 | .expect(format!("No command '{}' presented", command).as_str()) 37 | .value_of(&arg) 38 | .map(|s| s.to_string()) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /debian_bridge_core/src/sys/driver.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter, Result}; 2 | 3 | #[derive(Clone)] 4 | pub enum WindowManager { 5 | X11, 6 | Wayland, 7 | } 8 | 9 | impl Display for WindowManager { 10 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 11 | let val = match self { 12 | WindowManager::X11 => "X11", 13 | WindowManager::Wayland => "Wayland", 14 | }; 15 | 16 | write!(f, "{}", val) 17 | } 18 | } 19 | 20 | impl Driver for WindowManager {} 21 | 22 | #[derive(Clone)] 23 | pub enum SoundDriver { 24 | Alsa, 25 | PulseAudio, 26 | } 27 | 28 | impl Display for SoundDriver { 29 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 30 | let val = match self { 31 | SoundDriver::Alsa => "Alsa", 32 | SoundDriver::PulseAudio => "PulseAudio", 33 | }; 34 | 35 | write!(f, "{}", val) 36 | } 37 | } 38 | 39 | impl Driver for SoundDriver {} 40 | 41 | #[derive(Clone)] 42 | pub struct DockerVersion(pub String); 43 | 44 | impl Display for DockerVersion { 45 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 46 | write!(f, "{}", self.0) 47 | } 48 | } 49 | 50 | impl Driver for DockerVersion {} 51 | 52 | pub trait Driver: Display + Clone {} 53 | -------------------------------------------------------------------------------- /debian_bridge_core/build.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate dirs; 3 | extern crate xdg; 4 | 5 | use std::{error::Error, path::Path}; 6 | 7 | fn main() { 8 | if !cfg!(target_os = "linux") { 9 | panic!("Only linux supported for now."); 10 | } 11 | 12 | assets::prepare_assets().unwrap_or_else(|err| { 13 | println!("Can not load assets: {}", err.to_string()); 14 | }); 15 | } 16 | 17 | mod assets { 18 | use std::{ 19 | error::Error, 20 | path::{Path, PathBuf}, 21 | }; 22 | 23 | const ICON_NAME_DEFAULT: &str = "debian_bridge_default.ico"; 24 | 25 | pub fn prepare_assets() -> Result<(), Box> { 26 | let mut path = dirs::home_dir().unwrap(); 27 | 28 | prepare_icon_assets(path.as_path())?; 29 | 30 | Ok(()) 31 | } 32 | 33 | fn prepare_icon_assets(path: &Path) -> Result> { 34 | let mut path = path.to_owned(); 35 | path.push(".icons"); 36 | 37 | if !path.exists() { 38 | std::fs::create_dir(&path); 39 | } 40 | let mut path = default_icon_path(path.as_path()); 41 | 42 | if !path.exists() { 43 | std::fs::write(&path, include_bytes!("./resources/default.ico").to_vec())?; 44 | } 45 | 46 | Ok(path) 47 | } 48 | 49 | fn default_icon_path(path: &Path) -> PathBuf { 50 | let mut path = path.to_owned(); 51 | path.push(ICON_NAME_DEFAULT); 52 | path 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /debian_bridge_cli/build.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate clap; 3 | extern crate dirs; 4 | extern crate xdg; 5 | 6 | use clap::{App, Shell}; 7 | use std::{error::Error, path::Path}; 8 | 9 | fn main() { 10 | source_bashrc().unwrap_or_else(|err| { 11 | println!("Can not install autocompletion: {}", err.to_string()); 12 | println!( 13 | "You can do it manually by including generated {}. to your profile \ 14 | config", 15 | env!("CARGO_PKG_NAME") 16 | ); 17 | }); 18 | } 19 | 20 | fn source_bashrc() -> Result<(), Box> { 21 | let config_path = xdg::BaseDirectories::with_prefix(env!("CARGO_PKG_NAME"))?.get_config_home(); 22 | let yaml = load_yaml!("./config/cli.yaml"); 23 | let result = std::panic::catch_unwind(|| { 24 | App::from_yaml(yaml).gen_completions( 25 | env!("CARGO_PKG_NAME"), 26 | Shell::Bash, 27 | config_path.as_os_str().to_owned(), 28 | ); 29 | }); 30 | 31 | if let Err(err) = result { 32 | return Err("Can not create a file".into()); 33 | } 34 | 35 | let source_str = format!( 36 | "\nsource {}{}.bash", 37 | config_path.to_str().ok_or("Can't get a config path")?, 38 | env!("CARGO_PKG_NAME") 39 | ); 40 | let mut bashrc = dirs::home_dir().ok_or("Can't get a home path")?; 41 | bashrc.push(".bashrc"); 42 | let mut bashrc_str = std::fs::read_to_string(bashrc.as_path())?; 43 | 44 | if !bashrc_str.contains(&source_str) { 45 | bashrc_str.push_str(source_str.as_str()); 46 | std::fs::write(bashrc, bashrc_str)?; 47 | } 48 | 49 | Ok(()) 50 | } 51 | -------------------------------------------------------------------------------- /debian_bridge_cli/config/cli.yaml: -------------------------------------------------------------------------------- 1 | name: . 2 | 3 | args: 4 | - config: 5 | short: c 6 | long: config 7 | value_name: FILE 8 | help: Set a custom config file 9 | takes_value: true 10 | 11 | - verbose: 12 | short: v 13 | multiple: true 14 | help: Set the level of verbosity 15 | 16 | subcommands: 17 | - run: 18 | version: stable 19 | about: Run installed program 20 | args: 21 | - name: 22 | required: true 23 | index: 1 24 | help: Program name 25 | 26 | - remove: 27 | version: stable 28 | about: Remove program 29 | args: 30 | - name: 31 | required: true 32 | index: 1 33 | help: Program name 34 | 35 | - list: 36 | version: stable 37 | about: Show installed programs 38 | 39 | - test: 40 | version: stable 41 | about: Test compatibility and feature access 42 | 43 | - create: 44 | version: stable 45 | about: Create new docker build for existed package 46 | args: 47 | - package: 48 | required: true 49 | index: 1 50 | help: Path to .deb package 51 | - command: 52 | long: command 53 | takes_value: true 54 | help: Custom command to run 55 | - dependencies: 56 | long: dependencies 57 | takes_value: true 58 | help: Additional dependencies to install 59 | - display: 60 | short: d 61 | long: display 62 | help: Share host display 63 | - sound: 64 | short: s 65 | long: sound 66 | help: Share sound device 67 | - home: 68 | short: h 69 | long: home 70 | help: Mount home directory 71 | - notifications: 72 | short: n 73 | long: notifications 74 | help: Mount dbus 75 | - timezone: 76 | short: t 77 | long: timezone 78 | help: Share local timezone 79 | - devices: 80 | short: i 81 | long: devices 82 | help: Enable devices 83 | - desktop-icon: 84 | long: desktop-icon 85 | takes_value: true 86 | help: Set a path for a desktop icon of current application or use 'default' 87 | -------------------------------------------------------------------------------- /debian_bridge_core/src/sys/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod driver; 2 | pub mod error; 3 | 4 | use colorful::{Color, Colorful}; 5 | use driver::*; 6 | use error::SystemError; 7 | use shiplift::{rep::Version, Docker}; 8 | use std::{ 9 | error::Error, 10 | ffi::OsString, 11 | fmt::{Display, Formatter}, 12 | fs::File, 13 | process::{Command, ExitStatus, Stdio}, 14 | }; 15 | use tokio::{prelude::Future, runtime::Runtime}; 16 | 17 | type SystemResult = Result; 18 | 19 | #[derive(Clone)] 20 | pub struct System { 21 | pub wm: Option, 22 | pub sd: Option, 23 | pub docker_version: DockerVersion, 24 | } 25 | 26 | impl System { 27 | pub fn try_new(docker: &Docker) -> SystemResult { 28 | Ok(Self { 29 | wm: Self::get_window_manager(), 30 | sd: Self::get_sound_driver(), 31 | docker_version: Self::get_docker(docker)?, 32 | }) 33 | } 34 | 35 | fn get_docker(docker: &Docker) -> SystemResult { 36 | let version = docker.version(); 37 | let mut rt = Runtime::new().unwrap(); 38 | 39 | let result = match rt.block_on(version) { 40 | Ok(Version { api_version: v, .. }) => Ok(DockerVersion(v.to_owned())), 41 | Err(err) => Err(SystemError::DockerConnection), 42 | }; 43 | 44 | rt.shutdown_now() 45 | .wait() 46 | .map_err(|err| SystemError::DockerConnection)?; 47 | 48 | result 49 | } 50 | 51 | fn get_window_manager() -> Option { 52 | std::env::var_os("XDG_SESSION_TYPE") 53 | .map(|os_string| match os_string.as_os_str().to_str() { 54 | Some("x11") => Some(WindowManager::X11), 55 | Some("wayland") => Some(WindowManager::Wayland), 56 | _ => return None, 57 | }) 58 | .unwrap_or(None) 59 | } 60 | 61 | fn get_sound_driver() -> Option { 62 | let pulse = Command::new("pactl") 63 | .arg("list") 64 | .stdout(Stdio::null()) 65 | .status(); 66 | 67 | let alsa = Command::new("aplay") 68 | .arg("-l") 69 | .stdout(Stdio::null()) 70 | .status(); 71 | 72 | pulse 73 | .ok() 74 | .map(|o| SoundDriver::PulseAudio) 75 | .or(alsa.ok().map(|o| SoundDriver::Alsa)) 76 | } 77 | } 78 | 79 | impl Display for System { 80 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { 81 | writeln!( 82 | f, 83 | "\n\n\tDocker version ===> {docker_version}\n\tWindow manager ===> \ 84 | {window_manager}\n\tSound driver ===> {sound_driver}", 85 | docker_version = DisplayOption(Some(self.docker_version.to_owned())), 86 | window_manager = DisplayOption(self.wm.to_owned()), 87 | sound_driver = DisplayOption(self.sd.to_owned()), 88 | ) 89 | } 90 | } 91 | 92 | struct DisplayOption(pub Option); 93 | 94 | impl Display for DisplayOption { 95 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { 96 | match self.0 { 97 | Some(ref v) => write!(f, "{}", format!("{}", v).color(Color::Green)), 98 | None => write!(f, "{}", "None".color(Color::Red)), 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # debian_bridge 2 | [![Build Status](https://travis-ci.com/22116/debian_bridge.svg?branch=master)](https://travis-ci.com/22116/debian_bridge) 3 | 4 | ### Caution! 5 | 6 | > Author is not using non-debian distro anymore and will not support this project in near future. Be free to create a PRs or Fork the project at all. 7 | 8 | 9 | CLI tool to automatize creation and running an applications with debian using docker. 10 | 11 | ``` 12 | debian_bridge 1.0.0 13 | victor 14 | 15 | USAGE: 16 | debian_bridge [FLAGS] [OPTIONS] 17 | 18 | FLAGS: 19 | -h, --help Prints help information 20 | -V, --version Prints version information 21 | -v Set the level of verbosity 22 | 23 | OPTIONS: 24 | -c, --config Set a custom config file 25 | 26 | SUBCOMMANDS: 27 | create Create new docker build for existed package 28 | help Prints this message or the help of the given subcommand(s) 29 | list Show installed programs 30 | remove Remove program 31 | run Run installed program 32 | test Test compatibility and feature access 33 | 34 | ``` 35 | 36 | ## Installation 37 | 38 | * Install Cargo with 39 | ```shell script 40 | curl https://sh.rustup.rs -sSf | sh 41 | echo 'export PATH=$PATH:~/.cargo/bin' >> ~/.bashrc 42 | source ~/.bashrc 43 | ``` 44 | * Install `debian_bridge` with `cargo install --git https://github.com/22116/debian_bridge` 45 | (You might need gcc compiler to be installed. On solus you can get it by `sudo eopkg it -c system.devel` command) 46 | * Run `debian_bridge` 47 | 48 | ## Responsibilities 49 | 50 | * Building a docker image based on input .deb files 51 | * Creation a .desktop entries 52 | * Automate running of created containers 53 | 54 | ## Prerequirements 55 | 56 | * Docker ^1.11 with no `sudo` access 57 | 58 | ## Example 59 | 60 | Tested on Solus 3 OS (Budgie with X11 WM) with rocketchat_2.15.3.deb 61 | 62 | ### Check if your system has a support of features 63 | 64 | ``` 65 | $ debian_bridge test 66 | System settings: 67 | 68 | Docker version ===> 1.40 69 | Window manager ===> X11 70 | Sound driver ===> PulseAudio 71 | 72 | Available features: 73 | 74 | Notification ===> available 75 | Home persistent ===> available 76 | Timezone ===> available 77 | Display ===> available 78 | Devices ===> available 79 | Sound ===> available 80 | ``` 81 | 82 | ### Creating an application 83 | 84 | ``` 85 | $ debian_bridge create -dshnti --dependencies 'libasound2' --command 'rocketchat-desktop' ~/Downloads/rocketchat_2.15.3_amd64.deb 86 | ``` 87 | 88 | Fine, `rocketchat` application created with a shared `display`, `sound`, `notifications`, `timezone`, `devices` and `home` directory. All required dependencies for `rocketchat` were automatically installed. 89 | Additional libs like `libasound2` which are not specified in .deb package can be added with `dependencies` argument. \ 90 | By default package name will be used as a command, but it's not a case with a `rocketchat`, so command name (`rocketchat-desktop`) was additionaly passed.\ 91 | To automatically create a .desktop entry in `$HOME/Desktop` add `icon-desktop default` or `icon-desktop ` to the command 92 | 93 | ### Listing 94 | 95 | ``` 96 | $ debian_bridge list 97 | Available programs list: rocketchat 98 | ``` 99 | 100 | As you can see, created program has a default package name by default. 101 | 102 | ### Running 103 | 104 | ``` 105 | $ debian_bridge run rocketchat 106 | ``` 107 | 108 | ![running an application](./assets/running-example.png) 109 | 110 | ### Removing 111 | 112 | ``` 113 | $ debian_bridge remove rocketchat 114 | ``` 115 | -------------------------------------------------------------------------------- /debian_bridge_core/src/app/deb.rs: -------------------------------------------------------------------------------- 1 | use super::error::AppError; 2 | use colorful::core::StrMarker; 3 | #[cfg(test)] 4 | use mocktopus::macros::*; 5 | use pipers::Pipe; 6 | use regex::Regex; 7 | use std::{convert::TryInto, ffi::OsStr, path::Path}; 8 | 9 | #[derive(Debug, Clone, PartialEq)] 10 | pub struct Dependencies { 11 | list: Vec, 12 | } 13 | 14 | #[cfg_attr(test, mockable)] 15 | impl Dependencies { 16 | pub fn new>(deps: T) -> Self { 17 | let deps = deps.into(); 18 | 19 | Self { 20 | list: Self::parse(deps), 21 | } 22 | } 23 | 24 | fn parse(deps: String) -> Vec { 25 | let deps: Vec = deps.split(",").map(|dep| dep.to_owned()).collect(); 26 | 27 | deps.iter() 28 | .map(|dep| { 29 | Self::split_first( 30 | Self::split_first(dep.to_owned(), "|".to_string()), 31 | "(".to_string(), 32 | ) 33 | }) 34 | .collect() 35 | } 36 | 37 | fn split_first(dep: String, pat: String) -> String { 38 | let parts: Vec = dep.split(pat.as_str()).map(|dep| dep.to_owned()).collect(); 39 | parts.get(0).unwrap().trim().to_owned() 40 | } 41 | 42 | pub fn extract(&self) -> String { 43 | self.list.join(" ") 44 | } 45 | } 46 | 47 | #[derive(Debug, Clone, PartialEq)] 48 | pub struct Deb { 49 | pub package: String, 50 | pub version: Option, 51 | pub license: Option, 52 | pub vendor: Option, 53 | pub architecture: Option, 54 | pub maintainer: Option, 55 | pub installed_size: Option, 56 | pub dependencies: Option, 57 | pub section: Option, 58 | pub priority: Option, 59 | pub homepage: Option, 60 | pub description: Option, 61 | } 62 | 63 | impl Deb { 64 | pub fn try_new(path: &Path) -> Result { 65 | if !path.exists() || !path.extension().and_then(OsStr::to_str).eq(&Some("deb")) { 66 | return Err(AppError::File( 67 | "Input application doesn't exist or is in incorrect format".to_str(), 68 | )); 69 | } 70 | 71 | let info = Pipe::new(format!("ar p {} control.tar.gz", path.to_str().unwrap()).as_str()) 72 | .then("tar xzOf - ./control") 73 | .finally() 74 | .map_err(|err| { 75 | AppError::Program(format!("Can not parse a package: {}", err.to_string())) 76 | })? 77 | .wait_with_output(); 78 | 79 | let output = info 80 | .map(|o| (*String::from_utf8_lossy(&o.stdout)).to_owned()) 81 | .map_err(|e| AppError::File(e.to_string()))?; 82 | 83 | Ok(Deb { 84 | package: Deb::parse_output(&output, "Package").ok_or(AppError::Program( 85 | "Can not parse an input package".to_string(), 86 | ))?, 87 | version: Deb::parse_output(&output, "Version"), 88 | license: Deb::parse_output(&output, "License"), 89 | vendor: Deb::parse_output(&output, "Vendor"), 90 | architecture: Deb::parse_output(&output, "Architecture"), 91 | maintainer: Deb::parse_output(&output, "Maintainer"), 92 | installed_size: Deb::parse_output(&output, "Installed-Size"), 93 | dependencies: Deb::parse_output(&output, "Depends").map(|o| Dependencies::new(o)), 94 | section: Deb::parse_output(&output, "Section"), 95 | priority: Deb::parse_output(&output, "Priority"), 96 | homepage: Deb::parse_output(&output, "Homepage"), 97 | description: Deb::parse_output(&output, "Description"), 98 | }) 99 | } 100 | 101 | fn parse_output, S: Into>(output: T, param: S) -> Option { 102 | let pattern = Regex::new(format!(r"{}: (.*)\n", param.into()).as_str()).unwrap(); 103 | 104 | for caps in pattern.captures_iter(&output.into()) { 105 | return Some(caps.get(1).unwrap().as_str().to_str()); 106 | } 107 | 108 | None 109 | } 110 | } 111 | 112 | #[cfg(test)] 113 | mod tests { 114 | use super::*; 115 | 116 | #[test] 117 | fn dep_parses_success() { 118 | let deps = Dependencies::new( 119 | "git, libgconf-2-4 (>= 3.2.5) | libgconf2-4, libgtk-3-0 (>= 3.9.10),libgcrypt11 | \ 120 | libgcrypt20, libnotify4, libxtst6, libnss3 (>= 2:3.22), python, gvfs-bin, xdg-utils, \ 121 | libx11-xcb1, libxss1,libasound2 (>= 1.0.16), libxkbfile1, libcurl3 | libcurl4, \ 122 | policykit-1", 123 | ); 124 | 125 | assert_eq!( 126 | "git libgconf-2-4 libgtk-3-0 libgcrypt11 libnotify4 libxtst6 libnss3 python gvfs-bin \ 127 | xdg-utils libx11-xcb1 libxss1 libasound2 libxkbfile1 libcurl3 policykit-1", 128 | deps.extract() 129 | ); 130 | 131 | let deps = Dependencies::new("one_dep"); 132 | 133 | assert_eq!("one_dep", deps.extract()); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /debian_bridge_core/src/app/config.rs: -------------------------------------------------------------------------------- 1 | use super::error::AppError; 2 | use serde::{Deserialize, Serialize}; 3 | use std::{ 4 | error::Error, 5 | fmt::Display, 6 | fs::File, 7 | io::{BufReader, Read}, 8 | path::{Path, PathBuf}, 9 | }; 10 | 11 | pub type AppResult = Result; 12 | 13 | const ICON_NAME_DEFAULT: &str = "debian_bridge_default.ico"; 14 | 15 | #[derive(Clone, Serialize, Deserialize)] 16 | pub struct Icon { 17 | pub path: PathBuf, 18 | } 19 | 20 | impl Icon { 21 | pub fn new(path: &Path) -> Self { 22 | Icon { 23 | path: path.to_owned(), 24 | } 25 | } 26 | } 27 | 28 | impl Default for Icon { 29 | fn default() -> Self { 30 | let mut path = dirs::home_dir().unwrap(); 31 | 32 | path.push(".icons"); 33 | path.push(ICON_NAME_DEFAULT); 34 | 35 | Icon { path } 36 | } 37 | } 38 | 39 | #[derive(Clone, Serialize, Deserialize, Hash, Eq, PartialEq)] 40 | pub enum Feature { 41 | Display, 42 | Sound, 43 | Notification, 44 | Devices, 45 | HomePersistent, 46 | Time, 47 | } 48 | 49 | impl Display for Feature { 50 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 51 | write!( 52 | f, 53 | "{}", 54 | match self { 55 | Feature::Display => "Display", 56 | Feature::Sound => "Sound", 57 | Feature::Notification => "Notification", 58 | Feature::Devices => "Devices", 59 | Feature::HomePersistent => "Home persistent", 60 | Feature::Time => "Timezone", 61 | } 62 | ) 63 | } 64 | } 65 | 66 | #[derive(Clone, Serialize, Deserialize)] 67 | pub struct Program { 68 | name: String, 69 | pub path: PathBuf, 70 | pub settings: Vec, 71 | pub icon: Option, 72 | pub command: String, 73 | pub deps: Option, 74 | } 75 | 76 | impl Program { 77 | pub fn get_name>(&self, prefix: T) -> String { 78 | format!("{}_{}", prefix.into(), self.name) 79 | } 80 | 81 | pub fn get_name_short(&self) -> String { 82 | self.name.to_owned() 83 | } 84 | 85 | pub fn new( 86 | name: T, 87 | path: &Path, 88 | settings: &Vec, 89 | icon: &Option, 90 | cmd: &Option, 91 | deps: &Option, 92 | ) -> Self 93 | where 94 | T: Into, 95 | { 96 | let name = name.into(); 97 | 98 | Program { 99 | name: name.to_owned(), 100 | path: path.to_owned(), 101 | settings: settings.to_vec(), 102 | icon: icon.to_owned(), 103 | command: cmd.to_owned().unwrap_or(name), 104 | deps: deps.to_owned(), 105 | } 106 | } 107 | } 108 | 109 | #[derive(Clone, Serialize, Deserialize)] 110 | pub struct Config { 111 | pub programs: Vec, 112 | } 113 | 114 | impl Config { 115 | pub fn deserialize(path: &Path) -> AppResult { 116 | if !path.exists() { 117 | return File::create(path) 118 | .map(|_| { 119 | let config = Config { programs: vec![] }; 120 | 121 | config.serialize(path); 122 | 123 | config 124 | }) 125 | .map_err(|err| AppError::File(err.to_string())); 126 | } 127 | 128 | let mut config_str = String::new(); 129 | let config_file = File::open(path).map_err(|err| AppError::File(err.to_string()))?; 130 | 131 | let mut br = BufReader::new(config_file); 132 | 133 | br.read_to_string(&mut config_str) 134 | .map_err(|err| AppError::File(err.to_string()))?; 135 | 136 | if config_str.is_empty() { 137 | return Ok(Config { programs: vec![] }); 138 | } 139 | 140 | serde_json::from_str(config_str.as_str()).map_err(|err| AppError::File(err.to_string())) 141 | } 142 | 143 | pub fn serialize(&self, path: &Path) -> AppResult<&Self> { 144 | let data = serde_json::to_string(&self).map_err(|err| AppError::File(err.to_string()))?; 145 | 146 | std::fs::write(path, data.as_bytes()) 147 | .map(|_| self) 148 | .map_err(|err| AppError::File(err.to_string())) 149 | } 150 | 151 | pub fn push(&mut self, program: &Program) -> AppResult<&Self> { 152 | match self.programs.iter().find(|&x| x.name == program.name) { 153 | Some(elem) => { 154 | return Err(AppError::Program( 155 | format!( 156 | "Program with such name already exists '{}'. Remove it first or use a \ 157 | custom tag with -t (--tag) option", 158 | program.name 159 | ) 160 | .to_string(), 161 | )) 162 | } 163 | None => (), 164 | }; 165 | 166 | self.programs.push(program.to_owned()); 167 | Ok(self) 168 | } 169 | 170 | pub fn find>(&self, name: T) -> Option<(Program, usize)> { 171 | let name = name.into(); 172 | let idx = self.programs.iter().position(|x| x.name == name)?; 173 | self.programs.get(idx).map(|p| (p.to_owned(), idx)) 174 | } 175 | 176 | pub fn remove(&mut self, program: &Program) -> AppResult<&Self> { 177 | let program_idx = self 178 | .find(&program.name) 179 | .ok_or(AppError::Program( 180 | format!("Can't find a program '{}'", program.name).to_string(), 181 | ))? 182 | .1; 183 | 184 | self.programs.remove(program_idx); 185 | Ok(self) 186 | } 187 | 188 | pub fn clear(&mut self) -> &Self { 189 | self.programs = vec![]; 190 | self 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /debian_bridge_cli/src/starter.rs: -------------------------------------------------------------------------------- 1 | use crate::CommandMatcher; 2 | use clap::{App, AppSettings, ArgMatches}; 3 | use debian_bridge_core::{App as Wrapper, Config, Docker, Feature, Icon, Program, System}; 4 | use std::{ 5 | error::Error, 6 | net::IpAddr, 7 | path::{Path, PathBuf}, 8 | str::FromStr, 9 | }; 10 | 11 | pub fn start(package_name: T, authors: S, version: U) 12 | where 13 | T: Into, 14 | S: Into, 15 | U: Into, 16 | { 17 | if let Err(err) = _start(package_name, authors, version) { 18 | error!("{}", err.to_string()); 19 | } 20 | } 21 | 22 | fn _start(package_name: T, authors: S, version: U) -> Result<(), Box> 23 | where 24 | T: Into, 25 | S: Into, 26 | U: Into, 27 | { 28 | let package_name = package_name.into(); 29 | let authors = authors.into(); 30 | let version = version.into(); 31 | 32 | let yaml = load_yaml!("../config/cli.yaml"); 33 | let matches = App::from_yaml(yaml) 34 | .setting(AppSettings::ArgRequiredElseHelp) 35 | .setting(AppSettings::SubcommandRequiredElseHelp) 36 | .name(&package_name) 37 | .author(authors.as_str()) 38 | .version(version.as_str()) 39 | .get_matches(); 40 | 41 | let debug_level = match matches.occurrences_of("verbose") { 42 | 0 => "info", 43 | 1 => "debug", 44 | 2 | _ => "trace", 45 | }; 46 | 47 | std::env::set_var("RUST_APP_LOG", &debug_level); 48 | pretty_env_logger::init_custom_env("RUST_APP_LOG"); 49 | 50 | debug!("Logger configured: debug level: {}", debug_level); 51 | 52 | let config_path = matches 53 | .value_of("config") 54 | .map(|c| std::fs::canonicalize(c).unwrap()) 55 | .unwrap_or( 56 | xdg::BaseDirectories::with_prefix(&package_name)?.place_config_file("config.json")?, 57 | ); 58 | 59 | debug!("Configuration path: {}", config_path.to_str().unwrap()); 60 | 61 | let cache_path = xdg::BaseDirectories::with_prefix(&package_name)?.place_cache_file("")?; 62 | 63 | debug!("Cache path: {}", cache_path.to_str().unwrap()); 64 | 65 | let matcher = CommandMatcher::new(&matches); 66 | let docker = Docker::new(); 67 | let config = Config::deserialize(config_path.as_path())?; 68 | let system = System::try_new(&docker)?; 69 | let mut app = Wrapper::new( 70 | &package_name, 71 | &package_name, 72 | &cache_path, 73 | &config, 74 | &system, 75 | &docker, 76 | ); 77 | 78 | debug!("Subcommand processing..."); 79 | 80 | match matches.subcommand_name() { 81 | Some("test") => { 82 | println!("System settings: {}", system); 83 | println!("Available features: {}", app.features); 84 | } 85 | Some("create") => { 86 | app.create( 87 | get_create_package(&matcher)?.as_path(), 88 | &get_create_features(&matcher), 89 | &get_create_icon(&matcher), 90 | &get_create_command(&matcher), 91 | &get_create_deps(&matcher), 92 | )?; 93 | info!("Program successfuly created"); 94 | } 95 | Some("run") => { 96 | app.run( 97 | matches 98 | .subcommand_matches("run") 99 | .unwrap() 100 | .value_of(&"name") 101 | .unwrap(), 102 | )?; 103 | } 104 | Some("remove") => { 105 | app.remove( 106 | matches 107 | .subcommand_matches("remove") 108 | .unwrap() 109 | .value_of(&"name") 110 | .unwrap(), 111 | )?; 112 | info!("Program successfuly removed"); 113 | } 114 | Some("list") => { 115 | let list = app.list().join(", "); 116 | 117 | match list.as_str() { 118 | "" => println!("No program added yet"), 119 | list => println!("Available programs list: {}", list), 120 | } 121 | } 122 | _ => unreachable!(), 123 | } 124 | 125 | debug!("Subcommand processing finished"); 126 | 127 | app.save(&config_path)?; 128 | 129 | debug!("Exit"); 130 | 131 | std::env::remove_var("RUST_APP_LOG"); 132 | 133 | Ok(()) 134 | } 135 | 136 | fn get_create_features(matcher: &CommandMatcher) -> Vec { 137 | let mut features = vec![]; 138 | 139 | if matcher.is_option_present("create", "display") { 140 | features.push(Feature::Display); 141 | } 142 | 143 | if matcher.is_option_present("create", "sound") { 144 | features.push(Feature::Sound); 145 | } 146 | 147 | if matcher.is_option_present("create", "home") { 148 | features.push(Feature::HomePersistent); 149 | } 150 | 151 | if matcher.is_option_present("create", "notifications") { 152 | features.push(Feature::Notification); 153 | } 154 | 155 | if matcher.is_option_present("create", "timezone") { 156 | features.push(Feature::Time); 157 | } 158 | 159 | if matcher.is_option_present("create", "devices") { 160 | features.push(Feature::Devices); 161 | } 162 | 163 | features 164 | } 165 | 166 | fn get_create_package(matcher: &CommandMatcher) -> std::io::Result { 167 | std::fs::canonicalize(Path::new( 168 | matcher.get_argument("create", "package").unwrap().as_str(), 169 | )) 170 | } 171 | 172 | fn get_create_command(matcher: &CommandMatcher) -> Option { 173 | matcher.get_argument("create", "command") 174 | } 175 | 176 | fn get_create_deps(matcher: &CommandMatcher) -> Option { 177 | matcher.get_argument("create", "dependencies") 178 | } 179 | 180 | fn get_create_icon(matcher: &CommandMatcher) -> Option { 181 | let icon_owned = matcher.get_argument("create", "desktop-icon"); 182 | let icon = icon_owned.as_ref().map(String::as_str); 183 | 184 | if let Some("default") = icon { 185 | return Some(Icon::default()); 186 | } 187 | 188 | None 189 | } 190 | -------------------------------------------------------------------------------- /debian_bridge_core/src/app/util.rs: -------------------------------------------------------------------------------- 1 | use super::{deb::Deb, Program}; 2 | use dockerfile::{Cmd, Copy, Dockerfile, Env, Run, User, Workdir}; 3 | use freedesktop_desktop_entry::{Application, DesktopEntry, DesktopType}; 4 | use std::path::Path; 5 | 6 | use crate::{app::error::AppError, Feature}; 7 | #[cfg(test)] 8 | use mocktopus::macros::*; 9 | use std::process::{Command, Stdio}; 10 | 11 | type AppResult = Result; 12 | 13 | #[cfg_attr(test, mockable)] 14 | fn get_user() -> Option { 15 | std::env::var_os("USER")? 16 | .as_os_str() 17 | .to_str() 18 | .map(|s| s.to_string()) 19 | } 20 | 21 | #[cfg_attr(test, mockable)] 22 | fn get_package_path(package: &str) -> AppResult { 23 | Ok(String::from_utf8( 24 | Command::new("which") 25 | .arg(package) 26 | .output() 27 | .map_err(|err| { 28 | AppError::Program("Program is not installed or can not be reached".into()) 29 | })? 30 | .stdout, 31 | ) 32 | .unwrap() 33 | .trim() 34 | .into()) 35 | } 36 | 37 | #[cfg_attr(test, mockable)] 38 | fn is_gnome_terminal() -> bool { 39 | Command::new("gnome-terminal") 40 | .arg("-h") 41 | .stdout(Stdio::null()) 42 | .stderr(Stdio::null()) 43 | .status() 44 | .is_ok() 45 | } 46 | 47 | pub fn gen_dockerfile(deb: &Deb, program: &Program) -> AppResult { 48 | let mut dockerfile = Dockerfile::base("debian:9-slim") 49 | .push(Env::new(format!( 50 | "informuser={}", 51 | get_user().ok_or(AppError::Program("Can not find a current user".into()))? 52 | ))) 53 | .push(Workdir::new("/data")) 54 | .push(Copy::new("tmp.deb /data/application.deb")) 55 | .push(Run::new("apt-get update")); 56 | 57 | if let Some(d) = &deb.dependencies { 58 | dockerfile = dockerfile.push(Run::new(format!( 59 | "apt-get install -y {}; exit 0", 60 | d.extract() 61 | ))); 62 | } 63 | 64 | if let Some(d) = &program.deps { 65 | dockerfile = dockerfile.push(Run::new(format!("apt-get install -y {}", d))); 66 | } 67 | 68 | Ok(dockerfile 69 | .push(Run::new("dpkg -i /data/application.deb || true")) 70 | .push(Run::new( 71 | "apt-get install -y -f --no-install-recommends && rm -rf /var/lib/apt/lists/* && \ 72 | useradd $informuser", 73 | )) 74 | .push(User::new("$informuser")) 75 | .push(Env::new("HOME /home/$informuser")) 76 | .push(Cmd::new(program.command.to_owned())) 77 | .finish() 78 | .to_string()) 79 | } 80 | 81 | pub fn gen_desktop_entry, S: Into, U: Into>( 82 | package_name: T, 83 | name: S, 84 | description: U, 85 | icon: &Path, 86 | ) -> AppResult { 87 | if !is_gnome_terminal() { 88 | return Err(AppError::Program( 89 | "Only gnome-terminal supported for now".into(), 90 | )); 91 | } 92 | 93 | let package_name = package_name.into(); 94 | let name = name.into(); 95 | let exec = format!( 96 | "gnome-terminal -e '{} run {}'", 97 | get_package_path(package_name.as_str())?, 98 | name 99 | ); 100 | let description = description.into(); 101 | 102 | Ok(DesktopEntry::new( 103 | &name, 104 | &icon.to_str().unwrap(), 105 | DesktopType::Application( 106 | Application::new(&["GNOME", "GTK"], exec.as_str()).keywords(&[name.as_str()]), 107 | ), 108 | ) 109 | .comment(if description.is_empty() { 110 | "Empty description" 111 | } else { 112 | &description 113 | }) 114 | .generic_name(&name) 115 | .to_string()) 116 | } 117 | 118 | #[cfg(test)] 119 | mod tests { 120 | use super::*; 121 | use crate::app::deb::Dependencies; 122 | use mocktopus::mocking::{MockResult, Mockable}; 123 | 124 | #[rustfmt::skip::macros(assert_eq)] 125 | #[test] 126 | fn test_gen_dockerfile() { 127 | Dependencies::extract.mock_safe(|_| MockResult::Return("foo bar".to_string())); 128 | get_user.mock_safe(|| MockResult::Return(Some("user".to_string()))); 129 | 130 | let dockerfile = gen_dockerfile(&get_deb(), &get_program()).unwrap(); 131 | 132 | assert_eq!( 133 | dockerfile, 134 | "\ 135 | FROM debian:9-slim\n\ 136 | ENV informuser=user\n\ 137 | WORKDIR /data\n\ 138 | COPY tmp.deb /data/application.deb\n\ 139 | RUN apt-get update\n\ 140 | RUN apt-get install -y foo bar; exit 0\n\ 141 | RUN apt-get install -y baz qux\n\ 142 | RUN dpkg -i /data/application.deb || true\n\ 143 | RUN apt-get install -y -f --no-install-recommends && rm -rf /var/lib/apt/lists/* && \ 144 | useradd $informuser\nUSER $informuser\nENV HOME /home/$informuser\nCMD foobar\n" 145 | ) 146 | } 147 | 148 | #[rustfmt::skip::macros(assert_eq)] 149 | #[test] 150 | fn test_gen_entrypoint() { 151 | get_package_path.mock_safe(|_| MockResult::Return(Ok("/foo".to_string()))); 152 | is_gnome_terminal.mock_safe(|| MockResult::Return(true)); 153 | 154 | let entrypoint = gen_desktop_entry("debian_bridge", "Foo", "bar", Path::new("")).unwrap(); 155 | 156 | assert_eq!( 157 | entrypoint, 158 | "\ 159 | [Desktop Entry]\n\ 160 | Type=Application\n\ 161 | Name=Foo\n\ 162 | GenericName=Foo\n\ 163 | X-GNOME-FullName=Foo Foo\n\ 164 | Icon=\n\ 165 | Comment=bar\n\ 166 | Categories=GNOME;GTK\n\ 167 | Keywords=\"Foo;\"\n\ 168 | Exec=gnome-terminal -e \'/foo run Foo\'\n" 169 | ) 170 | } 171 | 172 | fn get_program() -> Program { 173 | Program::new( 174 | "foobar".to_string(), 175 | Path::new(""), 176 | &vec![], 177 | &None, 178 | &None, 179 | &Some("baz qux".to_string()), 180 | ) 181 | } 182 | 183 | fn get_deb() -> Deb { 184 | Deb { 185 | package: "".to_string(), 186 | version: None, 187 | license: None, 188 | vendor: None, 189 | architecture: None, 190 | maintainer: None, 191 | installed_size: None, 192 | dependencies: Some(Dependencies::new(String::new())), 193 | section: None, 194 | priority: None, 195 | homepage: None, 196 | description: None, 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /debian_bridge_core/src/app/docker.rs: -------------------------------------------------------------------------------- 1 | use super::{error::AppError, Feature, Program, System}; 2 | use colorful::core::StrMarker; 3 | use serde_json::Value; 4 | use shiplift::{BuildOptions, ContainerListOptions, Docker}; 5 | use std::{ 6 | path::{Path, PathBuf}, 7 | process::{Command, Stdio}, 8 | sync::{Arc, Mutex}, 9 | }; 10 | use tokio::{ 11 | prelude::{Future, Stream}, 12 | runtime::Runtime, 13 | }; 14 | 15 | type AppResult = Result; 16 | 17 | pub struct DockerFacade<'a> { 18 | docker: &'a Docker, 19 | system: &'a System, 20 | prefix: String, 21 | cache_path: PathBuf, 22 | } 23 | 24 | impl<'a> DockerFacade<'a> { 25 | pub fn new>( 26 | docker: &'a Docker, 27 | system: &'a System, 28 | prefix: T, 29 | cache_path: &Path, 30 | ) -> Self { 31 | DockerFacade { 32 | docker, 33 | system, 34 | prefix: prefix.into(), 35 | cache_path: cache_path.into(), 36 | } 37 | } 38 | 39 | fn get_containers(&self, image: &String) -> AppResult> { 40 | let program_name = Arc::new(image.to_owned()); 41 | 42 | let fut = self 43 | .docker 44 | .containers() 45 | .list(&ContainerListOptions::builder().all().build()) 46 | .map(move |containers| { 47 | containers 48 | .iter() 49 | .filter_map(|c| { 50 | if c.image.eq(&*program_name) { 51 | Some(c.id.to_owned()) 52 | } else { 53 | None 54 | } 55 | }) 56 | .collect() 57 | }) 58 | .map_err(|_| ()); 59 | 60 | let mut rt = Runtime::new().unwrap(); 61 | 62 | let container_ids = match rt.block_on(fut) { 63 | Ok(res) => Ok(res), 64 | Err(err) => Err(AppError::Docker), 65 | }; 66 | 67 | rt.shutdown_now().wait().map_err(|err| AppError::Docker)?; 68 | 69 | container_ids 70 | } 71 | 72 | fn delete_container(&self, id: &String) -> AppResult<&Self> { 73 | let fut = self 74 | .docker 75 | .containers() 76 | .get(&id) 77 | .delete() 78 | .map_err(|_| AppError::Docker); 79 | let mut rt = Runtime::new().unwrap(); 80 | 81 | rt.block_on(fut).map_err(|err| { 82 | warn!("{}", err.to_string()); 83 | AppError::Docker 84 | })?; 85 | rt.shutdown_now().wait().map_err(|err| AppError::Docker)?; 86 | 87 | Ok(self) 88 | } 89 | 90 | pub fn delete(&mut self, program: &Program) -> AppResult<&Self> { 91 | let name = program.get_name(&self.prefix); 92 | let containers_ids = self.get_containers(&name)?; 93 | 94 | containers_ids 95 | .iter() 96 | .try_for_each(|id| self.delete_container(&id).map(|_| ()))?; 97 | 98 | let fut = self.docker.images().get(&name).delete(); 99 | let mut rt = Runtime::new().unwrap(); 100 | 101 | rt.block_on(fut).map_err(|err| { 102 | warn!("{}", err.to_string()); 103 | AppError::DockerStatus(404) 104 | })?; 105 | rt.shutdown_now().wait().map_err(|err| AppError::Docker)?; 106 | 107 | Ok(self) 108 | } 109 | 110 | pub fn create>(&mut self, name: T) -> AppResult<&Self> { 111 | let tag = format!("{}_{}", self.prefix, name.into()); 112 | 113 | info!("Image name: {}", tag); 114 | 115 | let fut = self 116 | .docker 117 | .images() 118 | .build( 119 | &BuildOptions::builder(self.cache_path.as_os_str().to_str().unwrap()) 120 | .tag(&tag) 121 | .build(), 122 | ) 123 | .for_each(|output| { 124 | let output = output.as_object().unwrap(); 125 | 126 | if output.contains_key("error") { 127 | error!("Docker output: {}", output.get("error").unwrap()); 128 | return Err(shiplift::Error::InvalidResponse( 129 | "Failed to build an image".to_string(), 130 | )); 131 | } 132 | 133 | if output.contains_key("stream") { 134 | info!("Docker output: {}", output.get("stream").unwrap()); 135 | } 136 | 137 | Ok(()) 138 | }); 139 | let mut rt = Runtime::new().unwrap(); 140 | 141 | rt.block_on(fut).map_err(|err| { 142 | error!("{}", err.to_string()); 143 | AppError::Docker 144 | })?; 145 | rt.shutdown_now().wait().map_err(|err| AppError::Docker)?; 146 | 147 | Ok(self) 148 | } 149 | 150 | //TODO: add more options and rewrite with docker API if possible 151 | pub fn run(&self, program: &Program) -> AppResult<&Self> { 152 | let home = std::env::var_os("HOME") 153 | .unwrap() 154 | .to_str() 155 | .unwrap() 156 | .to_string(); 157 | let cmd_name = program.get_name(&self.prefix); 158 | let home_volume = format!("{}:{}", home, home); 159 | let mut args = vec![ 160 | "run", 161 | "-ti", 162 | "--net=host", 163 | "--rm", 164 | "-v", 165 | "/dev/shm:/dev/shm", 166 | "-v", 167 | "/etc/machine-id:/etc/machine-id", 168 | "-v", 169 | "/var/lib/dbus:/var/lib/dbus", 170 | "--privileged", 171 | ]; 172 | 173 | if program.settings.contains(&Feature::Display) { 174 | args.push_volume("/tmp/.X11-unix:/tmp/.X11-unix") 175 | .push_env("DISPLAY"); 176 | } 177 | 178 | if program.settings.contains(&Feature::Sound) { 179 | args.push_volume("/dev/snd:/dev/snd"); 180 | } 181 | 182 | if program.settings.contains(&Feature::HomePersistent) { 183 | args.push_volume(&home_volume); 184 | } 185 | 186 | if program.settings.contains(&Feature::Time) { 187 | args.push_volume("/etc/localtime:/etc/localtime"); 188 | } 189 | 190 | if program.settings.contains(&Feature::Notification) { 191 | args.push_volume("/var/lib/dbus:/var/lib/dbus"); 192 | } 193 | 194 | if program.settings.contains(&Feature::Devices) { 195 | args.push_volume("/dev:/dev"); 196 | } 197 | 198 | args.push(&cmd_name); 199 | 200 | let mut cmd = Command::new("docker") 201 | .args(args) 202 | .stdout(Stdio::inherit()) 203 | .stderr(Stdio::inherit()) 204 | .spawn() 205 | .map_err(|err| AppError::Docker)?; 206 | 207 | let status = cmd.wait().map_err(|err| { 208 | error!("{}", err.to_string()); 209 | AppError::Docker 210 | })?; 211 | 212 | info!("Exited with status {:?}", status); 213 | 214 | Ok(self) 215 | } 216 | } 217 | 218 | trait PushArgument> { 219 | fn push_volume(&mut self, v: T) -> &mut Self; 220 | fn push_env(&mut self, v: T) -> &mut Self; 221 | } 222 | 223 | impl<'a> PushArgument<&'a str> for Vec<&'a str> { 224 | fn push_volume(&mut self, v: &'a str) -> &mut Self { 225 | self.push("-v"); 226 | self.push(v); 227 | self 228 | } 229 | 230 | fn push_env(&mut self, v: &'a str) -> &mut Self { 231 | self.push("--env"); 232 | self.push(v); 233 | self 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /debian_bridge_core/src/app/mod.rs: -------------------------------------------------------------------------------- 1 | mod config; 2 | mod deb; 3 | mod docker; 4 | pub mod error; 5 | mod util; 6 | 7 | use crate::System; 8 | use colorful::{core::StrMarker, Color, Colorful}; 9 | pub use config::{Config, Feature, Icon, Program}; 10 | use deb::Deb; 11 | use docker::DockerFacade; 12 | use error::AppError; 13 | use serde_json::to_string; 14 | use shiplift::Docker; 15 | use std::{ 16 | collections::HashMap, 17 | error::Error, 18 | fmt::{Display, Formatter}, 19 | net::IpAddr, 20 | path::{Path, PathBuf}, 21 | }; 22 | 23 | type AppResult = Result; 24 | 25 | pub struct FeaturesList { 26 | list: HashMap, 27 | } 28 | 29 | impl FeaturesList { 30 | fn new(system: &System) -> Self { 31 | let mut list = HashMap::new(); 32 | 33 | list.insert(Feature::Display, system.wm.is_some()); 34 | list.insert(Feature::Sound, system.sd.is_some()); 35 | list.insert(Feature::Devices, true); 36 | list.insert(Feature::Notification, true); 37 | list.insert(Feature::Time, true); 38 | list.insert(Feature::HomePersistent, true); 39 | 40 | Self { list } 41 | } 42 | 43 | fn validate(&self, settings: &Vec) -> bool { 44 | settings 45 | .iter() 46 | .try_for_each(|f| { 47 | if !*self.list.get(f).ok_or(())? { 48 | Err(()) 49 | } else { 50 | Ok(()) 51 | } 52 | }) 53 | .is_ok() 54 | } 55 | } 56 | 57 | impl Display for FeaturesList { 58 | fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { 59 | writeln!(f, "\n"); 60 | 61 | for (feature, available) in &self.list { 62 | writeln!( 63 | f, 64 | "\t{:<15} ===> {}", 65 | format!("{}", feature), 66 | match available { 67 | true => "available".color(Color::Green), 68 | false => "unavailable".color(Color::Red), 69 | } 70 | ); 71 | } 72 | 73 | Ok(()) 74 | } 75 | } 76 | 77 | /// Main structure to run application 78 | /// 79 | /// # Example 80 | /// ```no_run 81 | /// use debian_bridge_core::{App, Config, Docker, System}; 82 | /// use std::path::Path; 83 | /// 84 | /// let docker = Docker::new(); 85 | /// let config = Config::deserialize(Path::new("./cfg")).unwrap(); 86 | /// let system = System::try_new(&docker).unwrap(); 87 | /// let mut app = App::new("debian_bridge", "foo_package", Path::new("./cache"), &config, &system, &docker); 88 | /// //... 89 | /// app.save(Path::new("./cfg")).unwrap(); 90 | /// ``` 91 | pub struct App<'a> { 92 | package_name: String, 93 | prefix: String, 94 | cache_path: PathBuf, 95 | config: Config, 96 | docker: DockerFacade<'a>, 97 | pub features: FeaturesList, 98 | } 99 | 100 | impl<'a> App<'a> { 101 | pub fn list(&self) -> Vec { 102 | self.config 103 | .programs 104 | .iter() 105 | .map(|program| (&program).get_name_short().to_owned()) 106 | .collect::>() 107 | .to_vec() 108 | } 109 | 110 | /// Removes existed program 111 | /// 112 | /// # Example 113 | /// ```no_run 114 | /// # use debian_bridge_core::{App, Config, Docker, System}; 115 | /// # use std::path::Path; 116 | /// # 117 | /// # let docker = Docker::new(); 118 | /// # let config = Config::deserialize(Path::new("./cfg")).unwrap(); 119 | /// # let system = System::try_new(&docker).unwrap(); 120 | /// let mut app = App::new("debian_bridge", "foo_package", Path::new("./cache"), &config, &system, &docker); 121 | /// app.remove("foo-program").unwrap(); 122 | /// app.save(Path::new("./cfg")).unwrap(); 123 | /// ``` 124 | pub fn remove>(&mut self, program: T) -> AppResult<&Self> { 125 | let program = self 126 | .config 127 | .find(program.into()) 128 | .ok_or(AppError::Program("Input program doesn't exist".to_str()))? 129 | .0; 130 | 131 | match self.docker.delete(&program) { 132 | Ok(_) => (), 133 | Err(AppError::DockerStatus(404)) => (), 134 | Err(err) => return Err(err), 135 | }; 136 | self.config.remove(&program)?; 137 | 138 | if let Some(_) = program.icon { 139 | let mut path = dirs::desktop_dir().unwrap(); 140 | let name = format!("{}.desktop", program.get_name_short()); 141 | 142 | path.push(name); 143 | 144 | std::fs::remove_file(path).unwrap_or_else(|err| { 145 | error!("Can't remove an entry file: '{}'", err.to_string()); 146 | () 147 | }); 148 | } 149 | 150 | Ok(self) 151 | } 152 | 153 | /// Creates new program 154 | /// 155 | /// # Example 156 | /// ```no_run 157 | /// # use debian_bridge_core::{App, Config, Docker, System, Feature}; 158 | /// # use std::path::Path; 159 | /// # 160 | /// # let docker = Docker::new(); 161 | /// # let config = Config::deserialize(Path::new("./cfg")).unwrap(); 162 | /// # let system = System::try_new(&docker).unwrap(); 163 | /// let mut app = App::new("debian_bridge", "foo_package", Path::new("./cache"), &config, &system, &docker); 164 | /// app.create(Path::new("./package.deb"), &vec![Feature::Display], &None, &None, &None).unwrap(); 165 | /// app.save(Path::new("./cfg")).unwrap(); 166 | /// ``` 167 | pub fn create( 168 | &mut self, 169 | app_path: &Path, 170 | settings: &Vec, 171 | icon: &Option, 172 | cmd: &Option, 173 | deps: &Option, 174 | ) -> AppResult<&Self> { 175 | if !self.features.validate(&settings) { 176 | return Err(AppError::Program( 177 | "You have set unavailable feature".to_string(), 178 | )); 179 | } 180 | 181 | let deb = Deb::try_new(app_path)?; 182 | let program = Program::new(&deb.package, &app_path, &settings, &icon, &cmd, &deps); 183 | let mut app_tmp_path = self.cache_path.to_owned(); 184 | 185 | std::fs::create_dir_all(&app_tmp_path).map_err(|err| AppError::File(err.to_string()))?; 186 | app_tmp_path.push(Path::new("tmp.deb")); 187 | std::fs::copy(app_path, &app_tmp_path).map_err(|err| AppError::File(err.to_string()))?; 188 | 189 | let mut dockerfile = util::gen_dockerfile(&deb, &program)?; 190 | 191 | debug!("Generated dockerfile:\n{}", dockerfile); 192 | 193 | let mut dockerfile_path = self.cache_path.to_owned(); 194 | dockerfile_path.push(Path::new("Dockerfile")); 195 | 196 | std::fs::write(&dockerfile_path, dockerfile) 197 | .map_err(|err| AppError::File(err.to_string()))?; 198 | 199 | self.config.push(&program)?; 200 | self.docker.create(&deb.package)?; 201 | 202 | std::fs::remove_file(&dockerfile_path).map_err(|err| AppError::File(err.to_string()))?; 203 | std::fs::remove_file(&app_tmp_path).map_err(|err| AppError::File(err.to_string()))?; 204 | 205 | if let Some(icon) = &icon { 206 | self.create_entry(&icon, &deb).unwrap_or_else(|err| { 207 | warn!("{}", err.to_string()); 208 | &self 209 | }); 210 | } 211 | 212 | Ok(self) 213 | } 214 | 215 | /// Runs existed program 216 | /// 217 | /// # Example 218 | /// ```no_run 219 | /// # use debian_bridge_core::{App, Config, Docker, System}; 220 | /// # use std::path::Path; 221 | /// # 222 | /// # let docker = Docker::new(); 223 | /// # let config = Config::deserialize(Path::new("./cfg")).unwrap(); 224 | /// # let system = System::try_new(&docker).unwrap(); 225 | /// let mut app = App::new("debian_bridge", "foo_package", Path::new("./cache"), &config, &system, &docker); 226 | /// app.run("foo_program").unwrap(); 227 | /// ``` 228 | pub fn run>(&self, program: T) -> AppResult<&Self> { 229 | let program = self 230 | .config 231 | .find(program) 232 | .ok_or(AppError::Program("Program not found".to_string()))? 233 | .0; 234 | 235 | self.docker.run(&program)?; 236 | Ok(self) 237 | } 238 | 239 | /// Saves current application configuration 240 | /// 241 | /// # Example 242 | /// ```no_run 243 | /// # use debian_bridge_core::{App, Config, Docker, System}; 244 | /// # use std::path::Path; 245 | /// # 246 | /// # let docker = Docker::new(); 247 | /// # let config = Config::deserialize(Path::new("./cfg")).unwrap(); 248 | /// # let system = System::try_new(&docker).unwrap(); 249 | /// let mut app = App::new("debian_bridge", "foo_package", Path::new("./cache"), &config, &system, &docker); 250 | /// app.save(Path::new("./cfg_new")).unwrap(); 251 | /// ``` 252 | pub fn save(&self, path: &Path) -> AppResult<&Self> { 253 | self.config.serialize(path)?; 254 | debug!("Config updated"); 255 | Ok(self) 256 | } 257 | 258 | /// Creates new App instance 259 | /// 260 | /// # Example 261 | /// ```no_run 262 | /// # use debian_bridge_core::{App, Config, Docker, System}; 263 | /// # use std::path::Path; 264 | /// # 265 | /// # let docker = Docker::new(); 266 | /// # let config = Config::deserialize(Path::new("./cfg")).unwrap(); 267 | /// # let system = System::try_new(&docker).unwrap(); 268 | /// let mut app = App::new("debian_bridge", "foo_package", Path::new("./cache"), &config, &system, &docker); 269 | /// ``` 270 | pub fn new, S: Into>( 271 | package_name: T, 272 | prefix: S, 273 | cache_path: &Path, 274 | config: &Config, 275 | system: &'a System, 276 | docker: &'a Docker, 277 | ) -> Self { 278 | let package_name = package_name.into(); 279 | let prefix = prefix.into(); 280 | 281 | App { 282 | package_name, 283 | prefix: prefix.to_owned(), 284 | config: config.to_owned(), 285 | docker: DockerFacade::new(docker, system, prefix, cache_path), 286 | cache_path: cache_path.to_owned(), 287 | features: FeaturesList::new(&system), 288 | } 289 | } 290 | 291 | fn create_entry(&self, icon: &Icon, deb: &Deb) -> AppResult<&Self> { 292 | let entry = util::gen_desktop_entry( 293 | &self.package_name, 294 | &deb.package, 295 | &deb.description 296 | .to_owned() 297 | .unwrap_or("Application".to_string()), 298 | &icon.path, 299 | ); 300 | 301 | let entry = entry.map_err(|err| AppError::File(err.to_string()))?; 302 | let mut path = dirs::desktop_dir().unwrap(); 303 | 304 | debug!( 305 | "Generated new entry in '{}':\n{}", 306 | path.to_str().unwrap(), 307 | entry 308 | ); 309 | 310 | if !path.exists() { 311 | std::fs::create_dir(&path).map_err(|err| AppError::File(err.to_string()))?; 312 | } 313 | 314 | path.push(format!("{}.desktop", deb.package)); 315 | 316 | std::fs::write(path, entry).map_err(|err| AppError::File(err.to_string()))?; 317 | 318 | Ok(self) 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler" 5 | version = "1.0.2" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 8 | 9 | [[package]] 10 | name = "aho-corasick" 11 | version = "0.7.18" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 14 | dependencies = [ 15 | "memchr", 16 | ] 17 | 18 | [[package]] 19 | name = "ansi_term" 20 | version = "0.11.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 23 | dependencies = [ 24 | "winapi 0.3.9", 25 | ] 26 | 27 | [[package]] 28 | name = "antidote" 29 | version = "1.0.0" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" 32 | 33 | [[package]] 34 | name = "atty" 35 | version = "0.2.14" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 38 | dependencies = [ 39 | "hermit-abi", 40 | "libc", 41 | "winapi 0.3.9", 42 | ] 43 | 44 | [[package]] 45 | name = "autocfg" 46 | version = "1.0.1" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 49 | 50 | [[package]] 51 | name = "base64" 52 | version = "0.10.1" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 55 | dependencies = [ 56 | "byteorder", 57 | ] 58 | 59 | [[package]] 60 | name = "bitflags" 61 | version = "1.2.1" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 64 | 65 | [[package]] 66 | name = "byteorder" 67 | version = "1.4.3" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 70 | 71 | [[package]] 72 | name = "bytes" 73 | version = "0.4.12" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 76 | dependencies = [ 77 | "byteorder", 78 | "either", 79 | "iovec", 80 | ] 81 | 82 | [[package]] 83 | name = "cc" 84 | version = "1.0.67" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" 87 | 88 | [[package]] 89 | name = "cfg-if" 90 | version = "0.1.10" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 93 | 94 | [[package]] 95 | name = "cfg-if" 96 | version = "1.0.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 99 | 100 | [[package]] 101 | name = "chrono" 102 | version = "0.4.19" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 105 | dependencies = [ 106 | "libc", 107 | "num-integer", 108 | "num-traits", 109 | "time", 110 | "winapi 0.3.9", 111 | ] 112 | 113 | [[package]] 114 | name = "clap" 115 | version = "2.33.3" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 118 | dependencies = [ 119 | "ansi_term", 120 | "atty", 121 | "bitflags", 122 | "strsim", 123 | "textwrap", 124 | "unicode-width", 125 | "vec_map", 126 | "yaml-rust", 127 | ] 128 | 129 | [[package]] 130 | name = "cloudabi" 131 | version = "0.0.3" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 134 | dependencies = [ 135 | "bitflags", 136 | ] 137 | 138 | [[package]] 139 | name = "colorful" 140 | version = "0.2.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "0bca1619ff57dd7a56b58a8e25ef4199f123e78e503fe1653410350a1b98ae65" 143 | 144 | [[package]] 145 | name = "crc32fast" 146 | version = "1.2.1" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 149 | dependencies = [ 150 | "cfg-if 1.0.0", 151 | ] 152 | 153 | [[package]] 154 | name = "crossbeam-deque" 155 | version = "0.7.3" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" 158 | dependencies = [ 159 | "crossbeam-epoch", 160 | "crossbeam-utils", 161 | "maybe-uninit", 162 | ] 163 | 164 | [[package]] 165 | name = "crossbeam-epoch" 166 | version = "0.8.2" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 169 | dependencies = [ 170 | "autocfg", 171 | "cfg-if 0.1.10", 172 | "crossbeam-utils", 173 | "lazy_static", 174 | "maybe-uninit", 175 | "memoffset", 176 | "scopeguard", 177 | ] 178 | 179 | [[package]] 180 | name = "crossbeam-queue" 181 | version = "0.2.3" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" 184 | dependencies = [ 185 | "cfg-if 0.1.10", 186 | "crossbeam-utils", 187 | "maybe-uninit", 188 | ] 189 | 190 | [[package]] 191 | name = "crossbeam-utils" 192 | version = "0.7.2" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 195 | dependencies = [ 196 | "autocfg", 197 | "cfg-if 0.1.10", 198 | "lazy_static", 199 | ] 200 | 201 | [[package]] 202 | name = "debian_bridge" 203 | version = "1.0.0" 204 | dependencies = [ 205 | "debian_bridge_cli", 206 | ] 207 | 208 | [[package]] 209 | name = "debian_bridge_cli" 210 | version = "0.2.2" 211 | dependencies = [ 212 | "clap", 213 | "debian_bridge_core", 214 | "dirs", 215 | "log", 216 | "mocktopus", 217 | "pretty_env_logger", 218 | "xdg", 219 | ] 220 | 221 | [[package]] 222 | name = "debian_bridge_core" 223 | version = "0.2.2" 224 | dependencies = [ 225 | "colorful", 226 | "dirs", 227 | "dockerfile", 228 | "freedesktop-desktop-entry", 229 | "log", 230 | "mocktopus", 231 | "pipers", 232 | "pretty_env_logger", 233 | "regex", 234 | "serde", 235 | "serde_json", 236 | "shiplift", 237 | "tokio", 238 | "xdg", 239 | ] 240 | 241 | [[package]] 242 | name = "dirs" 243 | version = "2.0.2" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" 246 | dependencies = [ 247 | "cfg-if 0.1.10", 248 | "dirs-sys", 249 | ] 250 | 251 | [[package]] 252 | name = "dirs-sys" 253 | version = "0.3.6" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" 256 | dependencies = [ 257 | "libc", 258 | "redox_users", 259 | "winapi 0.3.9", 260 | ] 261 | 262 | [[package]] 263 | name = "dockerfile" 264 | version = "0.2.1" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "f3c69e8d0b0821e461b84ea28480bcaa335e38d0548260f3734e219798e3d781" 267 | 268 | [[package]] 269 | name = "either" 270 | version = "1.6.1" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 273 | 274 | [[package]] 275 | name = "env_logger" 276 | version = "0.6.2" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" 279 | dependencies = [ 280 | "atty", 281 | "humantime", 282 | "log", 283 | "regex", 284 | "termcolor", 285 | ] 286 | 287 | [[package]] 288 | name = "filetime" 289 | version = "0.2.14" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" 292 | dependencies = [ 293 | "cfg-if 1.0.0", 294 | "libc", 295 | "redox_syscall 0.2.8", 296 | "winapi 0.3.9", 297 | ] 298 | 299 | [[package]] 300 | name = "flate2" 301 | version = "1.0.20" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" 304 | dependencies = [ 305 | "cfg-if 1.0.0", 306 | "crc32fast", 307 | "libc", 308 | "miniz_oxide", 309 | ] 310 | 311 | [[package]] 312 | name = "fnv" 313 | version = "1.0.7" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 316 | 317 | [[package]] 318 | name = "foreign-types" 319 | version = "0.3.2" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 322 | dependencies = [ 323 | "foreign-types-shared", 324 | ] 325 | 326 | [[package]] 327 | name = "foreign-types-shared" 328 | version = "0.1.1" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 331 | 332 | [[package]] 333 | name = "freedesktop-desktop-entry" 334 | version = "0.1.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "d8f6c340bead95f07434f2432ab52ce048f290d93e42e3c63f416a364801e4bf" 337 | dependencies = [ 338 | "markup", 339 | ] 340 | 341 | [[package]] 342 | name = "fuchsia-zircon" 343 | version = "0.3.3" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 346 | dependencies = [ 347 | "bitflags", 348 | "fuchsia-zircon-sys", 349 | ] 350 | 351 | [[package]] 352 | name = "fuchsia-zircon-sys" 353 | version = "0.3.3" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 356 | 357 | [[package]] 358 | name = "futures" 359 | version = "0.1.31" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" 362 | 363 | [[package]] 364 | name = "futures-cpupool" 365 | version = "0.1.8" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" 368 | dependencies = [ 369 | "futures", 370 | "num_cpus", 371 | ] 372 | 373 | [[package]] 374 | name = "getrandom" 375 | version = "0.2.2" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 378 | dependencies = [ 379 | "cfg-if 1.0.0", 380 | "libc", 381 | "wasi", 382 | ] 383 | 384 | [[package]] 385 | name = "h2" 386 | version = "0.1.26" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" 389 | dependencies = [ 390 | "byteorder", 391 | "bytes", 392 | "fnv", 393 | "futures", 394 | "http", 395 | "indexmap", 396 | "log", 397 | "slab", 398 | "string", 399 | "tokio-io", 400 | ] 401 | 402 | [[package]] 403 | name = "hashbrown" 404 | version = "0.9.1" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 407 | 408 | [[package]] 409 | name = "hermit-abi" 410 | version = "0.1.18" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 413 | dependencies = [ 414 | "libc", 415 | ] 416 | 417 | [[package]] 418 | name = "hex" 419 | version = "0.3.2" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 422 | 423 | [[package]] 424 | name = "http" 425 | version = "0.1.21" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" 428 | dependencies = [ 429 | "bytes", 430 | "fnv", 431 | "itoa", 432 | ] 433 | 434 | [[package]] 435 | name = "http-body" 436 | version = "0.1.0" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" 439 | dependencies = [ 440 | "bytes", 441 | "futures", 442 | "http", 443 | "tokio-buf", 444 | ] 445 | 446 | [[package]] 447 | name = "httparse" 448 | version = "1.4.0" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" 451 | 452 | [[package]] 453 | name = "humantime" 454 | version = "1.3.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 457 | dependencies = [ 458 | "quick-error", 459 | ] 460 | 461 | [[package]] 462 | name = "hyper" 463 | version = "0.12.36" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "5c843caf6296fc1f93444735205af9ed4e109a539005abb2564ae1d6fad34c52" 466 | dependencies = [ 467 | "bytes", 468 | "futures", 469 | "futures-cpupool", 470 | "h2", 471 | "http", 472 | "http-body", 473 | "httparse", 474 | "iovec", 475 | "itoa", 476 | "log", 477 | "net2", 478 | "rustc_version", 479 | "time", 480 | "tokio", 481 | "tokio-buf", 482 | "tokio-executor", 483 | "tokio-io", 484 | "tokio-reactor", 485 | "tokio-tcp", 486 | "tokio-threadpool", 487 | "tokio-timer", 488 | "want", 489 | ] 490 | 491 | [[package]] 492 | name = "hyper-openssl" 493 | version = "0.7.1" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "f52657b5cdb2a8067efd29a02e011b7cf656b473ec8a5c34e86645e85d763006" 496 | dependencies = [ 497 | "antidote", 498 | "bytes", 499 | "futures", 500 | "hyper", 501 | "lazy_static", 502 | "linked_hash_set", 503 | "openssl", 504 | "openssl-sys", 505 | "tokio-io", 506 | "tokio-openssl", 507 | ] 508 | 509 | [[package]] 510 | name = "hyperlocal" 511 | version = "0.6.0" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "d063d6d5658623c6ef16f452e11437c0e7e23a6d327470573fe78892dafbc4fb" 514 | dependencies = [ 515 | "futures", 516 | "hex", 517 | "hyper", 518 | "tokio", 519 | "tokio-io", 520 | "tokio-uds", 521 | ] 522 | 523 | [[package]] 524 | name = "idna" 525 | version = "0.1.5" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 528 | dependencies = [ 529 | "matches", 530 | "unicode-bidi", 531 | "unicode-normalization", 532 | ] 533 | 534 | [[package]] 535 | name = "indexmap" 536 | version = "1.6.2" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" 539 | dependencies = [ 540 | "autocfg", 541 | "hashbrown", 542 | ] 543 | 544 | [[package]] 545 | name = "iovec" 546 | version = "0.1.4" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 549 | dependencies = [ 550 | "libc", 551 | ] 552 | 553 | [[package]] 554 | name = "itoa" 555 | version = "0.4.7" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 558 | 559 | [[package]] 560 | name = "kernel32-sys" 561 | version = "0.2.2" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 564 | dependencies = [ 565 | "winapi 0.2.8", 566 | "winapi-build", 567 | ] 568 | 569 | [[package]] 570 | name = "lazy_static" 571 | version = "1.4.0" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 574 | 575 | [[package]] 576 | name = "libc" 577 | version = "0.2.94" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" 580 | 581 | [[package]] 582 | name = "linked-hash-map" 583 | version = "0.5.4" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" 586 | 587 | [[package]] 588 | name = "linked_hash_set" 589 | version = "0.1.4" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" 592 | dependencies = [ 593 | "linked-hash-map", 594 | ] 595 | 596 | [[package]] 597 | name = "lock_api" 598 | version = "0.3.4" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" 601 | dependencies = [ 602 | "scopeguard", 603 | ] 604 | 605 | [[package]] 606 | name = "log" 607 | version = "0.4.14" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 610 | dependencies = [ 611 | "cfg-if 1.0.0", 612 | ] 613 | 614 | [[package]] 615 | name = "markup" 616 | version = "0.3.1" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "360ec4d83ae8c3150530220fd89e0c5dba54cfc8d7675695f1fdc3581880dce9" 619 | dependencies = [ 620 | "markup-proc-macro", 621 | ] 622 | 623 | [[package]] 624 | name = "markup-proc-macro" 625 | version = "0.3.1" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "ba9c3711ed5187a843aaa960eb78db98f64d76ea22a47c204ca2affb3904bb92" 628 | dependencies = [ 629 | "proc-macro2 0.4.30", 630 | "quote 0.6.13", 631 | "syn 0.15.44", 632 | ] 633 | 634 | [[package]] 635 | name = "matches" 636 | version = "0.1.8" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 639 | 640 | [[package]] 641 | name = "maybe-uninit" 642 | version = "2.0.0" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 645 | 646 | [[package]] 647 | name = "memchr" 648 | version = "2.4.0" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" 651 | 652 | [[package]] 653 | name = "memoffset" 654 | version = "0.5.6" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" 657 | dependencies = [ 658 | "autocfg", 659 | ] 660 | 661 | [[package]] 662 | name = "mime" 663 | version = "0.3.16" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 666 | 667 | [[package]] 668 | name = "miniz_oxide" 669 | version = "0.4.4" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 672 | dependencies = [ 673 | "adler", 674 | "autocfg", 675 | ] 676 | 677 | [[package]] 678 | name = "mio" 679 | version = "0.6.23" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 682 | dependencies = [ 683 | "cfg-if 0.1.10", 684 | "fuchsia-zircon", 685 | "fuchsia-zircon-sys", 686 | "iovec", 687 | "kernel32-sys", 688 | "libc", 689 | "log", 690 | "miow", 691 | "net2", 692 | "slab", 693 | "winapi 0.2.8", 694 | ] 695 | 696 | [[package]] 697 | name = "mio-uds" 698 | version = "0.6.8" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" 701 | dependencies = [ 702 | "iovec", 703 | "libc", 704 | "mio", 705 | ] 706 | 707 | [[package]] 708 | name = "miow" 709 | version = "0.2.2" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 712 | dependencies = [ 713 | "kernel32-sys", 714 | "net2", 715 | "winapi 0.2.8", 716 | "ws2_32-sys", 717 | ] 718 | 719 | [[package]] 720 | name = "mocktopus" 721 | version = "0.7.11" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "d1e54a5bbecd61a064cb9c6ef396f8c896aee14e5baba8d1d555f35167dfd7c3" 724 | dependencies = [ 725 | "mocktopus_macros", 726 | ] 727 | 728 | [[package]] 729 | name = "mocktopus_macros" 730 | version = "0.7.11" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "3048ef3680533a27f9f8e7d6a0bce44dc61e4895ea0f42709337fa1c8616fefe" 733 | dependencies = [ 734 | "proc-macro2 1.0.26", 735 | "quote 1.0.9", 736 | "syn 1.0.72", 737 | ] 738 | 739 | [[package]] 740 | name = "net2" 741 | version = "0.2.37" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" 744 | dependencies = [ 745 | "cfg-if 0.1.10", 746 | "libc", 747 | "winapi 0.3.9", 748 | ] 749 | 750 | [[package]] 751 | name = "num-integer" 752 | version = "0.1.44" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 755 | dependencies = [ 756 | "autocfg", 757 | "num-traits", 758 | ] 759 | 760 | [[package]] 761 | name = "num-traits" 762 | version = "0.2.14" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 765 | dependencies = [ 766 | "autocfg", 767 | ] 768 | 769 | [[package]] 770 | name = "num_cpus" 771 | version = "1.13.0" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 774 | dependencies = [ 775 | "hermit-abi", 776 | "libc", 777 | ] 778 | 779 | [[package]] 780 | name = "once_cell" 781 | version = "1.7.2" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 784 | 785 | [[package]] 786 | name = "openssl" 787 | version = "0.10.34" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" 790 | dependencies = [ 791 | "bitflags", 792 | "cfg-if 1.0.0", 793 | "foreign-types", 794 | "libc", 795 | "once_cell", 796 | "openssl-sys", 797 | ] 798 | 799 | [[package]] 800 | name = "openssl-sys" 801 | version = "0.9.63" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98" 804 | dependencies = [ 805 | "autocfg", 806 | "cc", 807 | "libc", 808 | "pkg-config", 809 | "vcpkg", 810 | ] 811 | 812 | [[package]] 813 | name = "parking_lot" 814 | version = "0.9.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 817 | dependencies = [ 818 | "lock_api", 819 | "parking_lot_core", 820 | "rustc_version", 821 | ] 822 | 823 | [[package]] 824 | name = "parking_lot_core" 825 | version = "0.6.2" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 828 | dependencies = [ 829 | "cfg-if 0.1.10", 830 | "cloudabi", 831 | "libc", 832 | "redox_syscall 0.1.57", 833 | "rustc_version", 834 | "smallvec", 835 | "winapi 0.3.9", 836 | ] 837 | 838 | [[package]] 839 | name = "percent-encoding" 840 | version = "1.0.1" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 843 | 844 | [[package]] 845 | name = "pipers" 846 | version = "1.0.1" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "ee5fc4ee2584767241d624644f8dc720b0e4a6fa7af22cd38dfb66b05304cc26" 849 | 850 | [[package]] 851 | name = "pkg-config" 852 | version = "0.3.19" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 855 | 856 | [[package]] 857 | name = "pretty_env_logger" 858 | version = "0.3.1" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" 861 | dependencies = [ 862 | "chrono", 863 | "env_logger", 864 | "log", 865 | ] 866 | 867 | [[package]] 868 | name = "proc-macro2" 869 | version = "0.4.30" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 872 | dependencies = [ 873 | "unicode-xid 0.1.0", 874 | ] 875 | 876 | [[package]] 877 | name = "proc-macro2" 878 | version = "1.0.26" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 881 | dependencies = [ 882 | "unicode-xid 0.2.2", 883 | ] 884 | 885 | [[package]] 886 | name = "quick-error" 887 | version = "1.2.3" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 890 | 891 | [[package]] 892 | name = "quote" 893 | version = "0.6.13" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 896 | dependencies = [ 897 | "proc-macro2 0.4.30", 898 | ] 899 | 900 | [[package]] 901 | name = "quote" 902 | version = "1.0.9" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 905 | dependencies = [ 906 | "proc-macro2 1.0.26", 907 | ] 908 | 909 | [[package]] 910 | name = "redox_syscall" 911 | version = "0.1.57" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 914 | 915 | [[package]] 916 | name = "redox_syscall" 917 | version = "0.2.8" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" 920 | dependencies = [ 921 | "bitflags", 922 | ] 923 | 924 | [[package]] 925 | name = "redox_users" 926 | version = "0.4.0" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" 929 | dependencies = [ 930 | "getrandom", 931 | "redox_syscall 0.2.8", 932 | ] 933 | 934 | [[package]] 935 | name = "regex" 936 | version = "1.5.4" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 939 | dependencies = [ 940 | "aho-corasick", 941 | "memchr", 942 | "regex-syntax", 943 | ] 944 | 945 | [[package]] 946 | name = "regex-syntax" 947 | version = "0.6.25" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 950 | 951 | [[package]] 952 | name = "rustc_version" 953 | version = "0.2.3" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 956 | dependencies = [ 957 | "semver", 958 | ] 959 | 960 | [[package]] 961 | name = "ryu" 962 | version = "1.0.5" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 965 | 966 | [[package]] 967 | name = "scopeguard" 968 | version = "1.1.0" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 971 | 972 | [[package]] 973 | name = "semver" 974 | version = "0.9.0" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 977 | dependencies = [ 978 | "semver-parser", 979 | ] 980 | 981 | [[package]] 982 | name = "semver-parser" 983 | version = "0.7.0" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 986 | 987 | [[package]] 988 | name = "serde" 989 | version = "1.0.125" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" 992 | dependencies = [ 993 | "serde_derive", 994 | ] 995 | 996 | [[package]] 997 | name = "serde_derive" 998 | version = "1.0.125" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" 1001 | dependencies = [ 1002 | "proc-macro2 1.0.26", 1003 | "quote 1.0.9", 1004 | "syn 1.0.72", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "serde_json" 1009 | version = "1.0.64" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 1012 | dependencies = [ 1013 | "itoa", 1014 | "ryu", 1015 | "serde", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "shiplift" 1020 | version = "0.5.0" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "15d906428d23b85472e2c4af0e80d5ee6a955b6b1d0422b7c0730296a1ecd8df" 1023 | dependencies = [ 1024 | "base64", 1025 | "byteorder", 1026 | "bytes", 1027 | "flate2", 1028 | "futures", 1029 | "http", 1030 | "hyper", 1031 | "hyper-openssl", 1032 | "hyperlocal", 1033 | "log", 1034 | "mime", 1035 | "openssl", 1036 | "serde", 1037 | "serde_json", 1038 | "tar", 1039 | "tokio", 1040 | "tokio-codec", 1041 | "tokio-io", 1042 | "url", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "slab" 1047 | version = "0.4.3" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" 1050 | 1051 | [[package]] 1052 | name = "smallvec" 1053 | version = "0.6.14" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" 1056 | dependencies = [ 1057 | "maybe-uninit", 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "string" 1062 | version = "0.2.1" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" 1065 | dependencies = [ 1066 | "bytes", 1067 | ] 1068 | 1069 | [[package]] 1070 | name = "strsim" 1071 | version = "0.8.0" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1074 | 1075 | [[package]] 1076 | name = "syn" 1077 | version = "0.15.44" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 1080 | dependencies = [ 1081 | "proc-macro2 0.4.30", 1082 | "quote 0.6.13", 1083 | "unicode-xid 0.1.0", 1084 | ] 1085 | 1086 | [[package]] 1087 | name = "syn" 1088 | version = "1.0.72" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" 1091 | dependencies = [ 1092 | "proc-macro2 1.0.26", 1093 | "quote 1.0.9", 1094 | "unicode-xid 0.2.2", 1095 | ] 1096 | 1097 | [[package]] 1098 | name = "tar" 1099 | version = "0.4.33" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228" 1102 | dependencies = [ 1103 | "filetime", 1104 | "libc", 1105 | "xattr", 1106 | ] 1107 | 1108 | [[package]] 1109 | name = "termcolor" 1110 | version = "1.1.2" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1113 | dependencies = [ 1114 | "winapi-util", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "textwrap" 1119 | version = "0.11.0" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1122 | dependencies = [ 1123 | "unicode-width", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "time" 1128 | version = "0.1.43" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1131 | dependencies = [ 1132 | "libc", 1133 | "winapi 0.3.9", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "tinyvec" 1138 | version = "1.2.0" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" 1141 | dependencies = [ 1142 | "tinyvec_macros", 1143 | ] 1144 | 1145 | [[package]] 1146 | name = "tinyvec_macros" 1147 | version = "0.1.0" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1150 | 1151 | [[package]] 1152 | name = "tokio" 1153 | version = "0.1.22" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" 1156 | dependencies = [ 1157 | "bytes", 1158 | "futures", 1159 | "mio", 1160 | "num_cpus", 1161 | "tokio-codec", 1162 | "tokio-current-thread", 1163 | "tokio-executor", 1164 | "tokio-fs", 1165 | "tokio-io", 1166 | "tokio-reactor", 1167 | "tokio-sync", 1168 | "tokio-tcp", 1169 | "tokio-threadpool", 1170 | "tokio-timer", 1171 | "tokio-udp", 1172 | "tokio-uds", 1173 | ] 1174 | 1175 | [[package]] 1176 | name = "tokio-buf" 1177 | version = "0.1.1" 1178 | source = "registry+https://github.com/rust-lang/crates.io-index" 1179 | checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" 1180 | dependencies = [ 1181 | "bytes", 1182 | "either", 1183 | "futures", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "tokio-codec" 1188 | version = "0.1.2" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" 1191 | dependencies = [ 1192 | "bytes", 1193 | "futures", 1194 | "tokio-io", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "tokio-current-thread" 1199 | version = "0.1.7" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" 1202 | dependencies = [ 1203 | "futures", 1204 | "tokio-executor", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "tokio-executor" 1209 | version = "0.1.10" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" 1212 | dependencies = [ 1213 | "crossbeam-utils", 1214 | "futures", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "tokio-fs" 1219 | version = "0.1.7" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" 1222 | dependencies = [ 1223 | "futures", 1224 | "tokio-io", 1225 | "tokio-threadpool", 1226 | ] 1227 | 1228 | [[package]] 1229 | name = "tokio-io" 1230 | version = "0.1.13" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" 1233 | dependencies = [ 1234 | "bytes", 1235 | "futures", 1236 | "log", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "tokio-openssl" 1241 | version = "0.3.0" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "771d6246b170ae108d67d9963c23f31a579016c016d73bd4bd7d6ef0252afda7" 1244 | dependencies = [ 1245 | "futures", 1246 | "openssl", 1247 | "tokio-io", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "tokio-reactor" 1252 | version = "0.1.12" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" 1255 | dependencies = [ 1256 | "crossbeam-utils", 1257 | "futures", 1258 | "lazy_static", 1259 | "log", 1260 | "mio", 1261 | "num_cpus", 1262 | "parking_lot", 1263 | "slab", 1264 | "tokio-executor", 1265 | "tokio-io", 1266 | "tokio-sync", 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "tokio-sync" 1271 | version = "0.1.8" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" 1274 | dependencies = [ 1275 | "fnv", 1276 | "futures", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "tokio-tcp" 1281 | version = "0.1.4" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" 1284 | dependencies = [ 1285 | "bytes", 1286 | "futures", 1287 | "iovec", 1288 | "mio", 1289 | "tokio-io", 1290 | "tokio-reactor", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "tokio-threadpool" 1295 | version = "0.1.18" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" 1298 | dependencies = [ 1299 | "crossbeam-deque", 1300 | "crossbeam-queue", 1301 | "crossbeam-utils", 1302 | "futures", 1303 | "lazy_static", 1304 | "log", 1305 | "num_cpus", 1306 | "slab", 1307 | "tokio-executor", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "tokio-timer" 1312 | version = "0.2.13" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" 1315 | dependencies = [ 1316 | "crossbeam-utils", 1317 | "futures", 1318 | "slab", 1319 | "tokio-executor", 1320 | ] 1321 | 1322 | [[package]] 1323 | name = "tokio-udp" 1324 | version = "0.1.6" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" 1327 | dependencies = [ 1328 | "bytes", 1329 | "futures", 1330 | "log", 1331 | "mio", 1332 | "tokio-codec", 1333 | "tokio-io", 1334 | "tokio-reactor", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "tokio-uds" 1339 | version = "0.2.7" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" 1342 | dependencies = [ 1343 | "bytes", 1344 | "futures", 1345 | "iovec", 1346 | "libc", 1347 | "log", 1348 | "mio", 1349 | "mio-uds", 1350 | "tokio-codec", 1351 | "tokio-io", 1352 | "tokio-reactor", 1353 | ] 1354 | 1355 | [[package]] 1356 | name = "try-lock" 1357 | version = "0.2.3" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1360 | 1361 | [[package]] 1362 | name = "unicode-bidi" 1363 | version = "0.3.5" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" 1366 | dependencies = [ 1367 | "matches", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "unicode-normalization" 1372 | version = "0.1.17" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 1375 | dependencies = [ 1376 | "tinyvec", 1377 | ] 1378 | 1379 | [[package]] 1380 | name = "unicode-width" 1381 | version = "0.1.8" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 1384 | 1385 | [[package]] 1386 | name = "unicode-xid" 1387 | version = "0.1.0" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1390 | 1391 | [[package]] 1392 | name = "unicode-xid" 1393 | version = "0.2.2" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1396 | 1397 | [[package]] 1398 | name = "url" 1399 | version = "1.7.2" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 1402 | dependencies = [ 1403 | "idna", 1404 | "matches", 1405 | "percent-encoding", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "vcpkg" 1410 | version = "0.2.12" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d" 1413 | 1414 | [[package]] 1415 | name = "vec_map" 1416 | version = "0.8.2" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1419 | 1420 | [[package]] 1421 | name = "want" 1422 | version = "0.2.0" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" 1425 | dependencies = [ 1426 | "futures", 1427 | "log", 1428 | "try-lock", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "wasi" 1433 | version = "0.10.2+wasi-snapshot-preview1" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1436 | 1437 | [[package]] 1438 | name = "winapi" 1439 | version = "0.2.8" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1442 | 1443 | [[package]] 1444 | name = "winapi" 1445 | version = "0.3.9" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1448 | dependencies = [ 1449 | "winapi-i686-pc-windows-gnu", 1450 | "winapi-x86_64-pc-windows-gnu", 1451 | ] 1452 | 1453 | [[package]] 1454 | name = "winapi-build" 1455 | version = "0.1.1" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1458 | 1459 | [[package]] 1460 | name = "winapi-i686-pc-windows-gnu" 1461 | version = "0.4.0" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1464 | 1465 | [[package]] 1466 | name = "winapi-util" 1467 | version = "0.1.5" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1470 | dependencies = [ 1471 | "winapi 0.3.9", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "winapi-x86_64-pc-windows-gnu" 1476 | version = "0.4.0" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1479 | 1480 | [[package]] 1481 | name = "ws2_32-sys" 1482 | version = "0.2.1" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1485 | dependencies = [ 1486 | "winapi 0.2.8", 1487 | "winapi-build", 1488 | ] 1489 | 1490 | [[package]] 1491 | name = "xattr" 1492 | version = "0.2.2" 1493 | source = "registry+https://github.com/rust-lang/crates.io-index" 1494 | checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" 1495 | dependencies = [ 1496 | "libc", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "xdg" 1501 | version = "2.2.0" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" 1504 | 1505 | [[package]] 1506 | name = "yaml-rust" 1507 | version = "0.3.5" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" 1510 | --------------------------------------------------------------------------------