Patchwork D11563: WIP working on making rust components compile on windows systems

login
register
mail settings
Submitter phabricator
Date Oct. 2, 2021, 4:30 a.m.
Message ID <differential-rev-PHID-DREV-ivfy2kjiczdgxwutmbbx-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49887/
State New
Headers show

Comments

phabricator - Oct. 2, 2021, 4:30 a.m.
cspeckrun created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11563

AFFECTED FILES
  rust/Cargo.lock
  rust/hg-core/Cargo.toml
  rust/hg-core/src/config/config.rs
  rust/hg-core/src/dirstate/entry.rs
  rust/hg-core/src/dirstate_tree/status.rs
  rust/hg-core/src/filepatterns.rs
  rust/hg-core/src/utils.rs
  rust/hg-core/src/utils/files.rs
  rust/hg-core/src/utils/hg_path.rs
  rust/hg-cpython/src/dirstate/status.rs
  rust/rhg/Cargo.toml
  rust/rhg/src/blackbox.rs
  rust/rhg/src/commands/status.rs
  rust/rhg/src/main.rs

CHANGE DETAILS




To: cspeckrun, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs
--- a/rust/rhg/src/main.rs
+++ b/rust/rhg/src/main.rs
@@ -4,6 +4,7 @@ 
 use clap::AppSettings;
 use clap::Arg;
 use clap::ArgMatches;
+use directories::UserDirs;
 use format_bytes::{format_bytes, join};
 use hg::config::{Config, ConfigSource};
 use hg::exit_codes;
@@ -105,7 +106,7 @@ 
     let early_args = EarlyArgs::parse(std::env::args_os());
 
     let initial_current_dir = early_args.cwd.map(|cwd| {
-        let cwd = get_path_from_bytes(&cwd);
+        let cwd = &get_path_from_bytes(&cwd);
         std::env::current_dir()
             .and_then(|initial| {
                 std::env::set_current_dir(cwd)?;
@@ -212,7 +213,8 @@ 
             let non_repo_config_val = {
                 let non_repo_val = non_repo_config.get(b"paths", &repo_arg);
                 match &non_repo_val {
-                    Some(val) if val.len() > 0 => home::home_dir()
+                    Some(val) if val.len() > 0 => UserDirs::new()
+                        .map(|user_dirs| user_dirs.home_dir().to_path_buf())
                         .unwrap_or_else(|| PathBuf::from("~"))
                         .join(get_path_from_bytes(val))
                         .canonicalize()
@@ -333,7 +335,7 @@ 
         let mut args = std::env::args_os();
         let executable_path = get_path_from_bytes(&executable);
         let this_executable = args.next().expect("exepcted argv[0] to exist");
-        if executable_path == &PathBuf::from(this_executable) {
+        if executable_path == PathBuf::from(this_executable) {
             // Avoid spawning infinitely many processes until resource
             // exhaustion.
             let _ = ui.write_stderr(&format_bytes!(
diff --git a/rust/rhg/src/commands/status.rs b/rust/rhg/src/commands/status.rs
--- a/rust/rhg/src/commands/status.rs
+++ b/rust/rhg/src/commands/status.rs
@@ -160,15 +160,19 @@ 
     let repo = invocation.repo?;
     let mut dmap = repo.dirstate_map_mut()?;
 
+    let check_exec = if cfg!(target_os = "windows") {
+        false
+    } else {
+        true
+    };
+
     let options = StatusOptions {
         // TODO should be provided by the dirstate parsing and
         // hence be stored on dmap. Using a value that assumes we aren't
         // below the time resolution granularity of the FS and the
         // dirstate.
         last_normal_time: 0,
-        // we're currently supporting file systems with exec flags only
-        // anyway
-        check_exec: true,
+        check_exec,
         list_clean: display_states.clean,
         list_unknown: display_states.unknown,
         list_ignored: display_states.ignored,
diff --git a/rust/rhg/src/blackbox.rs b/rust/rhg/src/blackbox.rs
--- a/rust/rhg/src/blackbox.rs
+++ b/rust/rhg/src/blackbox.rs
@@ -112,8 +112,7 @@ 
 impl ConfiguredBlackbox<'_> {
     fn log(&self, date_time: &DateTime, message: &[u8]) {
         let date = format_bytes::Utf8(date_time.format(self.date_format));
-        let user = users::get_current_username().map(get_bytes_from_os_str);
-        let user = user.as_deref().unwrap_or(b"???");
+        let user = get_bytes_from_os_str(&whoami::username_os());
         let rev = format_bytes::Utf8(match self.repo.dirstate_parents() {
             Ok(parents) if parents.p2 == hg::revlog::node::NULL_NODE => {
                 format!("{:x}", parents.p1)
diff --git a/rust/rhg/Cargo.toml b/rust/rhg/Cargo.toml
--- a/rust/rhg/Cargo.toml
+++ b/rust/rhg/Cargo.toml
@@ -12,11 +12,13 @@ 
 chrono = "0.4.19"
 clap = "2.33.1"
 derive_more = "0.99"
-home = "0.5.3"
+directories = "4.0.1"
 lazy_static = "1.4.0"
 log = "0.4.11"
 micro-timer = "0.3.1"
 regex = "1.3.9"
 env_logger = "0.7.1"
 format-bytes = "0.2.1"
-users = "0.11.0"
+
+# The 1.1 series does not compile on rust 1.41, requires 1.43
+whoami = "1.0.3"
\ No newline at end of file
diff --git a/rust/hg-cpython/src/dirstate/status.rs b/rust/hg-cpython/src/dirstate/status.rs
--- a/rust/hg-cpython/src/dirstate/status.rs
+++ b/rust/hg-cpython/src/dirstate/status.rs
@@ -205,7 +205,7 @@ 
                     let pattern = pattern.data(py);
                     let source = k.get_item(py, 2)?.extract::<PyBytes>(py)?;
                     let source = get_path_from_bytes(source.data(py));
-                    let new = IgnorePattern::new(syntax, pattern, source);
+                    let new = IgnorePattern::new(syntax, pattern, &source);
                     Ok(new)
                 })
                 .collect();
diff --git a/rust/hg-core/src/utils/hg_path.rs b/rust/hg-core/src/utils/hg_path.rs
--- a/rust/hg-core/src/utils/hg_path.rs
+++ b/rust/hg-core/src/utils/hg_path.rs
@@ -5,6 +5,7 @@ 
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
+use crate::utils::files;
 use crate::utils::SliceExt;
 use std::borrow::Borrow;
 use std::borrow::Cow;
@@ -489,14 +490,7 @@ 
     hg_path: P,
 ) -> Result<OsString, HgPathError> {
     hg_path.as_ref().check_state()?;
-    let os_str;
-    #[cfg(unix)]
-    {
-        use std::os::unix::ffi::OsStrExt;
-        os_str = std::ffi::OsStr::from_bytes(&hg_path.as_ref().as_bytes());
-    }
-    // TODO Handle other platforms
-    // TODO: convert from WTF8 to Windows MBCS (ANSI encoding).
+    let os_str = files::get_os_str_from_bytes(&hg_path.as_ref().as_bytes());
     Ok(os_str.to_os_string())
 }
 
@@ -509,15 +503,9 @@ 
 pub fn os_string_to_hg_path_buf<S: AsRef<OsStr>>(
     os_string: S,
 ) -> Result<HgPathBuf, HgPathError> {
-    let buf;
-    #[cfg(unix)]
-    {
-        use std::os::unix::ffi::OsStrExt;
-        buf = HgPathBuf::from_bytes(&os_string.as_ref().as_bytes());
-    }
-    // TODO Handle other platforms
-    // TODO: convert from WTF8 to Windows MBCS (ANSI encoding).
-
+    let buf = HgPathBuf::from_bytes(&files::get_bytes_from_os_str(
+        os_string.as_ref(),
+    ));
     buf.check_state()?;
     Ok(buf)
 }
@@ -525,16 +513,7 @@ 
 pub fn path_to_hg_path_buf<P: AsRef<Path>>(
     path: P,
 ) -> Result<HgPathBuf, HgPathError> {
-    let buf;
-    let os_str = path.as_ref().as_os_str();
-    #[cfg(unix)]
-    {
-        use std::os::unix::ffi::OsStrExt;
-        buf = HgPathBuf::from_bytes(&os_str.as_bytes());
-    }
-    // TODO Handle other platforms
-    // TODO: convert from WTF8 to Windows MBCS (ANSI encoding).
-
+    let buf = HgPathBuf::from_bytes(&files::get_bytes_from_path(path));
     buf.check_state()?;
     Ok(buf)
 }
diff --git a/rust/hg-core/src/utils/files.rs b/rust/hg-core/src/utils/files.rs
--- a/rust/hg-core/src/utils/files.rs
+++ b/rust/hg-core/src/utils/files.rs
@@ -23,40 +23,62 @@ 
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
 
-pub fn get_os_str_from_bytes(bytes: &[u8]) -> &OsStr {
-    let os_str;
+// TODO Handle other platforms
+pub fn get_os_str_from_bytes(bytes: &[u8]) -> OsString {
     #[cfg(unix)]
     {
         use std::os::unix::ffi::OsStrExt;
-        os_str = std::ffi::OsStr::from_bytes(bytes);
+        let os_str = OsStr::from_bytes(bytes);
+        os_str.to_os_string()
     }
-    // TODO Handle other platforms
-    // TODO: convert from WTF8 to Windows MBCS (ANSI encoding).
-    // Perhaps, the return type would have to be Result<PathBuf>.
-    os_str
+
+    #[cfg(windows)]
+    {
+        use std::os::windows::ffi::OsStringExt;
+        // TODO: convert from WTF8 to Windows MBCS (ANSI encoding)
+        let wide_bytes: Vec<u16> = bytes.iter().map(|b| *b as u16).collect();
+        OsString::from_wide(wide_bytes.as_slice())
+    }
 }
 
-pub fn get_path_from_bytes(bytes: &[u8]) -> &Path {
-    Path::new(get_os_str_from_bytes(bytes))
+pub fn get_path_from_bytes(bytes: &[u8]) -> PathBuf {
+    Path::new(&get_os_str_from_bytes(bytes)).to_path_buf()
 }
 
 // TODO: need to convert from WTF8 to MBCS bytes on Windows.
 // that's why Vec<u8> is returned.
-#[cfg(unix)]
 pub fn get_bytes_from_path(path: impl AsRef<Path>) -> Vec<u8> {
     get_bytes_from_os_str(path.as_ref())
 }
 
-#[cfg(unix)]
 pub fn get_bytes_from_os_str(str: impl AsRef<OsStr>) -> Vec<u8> {
-    use std::os::unix::ffi::OsStrExt;
-    str.as_ref().as_bytes().to_vec()
+    #[cfg(unix)]
+    {
+        use std::os::unix::ffi::OsStrExt;
+        str.as_ref().as_bytes().to_vec()
+    }
+
+    #[cfg(windows)]
+    {
+        use std::os::windows::ffi::OsStrExt;
+        // TODO: convert from WTF8 to Windows MBCS (ANSI encoding)
+        //       If the conversion from u16 to u8 is lossy then issues will
+        //       occur elsewhere.
+        str.as_ref().encode_wide().map(|b| b as u8).collect()
+    }
 }
 
-#[cfg(unix)]
 pub fn get_bytes_from_os_string(str: OsString) -> Vec<u8> {
-    use std::os::unix::ffi::OsStringExt;
-    str.into_vec()
+    #[cfg(unix)]
+    {
+        use std::os::unix::ffi::OsStringExt;
+        str.into_vec()
+    }
+
+    #[cfg(windows)]
+    {
+        get_bytes_from_os_str(str.as_os_str())
+    }
 }
 
 /// An iterator over repository path yielding itself and its ancestors.
@@ -213,6 +235,45 @@ 
     }
 }
 
+#[cfg(windows)]
+impl HgMetadata {
+    pub fn from_metadata(metadata: Metadata) -> Self {
+        use std::os::windows::fs::MetadataExt;
+
+        let mode = match metadata.permissions().readonly() {
+            true => 0o400,
+            false => 0600,
+        };
+
+        Self {
+            st_dev: 0,
+            st_mode: mode,
+            st_nlink: 0,
+            st_size: metadata.len(),
+            st_mtime: from_win_filetime(metadata.last_write_time()) as i64,
+            // Last status change time -- windows doesn't have corresponding
+            st_ctime: from_win_filetime(metadata.last_write_time()) as i64,
+        }
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        // ?
+        false
+    }
+}
+
+#[cfg(windows)]
+/// Converts Windows' FILETIME (100 ns from Jan. 1, 1601) to seconds from
+/// the standard 1970 epoch.
+pub fn from_win_filetime(ticks: u64) -> u64 {
+    match ticks {
+        0 => 0,
+        // See from_intervals() implemented in
+        // https://github.com/alexcrichton/filetime/blob/master/src/windows.rs
+        n => n / 1_000_000_000 / 100,
+    }
+}
+
 /// Returns the canonical path of `name`, given `cwd` and `root`
 pub fn canonical_path(
     root: impl AsRef<Path>,
diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -205,20 +205,41 @@ 
     }
 }
 
-#[cfg(unix)]
 pub fn shell_quote(value: &[u8]) -> Vec<u8> {
     // TODO: Use the `matches!` macro when we require Rust 1.42+
-    if value.iter().all(|&byte| match byte {
-        b'a'..=b'z'
-        | b'A'..=b'Z'
-        | b'0'..=b'9'
-        | b'.'
-        | b'_'
-        | b'/'
-        | b'+'
-        | b'-' => true,
-        _ => false,
-    }) {
+    let valid_chars;
+    #[cfg(unix)]
+    {
+        valid_chars = |&byte| match byte {
+            b'a'..=b'z'
+            | b'A'..=b'Z'
+            | b'0'..=b'9'
+            | b'.'
+            | b'_'
+            | b'/'
+            | b'+'
+            | b'-' => true,
+            _ => false,
+        };
+    }
+
+    #[cfg(windows)]
+    {
+        valid_chars = |&byte| match byte {
+            b'a'..=b'z'
+            | b'A'..=b'Z'
+            | b'0'..=b'9'
+            | b'.'
+            | b'_'
+            | b'/'
+            | b'\\'
+            | b'+'
+            | b'-' => true,
+            _ => false,
+        };
+    }
+
+    if value.iter().all(valid_chars) {
         value.to_owned()
     } else {
         let mut quoted = Vec::with_capacity(value.len() + 2);
diff --git a/rust/hg-core/src/filepatterns.rs b/rust/hg-core/src/filepatterns.rs
--- a/rust/hg-core/src/filepatterns.rs
+++ b/rust/hg-core/src/filepatterns.rs
@@ -234,13 +234,13 @@ 
     [b'*', b'?', b'[', b']', b'{', b'}', b'\\'];
 
 /// TODO support other platforms
-#[cfg(unix)]
 pub fn normalize_path_bytes(bytes: &[u8]) -> Vec<u8> {
     if bytes.is_empty() {
         return b".".to_vec();
     }
-    let sep = b'/';
 
+    let sep = std::path::MAIN_SEPARATOR as u8;
+    
     let mut initial_slashes = bytes.iter().take_while(|b| **b == sep).count();
     if initial_slashes > 2 {
         // POSIX allows one or two initial slashes, but treats three or more
diff --git a/rust/hg-core/src/dirstate_tree/status.rs b/rust/hg-core/src/dirstate_tree/status.rs
--- a/rust/hg-core/src/dirstate_tree/status.rs
+++ b/rust/hg-core/src/dirstate_tree/status.rs
@@ -682,13 +682,25 @@ 
     }
 }
 
-#[cfg(unix)] // TODO
+// TODO: Support other systems
 fn mtime_seconds(metadata: &std::fs::Metadata) -> i64 {
     // Going through `Metadata::modified()` would be portable, but would take
     // care to construct a `SystemTime` value with sub-second precision just
     // for us to throw that away here.
-    use std::os::unix::fs::MetadataExt;
-    metadata.mtime()
+    #[cfg(unix)]
+    {
+        use std::os::unix::fs::MetadataExt;
+        metadata.mtime()
+    }
+
+    #[cfg(windows)]
+    {
+        use std::os::windows::fs::MetadataExt;
+        let ticks = metadata.last_write_time();
+
+        use crate::utils::files::from_win_filetime;
+        from_win_filetime(ticks) as i64
+    }
 }
 
 struct DirEntry {
diff --git a/rust/hg-core/src/dirstate/entry.rs b/rust/hg-core/src/dirstate/entry.rs
--- a/rust/hg-core/src/dirstate/entry.rs
+++ b/rust/hg-core/src/dirstate/entry.rs
@@ -107,16 +107,27 @@ 
     }
 
     // TODO: other platforms
-    #[cfg(unix)]
     pub fn mode_changed(
         &self,
+        #[cfg_attr(windows, allow(unused_variables))]
         filesystem_metadata: &std::fs::Metadata,
     ) -> bool {
-        use std::os::unix::fs::MetadataExt;
-        const EXEC_BIT_MASK: u32 = 0o100;
-        let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK;
-        let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
-        dirstate_exec_bit != fs_exec_bit
+        #[cfg(unix)]
+        {
+            use std::os::unix::fs::MetadataExt;
+            const EXEC_BIT_MASK: u32 = 0o100;
+            let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK;
+            let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
+            dirstate_exec_bit != fs_exec_bit
+        }
+
+        #[cfg(windows)]
+        {
+            // According to this SO, Mercurial only tracks executable bits on
+            // files, which it isn't able to do on Windows systems.
+            // https://stackoverflow.com/a/18926911
+            false
+        }
     }
 
     /// Returns a `(state, mode, size, mtime)` tuple as for
diff --git a/rust/hg-core/src/config/config.rs b/rust/hg-core/src/config/config.rs
--- a/rust/hg-core/src/config/config.rs
+++ b/rust/hg-core/src/config/config.rs
@@ -13,6 +13,7 @@ 
     ConfigError, ConfigLayer, ConfigOrigin, ConfigValue,
 };
 use crate::utils::files::get_bytes_from_os_str;
+use directories::{BaseDirs, UserDirs};
 use format_bytes::{write_bytes, DisplayBytes};
 use std::collections::HashSet;
 use std::env;
@@ -192,13 +193,20 @@ 
         }
     }
 
-    #[cfg(unix)] // TODO: other platforms
     fn add_system_config(&mut self) -> Result<(), ConfigError> {
+        // TODO: Windows, check this registry key
+        // - HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial
+        //   - or HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial for 32bit
+        //     Python on 64bit Windows.
+
         let mut add_for_prefix = |prefix: &Path| -> Result<(), ConfigError> {
-            let etc = prefix.join("etc").join("mercurial");
-            self.add_trusted_file(&etc.join("hgrc"))?;
-            self.add_trusted_dir(&etc.join("hgrc.d"))
+            #[cfg(unix)]
+            let prefix = prefix.join("etc").join("mercurial");
+
+            self.add_trusted_file(&prefix.join("hgrc"))?;
+            self.add_trusted_dir(&prefix.join("hgrc.d"))
         };
+        
         let root = Path::new("/");
         // TODO: use `std::env::args_os().next().unwrap()` a.k.a. argv[0]
         // instead? TODO: can this be a relative path?
@@ -211,20 +219,28 @@ 
                 add_for_prefix(&installation_prefix)?
             }
         }
+
+        #[cfg(unix)]
         add_for_prefix(root)?;
+
         Ok(())
     }
 
-    #[cfg(unix)] // TODO: other plateforms
     fn add_user_config(&mut self) -> Result<(), ConfigError> {
-        let opt_home = home::home_dir();
+        let opt_home = UserDirs::new()
+            .map(|user_dirs| user_dirs.home_dir().to_path_buf());
         if let Some(home) = &opt_home {
-            self.add_trusted_file(&home.join(".hgrc"))?
+            self.add_trusted_file(&home.join(".hgrc"))?;
+
+            #[cfg(windows)]
+            self.add_trusted_file(&home.join("Mercurial.ini"))?;
         }
+
+        let unix = cfg!(target_os = "unix");
         let darwin = cfg!(any(target_os = "macos", target_os = "ios"));
-        if !darwin {
-            if let Some(config_home) = env::var_os("XDG_CONFIG_HOME")
-                .map(PathBuf::from)
+        if unix && !darwin {
+            if let Some(config_home) = BaseDirs::new()
+                .map(|base_dirs| base_dirs.config_dir().to_path_buf())
                 .or_else(|| opt_home.map(|home| home.join(".config")))
             {
                 self.add_trusted_file(&config_home.join("hg").join("hgrc"))?
diff --git a/rust/hg-core/Cargo.toml b/rust/hg-core/Cargo.toml
--- a/rust/hg-core/Cargo.toml
+++ b/rust/hg-core/Cargo.toml
@@ -12,7 +12,7 @@ 
 bytes-cast = "0.2"
 byteorder = "1.3.4"
 derive_more = "0.99"
-home = "0.5"
+directories = "4.0.1"
 im-rc = "15.0.*"
 itertools = "0.9"
 lazy_static = "1.4.0"
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -1,6 +1,5 @@ 
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-
 [[package]]
 name = "adler"
 version = "0.2.3"
@@ -67,6 +66,12 @@ 
 ]
 
 [[package]]
+name = "bumpalo"
+version = "3.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
+
+[[package]]
 name = "byteorder"
 version = "1.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -282,6 +287,26 @@ 
 ]
 
 [[package]]
+name = "directories"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
 name = "either"
 version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -357,6 +382,17 @@ 
 ]
 
 [[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi 0.10.0+wasi-snapshot-preview1",
+]
+
+[[package]]
 name = "glob"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -380,9 +416,9 @@ 
  "clap",
  "crossbeam-channel 0.4.4",
  "derive_more",
+ "directories",
  "flate2",
  "format-bytes",
- "home",
  "im-rc",
  "itertools",
  "lazy_static",
@@ -417,15 +453,6 @@ 
 ]
 
 [[package]]
-name = "home"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
-dependencies = [
- "winapi",
-]
-
-[[package]]
 name = "humantime"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -467,6 +494,15 @@ 
 ]
 
 [[package]]
+name = "js-sys"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
 name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -691,7 +727,7 @@ 
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
 dependencies = [
- "getrandom",
+ "getrandom 0.1.15",
  "libc",
  "rand_chacha",
  "rand_core",
@@ -714,7 +750,7 @@ 
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
 dependencies = [
- "getrandom",
+ "getrandom 0.1.15",
 ]
 
 [[package]]
@@ -785,6 +821,25 @@ 
 checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
 
 [[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
+dependencies = [
+ "getrandom 0.2.3",
+ "redox_syscall 0.2.10",
+]
+
+[[package]]
 name = "regex"
 version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -818,15 +873,15 @@ 
  "chrono",
  "clap",
  "derive_more",
+ "directories",
  "env_logger",
  "format-bytes",
  "hg-core",
- "home",
  "lazy_static",
  "log",
  "micro-timer",
  "regex",
- "users",
+ "whoami",
 ]
 
 [[package]]
@@ -887,9 +942,9 @@ 
 
 [[package]]
 name = "syn"
-version = "1.0.54"
+version = "1.0.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
+checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -905,7 +960,7 @@ 
  "cfg-if 0.1.10",
  "libc",
  "rand",
- "redox_syscall",
+ "redox_syscall 0.1.57",
  "remove_dir_all",
  "winapi",
 ]
@@ -978,16 +1033,6 @@ 
 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
 [[package]]
-name = "users"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
-dependencies = [
- "libc",
- "log",
-]
-
-[[package]]
 name = "vcpkg"
 version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1018,6 +1063,80 @@ 
 checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
 
 [[package]]
+name = "wasm-bindgen"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
+dependencies = [
+ "cfg-if 1.0.0",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
+
+[[package]]
+name = "web-sys"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "whoami"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d595b2e146f36183d6a590b8d41568e2bc84c922267f43baf61c956330eeb436"
+dependencies = [
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1050,18 +1169,18 @@ 
 
 [[package]]
 name = "zstd"
-version = "0.5.3+zstd.1.4.5"
+version = "0.5.4+zstd.1.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
+checksum = "69996ebdb1ba8b1517f61387a883857818a66c8a295f487b1ffd8fd9d2c82910"
 dependencies = [
  "zstd-safe",
 ]
 
 [[package]]
 name = "zstd-safe"
-version = "2.0.5+zstd.1.4.5"
+version = "2.0.6+zstd.1.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
+checksum = "98aa931fb69ecee256d44589d19754e61851ae4769bf963b385119b1cc37a49e"
 dependencies = [
  "libc",
  "zstd-sys",
@@ -1069,9 +1188,9 @@ 
 
 [[package]]
 name = "zstd-sys"
-version = "1.4.17+zstd.1.4.5"
+version = "1.4.18+zstd.1.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
+checksum = "a1e6e8778706838f43f771d80d37787cb2fe06dafe89dd3aebaf6721b9eaec81"
 dependencies = [
  "cc",
  "glob",