├── .gitignore ├── doc ├── demo.png └── architecture.png ├── src ├── git.rs ├── git │ ├── gitter.rs │ └── commit_object.rs ├── settings.rs ├── external_command.rs └── main.rs ├── Cargo.toml ├── LICENSE ├── .github └── workflows │ └── ci.yml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /doc/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rnitta/commit_artist/HEAD/doc/demo.png -------------------------------------------------------------------------------- /doc/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rnitta/commit_artist/HEAD/doc/architecture.png -------------------------------------------------------------------------------- /src/git.rs: -------------------------------------------------------------------------------- 1 | pub mod commit_object; 2 | pub mod gitter; 3 | 4 | pub use self::commit_object::CommitObject; 5 | pub use self::gitter::Gitter; 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "commit_artist" 3 | version = "1.0.1" 4 | authors = ["rnitta "] 5 | description = "Git Commit Hash Beautifier" 6 | edition = "2018" 7 | keywords = ["git", "cli"] 8 | repository = "https://github.com/rnitta/commit_artist" 9 | readme = "README.md" 10 | license = "MIT" 11 | categories = ["command-line-interface"] 12 | include = [ 13 | "src/**/*", 14 | "Cargo.toml", 15 | "README.md" 16 | ] 17 | 18 | [features] 19 | 20 | [dependencies] 21 | rust-crypto = "^0.2" 22 | rand ="0.7.3" 23 | regex = "^1.3" 24 | num_cpus = "1.0" 25 | seahorse = "^1.0.0" 26 | 27 | [profile.release] 28 | opt-level = 3 29 | codegen-units = 1 30 | debug = false 31 | rpath = false 32 | lto = false 33 | debug-assertions = false 34 | overflow-checks = false 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 rnitta 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 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | name: Test 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | build: [stable, beta, nightly, macos, msrv] 15 | include: 16 | - build: stable 17 | os: ubuntu-latest 18 | rust: stable 19 | allow_failure: false 20 | - build: beta 21 | os: ubuntu-latest 22 | rust: beta 23 | allow_failure: false 24 | - build: nightly 25 | os: ubuntu-latest 26 | rust: nightly 27 | allow_failure: true 28 | - build: macos 29 | os: macos-latest 30 | rust: stable 31 | allow_failure: false 32 | - build: msrv 33 | os: ubuntu-latest 34 | rust: 1.35.0 35 | allow_failure: false 36 | steps: 37 | - uses: actions/checkout@master 38 | - name: Install Rust 39 | run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} 40 | - name: Build and run tests 41 | run: cargo test 42 | continue-on-error: ${{ matrix.allow_failure }} 43 | 44 | rustfmt: 45 | name: Rustfmt 46 | runs-on: ubuntu-latest 47 | steps: 48 | - uses: actions/checkout@master 49 | - name: Install Rust 50 | run: rustup update stable && rustup default stable && rustup component add rustfmt 51 | - run: cargo fmt -- --check -------------------------------------------------------------------------------- /src/git/gitter.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | 3 | #[derive(Clone)] 4 | pub struct Gitter { 5 | pub name: String, 6 | pub email_user: String, 7 | pub email_domain: String, 8 | pub time: String, 9 | } 10 | 11 | impl std::fmt::Display for Gitter { 12 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 13 | write!( 14 | f, 15 | "{} <{}@{}> {}", 16 | self.name, self.email_user, self.email_domain, self.time 17 | ) 18 | } 19 | } 20 | 21 | impl Gitter { 22 | pub fn parse(line: &str) -> Self { 23 | let regx = Regex::new(r"^(.+?) <(\S+?)@(\S+?)> (.+)$").unwrap(); 24 | let captures = regx.captures(line).expect("Error: unparsable"); 25 | 26 | let name: String = captures 27 | .get(1) 28 | .expect("Error in Getting Name") 29 | .as_str() 30 | .to_owned(); 31 | let email_user: String = captures 32 | .get(2) 33 | .expect("Error in Getting EmailUser") 34 | .as_str() 35 | .to_owned(); 36 | let email_domain: String = captures 37 | .get(3) 38 | .expect("Error in Getting EmailDomain") 39 | .as_str() 40 | .to_owned(); 41 | let time: String = captures 42 | .get(4) 43 | .expect("Error in Getting Time") 44 | .as_str() 45 | .to_owned(); 46 | 47 | Self { 48 | name, 49 | email_user, 50 | email_domain, 51 | time, 52 | } 53 | } 54 | 55 | // rnitta 1571472461 +0900 56 | pub fn bytes(&self) -> usize { 57 | self.name.len() 58 | + 2 // " <" 59 | + self.email_user.len() 60 | + 1 // "@" 61 | + self.email_domain.len() 62 | + 2 // "> " 63 | + self.time.len() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![crates.io](https://img.shields.io/crates/v/commit_artist.svg) 2 | ![license](https://img.shields.io/github/license/ksk001100/seahorse.svg) 3 | ![CI](https://github.com/rnitta/commit_artist/workflows/CI/badge.svg) 4 | 5 | # Commit Artist 6 | 7 | A CLI tool to beautify latest commit of your git repository. 8 | 9 | ![DEMO](./doc/demo.png) 10 | 11 | ## Usage 12 | 13 | ### Install Commit Artist 14 | 15 | ```shell 16 | $ cargo install commit_artist 17 | 18 | $ cd 19 | 20 | $ git log -1 --format=%H 21 | 86637c3f206d228df1dc1dafa49d31b159b8a358 22 | 23 | $ commit_artist -p 1234567 24 | 173015040 hashes calculated... 25 | Yay! Now your new hash of the latest commit is 12345672abd92a159f3886e08951f29ee7ce0041. 26 | 27 | $ git log -1 --format=%H 28 | 12345672abd92a159f3886e08951f29ee7ce0041 29 | ``` 30 | 31 | ### Command Line Options 32 | 33 | - [--path] Path to working directory. default: current directory 34 | - [--pattern, -p] Pattern to match. default: 0000000 35 | - [--block, -b] log\[2\](how many hashes should be calculated in each thread). default: 20 36 | - [--jobs, -j] the number of threads that will be spawned to bruteforce. default: your max - 1 37 | 38 | ## How it works 39 | ![architecture](./doc/architecture.png) 40 | 41 | A commit hash of git is generated from commit object. 42 | Commit object consists of 43 | 44 | - Tree hash 45 | - Parent hash 46 | - Author 47 | - Name 48 | - Email address 49 | - Timestamp 50 | - Committer 51 | - Name 52 | - Email address 53 | - Timestamp 54 | - Commit message 55 | 56 | One of the easiest thing to configure (even after the commit is done) among these attributes above is committer's name. 57 | Changing it may affect almost nothing but commit hash. 58 | 59 | So, after a commit is done, by running Commit Artist, through changing committer's name and calculating commit hash and loop back unless it is beautiful, finally you can get a commit which have sophisticated hash. 60 | 61 | ## Disclaimer 62 | Use this tool on your own responsibility. 63 | This tool is absolutely helpless with [signed commit](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work). -------------------------------------------------------------------------------- /src/settings.rs: -------------------------------------------------------------------------------- 1 | use crate::command; 2 | use num_cpus; 3 | use regex::Regex; 4 | 5 | #[derive(Clone)] 6 | pub struct Settings { 7 | pub path: String, 8 | pub pattern: String, 9 | pub block_size: usize, 10 | pub jobs: usize, 11 | } 12 | 13 | impl Settings { 14 | /// 15 | /// Construct. 16 | /// 17 | /// # Panics 18 | /// pattern chars length should be 1..=40 19 | /// jobs should be more than 0 20 | /// block size should be less than 64. 21 | /// 22 | pub fn new>(path: T, pattern: T, block_size: usize, jobs: usize) -> Self { 23 | let pattern: String = pattern.into(); 24 | let regx = Regex::new(r"^[0-9a-f]{1,40}$").unwrap(); 25 | assert!(regx.is_match(&pattern)); 26 | assert!(jobs > 0); 27 | assert!(block_size < 64); 28 | Self { 29 | path: path.into(), 30 | pattern, 31 | block_size, 32 | jobs, 33 | } 34 | } 35 | 36 | pub fn pattern>(&mut self, pattern: T) { 37 | let pattern: String = pattern.into(); 38 | let regx = Regex::new(r"^[0-9a-f]{1,40}$").unwrap(); 39 | assert!(regx.is_match(&pattern)); 40 | self.pattern = pattern; 41 | } 42 | 43 | pub fn jobs(&mut self, jobs: usize) { 44 | assert!(jobs > 0); 45 | self.jobs = jobs; 46 | } 47 | 48 | pub fn block_size(&mut self, block_size: usize) { 49 | assert!(block_size < 64); 50 | self.block_size = block_size; 51 | } 52 | } 53 | 54 | impl Default for Settings { 55 | fn default() -> Self { 56 | let path: String = command::current_dir_path(); 57 | let num = num_cpus::get(); 58 | Self::new(path, "0000000".to_owned(), 20, num - 1) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | use super::Settings; 65 | 66 | #[test] 67 | fn settings_constructor() { 68 | Settings::new("./", "0000000", 20, 10); 69 | } 70 | 71 | #[test] 72 | #[should_panic] 73 | fn nonnominal_settings1() { 74 | Settings::new("./", "invalidpattern", 20, 10); 75 | } 76 | 77 | #[test] 78 | #[should_panic] 79 | fn nonnominal_settings2() { 80 | Settings::new("./", "0000000", 1000, 10); 81 | } 82 | 83 | #[test] 84 | #[should_panic] 85 | fn nonnominal_settings3() { 86 | Settings::new("./", "0000000", 1000, 0); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/external_command.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::process::Command; 3 | 4 | /// Check if `git` command exists in your environment 5 | pub fn check() -> Result { 6 | Command::new("git").output() 7 | } 8 | 9 | /// Check if there are unstaged changes 10 | pub fn check_unstaged() -> bool { 11 | String::from_utf8( 12 | Command::new("git") 13 | .args(&["status", "-s"]) 14 | .output() 15 | .expect("Error in checking git status") 16 | .stdout, 17 | ) 18 | .expect("Error in getting output") 19 | .is_empty() 20 | } 21 | 22 | /// Get current working directory path string 23 | pub fn current_dir_path() -> String { 24 | env::current_dir().unwrap().to_str().unwrap().to_owned() 25 | } 26 | 27 | /// Get latest commit hash string by using `git log` 28 | pub fn latest_commit_hash(path: &str) -> String { 29 | String::from_utf8( 30 | Command::new("git") 31 | .args(vec!["-C", &path, "log", "-1", "--format=%H"]) 32 | .output() 33 | .unwrap_or_else(|_| { 34 | panic!(format!( 35 | "Error in executing `git -C {} log` -1 --format=%H", 36 | path 37 | )) 38 | }) 39 | .stdout, 40 | ) 41 | .expect("Error in getting output") 42 | .trim_end() 43 | .to_owned() 44 | } 45 | 46 | /// Get commit object file content using `git cat-file -p ` 47 | pub fn cat_file(path: &str, hash: &str) -> String { 48 | String::from_utf8( 49 | Command::new("git") 50 | .args(vec!["-C", &path, "cat-file", "-p", hash]) 51 | .output() 52 | .unwrap_or_else(|_| { 53 | panic!(format!( 54 | "Erorr in executing `git -C {} cat-file -p {}`", 55 | path, hash 56 | )) 57 | }) 58 | .stdout, 59 | ) 60 | .expect("Error in getting output") 61 | } 62 | 63 | /// Change committer name of the commit whose hash is specified. 64 | pub fn filter_branch(path: &str, latest_commit_hash: &str, committer_name: &str) { 65 | Command::new("git") 66 | .args(&[ 67 | "-C", 68 | path, 69 | "filter-branch", 70 | "-f", 71 | "--env-filter", 72 | &format!( 73 | r#"if [ "$GIT_COMMIT" = '{}' ]; then export GIT_COMMITTER_NAME='{}'; fi"#, 74 | latest_commit_hash, committer_name 75 | ), 76 | "HEAD^..HEAD", // "HEAD", 77 | ]) 78 | .output() 79 | .expect("err"); 80 | } 81 | -------------------------------------------------------------------------------- /src/git/commit_object.rs: -------------------------------------------------------------------------------- 1 | use super::Gitter; 2 | use crypto::{digest::Digest, sha1::Sha1}; 3 | use regex::Regex; 4 | 5 | #[derive(Clone)] 6 | pub struct CommitObject { 7 | pub tree: String, 8 | pub parent: Option, 9 | pub author: Gitter, 10 | pub committer: Gitter, 11 | pub message: String, 12 | } 13 | 14 | impl std::fmt::Display for CommitObject { 15 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 16 | match self.parent { 17 | Some(_) => write!( 18 | f, 19 | "tree {}\nparent {}\nauthor {}\ncommitter {}\n\n{}", 20 | self.tree, 21 | self.parent.clone().unwrap(), 22 | self.author, 23 | self.committer, 24 | self.message 25 | ), 26 | None => write!( 27 | f, 28 | "tree {}\nauthor {}\ncommitter {}\n\n{}", 29 | self.tree, self.author, self.committer, self.message 30 | ), 31 | } 32 | } 33 | } 34 | 35 | impl CommitObject { 36 | /// Construct from cat_file output string. 37 | pub fn parse_cat_file(s: &str) -> Self { 38 | let regx = Regex::new( 39 | r"^tree ([0-9a-f]{40})\r?\n(?:parent ([0-9a-f]{40})\r?\n)?author (.+?)\r?\ncommitter (.+?)\r?\n\r?\n([\s\S]+)", 40 | ) 41 | .unwrap(); 42 | let captures = regx 43 | .captures(s) 44 | .expect("Error: Commit Object Cannot Be Interpreted"); 45 | let tree: String = captures 46 | .get(1) 47 | .expect("Error in Getting Tree Hash.") 48 | .as_str() 49 | .to_owned(); 50 | let parent: Option = captures.get(2).map(|v| v.as_str().to_owned()); 51 | let author: Gitter = { 52 | let author: &str = captures.get(3).expect("Error in Getting Author").as_str(); 53 | Gitter::parse(author) 54 | }; 55 | let committer: Gitter = { 56 | let committer: &str = captures 57 | .get(4) 58 | .expect("Error in Getting Committer") 59 | .as_str(); 60 | Gitter::parse(committer) 61 | }; 62 | let message: String = captures 63 | .get(5) 64 | .expect("Error in Getting Message.") 65 | .as_str() 66 | .to_owned(); 67 | 68 | Self { 69 | tree, 70 | parent, 71 | author, 72 | committer, 73 | message, 74 | } 75 | } 76 | 77 | /// The size of commit object; not structure object's size 78 | pub fn bytes(&self) -> usize { 79 | let mut byte_count: usize = 5 // "tree " 80 | + self.tree.len() 81 | + 1 // "\n" 82 | + 7 // "author " 83 | + self.author.bytes() 84 | + 1 // "\n" 85 | + 10 // "committer " 86 | + self.committer.bytes() 87 | + 1 // "\n" 88 | + 1 // "\n" 89 | + self.message.len(); 90 | 91 | if self.parent.is_some() { 92 | byte_count = byte_count + 7 // "parent " 93 | + self.parent.as_ref().map(|p| p.len()).unwrap() + 1; // "\n" 94 | } 95 | byte_count 96 | } 97 | 98 | /// Calculate commit hash 99 | pub fn to_sha1(&self, hasher: &mut Sha1) -> String { 100 | hasher.input_str(&format!("commit {}\0{}", self.bytes(), self)); 101 | let r = hasher.result_str(); 102 | hasher.reset(); 103 | r 104 | } 105 | } 106 | 107 | // TODO: tests 108 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod external_command; 2 | mod git; 3 | mod settings; 4 | 5 | use crate::external_command as command; 6 | use crate::git::commit_object::CommitObject; 7 | use crate::settings::Settings; 8 | use crypto::sha1::Sha1; 9 | use seahorse::{App, Context, Flag, FlagType}; 10 | use std::env; 11 | use std::sync::mpsc::channel; 12 | use std::thread; 13 | 14 | fn main() { 15 | let args: Vec = env::args().collect(); 16 | let app = App::new("Commit Artist") 17 | .author(env!("CARGO_PKG_AUTHORS")) 18 | .description(env!("CARGO_PKG_DESCRIPTION")) 19 | .version(env!("CARGO_PKG_VERSION")) 20 | .usage("commit_artist ") 21 | .flag( 22 | Flag::new("path", FlagType::String) 23 | .usage("[optional] --path "), 24 | ) 25 | .flag( 26 | Flag::new("pattern", FlagType::String) 27 | .usage("[optional] --pattern <[0-9a-f]{1,40}>") 28 | .alias("p"), 29 | ) 30 | .flag( 31 | Flag::new("block", FlagType::Int) 32 | .usage("[optional] --block 28") 33 | .alias("b"), 34 | ) 35 | .flag( 36 | Flag::new("jobs", FlagType::Int) 37 | .usage("[optional] --jobs 4") 38 | .alias("j"), 39 | ) 40 | .action(art); 41 | 42 | app.run(args); 43 | } 44 | 45 | /// as you see 46 | fn art(c: &Context) { 47 | let mut settings = Settings::default(); 48 | 49 | if let Ok(path) = c.string_flag("path") { 50 | settings.path = path; 51 | } 52 | 53 | if let Ok(pattern) = c.string_flag("pattern") { 54 | settings.pattern(pattern); 55 | } 56 | 57 | if let Ok(block) = c.int_flag("block") { 58 | settings.block_size(block as usize); 59 | } 60 | 61 | if let Ok(jobs) = c.int_flag("jobs") { 62 | settings.jobs(jobs as usize); 63 | } 64 | 65 | if command::check().is_err() { 66 | println!("git command not found"); 67 | return; 68 | } 69 | 70 | if !command::check_unstaged() { 71 | println!( 72 | "There are unstages changes. You should stash or discard them before running this." 73 | ); 74 | return; 75 | } 76 | 77 | let latest_commit_hash = command::latest_commit_hash(&settings.path); 78 | if latest_commit_hash.is_empty() { 79 | println!("No Commits are Detected."); 80 | return; 81 | } 82 | 83 | let latest_cat_file: String = command::cat_file(&settings.path, &latest_commit_hash); 84 | let co = CommitObject::parse_cat_file(&latest_cat_file); 85 | let new_committer_name = bruteforce(settings.clone(), &co, settings.jobs); 86 | command::filter_branch(&settings.path, &latest_commit_hash, &new_committer_name); 87 | let latest_commit_hash = command::latest_commit_hash(&settings.path); 88 | println!( 89 | "Yay! Now your new hash of the latest commit is \x1b[31m{}\x1b[m.", 90 | latest_commit_hash 91 | ); 92 | } 93 | 94 | /// Spawn bruteforce thread and catch the result and check it and loop back unless there are no expected result. 95 | fn bruteforce(settings: Settings, commit_object: &CommitObject, job_count: usize) -> String { 96 | let mut found_hash: String = "".to_owned(); 97 | let mut iteration_count = 0; 98 | let (tx, rx) = channel(); 99 | println!(); 100 | 101 | while found_hash.is_empty() { 102 | for i in 0..job_count { 103 | let settings: Settings = settings.clone(); 104 | let tx = tx.clone(); 105 | let mut co = commit_object.clone(); 106 | 107 | thread::spawn(move || { 108 | let mut hasher = Sha1::new(); 109 | co.committer = { 110 | let mut committer = co.committer; 111 | committer 112 | .name 113 | .push_str(&(iteration_count * job_count + i).to_string()); 114 | committer 115 | }; 116 | co.to_sha1(&mut hasher); 117 | let mut commit_hash = co.to_sha1(&mut hasher); 118 | 119 | for _ in 0..1u64 << settings.block_size { 120 | co.committer.name = commit_hash.clone(); 121 | let pre = commit_hash.clone(); 122 | commit_hash = co.to_sha1(&mut hasher); 123 | if commit_hash.starts_with(&settings.pattern) { 124 | tx.send(Some(pre)).unwrap(); 125 | return; 126 | } 127 | } 128 | tx.send(None).unwrap(); 129 | }); 130 | } 131 | for _ in 0..job_count { 132 | let r = rx.recv().unwrap(); 133 | if let Some(r) = r { 134 | found_hash = r; 135 | } 136 | } 137 | iteration_count += 1; 138 | println!( 139 | "\x1b[1A{} hashes calculated...", 140 | iteration_count as u128 * (1 << settings.block_size) as u128 * settings.jobs as u128 141 | ); 142 | } 143 | found_hash 144 | } 145 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.8" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "c2-chacha" 13 | version = "0.2.3" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "cfg-if" 21 | version = "0.1.10" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | 24 | [[package]] 25 | name = "commit_artist" 26 | version = "1.0.1" 27 | dependencies = [ 28 | "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 30 | "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 31 | "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", 32 | "seahorse 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "fuchsia-cprng" 37 | version = "0.1.1" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | 40 | [[package]] 41 | name = "gcc" 42 | version = "0.3.55" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | 45 | [[package]] 46 | name = "getrandom" 47 | version = "0.1.14" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | dependencies = [ 50 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", 53 | ] 54 | 55 | [[package]] 56 | name = "hermit-abi" 57 | version = "0.1.7" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | dependencies = [ 60 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 61 | ] 62 | 63 | [[package]] 64 | name = "lazy_static" 65 | version = "1.4.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | 68 | [[package]] 69 | name = "libc" 70 | version = "0.2.66" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [[package]] 74 | name = "memchr" 75 | version = "2.3.2" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | 78 | [[package]] 79 | name = "num_cpus" 80 | version = "1.12.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | dependencies = [ 83 | "hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 84 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 85 | ] 86 | 87 | [[package]] 88 | name = "ppv-lite86" 89 | version = "0.2.6" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | 92 | [[package]] 93 | name = "rand" 94 | version = "0.3.23" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | dependencies = [ 97 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 98 | "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 99 | ] 100 | 101 | [[package]] 102 | name = "rand" 103 | version = "0.4.6" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | dependencies = [ 106 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 107 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 108 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 111 | ] 112 | 113 | [[package]] 114 | name = "rand" 115 | version = "0.7.3" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | dependencies = [ 118 | "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 121 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 122 | "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 123 | ] 124 | 125 | [[package]] 126 | name = "rand_chacha" 127 | version = "0.2.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | dependencies = [ 130 | "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 132 | ] 133 | 134 | [[package]] 135 | name = "rand_core" 136 | version = "0.3.1" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | dependencies = [ 139 | "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 140 | ] 141 | 142 | [[package]] 143 | name = "rand_core" 144 | version = "0.4.2" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | 147 | [[package]] 148 | name = "rand_core" 149 | version = "0.5.1" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | dependencies = [ 152 | "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 153 | ] 154 | 155 | [[package]] 156 | name = "rand_hc" 157 | version = "0.2.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | dependencies = [ 160 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 161 | ] 162 | 163 | [[package]] 164 | name = "rdrand" 165 | version = "0.4.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | dependencies = [ 168 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 169 | ] 170 | 171 | [[package]] 172 | name = "redox_syscall" 173 | version = "0.1.56" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | 176 | [[package]] 177 | name = "regex" 178 | version = "1.3.4" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | dependencies = [ 181 | "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", 182 | "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 183 | "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", 184 | "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 185 | ] 186 | 187 | [[package]] 188 | name = "regex-syntax" 189 | version = "0.6.14" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | 192 | [[package]] 193 | name = "rust-crypto" 194 | version = "0.2.36" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | dependencies = [ 197 | "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", 198 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 199 | "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", 200 | "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", 201 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 202 | ] 203 | 204 | [[package]] 205 | name = "rustc-serialize" 206 | version = "0.3.24" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | 209 | [[package]] 210 | name = "seahorse" 211 | version = "1.0.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | 214 | [[package]] 215 | name = "thread_local" 216 | version = "1.0.1" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | dependencies = [ 219 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 220 | ] 221 | 222 | [[package]] 223 | name = "time" 224 | version = "0.1.42" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | dependencies = [ 227 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 228 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 229 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 230 | ] 231 | 232 | [[package]] 233 | name = "wasi" 234 | version = "0.9.0+wasi-snapshot-preview1" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | 237 | [[package]] 238 | name = "winapi" 239 | version = "0.3.8" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | dependencies = [ 242 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 243 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 244 | ] 245 | 246 | [[package]] 247 | name = "winapi-i686-pc-windows-gnu" 248 | version = "0.4.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | 251 | [[package]] 252 | name = "winapi-x86_64-pc-windows-gnu" 253 | version = "0.4.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | 256 | [metadata] 257 | "checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" 258 | "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" 259 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 260 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 261 | "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" 262 | "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 263 | "checksum hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67" 264 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 265 | "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 266 | "checksum memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" 267 | "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" 268 | "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 269 | "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" 270 | "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 271 | "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 272 | "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" 273 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 274 | "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 275 | "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 276 | "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 277 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 278 | "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 279 | "checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" 280 | "checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" 281 | "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" 282 | "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" 283 | "checksum seahorse 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48badc1e4709936b554463f45691c5c5d667c2203a6872aa4283bc14bed3e9c7" 284 | "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 285 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 286 | "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 287 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 288 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 289 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 290 | --------------------------------------------------------------------------------