├── .gitignore ├── Cargo.toml ├── src ├── init.rs ├── add.rs ├── error.rs ├── types.rs ├── main.rs ├── index.rs ├── commit.rs └── file.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .tgit -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tgit" 3 | version = "0.1.0" 4 | authors = ["tensor-programming "] 5 | edition = "2018" 6 | 7 | 8 | [dependencies] 9 | clap = "2.33.0" 10 | rust-crypto = "0.2.36" 11 | regex = "1" 12 | lazy_static = "1.3.0" -------------------------------------------------------------------------------- /src/init.rs: -------------------------------------------------------------------------------- 1 | use super::error::TgitError; 2 | 3 | use std::fs; 4 | use std::fs::File; 5 | use std::io::Write; 6 | use std::path::Path; 7 | 8 | 9 | pub fn init() -> Result<(), TgitError> { 10 | let dir = Path::new(".tgit"); 11 | 12 | fs::create_dir(dir)?; 13 | fs::create_dir(dir.join("objects"))?; 14 | fs::create_dir(dir.join("refs"))?; 15 | fs::create_dir(dir.join("refs").join("heads"))?; 16 | 17 | let mut head = File::create(dir.join("HEAD"))?; 18 | head.write_all("refs: refs/heads/master".as_bytes())?; 19 | Ok(()) 20 | } -------------------------------------------------------------------------------- /src/add.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | 4 | use super::error::TgitError; 5 | use super::file::FileService; 6 | use super::index::Index; 7 | use super::types::Blob; 8 | 9 | pub fn add_all(add_data: &Vec<&str>) -> Result<(), TgitError> { 10 | let file_service = FileService::new()?; 11 | let current_dir = env::current_dir()?; 12 | let mut index = Index::new(&file_service.root_dir)?; 13 | 14 | for file in add_data { 15 | let full_path = current_dir.join(file); 16 | let blob = Blob::from_path(&full_path)?; 17 | file_service.write_blob(&blob)?; 18 | let relative_path = full_path.strip_prefix(&file_service.root_dir).unwrap(); 19 | index.update(&relative_path.to_str().unwrap(), &blob.hash) 20 | } 21 | index.write()?; 22 | Ok(()) 23 | } -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::io; 3 | 4 | pub enum TgitError { 5 | IoError(io::Error), 6 | NoDirectory, 7 | InvalidCommit, 8 | InvalidIndex, 9 | } 10 | 11 | impl fmt::Display for TgitError { 12 | fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { 13 | match self { 14 | &TgitError::IoError(ref e) => e.fmt(formatter), 15 | &TgitError::NoDirectory => formatter.write_str("No Directory Found"), 16 | &TgitError::InvalidCommit => formatter.write_str("The commit is invalid"), 17 | &TgitError::InvalidIndex => formatter.write_str("The index is corrupt"), 18 | } 19 | } 20 | } 21 | 22 | impl From for TgitError { 23 | fn from(err: io::Error) -> TgitError { 24 | TgitError::IoError(err) 25 | } 26 | } -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::Read; 3 | use std::fs::File; 4 | use std::path::PathBuf; 5 | use crypto::sha1::Sha1; 6 | use crypto::digest::Digest; 7 | 8 | pub enum Tree { 9 | BlobEntry { name: String, hash: String }, 10 | TreeEntry { 11 | name: String, 12 | hash: String, 13 | children: Vec, 14 | } 15 | } 16 | 17 | pub struct Blob { 18 | pub hash: String, 19 | pub data: Vec, 20 | } 21 | 22 | impl Blob { 23 | pub fn from_path(path: &PathBuf) -> io::Result { 24 | let mut file = File::open(path)?; 25 | let mut bytes = Vec::new(); 26 | file.read_to_end(&mut bytes)?; 27 | 28 | let mut sha = Sha1::new(); 29 | sha.input(&bytes); 30 | 31 | Ok( 32 | Blob { 33 | hash: sha.result_str(), 34 | data: bytes, 35 | } 36 | ) 37 | } 38 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | mod add; 5 | mod commit; 6 | mod error; 7 | mod file; 8 | mod index; 9 | mod init; 10 | mod types; 11 | 12 | use clap::{App, Arg, SubCommand}; 13 | 14 | fn main() { 15 | let m = App::new("tgit") 16 | .subcommand(SubCommand::with_name("init").about("Initialize the Repo")) 17 | .subcommand( 18 | SubCommand::with_name("add").about("Add a file").arg( 19 | Arg::with_name("file") 20 | .help("File to add") 21 | .index(1) 22 | .multiple(true) 23 | .required(true), 24 | ), 25 | ).subcommand(SubCommand::with_name("commit").about("commits a change")) 26 | .get_matches(); 27 | 28 | match m.subcommand() { 29 | ("init", Some(..)) => match init::init() { 30 | Ok(()) => println!("Repo initialized"), 31 | Err(..) => println!("Already Initialized!"), 32 | }, 33 | ("add", Some(submatch)) => { 34 | match add::add_all(&submatch.values_of("file").unwrap().collect()) { 35 | Ok(()) => (), 36 | Err(e) => println!("Error: {}", e), 37 | } 38 | } 39 | ("commit", Some(..)) => { 40 | match commit::commit() { 41 | Ok(()) => (), 42 | Err(e) => println!("Error: {}", e) 43 | } 44 | } 45 | 46 | _ => println!("Command not recognized."), 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/index.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::collections::BTreeMap; 3 | use std::io::{BufRead, BufReader, Write}; 4 | use std::fs::File; 5 | use std::path::PathBuf; 6 | 7 | use super::error::TgitError; 8 | 9 | pub struct Index { 10 | pub path: PathBuf, 11 | pub hashtree: BTreeMap, 12 | } 13 | 14 | impl Index { 15 | pub fn new(root_dir: &PathBuf) -> Result { 16 | let mut index = Index { 17 | path: root_dir.join(".tgit").join("index"), 18 | hashtree: BTreeMap::new(), 19 | }; 20 | 21 | if !index.path.exists() { 22 | return Ok(index); 23 | } 24 | 25 | let file = BufReader::new(File::open(&index.path)?); 26 | for line in file.lines() { 27 | let ln = line?; 28 | let blob: Vec<&str> = ln.split(' ').collect(); 29 | if blob.len() != 2 { 30 | return Err(TgitError::InvalidIndex); 31 | } 32 | index.update(blob[0], blob[1]); 33 | } 34 | Ok(index) 35 | } 36 | 37 | pub fn update(&mut self, path: &str, hash: &str) { 38 | self.hashtree.insert(path.to_string(), hash.to_string()); 39 | } 40 | 41 | pub fn print(&self) { 42 | for (ref hash, ref path) in self.hashtree.iter() { 43 | println!("{} {}", hash, path); 44 | } 45 | } 46 | 47 | pub fn write(&self) -> io::Result<()> { 48 | let mut index = File::create(&self.path)?; 49 | for (ref hash, ref path) in self.hashtree.iter() { 50 | writeln!(&mut index, "{} {}", hash, path); 51 | } 52 | Ok(()) 53 | } 54 | 55 | pub fn clear(&mut self) -> io::Result<()> { 56 | self.hashtree = BTreeMap::new(); 57 | self.write() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/commit.rs: -------------------------------------------------------------------------------- 1 | 2 | use crypto::digest::Digest; 3 | use crypto::sha1::Sha1; 4 | use regex::Regex; 5 | 6 | use std::collections::BTreeMap; 7 | use std::io::Write; 8 | 9 | use super::error::TgitError; 10 | 11 | use super::file::FileService; 12 | use super::index::Index; 13 | 14 | pub struct Commit { 15 | pub hash: Option, 16 | pub data: Option>, 17 | pub parent: Option, 18 | pub files: BTreeMap, 19 | } 20 | 21 | impl Commit { 22 | pub fn new(parent: Option<&Commit>) -> Commit { 23 | let mut commit = Commit { 24 | hash: None, 25 | data: None, 26 | parent: match parent { 27 | Some(&Commit { 28 | hash: Some(ref hash), 29 | .. 30 | }) => Some(hash.to_string()), 31 | _ => None, 32 | }, 33 | files: BTreeMap::new(), 34 | }; 35 | 36 | for (ref hash, ref path) in parent.iter().flat_map(|p| p.files.iter()) { 37 | commit.files.insert(hash.to_string(), path.to_string()); 38 | } 39 | 40 | commit 41 | } 42 | 43 | pub fn add_from_index(&mut self, index: &Index) { 44 | for (ref hash, ref path) in index.hashtree.iter() { 45 | self.files.insert(hash.to_string(), path.to_string()); 46 | } 47 | } 48 | 49 | pub fn from_string(hash: &str, input: &str) -> Result { 50 | let mut commit = Commit::new(None); 51 | commit.hash = Some(hash.to_string()); 52 | lazy_static! { 53 | static ref PARENT: Regex = Regex::new(r"parent ([0-9a-f]{40})").unwrap(); 54 | static ref BLOB: Regex = Regex::new(r"blob ([0-9a-f]{40}) (.*)").unwrap(); 55 | } 56 | 57 | for line in input.lines() { 58 | if let Some(ref caps) = PARENT.captures(line) { 59 | commit.parent = Some(caps.get(1).unwrap().as_str().to_string()); 60 | } 61 | 62 | if let Some(ref caps) = BLOB.captures(line) { 63 | let hash = caps.get(1).unwrap().as_str(); 64 | let path = caps.get(2).unwrap().as_str(); 65 | commit.files.insert(hash.to_string(), path.to_string()); 66 | } 67 | } 68 | 69 | Ok(commit) 70 | } 71 | 72 | pub fn print(&self) { 73 | if let Some(ref p) = self.parent { 74 | println!("parent {}", p); 75 | } 76 | for (ref hash, ref path) in self.files.iter() { 77 | println!("blob {} {}", hash, path); 78 | } 79 | } 80 | 81 | 82 | pub fn update(&mut self) { 83 | let mut data = Vec::new(); 84 | 85 | if let Some(ref p) = self.parent { 86 | writeln!(&mut data, "parent {}", p).unwrap(); 87 | } 88 | 89 | for (ref hash, ref path) in self.files.iter() { 90 | writeln!(&mut data, "blob {} {}", hash, path).unwrap(); 91 | } 92 | 93 | let mut sha = Sha1::new(); 94 | sha.input(&data); 95 | self.hash = Some(sha.result_str()); 96 | self.data = Some(data); 97 | } 98 | } 99 | 100 | pub fn commit() -> Result<(), TgitError> { 101 | let fs = FileService::new()?; 102 | let head_ref = fs.get_head_ref()?; 103 | let parent_hash = FileService::get_hash_from_ref(&head_ref); 104 | let mut index = Index::new(&fs.root_dir)?; 105 | 106 | let parent = match parent_hash { 107 | Some(ref h) => Some(fs.read_commit(h)?), 108 | None => None, 109 | }; 110 | 111 | let mut commit = Commit::new(parent.as_ref()); 112 | parent.map(|p| p.print()); 113 | commit.add_from_index(&index); 114 | commit.print(); 115 | 116 | fs.write_commit(&mut commit)?; 117 | index.clear()?; 118 | Ok(()) 119 | 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/file.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs; 3 | use std::fs::File; 4 | 5 | use std::io; 6 | use std::io::{Read, Write}; 7 | use std::path::{Path, PathBuf}; 8 | 9 | use super::commit::Commit; 10 | use super::error::TgitError; 11 | use super::types::Blob; 12 | 13 | 14 | pub struct FileService { 15 | pub root_dir: PathBuf, 16 | pub tgit_dir: PathBuf, 17 | pub object_dir: PathBuf, 18 | } 19 | 20 | impl FileService { 21 | pub fn new() -> Result { 22 | let root_dir = FileService::find_root()?; 23 | let tgit_dir = root_dir.join(".tgit").to_path_buf(); 24 | let object_dir = tgit_dir.join("objects").to_path_buf(); 25 | Ok(FileService { 26 | root_dir, 27 | tgit_dir, 28 | object_dir, 29 | }) 30 | } 31 | 32 | fn find_root() -> Result { 33 | let mut current_dir = env::current_dir()?; 34 | loop { 35 | if FileService::is_tgit(¤t_dir) { 36 | return Ok(current_dir); 37 | } 38 | if !current_dir.pop() { 39 | return Err(TgitError::NoDirectory); 40 | } 41 | } 42 | 43 | } 44 | 45 | fn is_tgit

(path: P) -> bool 46 | where 47 | P: Sized + AsRef, 48 | { 49 | path.as_ref().join(".tgit").exists() 50 | } 51 | 52 | pub fn get_head_ref(&self) -> io::Result { 53 | let mut head_file = File::open(self.root_dir.join(".tgit/HEAD"))?; 54 | let mut ref_path = String::new(); 55 | head_file.read_to_string(&mut ref_path)?; 56 | let ref_path = ref_path.split_off(6); 57 | Ok(self.tgit_dir.join(ref_path)) 58 | } 59 | 60 | pub fn get_hash_from_ref(ref_path: &PathBuf) -> Option { 61 | match File::open(ref_path) { 62 | Ok(ref mut f) => { 63 | let mut hash = String::new(); 64 | f.read_to_string(&mut hash).unwrap(); 65 | Some(hash) 66 | } 67 | Err(_) => None, 68 | } 69 | } 70 | 71 | pub fn write_blob(&self, blob: &Blob) -> io::Result<()> { 72 | self.write_object(&blob.hash, &blob.data) 73 | } 74 | 75 | pub fn read_commit(&self, hash: &str) -> Result { 76 | Commit::from_string(hash, &self.read_object(hash)?) 77 | } 78 | 79 | pub fn write_commit(&self, commit: &mut Commit) -> io::Result<()> { 80 | commit.update(); 81 | 82 | match commit { 83 | &mut Commit { 84 | hash: Some(ref hash), 85 | data: Some(ref data), 86 | .. 87 | } => { 88 | self.write_object(hash, data)?; 89 | let head = self.get_head_ref()?; 90 | let mut head_file = File::create(&head)?; 91 | head_file.write_all(hash.as_bytes())?; 92 | } 93 | 94 | _ => panic!("Commit should have data and hash"), 95 | } 96 | 97 | Ok(()) 98 | } 99 | 100 | pub fn write_object(&self, hash: &str, data: &Vec) -> io::Result<()> { 101 | let blob_dir = self.object_dir.join(&hash[..2]); 102 | if !blob_dir.exists() { 103 | fs::create_dir(&blob_dir)?; 104 | } 105 | let blob_filename = blob_dir.join(&hash[2..]); 106 | let mut blob_f = File::create(&blob_filename)?; 107 | blob_f.write_all(data)?; 108 | 109 | Ok(()) 110 | } 111 | 112 | pub fn read_object(&self, hash: &str) -> io::Result { 113 | let mut data = String::new(); 114 | let object_filename = self.object_dir.join(&hash[..2]).join(&hash[2..]); 115 | let mut object_file = File::open(&object_filename)?; 116 | object_file.read_to_string(&mut data)?; 117 | Ok(data) 118 | } 119 | } -------------------------------------------------------------------------------- /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.3" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "ansi_term" 13 | version = "0.11.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "atty" 21 | version = "0.2.11" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | dependencies = [ 24 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 27 | ] 28 | 29 | [[package]] 30 | name = "bitflags" 31 | version = "1.0.4" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | 34 | [[package]] 35 | name = "clap" 36 | version = "2.33.0" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | dependencies = [ 39 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 46 | ] 47 | 48 | [[package]] 49 | name = "fuchsia-cprng" 50 | version = "0.1.1" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | 53 | [[package]] 54 | name = "gcc" 55 | version = "0.3.55" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | 58 | [[package]] 59 | name = "lazy_static" 60 | version = "1.3.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | 63 | [[package]] 64 | name = "libc" 65 | version = "0.2.54" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | 68 | [[package]] 69 | name = "memchr" 70 | version = "2.2.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [[package]] 74 | name = "numtoa" 75 | version = "0.1.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | 78 | [[package]] 79 | name = "rand" 80 | version = "0.3.23" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | dependencies = [ 83 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 84 | "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 85 | ] 86 | 87 | [[package]] 88 | name = "rand" 89 | version = "0.4.6" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | dependencies = [ 92 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 93 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "rand_core" 101 | version = "0.3.1" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | dependencies = [ 104 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 105 | ] 106 | 107 | [[package]] 108 | name = "rand_core" 109 | version = "0.4.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | 112 | [[package]] 113 | name = "rdrand" 114 | version = "0.4.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | dependencies = [ 117 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 118 | ] 119 | 120 | [[package]] 121 | name = "redox_syscall" 122 | version = "0.1.54" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | 125 | [[package]] 126 | name = "redox_termios" 127 | version = "0.1.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | dependencies = [ 130 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 131 | ] 132 | 133 | [[package]] 134 | name = "regex" 135 | version = "1.1.6" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | dependencies = [ 138 | "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 140 | "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 141 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 143 | ] 144 | 145 | [[package]] 146 | name = "regex-syntax" 147 | version = "0.6.6" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | dependencies = [ 150 | "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 151 | ] 152 | 153 | [[package]] 154 | name = "rust-crypto" 155 | version = "0.2.36" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | dependencies = [ 158 | "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", 159 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 160 | "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", 161 | "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", 162 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 163 | ] 164 | 165 | [[package]] 166 | name = "rustc-serialize" 167 | version = "0.3.24" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | 170 | [[package]] 171 | name = "strsim" 172 | version = "0.8.0" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | 175 | [[package]] 176 | name = "termion" 177 | version = "1.5.2" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | dependencies = [ 180 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 181 | "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 182 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 183 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 184 | ] 185 | 186 | [[package]] 187 | name = "textwrap" 188 | version = "0.11.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | dependencies = [ 191 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 192 | ] 193 | 194 | [[package]] 195 | name = "tgit" 196 | version = "0.1.0" 197 | dependencies = [ 198 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 199 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 200 | "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 201 | "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", 202 | ] 203 | 204 | [[package]] 205 | name = "thread_local" 206 | version = "0.3.6" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | dependencies = [ 209 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 210 | ] 211 | 212 | [[package]] 213 | name = "time" 214 | version = "0.1.42" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | dependencies = [ 217 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 218 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 219 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 220 | ] 221 | 222 | [[package]] 223 | name = "ucd-util" 224 | version = "0.1.3" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | 227 | [[package]] 228 | name = "unicode-width" 229 | version = "0.1.5" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | 232 | [[package]] 233 | name = "utf8-ranges" 234 | version = "1.0.2" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | 237 | [[package]] 238 | name = "vec_map" 239 | version = "0.8.1" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | 242 | [[package]] 243 | name = "winapi" 244 | version = "0.3.7" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | dependencies = [ 247 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 248 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 249 | ] 250 | 251 | [[package]] 252 | name = "winapi-i686-pc-windows-gnu" 253 | version = "0.4.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | 256 | [[package]] 257 | name = "winapi-x86_64-pc-windows-gnu" 258 | version = "0.4.0" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | 261 | [metadata] 262 | "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" 263 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 264 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 265 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 266 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 267 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 268 | "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" 269 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 270 | "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" 271 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" 272 | "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" 273 | "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" 274 | "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 275 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 276 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 277 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 278 | "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" 279 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 280 | "checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" 281 | "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" 282 | "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" 283 | "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" 284 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 285 | "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" 286 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 287 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 288 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 289 | "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" 290 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 291 | "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" 292 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 293 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" 294 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 295 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 296 | --------------------------------------------------------------------------------