hgcli: remove legacy project
authorGregory Szorc <gregory.szorc@gmail.com>
Tue, 31 Mar 2020 18:56:41 -0700
changeset 44637 02f66b23cba3
parent 44636 c70bcaf7927b
child 44638 af739894a4c1
hgcli: remove legacy project This code is a logical precursor to PyOxidizer. It is now defunct. Differential Revision: https://phab.mercurial-scm.org/D8349
rust/Cargo.toml
rust/hgcli/Cargo.lock
rust/hgcli/Cargo.toml
rust/hgcli/README.rst
rust/hgcli/build.rs
rust/hgcli/src/main.rs
--- a/rust/Cargo.toml	Thu Mar 26 11:55:06 2020 +0100
+++ b/rust/Cargo.toml	Tue Mar 31 18:56:41 2020 -0700
@@ -1,3 +1,3 @@
 [workspace]
 members = ["hg-core", "hg-cpython"]
-exclude = ["chg", "hgcli"]
+exclude = ["chg"]
--- a/rust/hgcli/Cargo.lock	Thu Mar 26 11:55:06 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-[[package]]
-name = "aho-corasick"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "cpython"
-version = "0.1.0"
-source = "git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52#c90d65cf84abfffce7ef54476bbfed56017a2f52"
-dependencies = [
- "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "python27-sys 0.1.2 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)",
-]
-
-[[package]]
-name = "hgcli"
-version = "0.1.0"
-dependencies = [
- "cpython 0.1.0 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)",
- "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
- "python27-sys 0.1.2 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)",
-]
-
-[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "memchr"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "python27-sys"
-version = "0.1.2"
-source = "git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52#c90d65cf84abfffce7ef54476bbfed56017a2f52"
-dependencies = [
- "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex"
-version = "0.1.80"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "thread-id"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "thread_local"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "utf8-ranges"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi-build"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[metadata]
-"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
-"checksum cpython 0.1.0 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)" = "<none>"
-"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
-"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
-"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
-"checksum python27-sys 0.1.2 (git+https://github.com/indygreg/rust-cpython.git?rev=c90d65cf84abfffce7ef54476bbfed56017a2f52)" = "<none>"
-"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
-"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
-"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
-"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
-"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
-"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
--- a/rust/hgcli/Cargo.toml	Thu Mar 26 11:55:06 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-[package]
-name = "hgcli"
-version = "0.1.0"
-authors = ["Gregory Szorc <gregory.szorc@gmail.com>"]
-license = "GPL-2.0"
-
-build = "build.rs"
-
-[[bin]]
-name = "hg"
-path = "src/main.rs"
-
-[features]
-# localdev: detect Python in PATH and use files from source checkout.
-default = ["localdev"]
-localdev = []
-
-[dependencies]
-libc = "0.2.34"
-
-# We currently use a custom build of cpython and python27-sys with the
-# following changes:
-# * GILGuard call of prepare_freethreaded_python() is removed.
-# TODO switch to official release when our changes are incorporated.
-[dependencies.cpython]
-version = "0.1"
-default-features = false
-features = ["python27-sys"]
-git = "https://github.com/indygreg/rust-cpython.git"
-rev = "c90d65cf84abfffce7ef54476bbfed56017a2f52"
-
-[dependencies.python27-sys]
-version = "0.1.2"
-git = "https://github.com/indygreg/rust-cpython.git"
-rev = "c90d65cf84abfffce7ef54476bbfed56017a2f52"
--- a/rust/hgcli/README.rst	Thu Mar 26 11:55:06 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-Features
---------
-
-The following Cargo features are available:
-
-localdev (default)
-   Produce files that work with an in-source-tree build.
-
-   In this mode, the build finds and uses a ``python2.7`` binary from
-   ``PATH``. The ``hg`` binary assumes it runs from ``rust/target/<target>hg``
-   and it finds Mercurial files at ``dirname($0)/../../../``.
-
-Build Mechanism
----------------
-
-The produced ``hg`` binary is *bound* to a CPython installation. The
-binary links against and loads a CPython library that is discovered
-at build time (by a ``build.rs`` Cargo build script). The Python
-standard library defined by this CPython installation is also used.
-
-Finding the appropriate CPython installation to use is done by
-the ``python27-sys`` crate's ``build.rs``. Its search order is::
-
-1. ``PYTHON_SYS_EXECUTABLE`` environment variable.
-2. ``python`` executable on ``PATH``
-3. ``python2`` executable on ``PATH``
-4. ``python2.7`` executable on ``PATH``
-
-Additional verification of the found Python will be performed by our
-``build.rs`` to ensure it meets Mercurial's requirements.
-
-Details about the build-time configured Python are built into the
-produced ``hg`` binary. This means that a built ``hg`` binary is only
-suitable for a specific, well-defined role. These roles are controlled
-by Cargo features (see above).
-
-Running
-=======
-
-The ``hgcli`` crate produces an ``hg`` binary. You can run this binary
-via ``cargo run``::
-
-   $ cargo run --manifest-path hgcli/Cargo.toml
-
-Or directly::
-
-   $ target/debug/hg
-   $ target/release/hg
-
-You can also run the test harness with this binary::
-
-   $ ./run-tests.py --with-hg ../rust/target/debug/hg
-
-.. note::
-
-   Integration with the test harness is still preliminary. Remember to
-   ``cargo build`` after changes because the test harness doesn't yet
-   automatically build Rust code.
--- a/rust/hgcli/build.rs	Thu Mar 26 11:55:06 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-// build.rs -- Configure build environment for `hgcli` Rust package.
-//
-// Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
-//
-// This software may be used and distributed according to the terms of the
-// GNU General Public License version 2 or any later version.
-
-use std::collections::HashMap;
-use std::env;
-use std::path::Path;
-use std::process::Command;
-
-struct PythonConfig {
-    python: String,
-    config: HashMap<String, String>,
-}
-
-fn get_python_config() -> PythonConfig {
-    // The python27-sys crate exports a Cargo variable defining the full
-    // path to the interpreter being used.
-    let python = env::var("DEP_PYTHON27_PYTHON_INTERPRETER")
-        .expect("Missing DEP_PYTHON27_PYTHON_INTERPRETER; bad python27-sys crate?");
-
-    if !Path::new(&python).exists() {
-        panic!(
-            "Python interpreter {} does not exist; this should never happen",
-            python
-        );
-    }
-
-    // This is a bit hacky but it gets the job done.
-    let separator = "SEPARATOR STRING";
-
-    let script = "import sysconfig; \
-                  c = sysconfig.get_config_vars(); \
-                  print('SEPARATOR STRING'.join('%s=%s' % i for i in c.items()))";
-
-    let mut command = Command::new(&python);
-    command.arg("-c").arg(script);
-
-    let out = command.output().unwrap();
-
-    if !out.status.success() {
-        panic!(
-            "python script failed: {}",
-            String::from_utf8_lossy(&out.stderr)
-        );
-    }
-
-    let stdout = String::from_utf8_lossy(&out.stdout);
-    let mut m = HashMap::new();
-
-    for entry in stdout.split(separator) {
-        let mut parts = entry.splitn(2, "=");
-        let key = parts.next().unwrap();
-        let value = parts.next().unwrap();
-        m.insert(String::from(key), String::from(value));
-    }
-
-    PythonConfig {
-        python: python,
-        config: m,
-    }
-}
-
-#[cfg(not(target_os = "windows"))]
-fn have_shared(config: &PythonConfig) -> bool {
-    match config.config.get("Py_ENABLE_SHARED") {
-        Some(value) => value == "1",
-        None => false,
-    }
-}
-
-#[cfg(target_os = "windows")]
-fn have_shared(config: &PythonConfig) -> bool {
-    use std::path::PathBuf;
-
-    // python27.dll should exist next to python2.7.exe.
-    let mut dll = PathBuf::from(&config.python);
-    dll.pop();
-    dll.push("python27.dll");
-
-    return dll.exists();
-}
-
-const REQUIRED_CONFIG_FLAGS: [&str; 2] = ["Py_USING_UNICODE", "WITH_THREAD"];
-
-fn main() {
-    let config = get_python_config();
-
-    println!("Using Python: {}", config.python);
-    println!("cargo:rustc-env=PYTHON_INTERPRETER={}", config.python);
-
-    let prefix = config.config.get("prefix").unwrap();
-
-    println!("Prefix: {}", prefix);
-
-    // TODO Windows builds don't expose these config flags. Figure out another
-    // way.
-    #[cfg(not(target_os = "windows"))]
-    for key in REQUIRED_CONFIG_FLAGS.iter() {
-        let result = match config.config.get(*key) {
-            Some(value) => value == "1",
-            None => false,
-        };
-
-        if !result {
-            panic!("Detected Python requires feature {}", key);
-        }
-    }
-
-    // We need a Python shared library.
-    if !have_shared(&config) {
-        panic!("Detected Python lacks a shared library, which is required");
-    }
-
-    let ucs4 = match config.config.get("Py_UNICODE_SIZE") {
-        Some(value) => value == "4",
-        None => false,
-    };
-
-    if !ucs4 {
-        #[cfg(not(target_os = "windows"))]
-        panic!("Detected Python doesn't support UCS-4 code points");
-    }
-}
--- a/rust/hgcli/src/main.rs	Thu Mar 26 11:55:06 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-// main.rs -- Main routines for `hg` program
-//
-// Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
-//
-// This software may be used and distributed according to the terms of the
-// GNU General Public License version 2 or any later version.
-
-extern crate cpython;
-extern crate libc;
-extern crate python27_sys;
-
-use cpython::{NoArgs, ObjectProtocol, PyModule, PyResult, Python};
-use libc::{c_char, c_int};
-
-use std::env;
-use std::ffi::{CString, OsStr};
-#[cfg(target_family = "unix")]
-use std::os::unix::ffi::{OsStrExt, OsStringExt};
-use std::path::PathBuf;
-
-#[derive(Debug)]
-struct Environment {
-    _exe: PathBuf,
-    python_exe: PathBuf,
-    python_home: PathBuf,
-    mercurial_modules: PathBuf,
-}
-
-/// Run Mercurial locally from a source distribution or checkout.
-///
-/// hg is <srcdir>/rust/target/<target>/hg
-/// Python interpreter is detected by build script.
-/// Python home is relative to Python interpreter.
-/// Mercurial files are relative to hg binary, which is relative to source root.
-#[cfg(feature = "localdev")]
-fn get_environment() -> Environment {
-    let exe = env::current_exe().unwrap();
-
-    let mut mercurial_modules = exe.clone();
-    mercurial_modules.pop(); // /rust/target/<target>
-    mercurial_modules.pop(); // /rust/target
-    mercurial_modules.pop(); // /rust
-    mercurial_modules.pop(); // /
-
-    let python_exe: &'static str = env!("PYTHON_INTERPRETER");
-    let python_exe = PathBuf::from(python_exe);
-
-    let mut python_home = python_exe.clone();
-    python_home.pop();
-
-    // On Windows, python2.7.exe exists at the root directory of the Python
-    // install. Everywhere else, the Python install root is one level up.
-    if !python_exe.ends_with("python2.7.exe") {
-        python_home.pop();
-    }
-
-    Environment {
-        _exe: exe.clone(),
-        python_exe: python_exe,
-        python_home: python_home,
-        mercurial_modules: mercurial_modules.to_path_buf(),
-    }
-}
-
-// On UNIX, platform string is just bytes and should not contain NUL.
-#[cfg(target_family = "unix")]
-fn cstring_from_os<T: AsRef<OsStr>>(s: T) -> CString {
-    CString::new(s.as_ref().as_bytes()).unwrap()
-}
-
-// TODO convert to ANSI characters?
-#[cfg(target_family = "windows")]
-fn cstring_from_os<T: AsRef<OsStr>>(s: T) -> CString {
-    CString::new(s.as_ref().to_str().unwrap()).unwrap()
-}
-
-// On UNIX, argv starts as an array of char*. So it is easy to convert
-// to C strings.
-#[cfg(target_family = "unix")]
-fn args_to_cstrings() -> Vec<CString> {
-    env::args_os()
-        .map(|a| CString::new(a.into_vec()).unwrap())
-        .collect()
-}
-
-// TODO Windows support is incomplete. We should either use env::args_os()
-// (or call into GetCommandLineW() + CommandLinetoArgvW()), convert these to
-// PyUnicode instances, and pass these into Python/Mercurial outside the
-// standard PySys_SetArgvEx() mechanism. This will allow us to preserve the
-// raw bytes (since PySys_SetArgvEx() is based on char* and can drop wchar
-// data.
-//
-// For now, we use env::args(). This will choke on invalid UTF-8 arguments.
-// But it is better than nothing.
-#[cfg(target_family = "windows")]
-fn args_to_cstrings() -> Vec<CString> {
-    env::args().map(|a| CString::new(a).unwrap()).collect()
-}
-
-fn set_python_home(env: &Environment) {
-    let raw = cstring_from_os(&env.python_home).into_raw();
-    unsafe {
-        python27_sys::Py_SetPythonHome(raw);
-    }
-}
-
-fn update_modules_path(env: &Environment, py: Python, sys_mod: &PyModule) {
-    let sys_path = sys_mod.get(py, "path").unwrap();
-    sys_path
-        .call_method(py, "insert", (0, env.mercurial_modules.to_str()), None)
-        .expect("failed to update sys.path to location of Mercurial modules");
-}
-
-fn run() -> Result<(), i32> {
-    let env = get_environment();
-
-    //println!("{:?}", env);
-
-    // Tell Python where it is installed.
-    set_python_home(&env);
-
-    // Set program name. The backing memory needs to live for the duration of the
-    // interpreter.
-    //
-    // TODO consider storing this in a static or associating with lifetime of
-    // the Python interpreter.
-    //
-    // Yes, we use the path to the Python interpreter not argv[0] here. The
-    // reason is because Python uses the given path to find the location of
-    // Python files. Apparently we could define our own ``Py_GetPath()``
-    // implementation. But this may require statically linking Python, which is
-    // not desirable.
-    let program_name = cstring_from_os(&env.python_exe).as_ptr();
-    unsafe {
-        python27_sys::Py_SetProgramName(program_name as *mut i8);
-    }
-
-    unsafe {
-        python27_sys::Py_Initialize();
-    }
-
-    // https://docs.python.org/2/c-api/init.html#c.PySys_SetArgvEx has important
-    // usage information about PySys_SetArgvEx:
-    //
-    // * It says the first argument should be the script that is being executed.
-    //   If not a script, it can be empty. We are definitely not a script.
-    //   However, parts of Mercurial do look at sys.argv[0]. So we need to set
-    //   something here.
-    //
-    // * When embedding Python, we should use ``PySys_SetArgvEx()`` and set
-    //   ``updatepath=0`` for security reasons. Essentially, Python's default
-    //   logic will treat an empty argv[0] in a manner that could result in
-    //   sys.path picking up directories it shouldn't and this could lead to
-    //   loading untrusted modules.
-
-    // env::args() will panic if it sees a non-UTF-8 byte sequence. And
-    // Mercurial supports arbitrary encodings of input data. So we need to
-    // use OS-specific mechanisms to get the raw bytes without UTF-8
-    // interference.
-    let args = args_to_cstrings();
-    let argv: Vec<*const c_char> = args.iter().map(|a| a.as_ptr()).collect();
-
-    unsafe {
-        python27_sys::PySys_SetArgvEx(args.len() as c_int, argv.as_ptr() as *mut *mut i8, 0);
-    }
-
-    let result;
-    {
-        // These need to be dropped before we call Py_Finalize(). Hence the
-        // block.
-        let gil = Python::acquire_gil();
-        let py = gil.python();
-
-        // Mercurial code could call sys.exit(), which will call exit()
-        // itself. So this may not return.
-        // TODO this may cause issues on Windows due to the CRT mismatch.
-        // Investigate if we can intercept sys.exit() or SystemExit() to
-        // ensure we handle process exit.
-        result = match run_py(&env, py) {
-            // Print unhandled exceptions and exit code 255, as this is what
-            // `python` does.
-            Err(err) => {
-                err.print(py);
-                Err(255)
-            }
-            Ok(()) => Ok(()),
-        };
-    }
-
-    unsafe {
-        python27_sys::Py_Finalize();
-    }
-
-    result
-}
-
-fn run_py(env: &Environment, py: Python) -> PyResult<()> {
-    let sys_mod = py.import("sys").unwrap();
-
-    update_modules_path(&env, py, &sys_mod);
-
-    // TODO consider a better error message on failure to import.
-    let demand_mod = py.import("hgdemandimport")?;
-    demand_mod.call(py, "enable", NoArgs, None)?;
-
-    let dispatch_mod = py.import("mercurial.dispatch")?;
-    dispatch_mod.call(py, "run", NoArgs, None)?;
-
-    Ok(())
-}
-
-fn main() {
-    let exit_code = match run() {
-        Err(err) => err,
-        Ok(()) => 0,
-    };
-
-    std::process::exit(exit_code);
-}