Mercurial > hg
annotate rust/hgcli/src/main.rs @ 36728:f14ba6eb2b5a
archival: use py3 friendly replacements for chr() and long()
Differential Revision: https://phab.mercurial-scm.org/D2673
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 04 Mar 2018 16:06:47 -0500 |
parents | fa9747e7fc86 |
children | 5c9c71cde1c9 |
rev | line source |
---|---|
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_encoding(_py: Python, _sys_mod: &PyModule) { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
108 // Call sys.setdefaultencoding("undefined") if HGUNICODEPEDANTRY is set. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
109 let pedantry = env::var("HGUNICODEPEDANTRY").is_ok(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
110 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
111 if pedantry { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
112 // site.py removes the sys.setdefaultencoding attribute. So we need |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
113 // to reload the module to get a handle on it. This is a lesser |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
114 // used feature and we'll support this later. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
115 // TODO support this |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
116 panic!("HGUNICODEPEDANTRY is not yet supported"); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
117 } |
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 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
120 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
|
121 let sys_path = sys_mod.get(py, "path").unwrap(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
122 sys_path |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
123 .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
|
124 .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
|
125 } |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
126 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
127 fn run() -> Result<(), i32> { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
128 let env = get_environment(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
129 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
130 //println!("{:?}", env); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
131 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
132 // Tell Python where it is installed. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
133 set_python_home(&env); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
134 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
135 // 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
|
136 // interpreter. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
137 // |
35604
74bec9e74831
rust: add TODO about lifetime of program_name variable
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35569
diff
changeset
|
138 // 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
|
139 // the Python interpreter. |
74bec9e74831
rust: add TODO about lifetime of program_name variable
Gregory Szorc <gregory.szorc@gmail.com>
parents:
35569
diff
changeset
|
140 // |
35569
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
141 // 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
|
142 // 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
|
143 // Python files. Apparently we could define our own ``Py_GetPath()`` |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
144 // implementation. But this may require statically linking Python, which is |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
145 // not desirable. |
35631
edbe11cfedcf
rust: extract function to convert Path to platform CString
Yuya Nishihara <yuya@tcha.org>
parents:
35604
diff
changeset
|
146 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
|
147 unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
148 python27_sys::Py_SetProgramName(program_name as *mut i8); |
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 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
151 unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
152 python27_sys::Py_Initialize(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
153 } |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
154 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
155 // 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
|
156 // usage information about PySys_SetArgvEx: |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
157 // |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
158 // * 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
|
159 // 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
|
160 // 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
|
161 // something here. |
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 // * When embedding Python, we should use ``PySys_SetArgvEx()`` and set |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
164 // ``updatepath=0`` for security reasons. Essentially, Python's default |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
165 // 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
|
166 // 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
|
167 // loading untrusted modules. |
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 // 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
|
170 // 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
|
171 // 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
|
172 // interference. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
173 let args = args_to_cstrings(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
174 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
|
175 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
176 unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
177 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
|
178 } |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
179 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
180 let result; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
181 { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
182 // 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
|
183 // block. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
184 let gil = Python::acquire_gil(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
185 let py = gil.python(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
186 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
187 // Mercurial code could call sys.exit(), which will call exit() |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
188 // itself. So this may not return. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
189 // 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
|
190 // Investigate if we can intercept sys.exit() or SystemExit() to |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
191 // ensure we handle process exit. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
192 result = match run_py(&env, py) { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
193 // 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
|
194 // `python` does. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
195 Err(err) => { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
196 err.print(py); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
197 Err(255) |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
198 } |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
199 Ok(()) => Ok(()), |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
200 }; |
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 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
203 unsafe { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
204 python27_sys::Py_Finalize(); |
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 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
207 result |
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 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
210 fn run_py(env: &Environment, py: Python) -> PyResult<()> { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
211 let sys_mod = py.import("sys").unwrap(); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
212 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
213 update_encoding(py, &sys_mod); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
214 update_modules_path(&env, py, &sys_mod); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
215 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
216 // TODO consider a better error message on failure to import. |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
217 let demand_mod = py.import("hgdemandimport")?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
218 demand_mod.call(py, "enable", NoArgs, None)?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
219 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
220 let dispatch_mod = py.import("mercurial.dispatch")?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
221 dispatch_mod.call(py, "run", NoArgs, None)?; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
222 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
223 Ok(()) |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
224 } |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
225 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
226 fn main() { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
227 let exit_code = match run() { |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
228 Err(err) => err, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
229 Ok(()) => 0, |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
230 }; |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
231 |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
232 std::process::exit(exit_code); |
964212780daf
rust: implementation of `hg`
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff
changeset
|
233 } |