author | Gregory Szorc <gregory.szorc@gmail.com> |
Sat, 05 Oct 2019 17:01:02 -0400 | |
changeset 43073 | 5c9c71cde1c9 |
parent 35632 | fa9747e7fc86 |
child 43818 | ce088b38f92b |
permissions | -rw-r--r-- |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
1 |
// main.rs -- Main routines for `hg` program |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
2 |
// |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
3 |
// Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com> |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
4 |
// |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
5 |
// This software may be used and distributed according to the terms of the |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
6 |
// GNU General Public License version 2 or any later version. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
7 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
8 |
extern crate libc; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
9 |
extern crate cpython; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
10 |
extern crate python27_sys; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
11 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
12 |
use cpython::{NoArgs, ObjectProtocol, PyModule, PyResult, Python}; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
13 |
use libc::{c_char, c_int}; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
14 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
15 |
use std::env; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
16 |
use std::path::PathBuf; |
35631
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
17 |
use std::ffi::{CString, OsStr}; |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
18 |
#[cfg(target_family = "unix")] |
35632
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
19 |
use std::os::unix::ffi::{OsStrExt, OsStringExt}; |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
20 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
21 |
#[derive(Debug)] |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
22 |
struct Environment { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
23 |
_exe: PathBuf, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
24 |
python_exe: PathBuf, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
25 |
python_home: PathBuf, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
26 |
mercurial_modules: PathBuf, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
27 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
28 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
29 |
/// Run Mercurial locally from a source distribution or checkout. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
30 |
/// |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
31 |
/// hg is <srcdir>/rust/target/<target>/hg |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
32 |
/// Python interpreter is detected by build script. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
33 |
/// Python home is relative to Python interpreter. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
34 |
/// Mercurial files are relative to hg binary, which is relative to source root. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
35 |
#[cfg(feature = "localdev")] |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
36 |
fn get_environment() -> Environment { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
37 |
let exe = env::current_exe().unwrap(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
38 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
39 |
let mut mercurial_modules = exe.clone(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
40 |
mercurial_modules.pop(); // /rust/target/<target> |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
41 |
mercurial_modules.pop(); // /rust/target |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
42 |
mercurial_modules.pop(); // /rust |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
43 |
mercurial_modules.pop(); // / |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
44 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
45 |
let python_exe: &'static str = env!("PYTHON_INTERPRETER"); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
46 |
let python_exe = PathBuf::from(python_exe); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
47 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
48 |
let mut python_home = python_exe.clone(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
49 |
python_home.pop(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
50 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
51 |
// On Windows, python2.7.exe exists at the root directory of the Python |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
52 |
// install. Everywhere else, the Python install root is one level up. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
53 |
if !python_exe.ends_with("python2.7.exe") { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
54 |
python_home.pop(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
55 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
56 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
57 |
Environment { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
58 |
_exe: exe.clone(), |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
59 |
python_exe: python_exe, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
60 |
python_home: python_home, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
61 |
mercurial_modules: mercurial_modules.to_path_buf(), |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
62 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
63 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
64 |
|
35632
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
65 |
// On UNIX, platform string is just bytes and should not contain NUL. |
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
66 |
#[cfg(target_family = "unix")] |
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
67 |
fn cstring_from_os<T: AsRef<OsStr>>(s: T) -> CString { |
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
68 |
CString::new(s.as_ref().as_bytes()).unwrap() |
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
69 |
} |
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
70 |
|
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
71 |
// TODO convert to ANSI characters? |
fa9747e7fc86
rust: convert Unix path to CString transparently
Yuya Nishihara <yuya@tcha.org>
parents:
35631
diff
changeset
|
72 |
#[cfg(target_family = "windows")] |
35631
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
73 |
fn cstring_from_os<T: AsRef<OsStr>>(s: T) -> CString { |
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
74 |
CString::new(s.as_ref().to_str().unwrap()).unwrap() |
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
75 |
} |
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
76 |
|
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
77 |
// On UNIX, argv starts as an array of char*. So it is easy to convert |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
78 |
// to C strings. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
79 |
#[cfg(target_family = "unix")] |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
80 |
fn args_to_cstrings() -> Vec<CString> { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
81 |
env::args_os() |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
82 |
.map(|a| CString::new(a.into_vec()).unwrap()) |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
83 |
.collect() |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
84 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
85 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
86 |
// TODO Windows support is incomplete. We should either use env::args_os() |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
87 |
// (or call into GetCommandLineW() + CommandLinetoArgvW()), convert these to |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
88 |
// PyUnicode instances, and pass these into Python/Mercurial outside the |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
89 |
// standard PySys_SetArgvEx() mechanism. This will allow us to preserve the |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
90 |
// raw bytes (since PySys_SetArgvEx() is based on char* and can drop wchar |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
91 |
// data. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
92 |
// |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
93 |
// For now, we use env::args(). This will choke on invalid UTF-8 arguments. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
94 |
// But it is better than nothing. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
95 |
#[cfg(target_family = "windows")] |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
96 |
fn args_to_cstrings() -> Vec<CString> { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
97 |
env::args().map(|a| CString::new(a).unwrap()).collect() |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
98 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
99 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
100 |
fn set_python_home(env: &Environment) { |
35631
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
101 |
let raw = cstring_from_os(&env.python_home).into_raw(); |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
102 |
unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
103 |
python27_sys::Py_SetPythonHome(raw); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
104 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
105 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
106 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
107 |
fn update_modules_path(env: &Environment, py: Python, sys_mod: &PyModule) { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
108 |
let sys_path = sys_mod.get(py, "path").unwrap(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
109 |
sys_path |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
110 |
.call_method(py, "insert", (0, env.mercurial_modules.to_str()), None) |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
111 |
.expect("failed to update sys.path to location of Mercurial modules"); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
112 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
113 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
114 |
fn run() -> Result<(), i32> { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
115 |
let env = get_environment(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
116 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
117 |
//println!("{:?}", env); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
118 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
119 |
// Tell Python where it is installed. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
120 |
set_python_home(&env); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
121 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
122 |
// Set program name. The backing memory needs to live for the duration of the |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
123 |
// interpreter. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
124 |
// |
35604
74bec9e74831
rust: add TODO about lifetime of program_name variable
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35569
diff
changeset
|
125 |
// TODO consider storing this in a static or associating with lifetime of |
74bec9e74831
rust: add TODO about lifetime of program_name variable
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35569
diff
changeset
|
126 |
// the Python interpreter. |
74bec9e74831
rust: add TODO about lifetime of program_name variable
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35569
diff
changeset
|
127 |
// |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
128 |
// Yes, we use the path to the Python interpreter not argv[0] here. The |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
129 |
// reason is because Python uses the given path to find the location of |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
130 |
// Python files. Apparently we could define our own ``Py_GetPath()`` |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
131 |
// implementation. But this may require statically linking Python, which is |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
132 |
// not desirable. |
35631
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
133 |
let program_name = cstring_from_os(&env.python_exe).as_ptr(); |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
134 |
unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
135 |
python27_sys::Py_SetProgramName(program_name as *mut i8); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
136 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
137 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
138 |
unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
139 |
python27_sys::Py_Initialize(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
140 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
141 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
142 |
// https://docs.python.org/2/c-api/init.html#c.PySys_SetArgvEx has important |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
143 |
// usage information about PySys_SetArgvEx: |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
144 |
// |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
145 |
// * It says the first argument should be the script that is being executed. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
146 |
// If not a script, it can be empty. We are definitely not a script. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
147 |
// However, parts of Mercurial do look at sys.argv[0]. So we need to set |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
148 |
// something here. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
149 |
// |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
150 |
// * When embedding Python, we should use ``PySys_SetArgvEx()`` and set |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
151 |
// ``updatepath=0`` for security reasons. Essentially, Python's default |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
152 |
// logic will treat an empty argv[0] in a manner that could result in |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
153 |
// sys.path picking up directories it shouldn't and this could lead to |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
154 |
// loading untrusted modules. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
155 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
156 |
// env::args() will panic if it sees a non-UTF-8 byte sequence. And |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
157 |
// Mercurial supports arbitrary encodings of input data. So we need to |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
158 |
// use OS-specific mechanisms to get the raw bytes without UTF-8 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
159 |
// interference. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
160 |
let args = args_to_cstrings(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
161 |
let argv: Vec<*const c_char> = args.iter().map(|a| a.as_ptr()).collect(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
162 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
163 |
unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
164 |
python27_sys::PySys_SetArgvEx(args.len() as c_int, argv.as_ptr() as *mut *mut i8, 0); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
165 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
166 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
167 |
let result; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
168 |
{ |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
169 |
// These need to be dropped before we call Py_Finalize(). Hence the |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
170 |
// block. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
171 |
let gil = Python::acquire_gil(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
172 |
let py = gil.python(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
173 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
174 |
// Mercurial code could call sys.exit(), which will call exit() |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
175 |
// itself. So this may not return. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
176 |
// TODO this may cause issues on Windows due to the CRT mismatch. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
177 |
// Investigate if we can intercept sys.exit() or SystemExit() to |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
178 |
// ensure we handle process exit. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
179 |
result = match run_py(&env, py) { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
180 |
// Print unhandled exceptions and exit code 255, as this is what |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
181 |
// `python` does. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
182 |
Err(err) => { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
183 |
err.print(py); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
184 |
Err(255) |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
185 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
186 |
Ok(()) => Ok(()), |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
187 |
}; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
188 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
189 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
190 |
unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
191 |
python27_sys::Py_Finalize(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
192 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
193 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
194 |
result |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
195 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
196 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
197 |
fn run_py(env: &Environment, py: Python) -> PyResult<()> { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
198 |
let sys_mod = py.import("sys").unwrap(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
199 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
200 |
update_modules_path(&env, py, &sys_mod); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
201 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
202 |
// TODO consider a better error message on failure to import. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
203 |
let demand_mod = py.import("hgdemandimport")?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
204 |
demand_mod.call(py, "enable", NoArgs, None)?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
205 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
206 |
let dispatch_mod = py.import("mercurial.dispatch")?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
207 |
dispatch_mod.call(py, "run", NoArgs, None)?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
208 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
209 |
Ok(()) |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
210 |
} |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
211 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
212 |
fn main() { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
213 |
let exit_code = match run() { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
214 |
Err(err) => err, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
215 |
Ok(()) => 0, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
216 |
}; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
217 |
|
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
218 |
std::process::exit(exit_code); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
219 |
} |