]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Auto merge of #52046 - cramertj:fix-generator-mir, r=eddyb
[rust.git] / src / bootstrap / dist.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Implementation of the various distribution aspects of the compiler.
12 //!
13 //! This module is responsible for creating tarballs of the standard library,
14 //! compiler, and documentation. This ends up being what we distribute to
15 //! everyone as well.
16 //!
17 //! No tarball is actually created literally in this file, but rather we shell
18 //! out to `rust-installer` still. This may one day be replaced with bits and
19 //! pieces of `rustup.rs`!
20
21 use std::env;
22 use std::fs::{self, File};
23 use std::io::{Read, Write};
24 use std::path::{PathBuf, Path};
25 use std::process::{Command, Stdio};
26
27 use build_helper::output;
28
29 use {Compiler, Mode, LLVM_TOOLS};
30 use channel;
31 use util::{libdir, is_dylib, exe};
32 use builder::{Builder, RunConfig, ShouldRun, Step};
33 use compile;
34 use native;
35 use tool::{self, Tool};
36 use cache::{INTERNER, Interned};
37 use time;
38
39 pub fn pkgname(builder: &Builder, component: &str) -> String {
40     if component == "cargo" {
41         format!("{}-{}", component, builder.cargo_package_vers())
42     } else if component == "rls" {
43         format!("{}-{}", component, builder.rls_package_vers())
44     } else if component == "clippy" {
45         format!("{}-{}", component, builder.clippy_package_vers())
46     } else if component == "rustfmt" {
47         format!("{}-{}", component, builder.rustfmt_package_vers())
48     } else if component == "llvm-tools" {
49         format!("{}-{}", component, builder.llvm_tools_package_vers())
50     } else {
51         assert!(component.starts_with("rust"));
52         format!("{}-{}", component, builder.rust_package_vers())
53     }
54 }
55
56 fn distdir(builder: &Builder) -> PathBuf {
57     builder.out.join("dist")
58 }
59
60 pub fn tmpdir(builder: &Builder) -> PathBuf {
61     builder.out.join("tmp/dist")
62 }
63
64 fn rust_installer(builder: &Builder) -> Command {
65     builder.tool_cmd(Tool::RustInstaller)
66 }
67
68 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
69 pub struct Docs {
70     pub stage: u32,
71     pub host: Interned<String>,
72 }
73
74 impl Step for Docs {
75     type Output = PathBuf;
76     const DEFAULT: bool = true;
77
78     fn should_run(run: ShouldRun) -> ShouldRun {
79         run.path("src/doc")
80     }
81
82     fn make_run(run: RunConfig) {
83         run.builder.ensure(Docs {
84             stage: run.builder.top_stage,
85             host: run.target,
86         });
87     }
88
89     /// Builds the `rust-docs` installer component.
90     fn run(self, builder: &Builder) -> PathBuf {
91         let host = self.host;
92
93         let name = pkgname(builder, "rust-docs");
94
95         builder.info(&format!("Dist docs ({})", host));
96         if !builder.config.docs {
97             builder.info(&format!("\tskipping - docs disabled"));
98             return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
99         }
100
101         builder.default_doc(None);
102
103         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
104         let _ = fs::remove_dir_all(&image);
105
106         let dst = image.join("share/doc/rust/html");
107         t!(fs::create_dir_all(&dst));
108         let src = builder.doc_out(host);
109         builder.cp_r(&src, &dst);
110
111         let mut cmd = rust_installer(builder);
112         cmd.arg("generate")
113            .arg("--product-name=Rust-Documentation")
114            .arg("--rel-manifest-dir=rustlib")
115            .arg("--success-message=Rust-documentation-is-installed.")
116            .arg("--image-dir").arg(&image)
117            .arg("--work-dir").arg(&tmpdir(builder))
118            .arg("--output-dir").arg(&distdir(builder))
119            .arg(format!("--package-name={}-{}", name, host))
120            .arg("--component-name=rust-docs")
121            .arg("--legacy-manifest-dirs=rustlib,cargo")
122            .arg("--bulk-dirs=share/doc/rust/html");
123         builder.run(&mut cmd);
124         builder.remove_dir(&image);
125
126         distdir(builder).join(format!("{}-{}.tar.gz", name, host))
127     }
128 }
129
130 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
131 pub struct RustcDocs {
132     pub stage: u32,
133     pub host: Interned<String>,
134 }
135
136 impl Step for RustcDocs {
137     type Output = PathBuf;
138     const DEFAULT: bool = true;
139
140     fn should_run(run: ShouldRun) -> ShouldRun {
141         run.path("src/librustc")
142     }
143
144     fn make_run(run: RunConfig) {
145         run.builder.ensure(RustcDocs {
146             stage: run.builder.top_stage,
147             host: run.target,
148         });
149     }
150
151     /// Builds the `rustc-docs` installer component.
152     fn run(self, builder: &Builder) -> PathBuf {
153         let host = self.host;
154
155         let name = pkgname(builder, "rustc-docs");
156
157         builder.info(&format!("Dist compiler docs ({})", host));
158         if !builder.config.compiler_docs {
159             builder.info(&format!("\tskipping - compiler docs disabled"));
160             return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
161         }
162
163         builder.default_doc(None);
164
165         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
166         let _ = fs::remove_dir_all(&image);
167
168         let dst = image.join("share/doc/rust/html");
169         t!(fs::create_dir_all(&dst));
170         let src = builder.compiler_doc_out(host);
171         builder.cp_r(&src, &dst);
172
173         let mut cmd = rust_installer(builder);
174         cmd.arg("generate")
175            .arg("--product-name=Rustc-Documentation")
176            .arg("--rel-manifest-dir=rustlib")
177            .arg("--success-message=Rustc-documentation-is-installed.")
178            .arg("--image-dir").arg(&image)
179            .arg("--work-dir").arg(&tmpdir(builder))
180            .arg("--output-dir").arg(&distdir(builder))
181            .arg(format!("--package-name={}-{}", name, host))
182            .arg("--component-name=rustc-docs")
183            .arg("--legacy-manifest-dirs=rustlib,cargo")
184            .arg("--bulk-dirs=share/doc/rust/html");
185         builder.run(&mut cmd);
186         builder.remove_dir(&image);
187
188         distdir(builder).join(format!("{}-{}.tar.gz", name, host))
189     }
190 }
191
192 fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
193     let mut found = Vec::with_capacity(files.len());
194
195     for file in files {
196         let file_path =
197             path.iter()
198                 .map(|dir| dir.join(file))
199                 .find(|p| p.exists());
200
201         if let Some(file_path) = file_path {
202             found.push(file_path);
203         } else {
204             panic!("Could not find '{}' in {:?}", file, path);
205         }
206     }
207
208     found
209 }
210
211 fn make_win_dist(
212     rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, builder: &Builder
213 ) {
214     //Ask gcc where it keeps its stuff
215     let mut cmd = Command::new(builder.cc(target_triple));
216     cmd.arg("-print-search-dirs");
217     let gcc_out = output(&mut cmd);
218
219     let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
220     let mut lib_path = Vec::new();
221
222     for line in gcc_out.lines() {
223         let idx = line.find(':').unwrap();
224         let key = &line[..idx];
225         let trim_chars: &[_] = &[' ', '='];
226         let value =
227             line[(idx + 1)..]
228                 .trim_left_matches(trim_chars)
229                 .split(';')
230                 .map(PathBuf::from);
231
232         if key == "programs" {
233             bin_path.extend(value);
234         } else if key == "libraries" {
235             lib_path.extend(value);
236         }
237     }
238
239     let target_tools = ["gcc.exe", "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
240     let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"];
241     if target_triple.starts_with("i686-") {
242         rustc_dlls.push("libgcc_s_dw2-1.dll");
243     } else {
244         rustc_dlls.push("libgcc_s_seh-1.dll");
245     }
246
247     let target_libs = [ //MinGW libs
248         "libgcc.a",
249         "libgcc_eh.a",
250         "libgcc_s.a",
251         "libm.a",
252         "libmingw32.a",
253         "libmingwex.a",
254         "libstdc++.a",
255         "libiconv.a",
256         "libmoldname.a",
257         "libpthread.a",
258         //Windows import libs
259         "libadvapi32.a",
260         "libbcrypt.a",
261         "libcomctl32.a",
262         "libcomdlg32.a",
263         "libcredui.a",
264         "libcrypt32.a",
265         "libdbghelp.a",
266         "libgdi32.a",
267         "libimagehlp.a",
268         "libiphlpapi.a",
269         "libkernel32.a",
270         "libmsimg32.a",
271         "libmsvcrt.a",
272         "libodbc32.a",
273         "libole32.a",
274         "liboleaut32.a",
275         "libopengl32.a",
276         "libpsapi.a",
277         "librpcrt4.a",
278         "libsecur32.a",
279         "libsetupapi.a",
280         "libshell32.a",
281         "libsynchronization.a",
282         "libuser32.a",
283         "libuserenv.a",
284         "libuuid.a",
285         "libwinhttp.a",
286         "libwinmm.a",
287         "libwinspool.a",
288         "libws2_32.a",
289         "libwsock32.a",
290     ];
291
292     //Find mingw artifacts we want to bundle
293     let target_tools = find_files(&target_tools, &bin_path);
294     let rustc_dlls = find_files(&rustc_dlls, &bin_path);
295     let target_libs = find_files(&target_libs, &lib_path);
296
297     // Copy runtime dlls next to rustc.exe
298     let dist_bin_dir = rust_root.join("bin/");
299     fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
300     for src in rustc_dlls {
301         builder.copy_to_folder(&src, &dist_bin_dir);
302     }
303
304     //Copy platform tools to platform-specific bin directory
305     let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
306     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
307     for src in target_tools {
308         builder.copy_to_folder(&src, &target_bin_dir);
309     }
310
311     // Warn windows-gnu users that the bundled GCC cannot compile C files
312     builder.create(
313         &target_bin_dir.join("GCC-WARNING.txt"),
314         "gcc.exe contained in this folder cannot be used for compiling C files - it is only\
315          used as a linker. In order to be able to compile projects containing C code use\
316          the GCC provided by MinGW or Cygwin."
317     );
318
319     //Copy platform libs to platform-specific lib directory
320     let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
321     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
322     for src in target_libs {
323         builder.copy_to_folder(&src, &target_lib_dir);
324     }
325 }
326
327 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
328 pub struct Mingw {
329     pub host: Interned<String>,
330 }
331
332 impl Step for Mingw {
333     type Output = Option<PathBuf>;
334     const DEFAULT: bool = true;
335
336     fn should_run(run: ShouldRun) -> ShouldRun {
337         run.never()
338     }
339
340     fn make_run(run: RunConfig) {
341         run.builder.ensure(Mingw { host: run.target });
342     }
343
344     /// Build the `rust-mingw` installer component.
345     ///
346     /// This contains all the bits and pieces to run the MinGW Windows targets
347     /// without any extra installed software (e.g. we bundle gcc, libraries, etc).
348     fn run(self, builder: &Builder) -> Option<PathBuf> {
349         let host = self.host;
350
351         if !host.contains("pc-windows-gnu") {
352             return None;
353         }
354
355         builder.info(&format!("Dist mingw ({})", host));
356         let name = pkgname(builder, "rust-mingw");
357         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
358         let _ = fs::remove_dir_all(&image);
359         t!(fs::create_dir_all(&image));
360
361         // The first argument is a "temporary directory" which is just
362         // thrown away (this contains the runtime DLLs included in the rustc package
363         // above) and the second argument is where to place all the MinGW components
364         // (which is what we want).
365         make_win_dist(&tmpdir(builder), &image, host, &builder);
366
367         let mut cmd = rust_installer(builder);
368         cmd.arg("generate")
369            .arg("--product-name=Rust-MinGW")
370            .arg("--rel-manifest-dir=rustlib")
371            .arg("--success-message=Rust-MinGW-is-installed.")
372            .arg("--image-dir").arg(&image)
373            .arg("--work-dir").arg(&tmpdir(builder))
374            .arg("--output-dir").arg(&distdir(builder))
375            .arg(format!("--package-name={}-{}", name, host))
376            .arg("--component-name=rust-mingw")
377            .arg("--legacy-manifest-dirs=rustlib,cargo");
378         builder.run(&mut cmd);
379         t!(fs::remove_dir_all(&image));
380         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host)))
381     }
382 }
383
384 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
385 pub struct Rustc {
386     pub compiler: Compiler,
387 }
388
389 impl Step for Rustc {
390     type Output = PathBuf;
391     const DEFAULT: bool = true;
392     const ONLY_HOSTS: bool = true;
393
394     fn should_run(run: ShouldRun) -> ShouldRun {
395         run.path("src/librustc")
396     }
397
398     fn make_run(run: RunConfig) {
399         run.builder.ensure(Rustc {
400             compiler: run.builder.compiler(run.builder.top_stage, run.target),
401         });
402     }
403
404     /// Creates the `rustc` installer component.
405     fn run(self, builder: &Builder) -> PathBuf {
406         let compiler = self.compiler;
407         let host = self.compiler.host;
408
409         builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host));
410         let name = pkgname(builder, "rustc");
411         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
412         let _ = fs::remove_dir_all(&image);
413         let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host));
414         let _ = fs::remove_dir_all(&overlay);
415
416         // Prepare the rustc "image", what will actually end up getting installed
417         prepare_image(builder, compiler, &image);
418
419         // Prepare the overlay which is part of the tarball but won't actually be
420         // installed
421         let cp = |file: &str| {
422             builder.install(&builder.src.join(file), &overlay, 0o644);
423         };
424         cp("COPYRIGHT");
425         cp("LICENSE-APACHE");
426         cp("LICENSE-MIT");
427         cp("README.md");
428         // tiny morsel of metadata is used by rust-packaging
429         let version = builder.rust_version();
430         builder.create(&overlay.join("version"), &version);
431         if let Some(sha) = builder.rust_sha() {
432             builder.create(&overlay.join("git-commit-hash"), &sha);
433         }
434
435         // On MinGW we've got a few runtime DLL dependencies that we need to
436         // include. The first argument to this script is where to put these DLLs
437         // (the image we're creating), and the second argument is a junk directory
438         // to ignore all other MinGW stuff the script creates.
439         //
440         // On 32-bit MinGW we're always including a DLL which needs some extra
441         // licenses to distribute. On 64-bit MinGW we don't actually distribute
442         // anything requiring us to distribute a license, but it's likely the
443         // install will *also* include the rust-mingw package, which also needs
444         // licenses, so to be safe we just include it here in all MinGW packages.
445         if host.contains("pc-windows-gnu") {
446             make_win_dist(&image, &tmpdir(builder), host, builder);
447
448             let dst = image.join("share/doc");
449             t!(fs::create_dir_all(&dst));
450             builder.cp_r(&builder.src.join("src/etc/third-party"), &dst);
451         }
452
453         // Finally, wrap everything up in a nice tarball!
454         let mut cmd = rust_installer(builder);
455         cmd.arg("generate")
456            .arg("--product-name=Rust")
457            .arg("--rel-manifest-dir=rustlib")
458            .arg("--success-message=Rust-is-ready-to-roll.")
459            .arg("--image-dir").arg(&image)
460            .arg("--work-dir").arg(&tmpdir(builder))
461            .arg("--output-dir").arg(&distdir(builder))
462            .arg("--non-installed-overlay").arg(&overlay)
463            .arg(format!("--package-name={}-{}", name, host))
464            .arg("--component-name=rustc")
465            .arg("--legacy-manifest-dirs=rustlib,cargo");
466         builder.run(&mut cmd);
467         builder.remove_dir(&image);
468         builder.remove_dir(&overlay);
469
470         return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
471
472         fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) {
473             let host = compiler.host;
474             let src = builder.sysroot(compiler);
475             let libdir = libdir(&host);
476
477             // Copy rustc/rustdoc binaries
478             t!(fs::create_dir_all(image.join("bin")));
479             builder.cp_r(&src.join("bin"), &image.join("bin"));
480
481             builder.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
482
483             // Copy runtime DLLs needed by the compiler
484             if libdir != "bin" {
485                 for entry in builder.read_dir(&src.join(libdir)) {
486                     let name = entry.file_name();
487                     if let Some(s) = name.to_str() {
488                         if is_dylib(s) {
489                             builder.install(&entry.path(), &image.join(libdir), 0o644);
490                         }
491                     }
492                 }
493             }
494
495             // Copy over the codegen backends
496             let backends_src = builder.sysroot_codegen_backends(compiler);
497             let backends_rel = backends_src.strip_prefix(&src).unwrap();
498             let backends_dst = image.join(&backends_rel);
499             t!(fs::create_dir_all(&backends_dst));
500             builder.cp_r(&backends_src, &backends_dst);
501
502             // Copy over lld if it's there
503             if builder.config.lld_enabled {
504                 let exe = exe("rust-lld", &compiler.host);
505                 let src = builder.sysroot_libdir(compiler, host)
506                     .parent()
507                     .unwrap()
508                     .join("bin")
509                     .join(&exe);
510                 // for the rationale about this rename check `compile::copy_lld_to_sysroot`
511                 let dst = image.join("lib/rustlib")
512                     .join(&*host)
513                     .join("bin")
514                     .join(&exe);
515                 t!(fs::create_dir_all(&dst.parent().unwrap()));
516                 builder.copy(&src, &dst);
517             }
518
519             // Man pages
520             t!(fs::create_dir_all(image.join("share/man/man1")));
521             let man_src = builder.src.join("src/doc/man");
522             let man_dst = image.join("share/man/man1");
523             let month_year = t!(time::strftime("%B %Y", &time::now()));
524             // don't use our `bootstrap::util::{copy, cp_r}`, because those try
525             // to hardlink, and we don't want to edit the source templates
526             for file_entry in builder.read_dir(&man_src) {
527                 let page_src = file_entry.path();
528                 let page_dst = man_dst.join(file_entry.file_name());
529                 t!(fs::copy(&page_src, &page_dst));
530                 // template in month/year and version number
531                 builder.replace_in_file(&page_dst,
532                                 &[("<INSERT DATE HERE>", &month_year),
533                                   ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
534             }
535
536             // Debugger scripts
537             builder.ensure(DebuggerScripts {
538                 sysroot: INTERNER.intern_path(image.to_owned()),
539                 host,
540             });
541
542             // Misc license info
543             let cp = |file: &str| {
544                 builder.install(&builder.src.join(file), &image.join("share/doc/rust"), 0o644);
545             };
546             cp("COPYRIGHT");
547             cp("LICENSE-APACHE");
548             cp("LICENSE-MIT");
549             cp("README.md");
550         }
551     }
552 }
553
554 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
555 pub struct DebuggerScripts {
556     pub sysroot: Interned<PathBuf>,
557     pub host: Interned<String>,
558 }
559
560 impl Step for DebuggerScripts {
561     type Output = ();
562
563     fn should_run(run: ShouldRun) -> ShouldRun {
564         run.path("src/lldb_batchmode.py")
565     }
566
567     fn make_run(run: RunConfig) {
568         run.builder.ensure(DebuggerScripts {
569             sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)),
570             host: run.target,
571         });
572     }
573
574     /// Copies debugger scripts for `target` into the `sysroot` specified.
575     fn run(self, builder: &Builder) {
576         let host = self.host;
577         let sysroot = self.sysroot;
578         let dst = sysroot.join("lib/rustlib/etc");
579         t!(fs::create_dir_all(&dst));
580         let cp_debugger_script = |file: &str| {
581             builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644);
582         };
583         if host.contains("windows-msvc") {
584             // windbg debugger scripts
585             builder.install(&builder.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
586                 0o755);
587
588             cp_debugger_script("natvis/intrinsic.natvis");
589             cp_debugger_script("natvis/liballoc.natvis");
590             cp_debugger_script("natvis/libcore.natvis");
591         } else {
592             cp_debugger_script("debugger_pretty_printers_common.py");
593
594             // gdb debugger scripts
595             builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
596                     0o755);
597
598             cp_debugger_script("gdb_load_rust_pretty_printers.py");
599             cp_debugger_script("gdb_rust_pretty_printing.py");
600
601             // lldb debugger scripts
602             builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
603                     0o755);
604
605             cp_debugger_script("lldb_rust_formatters.py");
606         }
607     }
608 }
609
610 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
611 pub struct Std {
612     pub compiler: Compiler,
613     pub target: Interned<String>,
614 }
615
616 impl Step for Std {
617     type Output = PathBuf;
618     const DEFAULT: bool = true;
619
620     fn should_run(run: ShouldRun) -> ShouldRun {
621         run.path("src/libstd")
622     }
623
624     fn make_run(run: RunConfig) {
625         run.builder.ensure(Std {
626             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
627             target: run.target,
628         });
629     }
630
631     fn run(self, builder: &Builder) -> PathBuf {
632         let compiler = self.compiler;
633         let target = self.target;
634
635         let name = pkgname(builder, "rust-std");
636         builder.info(&format!("Dist std stage{} ({} -> {})",
637             compiler.stage, &compiler.host, target));
638
639         // The only true set of target libraries came from the build triple, so
640         // let's reduce redundant work by only producing archives from that host.
641         if compiler.host != builder.config.build {
642             builder.info(&format!("\tskipping, not a build host"));
643             return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
644         }
645
646         // We want to package up as many target libraries as possible
647         // for the `rust-std` package, so if this is a host target we
648         // depend on librustc and otherwise we just depend on libtest.
649         if builder.hosts.iter().any(|t| t == target) {
650             builder.ensure(compile::Rustc { compiler, target });
651         } else {
652             if builder.no_std(target) == Some(true) {
653                 // the `test` doesn't compile for no-std targets
654                 builder.ensure(compile::Std { compiler, target });
655             } else {
656                 builder.ensure(compile::Test { compiler, target });
657             }
658         }
659
660         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
661         let _ = fs::remove_dir_all(&image);
662
663         let dst = image.join("lib/rustlib").join(target);
664         t!(fs::create_dir_all(&dst));
665         let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
666         src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
667         builder.cp_filtered(&src, &dst, &|path| {
668             let name = path.file_name().and_then(|s| s.to_str());
669             name != Some(builder.config.rust_codegen_backends_dir.as_str()) &&
670                 name != Some("bin")
671
672         });
673
674         let mut cmd = rust_installer(builder);
675         cmd.arg("generate")
676            .arg("--product-name=Rust")
677            .arg("--rel-manifest-dir=rustlib")
678            .arg("--success-message=std-is-standing-at-the-ready.")
679            .arg("--image-dir").arg(&image)
680            .arg("--work-dir").arg(&tmpdir(builder))
681            .arg("--output-dir").arg(&distdir(builder))
682            .arg(format!("--package-name={}-{}", name, target))
683            .arg(format!("--component-name=rust-std-{}", target))
684            .arg("--legacy-manifest-dirs=rustlib,cargo");
685         builder.run(&mut cmd);
686         builder.remove_dir(&image);
687         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
688     }
689 }
690
691 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
692 pub struct Analysis {
693     pub compiler: Compiler,
694     pub target: Interned<String>,
695 }
696
697 impl Step for Analysis {
698     type Output = PathBuf;
699     const DEFAULT: bool = true;
700
701     fn should_run(run: ShouldRun) -> ShouldRun {
702         let builder = run.builder;
703         run.path("analysis").default_condition(builder.config.extended)
704     }
705
706     fn make_run(run: RunConfig) {
707         run.builder.ensure(Analysis {
708             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
709             target: run.target,
710         });
711     }
712
713     /// Creates a tarball of save-analysis metadata, if available.
714     fn run(self, builder: &Builder) -> PathBuf {
715         let compiler = self.compiler;
716         let target = self.target;
717         assert!(builder.config.extended);
718         builder.info(&format!("Dist analysis"));
719         let name = pkgname(builder, "rust-analysis");
720
721         if &compiler.host != builder.config.build {
722             builder.info(&format!("\tskipping, not a build host"));
723             return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
724         }
725
726         builder.ensure(Std { compiler, target });
727
728         // Package save-analysis from stage1 if not doing a full bootstrap, as the
729         // stage2 artifacts is simply copied from stage1 in that case.
730         let compiler = if builder.force_use_stage1(compiler, target) {
731             builder.compiler(1, compiler.host)
732         } else {
733             compiler.clone()
734         };
735
736         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
737
738         let src = builder.stage_out(compiler, Mode::Std)
739             .join(target).join(builder.cargo_dir()).join("deps");
740
741         let image_src = src.join("save-analysis");
742         let dst = image.join("lib/rustlib").join(target).join("analysis");
743         t!(fs::create_dir_all(&dst));
744         builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
745         builder.cp_r(&image_src, &dst);
746
747         let mut cmd = rust_installer(builder);
748         cmd.arg("generate")
749            .arg("--product-name=Rust")
750            .arg("--rel-manifest-dir=rustlib")
751            .arg("--success-message=save-analysis-saved.")
752            .arg("--image-dir").arg(&image)
753            .arg("--work-dir").arg(&tmpdir(builder))
754            .arg("--output-dir").arg(&distdir(builder))
755            .arg(format!("--package-name={}-{}", name, target))
756            .arg(format!("--component-name=rust-analysis-{}", target))
757            .arg("--legacy-manifest-dirs=rustlib,cargo");
758         builder.run(&mut cmd);
759         builder.remove_dir(&image);
760         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
761     }
762 }
763
764 fn copy_src_dirs(builder: &Builder, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
765     fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
766         let spath = match path.to_str() {
767             Some(path) => path,
768             None => return false,
769         };
770         if spath.ends_with("~") || spath.ends_with(".pyc") {
771             return false
772         }
773         if (spath.contains("llvm/test") || spath.contains("llvm\\test")) &&
774             (spath.ends_with(".ll") ||
775              spath.ends_with(".td") ||
776              spath.ends_with(".s")) {
777             return false
778         }
779         if spath.contains("test/emscripten") || spath.contains("test\\emscripten") {
780             return false
781         }
782
783         let full_path = Path::new(dir).join(path);
784         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
785             return false;
786         }
787
788         let excludes = [
789             "CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
790             ".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
791             "=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore",
792             ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
793         ];
794         !path.iter()
795              .map(|s| s.to_str().unwrap())
796              .any(|s| excludes.contains(&s))
797     }
798
799     // Copy the directories using our filter
800     for item in src_dirs {
801         let dst = &dst_dir.join(item);
802         t!(fs::create_dir_all(dst));
803         builder.cp_filtered(
804             &builder.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
805     }
806 }
807
808 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
809 pub struct Src;
810
811 impl Step for Src {
812     /// The output path of the src installer tarball
813     type Output = PathBuf;
814     const DEFAULT: bool = true;
815     const ONLY_HOSTS: bool = true;
816
817     fn should_run(run: ShouldRun) -> ShouldRun {
818         run.path("src")
819     }
820
821     fn make_run(run: RunConfig) {
822         run.builder.ensure(Src);
823     }
824
825     /// Creates the `rust-src` installer component
826     fn run(self, builder: &Builder) -> PathBuf {
827         builder.info(&format!("Dist src"));
828
829         let name = pkgname(builder, "rust-src");
830         let image = tmpdir(builder).join(format!("{}-image", name));
831         let _ = fs::remove_dir_all(&image);
832
833         let dst = image.join("lib/rustlib/src");
834         let dst_src = dst.join("rust");
835         t!(fs::create_dir_all(&dst_src));
836
837         let src_files = [
838             "src/Cargo.lock",
839         ];
840         // This is the reduced set of paths which will become the rust-src component
841         // (essentially libstd and all of its path dependencies)
842         let std_src_dirs = [
843             "src/build_helper",
844             "src/dlmalloc",
845             "src/liballoc",
846             "src/liballoc_jemalloc",
847             "src/liballoc_system",
848             "src/libbacktrace",
849             "src/libcompiler_builtins",
850             "src/libcore",
851             "src/liblibc",
852             "src/libpanic_abort",
853             "src/libpanic_unwind",
854             "src/librustc_asan",
855             "src/librustc_lsan",
856             "src/librustc_msan",
857             "src/librustc_tsan",
858             "src/libstd",
859             "src/libstd_unicode",
860             "src/libunwind",
861             "src/rustc/compiler_builtins_shim",
862             "src/rustc/libc_shim",
863             "src/rustc/dlmalloc_shim",
864             "src/libtest",
865             "src/libterm",
866             "src/jemalloc",
867             "src/libprofiler_builtins",
868             "src/stdsimd",
869         ];
870         let std_src_dirs_exclude = [
871             "src/libcompiler_builtins/compiler-rt/test",
872             "src/jemalloc/test/unit",
873         ];
874
875         copy_src_dirs(builder, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
876         for file in src_files.iter() {
877             builder.copy(&builder.src.join(file), &dst_src.join(file));
878         }
879
880         // Create source tarball in rust-installer format
881         let mut cmd = rust_installer(builder);
882         cmd.arg("generate")
883            .arg("--product-name=Rust")
884            .arg("--rel-manifest-dir=rustlib")
885            .arg("--success-message=Awesome-Source.")
886            .arg("--image-dir").arg(&image)
887            .arg("--work-dir").arg(&tmpdir(builder))
888            .arg("--output-dir").arg(&distdir(builder))
889            .arg(format!("--package-name={}", name))
890            .arg("--component-name=rust-src")
891            .arg("--legacy-manifest-dirs=rustlib,cargo");
892         builder.run(&mut cmd);
893
894         builder.remove_dir(&image);
895         distdir(builder).join(&format!("{}.tar.gz", name))
896     }
897 }
898
899 const CARGO_VENDOR_VERSION: &str = "0.1.4";
900
901 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
902 pub struct PlainSourceTarball;
903
904 impl Step for PlainSourceTarball {
905     /// Produces the location of the tarball generated
906     type Output = PathBuf;
907     const DEFAULT: bool = true;
908     const ONLY_HOSTS: bool = true;
909
910     fn should_run(run: ShouldRun) -> ShouldRun {
911         let builder = run.builder;
912         run.path("src").default_condition(builder.config.rust_dist_src)
913     }
914
915     fn make_run(run: RunConfig) {
916         run.builder.ensure(PlainSourceTarball);
917     }
918
919     /// Creates the plain source tarball
920     fn run(self, builder: &Builder) -> PathBuf {
921         builder.info(&format!("Create plain source tarball"));
922
923         // Make sure that the root folder of tarball has the correct name
924         let plain_name = format!("{}-src", pkgname(builder, "rustc"));
925         let plain_dst_src = tmpdir(builder).join(&plain_name);
926         let _ = fs::remove_dir_all(&plain_dst_src);
927         t!(fs::create_dir_all(&plain_dst_src));
928
929         // This is the set of root paths which will become part of the source package
930         let src_files = [
931             "COPYRIGHT",
932             "LICENSE-APACHE",
933             "LICENSE-MIT",
934             "CONTRIBUTING.md",
935             "README.md",
936             "RELEASES.md",
937             "configure",
938             "x.py",
939             "config.toml.example",
940         ];
941         let src_dirs = [
942             "src",
943         ];
944
945         copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src);
946
947         // Copy the files normally
948         for item in &src_files {
949             builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
950         }
951
952         // Create the version file
953         builder.create(&plain_dst_src.join("version"), &builder.rust_version());
954         if let Some(sha) = builder.rust_sha() {
955             builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
956         }
957
958         // If we're building from git sources, we need to vendor a complete distribution.
959         if builder.rust_info.is_git() {
960             // Get cargo-vendor installed, if it isn't already.
961             let mut has_cargo_vendor = false;
962             let mut cmd = Command::new(&builder.initial_cargo);
963             for line in output(cmd.arg("install").arg("--list")).lines() {
964                 has_cargo_vendor |= line.starts_with("cargo-vendor ");
965             }
966             if !has_cargo_vendor {
967                 let mut cmd = builder.cargo(
968                     builder.compiler(0, builder.config.build),
969                     Mode::ToolBootstrap,
970                     builder.config.build,
971                     "install"
972                 );
973                 cmd.arg("--force")
974                    .arg("--debug")
975                    .arg("--vers").arg(CARGO_VENDOR_VERSION)
976                    .arg("cargo-vendor");
977                 if let Some(dir) = builder.openssl_install_dir(builder.config.build) {
978                     builder.ensure(native::Openssl {
979                         target: builder.config.build,
980                     });
981                     cmd.env("OPENSSL_DIR", dir);
982                 }
983                 builder.run(&mut cmd);
984             }
985
986             // Vendor all Cargo dependencies
987             let mut cmd = Command::new(&builder.initial_cargo);
988             cmd.arg("vendor")
989                .current_dir(&plain_dst_src.join("src"));
990             builder.run(&mut cmd);
991         }
992
993         // Create plain source tarball
994         let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
995         let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
996         tarball.set_extension(""); // strip .gz
997         tarball.set_extension(""); // strip .tar
998         if let Some(dir) = tarball.parent() {
999             builder.create_dir(&dir);
1000         }
1001         builder.info(&format!("running installer"));
1002         let mut cmd = rust_installer(builder);
1003         cmd.arg("tarball")
1004            .arg("--input").arg(&plain_name)
1005            .arg("--output").arg(&tarball)
1006            .arg("--work-dir=.")
1007            .current_dir(tmpdir(builder));
1008         builder.run(&mut cmd);
1009         distdir(builder).join(&format!("{}.tar.gz", plain_name))
1010     }
1011 }
1012
1013 // We have to run a few shell scripts, which choke quite a bit on both `\`
1014 // characters and on `C:\` paths, so normalize both of them away.
1015 pub fn sanitize_sh(path: &Path) -> String {
1016     let path = path.to_str().unwrap().replace("\\", "/");
1017     return change_drive(&path).unwrap_or(path);
1018
1019     fn change_drive(s: &str) -> Option<String> {
1020         let mut ch = s.chars();
1021         let drive = ch.next().unwrap_or('C');
1022         if ch.next() != Some(':') {
1023             return None
1024         }
1025         if ch.next() != Some('/') {
1026             return None
1027         }
1028         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
1029     }
1030 }
1031
1032 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1033 pub struct Cargo {
1034     pub stage: u32,
1035     pub target: Interned<String>,
1036 }
1037
1038 impl Step for Cargo {
1039     type Output = PathBuf;
1040     const ONLY_HOSTS: bool = true;
1041
1042     fn should_run(run: ShouldRun) -> ShouldRun {
1043         run.path("cargo")
1044     }
1045
1046     fn make_run(run: RunConfig) {
1047         run.builder.ensure(Cargo {
1048             stage: run.builder.top_stage,
1049             target: run.target,
1050         });
1051     }
1052
1053     fn run(self, builder: &Builder) -> PathBuf {
1054         let stage = self.stage;
1055         let target = self.target;
1056
1057         builder.info(&format!("Dist cargo stage{} ({})", stage, target));
1058         let src = builder.src.join("src/tools/cargo");
1059         let etc = src.join("src/etc");
1060         let release_num = builder.release_num("cargo");
1061         let name = pkgname(builder, "cargo");
1062         let version = builder.cargo_info.version(builder, &release_num);
1063
1064         let tmp = tmpdir(builder);
1065         let image = tmp.join("cargo-image");
1066         drop(fs::remove_dir_all(&image));
1067         builder.create_dir(&image);
1068
1069         // Prepare the image directory
1070         builder.create_dir(&image.join("share/zsh/site-functions"));
1071         builder.create_dir(&image.join("etc/bash_completion.d"));
1072         let cargo = builder.ensure(tool::Cargo {
1073             compiler: builder.compiler(stage, builder.config.build),
1074             target
1075         });
1076         builder.install(&cargo, &image.join("bin"), 0o755);
1077         for man in t!(etc.join("man").read_dir()) {
1078             let man = t!(man);
1079             builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
1080         }
1081         builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
1082         builder.copy(&etc.join("cargo.bashcomp.sh"),
1083              &image.join("etc/bash_completion.d/cargo"));
1084         let doc = image.join("share/doc/cargo");
1085         builder.install(&src.join("README.md"), &doc, 0o644);
1086         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1087         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1088         builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
1089
1090         // Prepare the overlay
1091         let overlay = tmp.join("cargo-overlay");
1092         drop(fs::remove_dir_all(&overlay));
1093         builder.create_dir(&overlay);
1094         builder.install(&src.join("README.md"), &overlay, 0o644);
1095         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1096         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1097         builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1098         builder.create(&overlay.join("version"), &version);
1099
1100         // Generate the installer tarball
1101         let mut cmd = rust_installer(builder);
1102         cmd.arg("generate")
1103            .arg("--product-name=Rust")
1104            .arg("--rel-manifest-dir=rustlib")
1105            .arg("--success-message=Rust-is-ready-to-roll.")
1106            .arg("--image-dir").arg(&image)
1107            .arg("--work-dir").arg(&tmpdir(builder))
1108            .arg("--output-dir").arg(&distdir(builder))
1109            .arg("--non-installed-overlay").arg(&overlay)
1110            .arg(format!("--package-name={}-{}", name, target))
1111            .arg("--component-name=cargo")
1112            .arg("--legacy-manifest-dirs=rustlib,cargo");
1113         builder.run(&mut cmd);
1114         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
1115     }
1116 }
1117
1118 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1119 pub struct Rls {
1120     pub stage: u32,
1121     pub target: Interned<String>,
1122 }
1123
1124 impl Step for Rls {
1125     type Output = Option<PathBuf>;
1126     const ONLY_HOSTS: bool = true;
1127
1128     fn should_run(run: ShouldRun) -> ShouldRun {
1129         run.path("rls")
1130     }
1131
1132     fn make_run(run: RunConfig) {
1133         run.builder.ensure(Rls {
1134             stage: run.builder.top_stage,
1135             target: run.target,
1136         });
1137     }
1138
1139     fn run(self, builder: &Builder) -> Option<PathBuf> {
1140         let stage = self.stage;
1141         let target = self.target;
1142         assert!(builder.config.extended);
1143
1144         builder.info(&format!("Dist RLS stage{} ({})", stage, target));
1145         let src = builder.src.join("src/tools/rls");
1146         let release_num = builder.release_num("rls");
1147         let name = pkgname(builder, "rls");
1148         let version = builder.rls_info.version(builder, &release_num);
1149
1150         let tmp = tmpdir(builder);
1151         let image = tmp.join("rls-image");
1152         drop(fs::remove_dir_all(&image));
1153         t!(fs::create_dir_all(&image));
1154
1155         // Prepare the image directory
1156         // We expect RLS to build, because we've exited this step above if tool
1157         // state for RLS isn't testing.
1158         let rls = builder.ensure(tool::Rls {
1159             compiler: builder.compiler(stage, builder.config.build),
1160             target, extra_features: Vec::new()
1161         }).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
1162
1163         builder.install(&rls, &image.join("bin"), 0o755);
1164         let doc = image.join("share/doc/rls");
1165         builder.install(&src.join("README.md"), &doc, 0o644);
1166         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1167         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1168
1169         // Prepare the overlay
1170         let overlay = tmp.join("rls-overlay");
1171         drop(fs::remove_dir_all(&overlay));
1172         t!(fs::create_dir_all(&overlay));
1173         builder.install(&src.join("README.md"), &overlay, 0o644);
1174         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1175         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1176         builder.create(&overlay.join("version"), &version);
1177
1178         // Generate the installer tarball
1179         let mut cmd = rust_installer(builder);
1180         cmd.arg("generate")
1181            .arg("--product-name=Rust")
1182            .arg("--rel-manifest-dir=rustlib")
1183            .arg("--success-message=RLS-ready-to-serve.")
1184            .arg("--image-dir").arg(&image)
1185            .arg("--work-dir").arg(&tmpdir(builder))
1186            .arg("--output-dir").arg(&distdir(builder))
1187            .arg("--non-installed-overlay").arg(&overlay)
1188            .arg(format!("--package-name={}-{}", name, target))
1189            .arg("--legacy-manifest-dirs=rustlib,cargo")
1190            .arg("--component-name=rls-preview");
1191
1192         builder.run(&mut cmd);
1193         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1194     }
1195 }
1196
1197 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1198 pub struct Clippy {
1199     pub stage: u32,
1200     pub target: Interned<String>,
1201 }
1202
1203 impl Step for Clippy {
1204     type Output = Option<PathBuf>;
1205     const ONLY_HOSTS: bool = true;
1206
1207     fn should_run(run: ShouldRun) -> ShouldRun {
1208         run.path("clippy")
1209     }
1210
1211     fn make_run(run: RunConfig) {
1212         run.builder.ensure(Clippy {
1213             stage: run.builder.top_stage,
1214             target: run.target,
1215         });
1216     }
1217
1218     fn run(self, builder: &Builder) -> Option<PathBuf> {
1219         let stage = self.stage;
1220         let target = self.target;
1221         assert!(builder.config.extended);
1222
1223         builder.info(&format!("Dist clippy stage{} ({})", stage, target));
1224         let src = builder.src.join("src/tools/clippy");
1225         let release_num = builder.release_num("clippy");
1226         let name = pkgname(builder, "clippy");
1227         let version = builder.clippy_info.version(builder, &release_num);
1228
1229         let tmp = tmpdir(builder);
1230         let image = tmp.join("clippy-image");
1231         drop(fs::remove_dir_all(&image));
1232         builder.create_dir(&image);
1233
1234         // Prepare the image directory
1235         // We expect clippy to build, because we've exited this step above if tool
1236         // state for clippy isn't testing.
1237         let clippy = builder.ensure(tool::Clippy {
1238             compiler: builder.compiler(stage, builder.config.build),
1239             target, extra_features: Vec::new()
1240         }).or_else(|| { println!("Unable to build clippy, skipping dist"); None })?;
1241         let cargoclippy = builder.ensure(tool::CargoClippy {
1242             compiler: builder.compiler(stage, builder.config.build),
1243             target, extra_features: Vec::new()
1244         }).or_else(|| { println!("Unable to build cargo clippy, skipping dist"); None })?;
1245
1246         builder.install(&clippy, &image.join("bin"), 0o755);
1247         builder.install(&cargoclippy, &image.join("bin"), 0o755);
1248         let doc = image.join("share/doc/clippy");
1249         builder.install(&src.join("README.md"), &doc, 0o644);
1250         builder.install(&src.join("LICENSE"), &doc, 0o644);
1251
1252         // Prepare the overlay
1253         let overlay = tmp.join("clippy-overlay");
1254         drop(fs::remove_dir_all(&overlay));
1255         t!(fs::create_dir_all(&overlay));
1256         builder.install(&src.join("README.md"), &overlay, 0o644);
1257         builder.install(&src.join("LICENSE"), &doc, 0o644);
1258         builder.create(&overlay.join("version"), &version);
1259
1260         // Generate the installer tarball
1261         let mut cmd = rust_installer(builder);
1262         cmd.arg("generate")
1263            .arg("--product-name=Rust")
1264            .arg("--rel-manifest-dir=rustlib")
1265            .arg("--success-message=clippy-ready-to-serve.")
1266            .arg("--image-dir").arg(&image)
1267            .arg("--work-dir").arg(&tmpdir(builder))
1268            .arg("--output-dir").arg(&distdir(builder))
1269            .arg("--non-installed-overlay").arg(&overlay)
1270            .arg(format!("--package-name={}-{}", name, target))
1271            .arg("--legacy-manifest-dirs=rustlib,cargo")
1272            .arg("--component-name=clippy-preview");
1273
1274         builder.run(&mut cmd);
1275         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1276     }
1277 }
1278
1279 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1280 pub struct Rustfmt {
1281     pub stage: u32,
1282     pub target: Interned<String>,
1283 }
1284
1285 impl Step for Rustfmt {
1286     type Output = Option<PathBuf>;
1287     const ONLY_HOSTS: bool = true;
1288
1289     fn should_run(run: ShouldRun) -> ShouldRun {
1290         run.path("rustfmt")
1291     }
1292
1293     fn make_run(run: RunConfig) {
1294         run.builder.ensure(Rustfmt {
1295             stage: run.builder.top_stage,
1296             target: run.target,
1297         });
1298     }
1299
1300     fn run(self, builder: &Builder) -> Option<PathBuf> {
1301         let stage = self.stage;
1302         let target = self.target;
1303
1304         builder.info(&format!("Dist Rustfmt stage{} ({})", stage, target));
1305         let src = builder.src.join("src/tools/rustfmt");
1306         let release_num = builder.release_num("rustfmt");
1307         let name = pkgname(builder, "rustfmt");
1308         let version = builder.rustfmt_info.version(builder, &release_num);
1309
1310         let tmp = tmpdir(builder);
1311         let image = tmp.join("rustfmt-image");
1312         drop(fs::remove_dir_all(&image));
1313         builder.create_dir(&image);
1314
1315         // Prepare the image directory
1316         let rustfmt = builder.ensure(tool::Rustfmt {
1317             compiler: builder.compiler(stage, builder.config.build),
1318             target, extra_features: Vec::new()
1319         }).or_else(|| { println!("Unable to build Rustfmt, skipping dist"); None })?;
1320         let cargofmt = builder.ensure(tool::Cargofmt {
1321             compiler: builder.compiler(stage, builder.config.build),
1322             target, extra_features: Vec::new()
1323         }).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
1324
1325         builder.install(&rustfmt, &image.join("bin"), 0o755);
1326         builder.install(&cargofmt, &image.join("bin"), 0o755);
1327         let doc = image.join("share/doc/rustfmt");
1328         builder.install(&src.join("README.md"), &doc, 0o644);
1329         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1330         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1331
1332         // Prepare the overlay
1333         let overlay = tmp.join("rustfmt-overlay");
1334         drop(fs::remove_dir_all(&overlay));
1335         builder.create_dir(&overlay);
1336         builder.install(&src.join("README.md"), &overlay, 0o644);
1337         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1338         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1339         builder.create(&overlay.join("version"), &version);
1340
1341         // Generate the installer tarball
1342         let mut cmd = rust_installer(builder);
1343         cmd.arg("generate")
1344            .arg("--product-name=Rust")
1345            .arg("--rel-manifest-dir=rustlib")
1346            .arg("--success-message=rustfmt-ready-to-fmt.")
1347            .arg("--image-dir").arg(&image)
1348            .arg("--work-dir").arg(&tmpdir(builder))
1349            .arg("--output-dir").arg(&distdir(builder))
1350            .arg("--non-installed-overlay").arg(&overlay)
1351            .arg(format!("--package-name={}-{}", name, target))
1352            .arg("--legacy-manifest-dirs=rustlib,cargo")
1353            .arg("--component-name=rustfmt-preview");
1354
1355         builder.run(&mut cmd);
1356         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1357     }
1358 }
1359
1360 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1361 pub struct Extended {
1362     stage: u32,
1363     host: Interned<String>,
1364     target: Interned<String>,
1365 }
1366
1367 impl Step for Extended {
1368     type Output = ();
1369     const DEFAULT: bool = true;
1370     const ONLY_HOSTS: bool = true;
1371
1372     fn should_run(run: ShouldRun) -> ShouldRun {
1373         let builder = run.builder;
1374         run.path("extended").default_condition(builder.config.extended)
1375     }
1376
1377     fn make_run(run: RunConfig) {
1378         run.builder.ensure(Extended {
1379             stage: run.builder.top_stage,
1380             host: run.builder.config.build,
1381             target: run.target,
1382         });
1383     }
1384
1385     /// Creates a combined installer for the specified target in the provided stage.
1386     fn run(self, builder: &Builder) {
1387         let stage = self.stage;
1388         let target = self.target;
1389
1390         builder.info(&format!("Dist extended stage{} ({})", stage, target));
1391
1392         let rustc_installer = builder.ensure(Rustc {
1393             compiler: builder.compiler(stage, target),
1394         });
1395         let cargo_installer = builder.ensure(Cargo { stage, target });
1396         let rustfmt_installer = builder.ensure(Rustfmt { stage, target });
1397         let rls_installer = builder.ensure(Rls { stage, target });
1398         let llvm_tools_installer = builder.ensure(LlvmTools { stage, target });
1399         let clippy_installer = builder.ensure(Clippy { stage, target });
1400         let mingw_installer = builder.ensure(Mingw { host: target });
1401         let analysis_installer = builder.ensure(Analysis {
1402             compiler: builder.compiler(stage, self.host),
1403             target
1404         });
1405
1406         let docs_installer = builder.ensure(Docs { stage, host: target, });
1407         let std_installer = builder.ensure(Std {
1408             compiler: builder.compiler(stage, self.host),
1409             target,
1410         });
1411
1412         let tmp = tmpdir(builder);
1413         let overlay = tmp.join("extended-overlay");
1414         let etc = builder.src.join("src/etc/installer");
1415         let work = tmp.join("work");
1416
1417         let _ = fs::remove_dir_all(&overlay);
1418         builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
1419         builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
1420         builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
1421         let version = builder.rust_version();
1422         builder.create(&overlay.join("version"), &version);
1423         if let Some(sha) = builder.rust_sha() {
1424             builder.create(&overlay.join("git-commit-hash"), &sha);
1425         }
1426         builder.install(&etc.join("README.md"), &overlay, 0o644);
1427
1428         // When rust-std package split from rustc, we needed to ensure that during
1429         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1430         // the std files during uninstall. To do this ensure that rustc comes
1431         // before rust-std in the list below.
1432         let mut tarballs = Vec::new();
1433         tarballs.push(rustc_installer);
1434         tarballs.push(cargo_installer);
1435         tarballs.extend(rls_installer.clone());
1436         tarballs.extend(clippy_installer.clone());
1437         tarballs.extend(rustfmt_installer.clone());
1438         tarballs.extend(llvm_tools_installer.clone());
1439         tarballs.push(analysis_installer);
1440         tarballs.push(std_installer);
1441         if builder.config.docs {
1442             tarballs.push(docs_installer);
1443         }
1444         if target.contains("pc-windows-gnu") {
1445             tarballs.push(mingw_installer.unwrap());
1446         }
1447         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1448         for tarball in &tarballs[1..] {
1449             input_tarballs.push(",");
1450             input_tarballs.push(tarball);
1451         }
1452
1453         let mut cmd = rust_installer(builder);
1454         cmd.arg("combine")
1455             .arg("--product-name=Rust")
1456             .arg("--rel-manifest-dir=rustlib")
1457             .arg("--success-message=Rust-is-ready-to-roll.")
1458             .arg("--work-dir").arg(&work)
1459             .arg("--output-dir").arg(&distdir(builder))
1460             .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
1461             .arg("--legacy-manifest-dirs=rustlib,cargo")
1462             .arg("--input-tarballs").arg(input_tarballs)
1463             .arg("--non-installed-overlay").arg(&overlay);
1464         builder.run(&mut cmd);
1465
1466         let mut license = String::new();
1467         license += &builder.read(&builder.src.join("COPYRIGHT"));
1468         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1469         license += &builder.read(&builder.src.join("LICENSE-MIT"));
1470         license.push_str("\n");
1471         license.push_str("\n");
1472
1473         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1474         let mut rtf = rtf.to_string();
1475         rtf.push_str("\n");
1476         for line in license.lines() {
1477             rtf.push_str(line);
1478             rtf.push_str("\\line ");
1479         }
1480         rtf.push_str("}");
1481
1482         fn filter(contents: &str, marker: &str) -> String {
1483             let start = format!("tool-{}-start", marker);
1484             let end = format!("tool-{}-end", marker);
1485             let mut lines = Vec::new();
1486             let mut omitted = false;
1487             for line in contents.lines() {
1488                 if line.contains(&start) {
1489                     omitted = true;
1490                 } else if line.contains(&end) {
1491                     omitted = false;
1492                 } else if !omitted {
1493                     lines.push(line);
1494                 }
1495             }
1496
1497             lines.join("\n")
1498         }
1499
1500         let xform = |p: &Path| {
1501             let mut contents = String::new();
1502             t!(t!(File::open(p)).read_to_string(&mut contents));
1503             if rls_installer.is_none() {
1504                 contents = filter(&contents, "rls");
1505             }
1506             if clippy_installer.is_none() {
1507                 contents = filter(&contents, "clippy");
1508             }
1509             if rustfmt_installer.is_none() {
1510                 contents = filter(&contents, "rustfmt");
1511             }
1512             let ret = tmp.join(p.file_name().unwrap());
1513             t!(t!(File::create(&ret)).write_all(contents.as_bytes()));
1514             return ret
1515         };
1516
1517         if target.contains("apple-darwin") {
1518             let pkg = tmp.join("pkg");
1519             let _ = fs::remove_dir_all(&pkg);
1520
1521             let pkgbuild = |component: &str| {
1522                 let mut cmd = Command::new("pkgbuild");
1523                 cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
1524                     .arg("--scripts").arg(pkg.join(component))
1525                     .arg("--nopayload")
1526                     .arg(pkg.join(component).with_extension("pkg"));
1527                 builder.run(&mut cmd);
1528             };
1529
1530             let prepare = |name: &str| {
1531                 builder.create_dir(&pkg.join(name));
1532                 builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target)),
1533                         &pkg.join(name));
1534                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1535                 pkgbuild(name);
1536             };
1537             prepare("rustc");
1538             prepare("cargo");
1539             prepare("rust-docs");
1540             prepare("rust-std");
1541             prepare("rust-analysis");
1542
1543             if rls_installer.is_some() {
1544                 prepare("rls");
1545             }
1546             if clippy_installer.is_some() {
1547                 prepare("clippy");
1548             }
1549
1550             // create an 'uninstall' package
1551             builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1552             pkgbuild("uninstall");
1553
1554             builder.create_dir(&pkg.join("res"));
1555             builder.create(&pkg.join("res/LICENSE.txt"), &license);
1556             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1557             let mut cmd = Command::new("productbuild");
1558             cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
1559                 .arg("--resources").arg(pkg.join("res"))
1560                 .arg(distdir(builder).join(format!("{}-{}.pkg",
1561                                                     pkgname(builder, "rust"),
1562                                                     target)))
1563                 .arg("--package-path").arg(&pkg);
1564             builder.run(&mut cmd);
1565         }
1566
1567         if target.contains("windows") {
1568             let exe = tmp.join("exe");
1569             let _ = fs::remove_dir_all(&exe);
1570
1571             let prepare = |name: &str| {
1572                 builder.create_dir(&exe.join(name));
1573                 let dir = if name == "rust-std" || name == "rust-analysis" {
1574                     format!("{}-{}", name, target)
1575                 } else if name == "rls" {
1576                     "rls-preview".to_string()
1577                 } else if name == "clippy" {
1578                     "clippy-preview".to_string()
1579                 } else {
1580                     name.to_string()
1581                 };
1582                 builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target))
1583                             .join(dir),
1584                         &exe.join(name));
1585                 builder.remove(&exe.join(name).join("manifest.in"));
1586             };
1587             prepare("rustc");
1588             prepare("cargo");
1589             prepare("rust-analysis");
1590             prepare("rust-docs");
1591             prepare("rust-std");
1592             if rls_installer.is_some() {
1593                 prepare("rls");
1594             }
1595             if clippy_installer.is_some() {
1596                 prepare("clippy");
1597             }
1598             if target.contains("windows-gnu") {
1599                 prepare("rust-mingw");
1600             }
1601
1602             builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
1603             builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1604             builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1605             builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1606             builder.create(&exe.join("LICENSE.txt"), &license);
1607
1608             // Generate exe installer
1609             let mut cmd = Command::new("iscc");
1610             cmd.arg("rust.iss")
1611                 .current_dir(&exe);
1612             if target.contains("windows-gnu") {
1613                 cmd.arg("/dMINGW");
1614             }
1615             add_env(builder, &mut cmd, target);
1616             builder.run(&mut cmd);
1617             builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)),
1618                     &distdir(builder),
1619                     0o755);
1620
1621             // Generate msi installer
1622             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1623             let heat = wix.join("bin/heat.exe");
1624             let candle = wix.join("bin/candle.exe");
1625             let light = wix.join("bin/light.exe");
1626
1627             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1628             builder.run(Command::new(&heat)
1629                             .current_dir(&exe)
1630                             .arg("dir")
1631                             .arg("rustc")
1632                             .args(&heat_flags)
1633                             .arg("-cg").arg("RustcGroup")
1634                             .arg("-dr").arg("Rustc")
1635                             .arg("-var").arg("var.RustcDir")
1636                             .arg("-out").arg(exe.join("RustcGroup.wxs")));
1637             builder.run(Command::new(&heat)
1638                             .current_dir(&exe)
1639                             .arg("dir")
1640                             .arg("rust-docs")
1641                             .args(&heat_flags)
1642                             .arg("-cg").arg("DocsGroup")
1643                             .arg("-dr").arg("Docs")
1644                             .arg("-var").arg("var.DocsDir")
1645                             .arg("-out").arg(exe.join("DocsGroup.wxs"))
1646                             .arg("-t").arg(etc.join("msi/squash-components.xsl")));
1647             builder.run(Command::new(&heat)
1648                             .current_dir(&exe)
1649                             .arg("dir")
1650                             .arg("cargo")
1651                             .args(&heat_flags)
1652                             .arg("-cg").arg("CargoGroup")
1653                             .arg("-dr").arg("Cargo")
1654                             .arg("-var").arg("var.CargoDir")
1655                             .arg("-out").arg(exe.join("CargoGroup.wxs"))
1656                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1657             builder.run(Command::new(&heat)
1658                             .current_dir(&exe)
1659                             .arg("dir")
1660                             .arg("rust-std")
1661                             .args(&heat_flags)
1662                             .arg("-cg").arg("StdGroup")
1663                             .arg("-dr").arg("Std")
1664                             .arg("-var").arg("var.StdDir")
1665                             .arg("-out").arg(exe.join("StdGroup.wxs")));
1666             if rls_installer.is_some() {
1667                 builder.run(Command::new(&heat)
1668                                 .current_dir(&exe)
1669                                 .arg("dir")
1670                                 .arg("rls")
1671                                 .args(&heat_flags)
1672                                 .arg("-cg").arg("RlsGroup")
1673                                 .arg("-dr").arg("Rls")
1674                                 .arg("-var").arg("var.RlsDir")
1675                                 .arg("-out").arg(exe.join("RlsGroup.wxs"))
1676                                 .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1677             }
1678             if clippy_installer.is_some() {
1679                 builder.run(Command::new(&heat)
1680                                 .current_dir(&exe)
1681                                 .arg("dir")
1682                                 .arg("clippy")
1683                                 .args(&heat_flags)
1684                                 .arg("-cg").arg("ClippyGroup")
1685                                 .arg("-dr").arg("Clippy")
1686                                 .arg("-var").arg("var.ClippyDir")
1687                                 .arg("-out").arg(exe.join("ClippyGroup.wxs"))
1688                                 .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1689             }
1690             builder.run(Command::new(&heat)
1691                             .current_dir(&exe)
1692                             .arg("dir")
1693                             .arg("rust-analysis")
1694                             .args(&heat_flags)
1695                             .arg("-cg").arg("AnalysisGroup")
1696                             .arg("-dr").arg("Analysis")
1697                             .arg("-var").arg("var.AnalysisDir")
1698                             .arg("-out").arg(exe.join("AnalysisGroup.wxs"))
1699                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1700             if target.contains("windows-gnu") {
1701                 builder.run(Command::new(&heat)
1702                                 .current_dir(&exe)
1703                                 .arg("dir")
1704                                 .arg("rust-mingw")
1705                                 .args(&heat_flags)
1706                                 .arg("-cg").arg("GccGroup")
1707                                 .arg("-dr").arg("Gcc")
1708                                 .arg("-var").arg("var.GccDir")
1709                                 .arg("-out").arg(exe.join("GccGroup.wxs")));
1710             }
1711
1712             let candle = |input: &Path| {
1713                 let output = exe.join(input.file_stem().unwrap())
1714                                 .with_extension("wixobj");
1715                 let arch = if target.contains("x86_64") {"x64"} else {"x86"};
1716                 let mut cmd = Command::new(&candle);
1717                 cmd.current_dir(&exe)
1718                     .arg("-nologo")
1719                     .arg("-dRustcDir=rustc")
1720                     .arg("-dDocsDir=rust-docs")
1721                     .arg("-dCargoDir=cargo")
1722                     .arg("-dStdDir=rust-std")
1723                     .arg("-dAnalysisDir=rust-analysis")
1724                     .arg("-arch").arg(&arch)
1725                     .arg("-out").arg(&output)
1726                     .arg(&input);
1727                 add_env(builder, &mut cmd, target);
1728
1729                 if rls_installer.is_some() {
1730                     cmd.arg("-dRlsDir=rls");
1731                 }
1732                 if clippy_installer.is_some() {
1733                     cmd.arg("-dClippyDir=clippy");
1734                 }
1735                 if target.contains("windows-gnu") {
1736                     cmd.arg("-dGccDir=rust-mingw");
1737                 }
1738                 builder.run(&mut cmd);
1739             };
1740             candle(&xform(&etc.join("msi/rust.wxs")));
1741             candle(&etc.join("msi/ui.wxs"));
1742             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1743             candle("RustcGroup.wxs".as_ref());
1744             candle("DocsGroup.wxs".as_ref());
1745             candle("CargoGroup.wxs".as_ref());
1746             candle("StdGroup.wxs".as_ref());
1747             if rls_installer.is_some() {
1748                 candle("RlsGroup.wxs".as_ref());
1749             }
1750             if clippy_installer.is_some() {
1751                 candle("ClippyGroup.wxs".as_ref());
1752             }
1753             candle("AnalysisGroup.wxs".as_ref());
1754
1755             if target.contains("windows-gnu") {
1756                 candle("GccGroup.wxs".as_ref());
1757             }
1758
1759             builder.create(&exe.join("LICENSE.rtf"), &rtf);
1760             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1761             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1762
1763             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
1764             let mut cmd = Command::new(&light);
1765             cmd.arg("-nologo")
1766                 .arg("-ext").arg("WixUIExtension")
1767                 .arg("-ext").arg("WixUtilExtension")
1768                 .arg("-out").arg(exe.join(&filename))
1769                 .arg("rust.wixobj")
1770                 .arg("ui.wixobj")
1771                 .arg("rustwelcomedlg.wixobj")
1772                 .arg("RustcGroup.wixobj")
1773                 .arg("DocsGroup.wixobj")
1774                 .arg("CargoGroup.wixobj")
1775                 .arg("StdGroup.wixobj")
1776                 .arg("AnalysisGroup.wixobj")
1777                 .current_dir(&exe);
1778
1779             if rls_installer.is_some() {
1780                 cmd.arg("RlsGroup.wixobj");
1781             }
1782             if clippy_installer.is_some() {
1783                 cmd.arg("ClippyGroup.wixobj");
1784             }
1785
1786             if target.contains("windows-gnu") {
1787                 cmd.arg("GccGroup.wixobj");
1788             }
1789             // ICE57 wrongly complains about the shortcuts
1790             cmd.arg("-sice:ICE57");
1791
1792             builder.run(&mut cmd);
1793
1794             if !builder.config.dry_run {
1795                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
1796             }
1797         }
1798     }
1799 }
1800
1801 fn add_env(builder: &Builder, cmd: &mut Command, target: Interned<String>) {
1802     let mut parts = channel::CFG_RELEASE_NUM.split('.');
1803     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
1804        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
1805        .env("CFG_RELEASE", builder.rust_release())
1806        .env("CFG_VER_MAJOR", parts.next().unwrap())
1807        .env("CFG_VER_MINOR", parts.next().unwrap())
1808        .env("CFG_VER_PATCH", parts.next().unwrap())
1809        .env("CFG_VER_BUILD", "0") // just needed to build
1810        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
1811        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
1812        .env("CFG_BUILD", target)
1813        .env("CFG_CHANNEL", &builder.config.channel);
1814
1815     if target.contains("windows-gnu") {
1816        cmd.env("CFG_MINGW", "1")
1817           .env("CFG_ABI", "GNU");
1818     } else {
1819        cmd.env("CFG_MINGW", "0")
1820           .env("CFG_ABI", "MSVC");
1821     }
1822
1823     if target.contains("x86_64") {
1824        cmd.env("CFG_PLATFORM", "x64");
1825     } else {
1826        cmd.env("CFG_PLATFORM", "x86");
1827     }
1828 }
1829
1830 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1831 pub struct HashSign;
1832
1833 impl Step for HashSign {
1834     type Output = ();
1835     const ONLY_HOSTS: bool = true;
1836
1837     fn should_run(run: ShouldRun) -> ShouldRun {
1838         run.path("hash-and-sign")
1839     }
1840
1841     fn make_run(run: RunConfig) {
1842         run.builder.ensure(HashSign);
1843     }
1844
1845     fn run(self, builder: &Builder) {
1846         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
1847         if builder.config.dry_run {
1848             return;
1849         }
1850         let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
1851             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
1852         });
1853         let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
1854             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
1855         });
1856         let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
1857             panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
1858         });
1859         let mut pass = String::new();
1860         t!(t!(File::open(&file)).read_to_string(&mut pass));
1861
1862         let today = output(Command::new("date").arg("+%Y-%m-%d"));
1863
1864         cmd.arg(sign);
1865         cmd.arg(distdir(builder));
1866         cmd.arg(today.trim());
1867         cmd.arg(builder.rust_package_vers());
1868         cmd.arg(builder.package_vers(&builder.release_num("cargo")));
1869         cmd.arg(builder.package_vers(&builder.release_num("rls")));
1870         cmd.arg(builder.package_vers(&builder.release_num("clippy")));
1871         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
1872         cmd.arg(builder.llvm_tools_package_vers());
1873         cmd.arg(addr);
1874
1875         builder.create_dir(&distdir(builder));
1876
1877         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
1878         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
1879         let status = t!(child.wait());
1880         assert!(status.success());
1881     }
1882 }
1883
1884 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1885 pub struct LlvmTools {
1886     pub stage: u32,
1887     pub target: Interned<String>,
1888 }
1889
1890 impl Step for LlvmTools {
1891     type Output = Option<PathBuf>;
1892     const ONLY_HOSTS: bool = true;
1893
1894     fn should_run(run: ShouldRun) -> ShouldRun {
1895         run.path("llvm-tools")
1896     }
1897
1898     fn make_run(run: RunConfig) {
1899         run.builder.ensure(LlvmTools {
1900             stage: run.builder.top_stage,
1901             target: run.target,
1902         });
1903     }
1904
1905     fn run(self, builder: &Builder) -> Option<PathBuf> {
1906         let stage = self.stage;
1907         let target = self.target;
1908         assert!(builder.config.extended);
1909
1910         builder.info(&format!("Dist LlvmTools stage{} ({})", stage, target));
1911         let src = builder.src.join("src/llvm");
1912         let name = pkgname(builder, "llvm-tools");
1913
1914         let tmp = tmpdir(builder);
1915         let image = tmp.join("llvm-tools-image");
1916         drop(fs::remove_dir_all(&image));
1917
1918         // Prepare the image directory
1919         let bindir = builder
1920             .llvm_out(target)
1921             .join("bin");
1922         let dst = image.join("lib/rustlib")
1923             .join(target)
1924             .join("bin");
1925         t!(fs::create_dir_all(&dst));
1926         for tool in LLVM_TOOLS {
1927             let exe = bindir.join(exe(tool, &target));
1928             builder.install(&exe, &dst, 0o755);
1929         }
1930
1931         // Prepare the overlay
1932         let overlay = tmp.join("llvm-tools-overlay");
1933         drop(fs::remove_dir_all(&overlay));
1934         builder.create_dir(&overlay);
1935         builder.install(&src.join("README.txt"), &overlay, 0o644);
1936         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
1937         builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
1938
1939         // Generate the installer tarball
1940         let mut cmd = rust_installer(builder);
1941         cmd.arg("generate")
1942             .arg("--product-name=Rust")
1943             .arg("--rel-manifest-dir=rustlib")
1944             .arg("--success-message=llvm-tools-installed.")
1945             .arg("--image-dir").arg(&image)
1946             .arg("--work-dir").arg(&tmpdir(builder))
1947             .arg("--output-dir").arg(&distdir(builder))
1948             .arg("--non-installed-overlay").arg(&overlay)
1949             .arg(format!("--package-name={}-{}", name, target))
1950             .arg("--legacy-manifest-dirs=rustlib,cargo")
1951             .arg("--component-name=llvm-tools-preview");
1952
1953
1954         builder.run(&mut cmd);
1955         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1956     }
1957 }