├── .gitignore ├── src ├── models │ ├── mod.rs │ └── docker.rs ├── commands │ ├── mod.rs │ ├── run.rs │ └── pull.rs ├── storage │ ├── mod.rs │ ├── container.rs │ └── image.rs ├── clap.yaml └── main.rs ├── docs ├── logo.png └── screenshots │ ├── run_nginx.png │ ├── pull_hello_world.png │ └── run_hello_world.png ├── Cargo.toml ├── README.md ├── LICENSE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod docker; 2 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KernelErr/shallow-container/HEAD/docs/logo.png -------------------------------------------------------------------------------- /src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod pull; 2 | pub mod run; 3 | 4 | pub use self::pull::pull; 5 | pub use self::run::run; 6 | -------------------------------------------------------------------------------- /docs/screenshots/run_nginx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KernelErr/shallow-container/HEAD/docs/screenshots/run_nginx.png -------------------------------------------------------------------------------- /docs/screenshots/pull_hello_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KernelErr/shallow-container/HEAD/docs/screenshots/pull_hello_world.png -------------------------------------------------------------------------------- /docs/screenshots/run_hello_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KernelErr/shallow-container/HEAD/docs/screenshots/run_hello_world.png -------------------------------------------------------------------------------- /src/storage/mod.rs: -------------------------------------------------------------------------------- 1 | pub const IMAGE_PATH: &str = "/var/lib/shallow/image"; 2 | pub const CONTAINER_PATH: &str = "/var/lib/shallow/container"; 3 | 4 | pub mod container; 5 | pub mod image; 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shallow-container" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | serde = "1.0" 10 | sscanf = "0.1" 11 | nanoid = "0.4" 12 | serde_json = "1.0" 13 | reqwest = { version = "0.11", features = ["json"] } 14 | clap = { version = "3.0.0-beta.4", features = ["yaml"] } 15 | tokio = { version = "1", features = ["full"] } 16 | 17 | log = "0.4" 18 | moe_logger = "0.2" 19 | 20 | oci-spec = "0.5.1" 21 | unshare = "0.7.0" 22 | 23 | tar = "0.4" 24 | flate2 = "1.0" -------------------------------------------------------------------------------- /src/clap.yaml: -------------------------------------------------------------------------------- 1 | name: shallow-container 2 | version: "0.1.0" 3 | author: LI Rui 4 | about: Simple application container for linux written in Rust. 5 | subcommands: 6 | - pull: 7 | about: Pull image 8 | args: 9 | - image: 10 | about: Image name 11 | required: true 12 | index: 1 13 | 14 | - run: 15 | about: Run container 16 | args: 17 | - image: 18 | about: Image name 19 | required: true 20 | index: 1 21 | - share_net: 22 | long: Sn 23 | about: Share NET namespace -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{load_yaml, App}; 2 | use log::{debug, error}; 3 | use moe_logger::LogConfig; 4 | 5 | mod commands; 6 | mod models; 7 | mod storage; 8 | use commands::pull; 9 | use commands::run; 10 | 11 | #[tokio::main] 12 | async fn main() { 13 | let log_config = LogConfig::default(); 14 | moe_logger::init(log_config); 15 | 16 | let clap_yaml = load_yaml!("clap.yaml"); 17 | let matches = App::from(clap_yaml).get_matches(); 18 | 19 | debug!("{:?}", matches); 20 | 21 | let res = match matches.subcommand() { 22 | Some(("pull", sub_m)) => pull(sub_m).await, 23 | Some(("run", sub_m)) => run(sub_m).await, 24 | _ => false, 25 | }; 26 | 27 | if !res { 28 | error!("Command exited with error"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![Shallow Container](./docs/logo.png) 4 | 5 | Shallow Container is a light-weight container tool written in Rust. It is totally for proof-of-concept and may not suit for production environment. 6 | 7 | Shallow Container 是一款Rust编写的轻量级容器工具,用于探索在Rust中实现管理Linux命名空间等功能的可能性。请注意,本程序仅作为学习用途,其设计可能不适合生产用途,请勿在生产环境下使用。 8 | 9 | 在开发本项目时并没有考虑到诸多方面,致使本项目更像是一个玩具,如果需要细致了解Docker的原理,推荐研究Linux Namespace、cgroups、aufs等知识。 10 | 11 | ## 概念 12 | 13 | Rust是一门非常棒的编程语言,在这入门后不到一年的时间,我逐渐感受到了Rust的魅力,并尝试以Rust为切入点去理解后端框架、操作系统等应用。Shallow Container(简称SC)是100% Rust编写的轻型容器工具,目前支持下面的功能: 14 | 15 | - 从Docker Hub下载镜像 16 | - 启动镜像(可选和主机共享Net命名空间) 17 | 18 | SC在设计上一定程度参考了[mocker](https://github.com/tonybaloney/mocker),我和mocker的作者一样花了两天时间写了这样一个程序。程序功能完全比不上Docker的n分之一,在实际执行的过程中也可能有不少问题,不过这已经达到了探索基础知识的目的,后续更深入的容器原理就交给大家和我独自去研究了。 19 | 20 | SC的所有文件均保存在`/var/lib/shallow`中,如果需要释放空间,直接删除即可。 21 | 22 | ## pull 23 | 24 | 假设程序编译位置为`./target/debug/shallow-container`,如果想pull一个镜像,请执行下面的命令: 25 | 26 | ```bash 27 | $ sudo ./target/debug/shallow-container pull library/hello-world:latest 28 | ``` 29 | 30 | Image需要是完整的scope/image:tag格式,如果为官方镜像,scope请设置为`library`。你大概会看到这样的输出: 31 | 32 | ![Pull Hello World](./docs/screenshots/pull_hello_world.png) 33 | 34 | ## run 35 | 36 | 类似的,如果想启动一个容器,请执行下面的命令,如果没找到镜像会先尝试pull: 37 | 38 | ```bash 39 | $ sudo ./target/debug/shallow-container run library/hello-world:latest 40 | ``` 41 | 42 | 默认情况下,SC会为容器使用独立的PID、Net等命名空间。由于SC设计上未考虑到网络相关的功能,所以如果你想运行Nginx容器,可以加上`--Sn`来和主机共享网络命名空间。 43 | 44 | ```bash 45 | $ sudo ./target/debug/shallow-container run --Sn nginxinc/nginx-unprivileged:latest 46 | ``` 47 | 48 | 可以预期的输出如下: 49 | 50 | ![Run Nginx](./docs/screenshots/run_nginx.png) 51 | 52 | 同时你可以访问`http://127.0.0.1:8080`,你应该能够看到Nginx经典的默认网页。 53 | 54 | ## License 55 | 56 | Shallow Container is available under terms of Apache-2.0. 57 | -------------------------------------------------------------------------------- /src/models/docker.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use serde_json::Value; 3 | use std::collections::HashMap; 4 | 5 | #[derive(Serialize, Deserialize, Debug)] 6 | pub struct DockerToken { 7 | pub token: String, 8 | pub access_token: String, 9 | pub expires_in: i32, 10 | pub issued_at: String, 11 | } 12 | 13 | #[derive(Serialize, Deserialize, Debug)] 14 | pub struct DockerImageConfig { 15 | architecture: String, 16 | pub config: DockerContainerConfig, 17 | container: Option, 18 | container_config: Option, 19 | created: String, 20 | docker_version: Option, 21 | history: Vec, 22 | os: String, 23 | rootfs: DockerImageRootfs, 24 | } 25 | 26 | #[allow(non_snake_case)] 27 | #[derive(Serialize, Deserialize, Debug)] 28 | pub struct DockerContainerConfig { 29 | Hostname: Option, 30 | Domainname: Option, 31 | User: Option, 32 | AttachStdin: Option, 33 | AttachStdout: Option, 34 | AttachStderr: Option, 35 | ExposedPorts: Option, 36 | Tty: Option, 37 | OpenStdin: Option, 38 | StdinOnce: Option, 39 | pub Env: Vec, 40 | pub Cmd: Vec, 41 | Image: Option, 42 | Volumes: Option>, 43 | WorkingDir: Option, 44 | pub Entrypoint: Option>, 45 | OnBuild: Option>, 46 | Labels: Option>, 47 | StopSignal: Option, 48 | } 49 | 50 | #[derive(Serialize, Deserialize, Debug)] 51 | pub struct DockerImageHistory { 52 | created: String, 53 | created_by: String, 54 | empty_layer: Option, 55 | } 56 | 57 | #[derive(Serialize, Deserialize, Debug)] 58 | pub struct DockerImageRootfs { 59 | r#type: String, 60 | diff_ids: Vec, 61 | } 62 | -------------------------------------------------------------------------------- /src/storage/container.rs: -------------------------------------------------------------------------------- 1 | use crate::storage::image::load_manifest; 2 | use crate::storage::{CONTAINER_PATH, IMAGE_PATH}; 3 | use flate2::read::GzDecoder; 4 | use log::{error, info}; 5 | use std::fs::{create_dir_all, File}; 6 | use tar::Archive; 7 | 8 | pub fn extract_image( 9 | image: &str, 10 | tag: &str, 11 | name: &str, 12 | ) -> Result> { 13 | let manifest = match load_manifest(image, tag) { 14 | Ok(manifest) => manifest, 15 | Err(e) => return Err(e), 16 | }; 17 | let path = format!("{}/{}", CONTAINER_PATH, name); 18 | match create_dir_all(path.clone()) { 19 | Ok(_) => { 20 | let layers = manifest.layers(); 21 | for layer in layers.iter() { 22 | let digest = layer.digest(); 23 | let layer_path = format!("{}/{}/{}/layers/{}", IMAGE_PATH, image, tag, digest); 24 | let layer_file = match File::open(layer_path) { 25 | Ok(file) => file, 26 | Err(e) => { 27 | error!("Failed to open layer file: {}", e); 28 | return Err(Box::new(e)); 29 | } 30 | }; 31 | let gz_decoder = GzDecoder::new(layer_file); 32 | let mut tar_archive = Archive::new(gz_decoder); 33 | match tar_archive.unpack(path.clone()) { 34 | Ok(_) => { 35 | info!("Successfully extracted layer {}", digest); 36 | } 37 | Err(e) => { 38 | error!("Failed to extract layer {}: {}", digest, e); 39 | return Err(Box::new(e)); 40 | } 41 | } 42 | } 43 | } 44 | Err(e) => { 45 | error!("Failed to create container directory: {}", e); 46 | return Err(Box::new(e)); 47 | } 48 | } 49 | Ok(path) 50 | } 51 | -------------------------------------------------------------------------------- /src/commands/run.rs: -------------------------------------------------------------------------------- 1 | use crate::commands::pull::pull_image; 2 | use crate::storage::container::extract_image; 3 | use crate::storage::image::load_config; 4 | use crate::storage::IMAGE_PATH; 5 | use clap::ArgMatches; 6 | use log::{error, info}; 7 | use nanoid::nanoid; 8 | use std::path::Path; 9 | use unshare; 10 | use unshare::Namespace; 11 | 12 | pub async fn run(arg: &ArgMatches) -> bool { 13 | let image = arg.value_of("image").unwrap(); 14 | let (scope, image, tag) = match sscanf::scanf!(image, "{}/{}:{}", String, String, String) { 15 | Some((scope, image, tag)) => (scope, image, tag), 16 | None => { 17 | error!("Invalid image format: {}", image); 18 | return false; 19 | } 20 | }; 21 | 22 | if !Path::new(&format!("{}/{}/{}", IMAGE_PATH, image, tag)).exists() { 23 | info!("Image not found, trying to pull it"); 24 | if !pull_image(scope, image.clone(), tag.clone()).await { 25 | return false; 26 | }; 27 | } 28 | 29 | let config = match load_config(&image, &tag) { 30 | Ok(config) => config, 31 | Err(_) => { 32 | return false; 33 | } 34 | }; 35 | let container_name = nanoid!(); 36 | let path = match extract_image(&image, &tag, &container_name) { 37 | Ok(path) => path, 38 | Err(_) => { 39 | return false; 40 | } 41 | }; 42 | 43 | // commands & envs 44 | let commands = config.config.Cmd; 45 | if commands.is_empty() { 46 | error!("No commands found in config"); 47 | return false; 48 | } 49 | let entry_point = config.config.Entrypoint; 50 | let mut cmd = match entry_point { 51 | Some(ep) => { 52 | let mut cmd = unshare::Command::new(ep[0].clone()); 53 | for entry in ep.iter().skip(1) { 54 | cmd.arg(entry); 55 | } 56 | for c in &commands { 57 | cmd.arg(c); 58 | } 59 | cmd 60 | } 61 | None => { 62 | let mut cmd = unshare::Command::new(commands[0].clone()); 63 | for c in commands.iter().skip(1) { 64 | cmd.arg(c); 65 | } 66 | cmd 67 | } 68 | }; 69 | cmd.chroot_dir(path); 70 | for env in config.config.Env { 71 | let mut split = env.split('='); 72 | let key = split.next().unwrap(); 73 | let value = split.next().unwrap(); 74 | cmd.env(key, value); 75 | } 76 | 77 | // namespaces 78 | let mut namespaces = vec![ 79 | Namespace::Pid, 80 | Namespace::Uts, 81 | Namespace::Ipc, 82 | Namespace::Mount, 83 | Namespace::User, 84 | ]; 85 | if !arg.is_present("share_net") { 86 | namespaces.push(Namespace::Net); 87 | } 88 | cmd.unshare(&namespaces); 89 | 90 | cmd.close_fds(..); 91 | 92 | let mut child = match cmd.spawn() { 93 | Ok(child) => { 94 | info!("Started container {}", container_name); 95 | child 96 | } 97 | Err(e) => { 98 | error!("Failed to spawn process: {}", e); 99 | return false; 100 | } 101 | }; 102 | 103 | child.wait().unwrap(); 104 | true 105 | } 106 | -------------------------------------------------------------------------------- /src/storage/image.rs: -------------------------------------------------------------------------------- 1 | use crate::models::docker::DockerImageConfig; 2 | use crate::storage::IMAGE_PATH; 3 | use log::error; 4 | use oci_spec::image::ImageManifest; 5 | use reqwest::RequestBuilder; 6 | use std::fs::{create_dir_all, File}; 7 | use std::io::prelude::*; 8 | use std::io::{copy, Cursor}; 9 | 10 | pub fn store_manifest( 11 | image: &str, 12 | tag: &str, 13 | content: &str, 14 | ) -> Result<(), Box> { 15 | let path = format!("{}/{}/{}", IMAGE_PATH, image, tag); 16 | match create_dir_all(path.clone()) { 17 | Ok(_) => { 18 | let output = format!("{}/{}", path, "manifest.json"); 19 | let mut f = match File::create(output) { 20 | Ok(f) => f, 21 | Err(e) => { 22 | error!("Failed to write manifest: {}", e); 23 | return Err(Box::new(e)); 24 | } 25 | }; 26 | match f.write_all(content.as_bytes()) { 27 | Ok(_) => Ok(()), 28 | Err(e) => { 29 | error!("Failed to write manifest: {}", e); 30 | Err(Box::new(e)) 31 | } 32 | } 33 | } 34 | Err(e) => { 35 | error!("Failed to create manifest directory: {}", e); 36 | Err(Box::new(e)) 37 | } 38 | } 39 | } 40 | 41 | pub fn load_manifest(image: &str, tag: &str) -> Result> { 42 | let path = format!("{}/{}/{}/manifest.json", IMAGE_PATH, image, tag); 43 | match ImageManifest::from_file(path) { 44 | Ok(manifest) => Ok(manifest), 45 | Err(e) => { 46 | error!("Failed to load manifest: {}", e); 47 | Err(Box::new(e)) 48 | } 49 | } 50 | } 51 | 52 | pub fn store_config( 53 | image: &str, 54 | tag: &str, 55 | content: &str, 56 | ) -> Result<(), Box> { 57 | let path = format!("{}/{}/{}", IMAGE_PATH, image, tag); 58 | match create_dir_all(path.clone()) { 59 | Ok(_) => { 60 | let output = format!("{}/{}", path, "config.json"); 61 | let mut f = match File::create(output) { 62 | Ok(f) => f, 63 | Err(e) => { 64 | error!("Failed to write image config: {}", e); 65 | return Err(Box::new(e)); 66 | } 67 | }; 68 | match f.write_all(content.as_bytes()) { 69 | Ok(_) => Ok(()), 70 | Err(e) => { 71 | error!("Failed to write image config: {}", e); 72 | Err(Box::new(e)) 73 | } 74 | } 75 | } 76 | Err(e) => { 77 | error!("Failed to create image config directory: {}", e); 78 | Err(Box::new(e)) 79 | } 80 | } 81 | } 82 | 83 | pub fn load_config( 84 | image: &str, 85 | tag: &str, 86 | ) -> Result> { 87 | let path = format!("{}/{}/{}/config.json", IMAGE_PATH, image, tag); 88 | let mut file = match File::open(path) { 89 | Ok(file) => file, 90 | Err(e) => { 91 | error!("Failed to load image config: {}", e); 92 | return Err(Box::new(e)); 93 | } 94 | }; 95 | let mut data = String::new(); 96 | match file.read_to_string(&mut data) { 97 | Ok(_) => { 98 | let image_config: DockerImageConfig = match serde_json::from_str(&data) { 99 | Ok(image_config) => image_config, 100 | Err(e) => { 101 | error!("Failed to parse image config: {}", e); 102 | return Err(Box::new(e)); 103 | } 104 | }; 105 | Ok(image_config) 106 | } 107 | Err(e) => { 108 | error!("Failed to load image config: {}", e); 109 | Err(Box::new(e)) 110 | } 111 | } 112 | } 113 | 114 | pub async fn save_layer( 115 | image: &str, 116 | tag: &str, 117 | digest: &str, 118 | req: RequestBuilder, 119 | ) -> Result<(), Box> { 120 | let path = format!("{}/{}/{}/layers", IMAGE_PATH, image, tag); 121 | match create_dir_all(path.clone()) { 122 | Ok(_) => { 123 | let resp = req.send().await?; 124 | let mut dest = { 125 | let output = format!("{}/{}", path, digest); 126 | File::create(output)? 127 | }; 128 | let mut content = Cursor::new(resp.bytes().await?); 129 | copy(&mut content, &mut dest)?; 130 | Ok(()) 131 | } 132 | Err(e) => { 133 | error!("Failed to create layer directory: {}", e); 134 | Err(Box::new(e)) 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/commands/pull.rs: -------------------------------------------------------------------------------- 1 | use crate::models::docker::DockerToken; 2 | use crate::storage::image::{load_config, load_manifest, save_layer, store_config, store_manifest}; 3 | use clap::ArgMatches; 4 | use log::{debug, error, info}; 5 | use oci_spec::image::ImageManifest; 6 | use reqwest; 7 | use reqwest::header::{ACCEPT, AUTHORIZATION}; 8 | 9 | struct PullRequest { 10 | image: String, 11 | tag: String, 12 | scope: String, 13 | token: Option, 14 | } 15 | 16 | impl PullRequest { 17 | pub fn new(scope: String, image: String, tag: String) -> PullRequest { 18 | PullRequest { 19 | image, 20 | tag, 21 | scope, 22 | token: None, 23 | } 24 | } 25 | 26 | pub async fn docker_hub_auth(&mut self) -> PullRequest { 27 | info!("Auth to Docker Hub"); 28 | let url = format!( 29 | "https://auth.docker.io/token?service=registry.docker.io&scope=repository:{}/{}:pull", 30 | self.scope, self.image 31 | ); 32 | let resp = reqwest::get(url).await; 33 | match resp { 34 | Ok(resp) => match resp.json::().await { 35 | Ok(data) => { 36 | self.token = Some(data.token); 37 | PullRequest { 38 | image: self.image.clone(), 39 | tag: self.tag.clone(), 40 | scope: self.scope.clone(), 41 | token: self.token.clone(), 42 | } 43 | } 44 | Err(e) => { 45 | error!("Failed to parse Docker Token: {}", e); 46 | PullRequest { 47 | image: self.image.clone(), 48 | tag: self.tag.clone(), 49 | scope: self.scope.clone(), 50 | token: None, 51 | } 52 | } 53 | }, 54 | Err(e) => { 55 | error!("Failed to auth Docker Hub: {}", e); 56 | PullRequest { 57 | image: self.image.clone(), 58 | tag: self.tag.clone(), 59 | scope: self.scope.clone(), 60 | token: None, 61 | } 62 | } 63 | } 64 | } 65 | 66 | pub async fn docker_hub_manifest(&self) -> Result> { 67 | info!("Fetching image manifest"); 68 | let url = format!( 69 | "https://registry.hub.docker.com/v2/{}/{}/manifests/{}", 70 | self.scope, self.image, self.tag 71 | ); 72 | let client = reqwest::Client::new(); 73 | let resp = client 74 | .get(url) 75 | .header( 76 | AUTHORIZATION, 77 | format!("Bearer {}", self.token.clone().unwrap()), 78 | ) 79 | .header( 80 | ACCEPT, 81 | "application/vnd.docker.distribution.manifest.v2+json", 82 | ) 83 | .send() 84 | .await; 85 | match resp { 86 | Ok(resp) => { 87 | let text = match resp.text().await { 88 | Ok(text) => text, 89 | Err(e) => { 90 | error!("Failed to fetch manifest: {}", e); 91 | return Err(Box::new(e)); 92 | } 93 | }; 94 | debug!("{:?}", text); 95 | match store_manifest(&self.image, &self.tag, &text) { 96 | Ok(_) => {} 97 | Err(e) => { 98 | error!("Failed to store manifest: {}", e); 99 | return Err(e); 100 | } 101 | } 102 | match load_manifest(&self.image, &self.tag) { 103 | Ok(manifest) => { 104 | info!("Successfully fetched manifest"); 105 | Ok(manifest) 106 | } 107 | Err(e) => { 108 | error!("Failed to load manifest: {}", e); 109 | Err(e) 110 | } 111 | } 112 | } 113 | Err(e) => { 114 | error!("Failed to fetch manifest: {}", e); 115 | Err(Box::new(e)) 116 | } 117 | } 118 | } 119 | 120 | pub async fn fetch_layers( 121 | &self, 122 | manifest: ImageManifest, 123 | ) -> Result<(), Box> { 124 | let config_digest = manifest.config().digest(); 125 | let url = format!( 126 | "https://registry.hub.docker.com/v2/{}/{}/blobs/{}", 127 | self.scope, self.image, config_digest 128 | ); 129 | let client = reqwest::Client::new(); 130 | let resp = client 131 | .get(url) 132 | .header( 133 | AUTHORIZATION, 134 | format!("Bearer {}", self.token.clone().unwrap()), 135 | ) 136 | .send() 137 | .await; 138 | match resp { 139 | Ok(resp) => { 140 | let text = match resp.text().await { 141 | Ok(text) => text, 142 | Err(e) => { 143 | error!("Failed to fetch config: {}", e); 144 | return Err(Box::new(e)); 145 | } 146 | }; 147 | match store_config(&self.image, &self.tag, &text) { 148 | Ok(_) => {} 149 | Err(e) => { 150 | error!("Failed to store config: {}", e); 151 | return Err(e); 152 | } 153 | } 154 | match load_config(&self.image, &self.tag) { 155 | Ok(config) => { 156 | debug!("{:?}", config); 157 | info!("Successfully fetched image config"); 158 | } 159 | Err(e) => { 160 | error!("Bad image config format: {}", e); 161 | return Err(e); 162 | } 163 | } 164 | } 165 | Err(e) => { 166 | error!("Failed to fetch config: {}", e); 167 | return Err(Box::new(e)); 168 | } 169 | } 170 | 171 | info!("Fetching image layers"); 172 | let layers = manifest.layers(); 173 | for layer in layers.iter() { 174 | let digest = layer.digest(); 175 | let url = format!( 176 | "https://registry.hub.docker.com/v2/{}/{}/blobs/{}", 177 | self.scope, self.image, digest 178 | ); 179 | let client = reqwest::Client::new(); 180 | let req = client 181 | .get(url) 182 | .header( 183 | AUTHORIZATION, 184 | format!("Bearer {}", self.token.clone().unwrap()), 185 | ) 186 | .header(ACCEPT, "application/vnd.docker.image.rootfs.diff.tar.gzip"); 187 | info!("Fetching layer {}", digest); 188 | match save_layer(&self.image, &self.tag, digest, req).await { 189 | Ok(_) => { 190 | info!("Successfully fetched layer {}", digest); 191 | } 192 | Err(e) => { 193 | error!("Failed to fetch layer: {}", e); 194 | return Err(e); 195 | } 196 | } 197 | } 198 | Ok(()) 199 | } 200 | } 201 | 202 | pub async fn pull(arg: &ArgMatches) -> bool { 203 | let image = arg.value_of("image").unwrap(); 204 | let mut pull_request = match sscanf::scanf!(image, "{}/{}:{}", String, String, String) { 205 | Some((scope, image, tag)) => PullRequest::new(scope, image, tag), 206 | None => { 207 | error!("Invalid image format: {}", image); 208 | return false; 209 | } 210 | }; 211 | pull_request.docker_hub_auth().await; 212 | if pull_request.token.is_none() { 213 | return false; 214 | } 215 | let manifest = match pull_request.docker_hub_manifest().await { 216 | Ok(manifest) => manifest, 217 | Err(_) => { 218 | return false; 219 | } 220 | }; 221 | pull_request.fetch_layers(manifest).await.is_ok() 222 | } 223 | 224 | pub async fn pull_image(scope: String, image: String, tag: String) -> bool { 225 | let mut pull_request = PullRequest::new(scope, image, tag); 226 | pull_request.docker_hub_auth().await; 227 | if pull_request.token.is_none() { 228 | return false; 229 | } 230 | let manifest = match pull_request.docker_hub_manifest().await { 231 | Ok(manifest) => manifest, 232 | Err(_) => { 233 | return false; 234 | } 235 | }; 236 | pull_request.fetch_layers(manifest).await.is_ok() 237 | } 238 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "aho-corasick" 13 | version = "0.7.18" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 16 | dependencies = [ 17 | "memchr", 18 | ] 19 | 20 | [[package]] 21 | name = "atty" 22 | version = "0.2.14" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 25 | dependencies = [ 26 | "hermit-abi", 27 | "libc", 28 | "winapi", 29 | ] 30 | 31 | [[package]] 32 | name = "autocfg" 33 | version = "1.0.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 36 | 37 | [[package]] 38 | name = "base64" 39 | version = "0.13.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 42 | 43 | [[package]] 44 | name = "bitflags" 45 | version = "1.2.1" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 48 | 49 | [[package]] 50 | name = "bumpalo" 51 | version = "3.7.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" 54 | 55 | [[package]] 56 | name = "bytes" 57 | version = "1.1.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 60 | 61 | [[package]] 62 | name = "cc" 63 | version = "1.0.70" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" 66 | 67 | [[package]] 68 | name = "cfg-if" 69 | version = "1.0.0" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 72 | 73 | [[package]] 74 | name = "clap" 75 | version = "3.0.0-beta.4" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" 78 | dependencies = [ 79 | "atty", 80 | "bitflags", 81 | "clap_derive", 82 | "indexmap", 83 | "lazy_static", 84 | "os_str_bytes", 85 | "strsim", 86 | "termcolor", 87 | "textwrap", 88 | "vec_map", 89 | "yaml-rust", 90 | ] 91 | 92 | [[package]] 93 | name = "clap_derive" 94 | version = "3.0.0-beta.4" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" 97 | dependencies = [ 98 | "heck", 99 | "proc-macro-error", 100 | "proc-macro2", 101 | "quote", 102 | "syn", 103 | ] 104 | 105 | [[package]] 106 | name = "const_format" 107 | version = "0.2.20" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "ae592b8ddbf42b388f8211f0fd4d0985768ed7316348277c250dca4513695492" 110 | dependencies = [ 111 | "const_format_proc_macros", 112 | ] 113 | 114 | [[package]] 115 | name = "const_format_proc_macros" 116 | version = "0.2.20" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "98b53b21a34874c03f4ee8fe5a5dbd977fbe09cfa43b7e2362d94f33e42d56af" 119 | dependencies = [ 120 | "proc-macro2", 121 | "quote", 122 | "unicode-xid", 123 | ] 124 | 125 | [[package]] 126 | name = "core-foundation" 127 | version = "0.9.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" 130 | dependencies = [ 131 | "core-foundation-sys", 132 | "libc", 133 | ] 134 | 135 | [[package]] 136 | name = "core-foundation-sys" 137 | version = "0.8.2" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" 140 | 141 | [[package]] 142 | name = "crc32fast" 143 | version = "1.2.1" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 146 | dependencies = [ 147 | "cfg-if", 148 | ] 149 | 150 | [[package]] 151 | name = "darling" 152 | version = "0.12.4" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" 155 | dependencies = [ 156 | "darling_core", 157 | "darling_macro", 158 | ] 159 | 160 | [[package]] 161 | name = "darling_core" 162 | version = "0.12.4" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" 165 | dependencies = [ 166 | "fnv", 167 | "ident_case", 168 | "proc-macro2", 169 | "quote", 170 | "strsim", 171 | "syn", 172 | ] 173 | 174 | [[package]] 175 | name = "darling_macro" 176 | version = "0.12.4" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" 179 | dependencies = [ 180 | "darling_core", 181 | "quote", 182 | "syn", 183 | ] 184 | 185 | [[package]] 186 | name = "derive_builder" 187 | version = "0.10.2" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30" 190 | dependencies = [ 191 | "derive_builder_macro", 192 | ] 193 | 194 | [[package]] 195 | name = "derive_builder_core" 196 | version = "0.10.2" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" 199 | dependencies = [ 200 | "darling", 201 | "proc-macro2", 202 | "quote", 203 | "syn", 204 | ] 205 | 206 | [[package]] 207 | name = "derive_builder_macro" 208 | version = "0.10.2" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73" 211 | dependencies = [ 212 | "derive_builder_core", 213 | "syn", 214 | ] 215 | 216 | [[package]] 217 | name = "encoding_rs" 218 | version = "0.8.28" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" 221 | dependencies = [ 222 | "cfg-if", 223 | ] 224 | 225 | [[package]] 226 | name = "env_logger" 227 | version = "0.9.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 230 | dependencies = [ 231 | "atty", 232 | "humantime", 233 | "log", 234 | "regex", 235 | "termcolor", 236 | ] 237 | 238 | [[package]] 239 | name = "filetime" 240 | version = "0.2.15" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" 243 | dependencies = [ 244 | "cfg-if", 245 | "libc", 246 | "redox_syscall", 247 | "winapi", 248 | ] 249 | 250 | [[package]] 251 | name = "flate2" 252 | version = "1.0.22" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" 255 | dependencies = [ 256 | "cfg-if", 257 | "crc32fast", 258 | "libc", 259 | "miniz_oxide", 260 | ] 261 | 262 | [[package]] 263 | name = "fnv" 264 | version = "1.0.7" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 267 | 268 | [[package]] 269 | name = "foreign-types" 270 | version = "0.3.2" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 273 | dependencies = [ 274 | "foreign-types-shared", 275 | ] 276 | 277 | [[package]] 278 | name = "foreign-types-shared" 279 | version = "0.1.1" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 282 | 283 | [[package]] 284 | name = "form_urlencoded" 285 | version = "1.0.1" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 288 | dependencies = [ 289 | "matches", 290 | "percent-encoding", 291 | ] 292 | 293 | [[package]] 294 | name = "futures-channel" 295 | version = "0.3.17" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 298 | dependencies = [ 299 | "futures-core", 300 | ] 301 | 302 | [[package]] 303 | name = "futures-core" 304 | version = "0.3.17" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 307 | 308 | [[package]] 309 | name = "futures-sink" 310 | version = "0.3.17" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 313 | 314 | [[package]] 315 | name = "futures-task" 316 | version = "0.3.17" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 319 | 320 | [[package]] 321 | name = "futures-util" 322 | version = "0.3.17" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 325 | dependencies = [ 326 | "autocfg", 327 | "futures-core", 328 | "futures-task", 329 | "pin-project-lite", 330 | "pin-utils", 331 | ] 332 | 333 | [[package]] 334 | name = "getrandom" 335 | version = "0.2.3" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 338 | dependencies = [ 339 | "cfg-if", 340 | "libc", 341 | "wasi", 342 | ] 343 | 344 | [[package]] 345 | name = "getset" 346 | version = "0.1.1" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504" 349 | dependencies = [ 350 | "proc-macro-error", 351 | "proc-macro2", 352 | "quote", 353 | "syn", 354 | ] 355 | 356 | [[package]] 357 | name = "h2" 358 | version = "0.3.4" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" 361 | dependencies = [ 362 | "bytes", 363 | "fnv", 364 | "futures-core", 365 | "futures-sink", 366 | "futures-util", 367 | "http", 368 | "indexmap", 369 | "slab", 370 | "tokio", 371 | "tokio-util", 372 | "tracing", 373 | ] 374 | 375 | [[package]] 376 | name = "hashbrown" 377 | version = "0.11.2" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 380 | 381 | [[package]] 382 | name = "heck" 383 | version = "0.3.3" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 386 | dependencies = [ 387 | "unicode-segmentation", 388 | ] 389 | 390 | [[package]] 391 | name = "hermit-abi" 392 | version = "0.1.19" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 395 | dependencies = [ 396 | "libc", 397 | ] 398 | 399 | [[package]] 400 | name = "http" 401 | version = "0.2.4" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" 404 | dependencies = [ 405 | "bytes", 406 | "fnv", 407 | "itoa", 408 | ] 409 | 410 | [[package]] 411 | name = "http-body" 412 | version = "0.4.3" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" 415 | dependencies = [ 416 | "bytes", 417 | "http", 418 | "pin-project-lite", 419 | ] 420 | 421 | [[package]] 422 | name = "httparse" 423 | version = "1.5.1" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 426 | 427 | [[package]] 428 | name = "httpdate" 429 | version = "1.0.1" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" 432 | 433 | [[package]] 434 | name = "humantime" 435 | version = "2.1.0" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 438 | 439 | [[package]] 440 | name = "hyper" 441 | version = "0.14.12" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd" 444 | dependencies = [ 445 | "bytes", 446 | "futures-channel", 447 | "futures-core", 448 | "futures-util", 449 | "h2", 450 | "http", 451 | "http-body", 452 | "httparse", 453 | "httpdate", 454 | "itoa", 455 | "pin-project-lite", 456 | "socket2", 457 | "tokio", 458 | "tower-service", 459 | "tracing", 460 | "want", 461 | ] 462 | 463 | [[package]] 464 | name = "hyper-tls" 465 | version = "0.5.0" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 468 | dependencies = [ 469 | "bytes", 470 | "hyper", 471 | "native-tls", 472 | "tokio", 473 | "tokio-native-tls", 474 | ] 475 | 476 | [[package]] 477 | name = "ident_case" 478 | version = "1.0.1" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 481 | 482 | [[package]] 483 | name = "idna" 484 | version = "0.2.3" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 487 | dependencies = [ 488 | "matches", 489 | "unicode-bidi", 490 | "unicode-normalization", 491 | ] 492 | 493 | [[package]] 494 | name = "indexmap" 495 | version = "1.7.0" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 498 | dependencies = [ 499 | "autocfg", 500 | "hashbrown", 501 | ] 502 | 503 | [[package]] 504 | name = "instant" 505 | version = "0.1.10" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" 508 | dependencies = [ 509 | "cfg-if", 510 | ] 511 | 512 | [[package]] 513 | name = "io-uring" 514 | version = "0.5.2" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "8d75829ed9377bab6c90039fe47b9d84caceb4b5063266142e21bcce6550cda8" 517 | dependencies = [ 518 | "bitflags", 519 | "libc", 520 | ] 521 | 522 | [[package]] 523 | name = "ipnet" 524 | version = "2.3.1" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" 527 | 528 | [[package]] 529 | name = "itoa" 530 | version = "0.4.8" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 533 | 534 | [[package]] 535 | name = "js-sys" 536 | version = "0.3.55" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 539 | dependencies = [ 540 | "wasm-bindgen", 541 | ] 542 | 543 | [[package]] 544 | name = "lazy_static" 545 | version = "1.4.0" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 548 | 549 | [[package]] 550 | name = "libc" 551 | version = "0.2.102" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" 554 | 555 | [[package]] 556 | name = "linked-hash-map" 557 | version = "0.5.4" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" 560 | 561 | [[package]] 562 | name = "lock_api" 563 | version = "0.4.5" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 566 | dependencies = [ 567 | "scopeguard", 568 | ] 569 | 570 | [[package]] 571 | name = "log" 572 | version = "0.4.14" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 575 | dependencies = [ 576 | "cfg-if", 577 | ] 578 | 579 | [[package]] 580 | name = "matches" 581 | version = "0.1.9" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 584 | 585 | [[package]] 586 | name = "memchr" 587 | version = "2.4.1" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 590 | 591 | [[package]] 592 | name = "memoffset" 593 | version = "0.6.4" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" 596 | dependencies = [ 597 | "autocfg", 598 | ] 599 | 600 | [[package]] 601 | name = "mime" 602 | version = "0.3.16" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 605 | 606 | [[package]] 607 | name = "miniz_oxide" 608 | version = "0.4.4" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 611 | dependencies = [ 612 | "adler", 613 | "autocfg", 614 | ] 615 | 616 | [[package]] 617 | name = "mio" 618 | version = "0.7.13" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" 621 | dependencies = [ 622 | "libc", 623 | "log", 624 | "miow", 625 | "ntapi", 626 | "winapi", 627 | ] 628 | 629 | [[package]] 630 | name = "miow" 631 | version = "0.3.7" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 634 | dependencies = [ 635 | "winapi", 636 | ] 637 | 638 | [[package]] 639 | name = "moe_logger" 640 | version = "0.2.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "6ffe43bcf7a96f2c46ff5cf98000950bc6cf266a80c87783157d8446c3e45cf2" 643 | dependencies = [ 644 | "env_logger", 645 | "log", 646 | "serde", 647 | "tinytemplate", 648 | "tokio-uring", 649 | ] 650 | 651 | [[package]] 652 | name = "nanoid" 653 | version = "0.4.0" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" 656 | dependencies = [ 657 | "rand", 658 | ] 659 | 660 | [[package]] 661 | name = "native-tls" 662 | version = "0.2.8" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" 665 | dependencies = [ 666 | "lazy_static", 667 | "libc", 668 | "log", 669 | "openssl", 670 | "openssl-probe", 671 | "openssl-sys", 672 | "schannel", 673 | "security-framework", 674 | "security-framework-sys", 675 | "tempfile", 676 | ] 677 | 678 | [[package]] 679 | name = "nix" 680 | version = "0.20.1" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "df8e5e343312e7fbeb2a52139114e9e702991ef9c2aea6817ff2440b35647d56" 683 | dependencies = [ 684 | "bitflags", 685 | "cc", 686 | "cfg-if", 687 | "libc", 688 | "memoffset", 689 | ] 690 | 691 | [[package]] 692 | name = "ntapi" 693 | version = "0.3.6" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 696 | dependencies = [ 697 | "winapi", 698 | ] 699 | 700 | [[package]] 701 | name = "num_cpus" 702 | version = "1.13.0" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 705 | dependencies = [ 706 | "hermit-abi", 707 | "libc", 708 | ] 709 | 710 | [[package]] 711 | name = "oci-spec" 712 | version = "0.5.1" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "b33c04af97b8e9e3155d9c530a1260e7e6c8d36a1e7353e54f3aa013d388a0c7" 715 | dependencies = [ 716 | "derive_builder", 717 | "getset", 718 | "serde", 719 | "serde_json", 720 | "thiserror", 721 | ] 722 | 723 | [[package]] 724 | name = "once_cell" 725 | version = "1.8.0" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 728 | 729 | [[package]] 730 | name = "openssl" 731 | version = "0.10.36" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" 734 | dependencies = [ 735 | "bitflags", 736 | "cfg-if", 737 | "foreign-types", 738 | "libc", 739 | "once_cell", 740 | "openssl-sys", 741 | ] 742 | 743 | [[package]] 744 | name = "openssl-probe" 745 | version = "0.1.4" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" 748 | 749 | [[package]] 750 | name = "openssl-sys" 751 | version = "0.9.66" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" 754 | dependencies = [ 755 | "autocfg", 756 | "cc", 757 | "libc", 758 | "pkg-config", 759 | "vcpkg", 760 | ] 761 | 762 | [[package]] 763 | name = "os_str_bytes" 764 | version = "3.1.0" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" 767 | 768 | [[package]] 769 | name = "parking_lot" 770 | version = "0.11.2" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 773 | dependencies = [ 774 | "instant", 775 | "lock_api", 776 | "parking_lot_core", 777 | ] 778 | 779 | [[package]] 780 | name = "parking_lot_core" 781 | version = "0.8.5" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 784 | dependencies = [ 785 | "cfg-if", 786 | "instant", 787 | "libc", 788 | "redox_syscall", 789 | "smallvec", 790 | "winapi", 791 | ] 792 | 793 | [[package]] 794 | name = "percent-encoding" 795 | version = "2.1.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 798 | 799 | [[package]] 800 | name = "pin-project-lite" 801 | version = "0.2.7" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 804 | 805 | [[package]] 806 | name = "pin-utils" 807 | version = "0.1.0" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 810 | 811 | [[package]] 812 | name = "pkg-config" 813 | version = "0.3.19" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 816 | 817 | [[package]] 818 | name = "ppv-lite86" 819 | version = "0.2.10" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 822 | 823 | [[package]] 824 | name = "proc-macro-error" 825 | version = "1.0.4" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 828 | dependencies = [ 829 | "proc-macro-error-attr", 830 | "proc-macro2", 831 | "quote", 832 | "syn", 833 | "version_check", 834 | ] 835 | 836 | [[package]] 837 | name = "proc-macro-error-attr" 838 | version = "1.0.4" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 841 | dependencies = [ 842 | "proc-macro2", 843 | "quote", 844 | "version_check", 845 | ] 846 | 847 | [[package]] 848 | name = "proc-macro2" 849 | version = "1.0.29" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" 852 | dependencies = [ 853 | "unicode-xid", 854 | ] 855 | 856 | [[package]] 857 | name = "quote" 858 | version = "1.0.9" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 861 | dependencies = [ 862 | "proc-macro2", 863 | ] 864 | 865 | [[package]] 866 | name = "rand" 867 | version = "0.8.4" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 870 | dependencies = [ 871 | "libc", 872 | "rand_chacha", 873 | "rand_core", 874 | "rand_hc", 875 | ] 876 | 877 | [[package]] 878 | name = "rand_chacha" 879 | version = "0.3.1" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 882 | dependencies = [ 883 | "ppv-lite86", 884 | "rand_core", 885 | ] 886 | 887 | [[package]] 888 | name = "rand_core" 889 | version = "0.6.3" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 892 | dependencies = [ 893 | "getrandom", 894 | ] 895 | 896 | [[package]] 897 | name = "rand_hc" 898 | version = "0.3.1" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 901 | dependencies = [ 902 | "rand_core", 903 | ] 904 | 905 | [[package]] 906 | name = "redox_syscall" 907 | version = "0.2.10" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 910 | dependencies = [ 911 | "bitflags", 912 | ] 913 | 914 | [[package]] 915 | name = "regex" 916 | version = "1.5.4" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 919 | dependencies = [ 920 | "aho-corasick", 921 | "memchr", 922 | "regex-syntax", 923 | ] 924 | 925 | [[package]] 926 | name = "regex-syntax" 927 | version = "0.6.25" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 930 | 931 | [[package]] 932 | name = "remove_dir_all" 933 | version = "0.5.3" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 936 | dependencies = [ 937 | "winapi", 938 | ] 939 | 940 | [[package]] 941 | name = "reqwest" 942 | version = "0.11.4" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" 945 | dependencies = [ 946 | "base64", 947 | "bytes", 948 | "encoding_rs", 949 | "futures-core", 950 | "futures-util", 951 | "http", 952 | "http-body", 953 | "hyper", 954 | "hyper-tls", 955 | "ipnet", 956 | "js-sys", 957 | "lazy_static", 958 | "log", 959 | "mime", 960 | "native-tls", 961 | "percent-encoding", 962 | "pin-project-lite", 963 | "serde", 964 | "serde_json", 965 | "serde_urlencoded", 966 | "tokio", 967 | "tokio-native-tls", 968 | "url", 969 | "wasm-bindgen", 970 | "wasm-bindgen-futures", 971 | "web-sys", 972 | "winreg", 973 | ] 974 | 975 | [[package]] 976 | name = "ryu" 977 | version = "1.0.5" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 980 | 981 | [[package]] 982 | name = "schannel" 983 | version = "0.1.19" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 986 | dependencies = [ 987 | "lazy_static", 988 | "winapi", 989 | ] 990 | 991 | [[package]] 992 | name = "scoped-tls" 993 | version = "1.0.0" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 996 | 997 | [[package]] 998 | name = "scopeguard" 999 | version = "1.1.0" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1002 | 1003 | [[package]] 1004 | name = "security-framework" 1005 | version = "2.3.1" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" 1008 | dependencies = [ 1009 | "bitflags", 1010 | "core-foundation", 1011 | "core-foundation-sys", 1012 | "libc", 1013 | "security-framework-sys", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "security-framework-sys" 1018 | version = "2.4.2" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" 1021 | dependencies = [ 1022 | "core-foundation-sys", 1023 | "libc", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "serde" 1028 | version = "1.0.130" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 1031 | dependencies = [ 1032 | "serde_derive", 1033 | ] 1034 | 1035 | [[package]] 1036 | name = "serde_derive" 1037 | version = "1.0.130" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 1040 | dependencies = [ 1041 | "proc-macro2", 1042 | "quote", 1043 | "syn", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "serde_json" 1048 | version = "1.0.68" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" 1051 | dependencies = [ 1052 | "itoa", 1053 | "ryu", 1054 | "serde", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "serde_urlencoded" 1059 | version = "0.7.0" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 1062 | dependencies = [ 1063 | "form_urlencoded", 1064 | "itoa", 1065 | "ryu", 1066 | "serde", 1067 | ] 1068 | 1069 | [[package]] 1070 | name = "shallow-container" 1071 | version = "0.1.0" 1072 | dependencies = [ 1073 | "clap", 1074 | "flate2", 1075 | "log", 1076 | "moe_logger", 1077 | "nanoid", 1078 | "oci-spec", 1079 | "reqwest", 1080 | "serde", 1081 | "serde_json", 1082 | "sscanf", 1083 | "tar", 1084 | "tokio", 1085 | "unshare", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "signal-hook-registry" 1090 | version = "1.4.0" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1093 | dependencies = [ 1094 | "libc", 1095 | ] 1096 | 1097 | [[package]] 1098 | name = "slab" 1099 | version = "0.4.4" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" 1102 | 1103 | [[package]] 1104 | name = "smallvec" 1105 | version = "1.6.1" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 1108 | 1109 | [[package]] 1110 | name = "socket2" 1111 | version = "0.4.2" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 1114 | dependencies = [ 1115 | "libc", 1116 | "winapi", 1117 | ] 1118 | 1119 | [[package]] 1120 | name = "sscanf" 1121 | version = "0.1.3" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "a812bcc6cd3cb6f4832fd68dfd2ce835901ddd592d181b5e5a63f8e1d66257ec" 1124 | dependencies = [ 1125 | "const_format", 1126 | "lazy_static", 1127 | "regex", 1128 | "sscanf_macro", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "sscanf_macro" 1133 | version = "0.1.3" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "b7462034123ad94cc80b60b48d262e622e3689ab25e53ab7a1b8e05c89b98c65" 1136 | dependencies = [ 1137 | "proc-macro2", 1138 | "quote", 1139 | "regex-syntax", 1140 | "syn", 1141 | ] 1142 | 1143 | [[package]] 1144 | name = "strsim" 1145 | version = "0.10.0" 1146 | source = "registry+https://github.com/rust-lang/crates.io-index" 1147 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1148 | 1149 | [[package]] 1150 | name = "syn" 1151 | version = "1.0.76" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" 1154 | dependencies = [ 1155 | "proc-macro2", 1156 | "quote", 1157 | "unicode-xid", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "tar" 1162 | version = "0.4.37" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c" 1165 | dependencies = [ 1166 | "filetime", 1167 | "libc", 1168 | "xattr", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "tempfile" 1173 | version = "3.2.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1176 | dependencies = [ 1177 | "cfg-if", 1178 | "libc", 1179 | "rand", 1180 | "redox_syscall", 1181 | "remove_dir_all", 1182 | "winapi", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "termcolor" 1187 | version = "1.1.2" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1190 | dependencies = [ 1191 | "winapi-util", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "textwrap" 1196 | version = "0.14.2" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 1199 | dependencies = [ 1200 | "unicode-width", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "thiserror" 1205 | version = "1.0.29" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" 1208 | dependencies = [ 1209 | "thiserror-impl", 1210 | ] 1211 | 1212 | [[package]] 1213 | name = "thiserror-impl" 1214 | version = "1.0.29" 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" 1216 | checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" 1217 | dependencies = [ 1218 | "proc-macro2", 1219 | "quote", 1220 | "syn", 1221 | ] 1222 | 1223 | [[package]] 1224 | name = "tinytemplate" 1225 | version = "1.2.1" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 1228 | dependencies = [ 1229 | "serde", 1230 | "serde_json", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "tinyvec" 1235 | version = "1.4.0" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986" 1238 | dependencies = [ 1239 | "tinyvec_macros", 1240 | ] 1241 | 1242 | [[package]] 1243 | name = "tinyvec_macros" 1244 | version = "0.1.0" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1247 | 1248 | [[package]] 1249 | name = "tokio" 1250 | version = "1.11.0" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" 1253 | dependencies = [ 1254 | "autocfg", 1255 | "bytes", 1256 | "libc", 1257 | "memchr", 1258 | "mio", 1259 | "num_cpus", 1260 | "once_cell", 1261 | "parking_lot", 1262 | "pin-project-lite", 1263 | "signal-hook-registry", 1264 | "tokio-macros", 1265 | "winapi", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "tokio-macros" 1270 | version = "1.3.0" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" 1273 | dependencies = [ 1274 | "proc-macro2", 1275 | "quote", 1276 | "syn", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "tokio-native-tls" 1281 | version = "0.3.0" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1284 | dependencies = [ 1285 | "native-tls", 1286 | "tokio", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "tokio-uring" 1291 | version = "0.1.0" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "09f54af096a39b937631659f1a5da60ab7c1af334025c33b87ed913072c3c8a9" 1294 | dependencies = [ 1295 | "io-uring", 1296 | "libc", 1297 | "scoped-tls", 1298 | "slab", 1299 | "tokio", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "tokio-util" 1304 | version = "0.6.8" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" 1307 | dependencies = [ 1308 | "bytes", 1309 | "futures-core", 1310 | "futures-sink", 1311 | "log", 1312 | "pin-project-lite", 1313 | "tokio", 1314 | ] 1315 | 1316 | [[package]] 1317 | name = "tower-service" 1318 | version = "0.3.1" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1321 | 1322 | [[package]] 1323 | name = "tracing" 1324 | version = "0.1.27" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "c2ba9ab62b7d6497a8638dfda5e5c4fb3b2d5a7fca4118f2b96151c8ef1a437e" 1327 | dependencies = [ 1328 | "cfg-if", 1329 | "pin-project-lite", 1330 | "tracing-core", 1331 | ] 1332 | 1333 | [[package]] 1334 | name = "tracing-core" 1335 | version = "0.1.20" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf" 1338 | dependencies = [ 1339 | "lazy_static", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "try-lock" 1344 | version = "0.2.3" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1347 | 1348 | [[package]] 1349 | name = "unicode-bidi" 1350 | version = "0.3.6" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" 1353 | 1354 | [[package]] 1355 | name = "unicode-normalization" 1356 | version = "0.1.19" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 1359 | dependencies = [ 1360 | "tinyvec", 1361 | ] 1362 | 1363 | [[package]] 1364 | name = "unicode-segmentation" 1365 | version = "1.8.0" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1368 | 1369 | [[package]] 1370 | name = "unicode-width" 1371 | version = "0.1.8" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 1374 | 1375 | [[package]] 1376 | name = "unicode-xid" 1377 | version = "0.2.2" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1380 | 1381 | [[package]] 1382 | name = "unshare" 1383 | version = "0.7.0" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "1ceda295552a1eda89f8a748237654ad76b9c87e383fc07af5c4e423eb8e7b9b" 1386 | dependencies = [ 1387 | "libc", 1388 | "nix", 1389 | ] 1390 | 1391 | [[package]] 1392 | name = "url" 1393 | version = "2.2.2" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1396 | dependencies = [ 1397 | "form_urlencoded", 1398 | "idna", 1399 | "matches", 1400 | "percent-encoding", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "vcpkg" 1405 | version = "0.2.15" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1408 | 1409 | [[package]] 1410 | name = "vec_map" 1411 | version = "0.8.2" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1414 | 1415 | [[package]] 1416 | name = "version_check" 1417 | version = "0.9.3" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1420 | 1421 | [[package]] 1422 | name = "want" 1423 | version = "0.3.0" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1426 | dependencies = [ 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 = "wasm-bindgen" 1439 | version = "0.2.78" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 1442 | dependencies = [ 1443 | "cfg-if", 1444 | "serde", 1445 | "serde_json", 1446 | "wasm-bindgen-macro", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "wasm-bindgen-backend" 1451 | version = "0.2.78" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 1454 | dependencies = [ 1455 | "bumpalo", 1456 | "lazy_static", 1457 | "log", 1458 | "proc-macro2", 1459 | "quote", 1460 | "syn", 1461 | "wasm-bindgen-shared", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "wasm-bindgen-futures" 1466 | version = "0.4.28" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" 1469 | dependencies = [ 1470 | "cfg-if", 1471 | "js-sys", 1472 | "wasm-bindgen", 1473 | "web-sys", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "wasm-bindgen-macro" 1478 | version = "0.2.78" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 1481 | dependencies = [ 1482 | "quote", 1483 | "wasm-bindgen-macro-support", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "wasm-bindgen-macro-support" 1488 | version = "0.2.78" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 1491 | dependencies = [ 1492 | "proc-macro2", 1493 | "quote", 1494 | "syn", 1495 | "wasm-bindgen-backend", 1496 | "wasm-bindgen-shared", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "wasm-bindgen-shared" 1501 | version = "0.2.78" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 1504 | 1505 | [[package]] 1506 | name = "web-sys" 1507 | version = "0.3.55" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 1510 | dependencies = [ 1511 | "js-sys", 1512 | "wasm-bindgen", 1513 | ] 1514 | 1515 | [[package]] 1516 | name = "winapi" 1517 | version = "0.3.9" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1520 | dependencies = [ 1521 | "winapi-i686-pc-windows-gnu", 1522 | "winapi-x86_64-pc-windows-gnu", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "winapi-i686-pc-windows-gnu" 1527 | version = "0.4.0" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1530 | 1531 | [[package]] 1532 | name = "winapi-util" 1533 | version = "0.1.5" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1536 | dependencies = [ 1537 | "winapi", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "winapi-x86_64-pc-windows-gnu" 1542 | version = "0.4.0" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1545 | 1546 | [[package]] 1547 | name = "winreg" 1548 | version = "0.7.0" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 1551 | dependencies = [ 1552 | "winapi", 1553 | ] 1554 | 1555 | [[package]] 1556 | name = "xattr" 1557 | version = "0.2.2" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" 1560 | dependencies = [ 1561 | "libc", 1562 | ] 1563 | 1564 | [[package]] 1565 | name = "yaml-rust" 1566 | version = "0.4.5" 1567 | source = "registry+https://github.com/rust-lang/crates.io-index" 1568 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 1569 | dependencies = [ 1570 | "linked-hash-map", 1571 | ] 1572 | --------------------------------------------------------------------------------