@@ -2,6 +2,9 @@ use std::env;
2
2
use std:: ffi:: OsString ;
3
3
use std:: io:: Write ;
4
4
use std:: ops:: Not ;
5
+ use std:: process;
6
+ use std:: thread;
7
+ use std:: time;
5
8
6
9
use anyhow:: { anyhow, bail, Context , Result } ;
7
10
use path_macro:: path;
@@ -14,6 +17,7 @@ use crate::Command;
14
17
/// Used for rustc syncs.
15
18
const JOSH_FILTER : & str =
16
19
":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri" ;
20
+ const JOSH_PORT : & str = "42042" ;
17
21
18
22
impl MiriEnv {
19
23
fn build_miri_sysroot ( & mut self , quiet : bool ) -> Result < ( ) > {
@@ -81,6 +85,55 @@ impl Command {
81
85
Ok ( ( ) )
82
86
}
83
87
88
+ fn start_josh ( ) -> Result < impl Drop > {
89
+ // Determine cache directory.
90
+ let local_dir = {
91
+ let user_dirs =
92
+ directories:: ProjectDirs :: from ( "org" , "rust-lang" , "miri-josh" ) . unwrap ( ) ;
93
+ user_dirs. cache_dir ( ) . to_owned ( )
94
+ } ;
95
+
96
+ // Start josh, silencing its output.
97
+ let mut cmd = process:: Command :: new ( "josh-proxy" ) ;
98
+ cmd. arg ( "--local" ) . arg ( local_dir) ;
99
+ cmd. arg ( "--remote" ) . arg ( "https://github.com" ) ;
100
+ cmd. arg ( "--port" ) . arg ( JOSH_PORT ) ;
101
+ cmd. arg ( "--no-background" ) ;
102
+ cmd. stdout ( process:: Stdio :: null ( ) ) ;
103
+ cmd. stderr ( process:: Stdio :: null ( ) ) ;
104
+ let josh = cmd. spawn ( ) . context ( "failed to start josh-proxy, make sure it is installed" ) ?;
105
+ // Give it some time so hopefully the port is open. (10ms was not enough.)
106
+ thread:: sleep ( time:: Duration :: from_millis ( 100 ) ) ;
107
+
108
+ // Create a wrapper that stops it on drop.
109
+ struct Josh ( process:: Child ) ;
110
+ impl Drop for Josh {
111
+ fn drop ( & mut self ) {
112
+ #[ cfg( unix) ]
113
+ {
114
+ // Try to gracefully shut it down.
115
+ process:: Command :: new ( "kill" )
116
+ . args ( [ "-s" , "INT" , & self . 0 . id ( ) . to_string ( ) ] )
117
+ . output ( )
118
+ . expect ( "failed to SIGINT josh-proxy" ) ;
119
+ // Sadly there is no "wait with timeout"... so we just give it some time to finish.
120
+ thread:: sleep ( time:: Duration :: from_millis ( 100 ) ) ;
121
+ // Now hopefully it is gone.
122
+ if self . 0 . try_wait ( ) . expect ( "failed to wait for josh-proxy" ) . is_some ( ) {
123
+ return ;
124
+ }
125
+ }
126
+ // If that didn't work (or we're not on Unix), kill it hard.
127
+ eprintln ! (
128
+ "I have to kill josh-proxy the hard way, let's hope this does not break anything."
129
+ ) ;
130
+ self . 0 . kill ( ) . expect ( "failed to SIGKILL josh-proxy" ) ;
131
+ }
132
+ }
133
+
134
+ Ok ( Josh ( josh) )
135
+ }
136
+
84
137
pub fn exec ( self ) -> Result < ( ) > {
85
138
// First, and crucially only once, run the auto-actions -- but not for all commands.
86
139
match & self {
@@ -174,6 +227,8 @@ impl Command {
174
227
if cmd ! ( sh, "git status --untracked-files=no --porcelain" ) . read ( ) ?. is_empty ( ) . not ( ) {
175
228
bail ! ( "working directory must be clean before running `./miri rustc-pull`" ) ;
176
229
}
230
+ // Make sure josh is running.
231
+ let josh = Self :: start_josh ( ) ?;
177
232
178
233
// Update rust-version file. As a separate commit, since making it part of
179
234
// the merge has confused the heck out of josh in the past.
@@ -186,7 +241,7 @@ impl Command {
186
241
. context ( "FAILED to commit rust-version file, something went wrong" ) ?;
187
242
188
243
// Fetch given rustc commit.
189
- cmd ! ( sh, "git fetch http://localhost:8000 /rust-lang/rust.git@{commit}{JOSH_FILTER}.git" )
244
+ cmd ! ( sh, "git fetch http://localhost:{JOSH_PORT} /rust-lang/rust.git@{commit}{JOSH_FILTER}.git" )
190
245
. run ( )
191
246
. map_err ( |e| {
192
247
// Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
@@ -202,6 +257,8 @@ impl Command {
202
257
cmd ! ( sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}" )
203
258
. run ( )
204
259
. context ( "FAILED to merge new commits, something went wrong" ) ?;
260
+
261
+ drop ( josh) ;
205
262
Ok ( ( ) )
206
263
}
207
264
@@ -213,6 +270,8 @@ impl Command {
213
270
if cmd ! ( sh, "git status --untracked-files=no --porcelain" ) . read ( ) ?. is_empty ( ) . not ( ) {
214
271
bail ! ( "working directory must be clean before running `./miri rustc-push`" ) ;
215
272
}
273
+ // Make sure josh is running.
274
+ let josh = Self :: start_josh ( ) ?;
216
275
217
276
// Find a repo we can do our preparation in.
218
277
if let Ok ( rustc_git) = env:: var ( "RUSTC_GIT" ) {
@@ -249,6 +308,8 @@ impl Command {
249
308
}
250
309
cmd ! ( sh, "git fetch https://github.com/rust-lang/rust {base}" ) . run ( ) ?;
251
310
cmd ! ( sh, "git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}" )
311
+ . ignore_stdout ( )
312
+ . ignore_stderr ( ) // silence the "create GitHub PR" message
252
313
. run ( ) ?;
253
314
println ! ( ) ;
254
315
@@ -257,15 +318,15 @@ impl Command {
257
318
println ! ( "Pushing miri changes..." ) ;
258
319
cmd ! (
259
320
sh,
260
- "git push http://localhost:8000 /{github_user}/rust.git{JOSH_FILTER}.git HEAD:{branch}"
321
+ "git push http://localhost:{JOSH_PORT} /{github_user}/rust.git{JOSH_FILTER}.git HEAD:{branch}"
261
322
)
262
323
. run ( ) ?;
263
324
println ! ( ) ;
264
325
265
326
// Do a round-trip check to make sure the push worked as expected.
266
327
cmd ! (
267
328
sh,
268
- "git fetch http://localhost:8000 /{github_user}/rust.git{JOSH_FILTER}.git {branch}"
329
+ "git fetch http://localhost:{JOSH_PORT} /{github_user}/rust.git{JOSH_FILTER}.git {branch}"
269
330
)
270
331
. ignore_stderr ( )
271
332
. read ( ) ?;
@@ -278,6 +339,8 @@ impl Command {
278
339
"Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
279
340
) ;
280
341
println ! ( " https://github.com/{github_user}/rust/pull/new/{branch}" ) ;
342
+
343
+ drop ( josh) ;
281
344
Ok ( ( ) )
282
345
}
283
346
0 commit comments