@@ -2,6 +2,9 @@ use std::env;
22use std:: ffi:: OsString ;
33use std:: io:: Write ;
44use std:: ops:: Not ;
5+ use std:: process;
6+ use std:: thread;
7+ use std:: time;
58
69use anyhow:: { anyhow, bail, Context , Result } ;
710use path_macro:: path;
@@ -14,6 +17,7 @@ use crate::Command;
1417/// Used for rustc syncs.
1518const JOSH_FILTER : & str =
1619 ":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri" ;
20+ const JOSH_PORT : & str = "42042" ;
1721
1822impl MiriEnv {
1923 fn build_miri_sysroot ( & mut self , quiet : bool ) -> Result < ( ) > {
@@ -81,6 +85,55 @@ impl Command {
8185 Ok ( ( ) )
8286 }
8387
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+
84137 pub fn exec ( self ) -> Result < ( ) > {
85138 // First, and crucially only once, run the auto-actions -- but not for all commands.
86139 match & self {
@@ -174,6 +227,8 @@ impl Command {
174227 if cmd ! ( sh, "git status --untracked-files=no --porcelain" ) . read ( ) ?. is_empty ( ) . not ( ) {
175228 bail ! ( "working directory must be clean before running `./miri rustc-pull`" ) ;
176229 }
230+ // Make sure josh is running.
231+ let josh = Self :: start_josh ( ) ?;
177232
178233 // Update rust-version file. As a separate commit, since making it part of
179234 // the merge has confused the heck out of josh in the past.
@@ -186,7 +241,7 @@ impl Command {
186241 . context ( "FAILED to commit rust-version file, something went wrong" ) ?;
187242
188243 // 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" )
190245 . run ( )
191246 . map_err ( |e| {
192247 // 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 {
202257 cmd ! ( sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}" )
203258 . run ( )
204259 . context ( "FAILED to merge new commits, something went wrong" ) ?;
260+
261+ drop ( josh) ;
205262 Ok ( ( ) )
206263 }
207264
@@ -213,6 +270,8 @@ impl Command {
213270 if cmd ! ( sh, "git status --untracked-files=no --porcelain" ) . read ( ) ?. is_empty ( ) . not ( ) {
214271 bail ! ( "working directory must be clean before running `./miri rustc-push`" ) ;
215272 }
273+ // Make sure josh is running.
274+ let josh = Self :: start_josh ( ) ?;
216275
217276 // Find a repo we can do our preparation in.
218277 if let Ok ( rustc_git) = env:: var ( "RUSTC_GIT" ) {
@@ -249,6 +308,8 @@ impl Command {
249308 }
250309 cmd ! ( sh, "git fetch https://github.com/rust-lang/rust {base}" ) . run ( ) ?;
251310 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
252313 . run ( ) ?;
253314 println ! ( ) ;
254315
@@ -257,15 +318,15 @@ impl Command {
257318 println ! ( "Pushing miri changes..." ) ;
258319 cmd ! (
259320 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}"
261322 )
262323 . run ( ) ?;
263324 println ! ( ) ;
264325
265326 // Do a round-trip check to make sure the push worked as expected.
266327 cmd ! (
267328 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}"
269330 )
270331 . ignore_stderr ( )
271332 . read ( ) ?;
@@ -278,6 +339,8 @@ impl Command {
278339 "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
279340 ) ;
280341 println ! ( " https://github.com/{github_user}/rust/pull/new/{branch}" ) ;
342+
343+ drop ( josh) ;
281344 Ok ( ( ) )
282345 }
283346
0 commit comments