]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Change code to work with the new system
[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 // /// Helper to depend on a stage0 build-only rust-installer tool.
22 // fn tool_rust_installer<'a>(build: &'a Build, step: &Step<'a>) -> Step<'a> {
23 //     step.name("tool-rust-installer")
24 //         .host(&build.build)
25 //         .target(&build.build)
26 //         .stage(0)
27 // }
28
29 use std::env;
30 use std::fs::{self, File};
31 use std::io::{Read, Write};
32 use std::path::{PathBuf, Path};
33 use std::process::{Command, Stdio};
34
35 use build_helper::output;
36
37 use {Build, Compiler, Mode};
38 use channel;
39 use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe};
40
41 pub fn pkgname(build: &Build, component: &str) -> String {
42     if component == "cargo" {
43         format!("{}-{}", component, build.cargo_package_vers())
44     } else if component == "rls" {
45         format!("{}-{}", component, build.rls_package_vers())
46     } else {
47         assert!(component.starts_with("rust"));
48         format!("{}-{}", component, build.rust_package_vers())
49     }
50 }
51
52 fn distdir(build: &Build) -> PathBuf {
53     build.out.join("dist")
54 }
55
56 pub fn tmpdir(build: &Build) -> PathBuf {
57     build.out.join("tmp/dist")
58 }
59
60 fn rust_installer(build: &Build) -> Command {
61     build.tool_cmd(&Compiler::new(0, &build.build), "rust-installer")
62 }
63
64 // rules.dist("dist-docs", "src/doc")
65 //      .default(true)
66 //      .only_host_build(true)
67 //      .dep(|s| s.name("default:doc"))
68 //      .dep(move |s| tool_rust_installer(build, s))
69 //      .run(move |s| dist::docs(build, s.stage, s.target));
70
71 #[derive(Serialize)]
72 pub struct Docs<'a> {
73     stage: u32,
74     host: &'a str,
75 }
76
77 impl<'a> Step<'a> for Docs<'a> {
78     type Output = ();
79     const DEFAULT: bool = true;
80     const ONLY_BUILD_TARGETS: bool = true;
81
82     fn should_run(_builder: &Builder, path: &Path) -> bool {
83         path.ends_with("src/doc")
84     }
85
86     fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
87         builder.ensure(Docs {
88             stage: builder.top_stage,
89             host: target,
90         });
91     }
92
93     /// Builds the `rust-docs` installer component.
94     ///
95     /// Slurps up documentation from the `stage`'s `host`.
96     fn run(self, builder: &Builder) {
97         let build = builder.build;
98         let stage = self.stage;
99         let host = self.host;
100
101         builder.default_doc(None);
102
103         println!("Dist docs stage{} ({})", stage, host);
104         if !build.config.docs {
105             println!("\tskipping - docs disabled");
106             return
107         }
108
109         let name = pkgname(build, "rust-docs");
110         let image = tmpdir(build).join(format!("{}-{}-image", name, host));
111         let _ = fs::remove_dir_all(&image);
112
113         let dst = image.join("share/doc/rust/html");
114         t!(fs::create_dir_all(&dst));
115         let src = build.out.join(host).join("doc");
116         cp_r(&src, &dst);
117
118         let mut cmd = rust_installer(build);
119         cmd.arg("generate")
120            .arg("--product-name=Rust-Documentation")
121            .arg("--rel-manifest-dir=rustlib")
122            .arg("--success-message=Rust-documentation-is-installed.")
123            .arg("--image-dir").arg(&image)
124            .arg("--work-dir").arg(&tmpdir(build))
125            .arg("--output-dir").arg(&distdir(build))
126            .arg(format!("--package-name={}-{}", name, host))
127            .arg("--component-name=rust-docs")
128            .arg("--legacy-manifest-dirs=rustlib,cargo")
129            .arg("--bulk-dirs=share/doc/rust/html");
130         build.run(&mut cmd);
131         t!(fs::remove_dir_all(&image));
132
133         // As part of this step, *also* copy the docs directory to a directory which
134         // buildbot typically uploads.
135         if host == build.build {
136             let dst = distdir(build).join("doc").join(build.rust_package_vers());
137             t!(fs::create_dir_all(&dst));
138             cp_r(&src, &dst);
139         }
140     }
141 }
142
143 fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
144     let mut found = Vec::with_capacity(files.len());
145
146     for file in files {
147         let file_path =
148             path.iter()
149                 .map(|dir| dir.join(file))
150                 .find(|p| p.exists());
151
152         if let Some(file_path) = file_path {
153             found.push(file_path);
154         } else {
155             panic!("Could not find '{}' in {:?}", file, path);
156         }
157     }
158
159     found
160 }
161
162 fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: &Build) {
163     //Ask gcc where it keeps its stuff
164     let mut cmd = Command::new(build.cc(target_triple));
165     cmd.arg("-print-search-dirs");
166     let gcc_out = output(&mut cmd);
167
168     let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
169     let mut lib_path = Vec::new();
170
171     for line in gcc_out.lines() {
172         let idx = line.find(':').unwrap();
173         let key = &line[..idx];
174         let trim_chars: &[_] = &[' ', '='];
175         let value =
176             line[(idx + 1)..]
177                 .trim_left_matches(trim_chars)
178                 .split(';')
179                 .map(PathBuf::from);
180
181         if key == "programs" {
182             bin_path.extend(value);
183         } else if key == "libraries" {
184             lib_path.extend(value);
185         }
186     }
187
188     let target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"];
189     let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"];
190     if target_triple.starts_with("i686-") {
191         rustc_dlls.push("libgcc_s_dw2-1.dll");
192     } else {
193         rustc_dlls.push("libgcc_s_seh-1.dll");
194     }
195
196     let target_libs = [ //MinGW libs
197         "libgcc.a",
198         "libgcc_eh.a",
199         "libgcc_s.a",
200         "libm.a",
201         "libmingw32.a",
202         "libmingwex.a",
203         "libstdc++.a",
204         "libiconv.a",
205         "libmoldname.a",
206         "libpthread.a",
207         //Windows import libs
208         "libadvapi32.a",
209         "libbcrypt.a",
210         "libcomctl32.a",
211         "libcomdlg32.a",
212         "libcrypt32.a",
213         "libgdi32.a",
214         "libimagehlp.a",
215         "libiphlpapi.a",
216         "libkernel32.a",
217         "libmsvcrt.a",
218         "libodbc32.a",
219         "libole32.a",
220         "liboleaut32.a",
221         "libopengl32.a",
222         "libpsapi.a",
223         "librpcrt4.a",
224         "libsetupapi.a",
225         "libshell32.a",
226         "libuser32.a",
227         "libuserenv.a",
228         "libuuid.a",
229         "libwinhttp.a",
230         "libwinmm.a",
231         "libwinspool.a",
232         "libws2_32.a",
233         "libwsock32.a",
234     ];
235
236     //Find mingw artifacts we want to bundle
237     let target_tools = find_files(&target_tools, &bin_path);
238     let rustc_dlls = find_files(&rustc_dlls, &bin_path);
239     let target_libs = find_files(&target_libs, &lib_path);
240
241     fn copy_to_folder(src: &Path, dest_folder: &Path) {
242         let file_name = src.file_name().unwrap();
243         let dest = dest_folder.join(file_name);
244         copy(src, &dest);
245     }
246
247     //Copy runtime dlls next to rustc.exe
248     let dist_bin_dir = rust_root.join("bin/");
249     fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
250     for src in rustc_dlls {
251         copy_to_folder(&src, &dist_bin_dir);
252     }
253
254     //Copy platform tools to platform-specific bin directory
255     let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
256     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
257     for src in target_tools {
258         copy_to_folder(&src, &target_bin_dir);
259     }
260
261     //Copy platform libs to platform-specific lib directory
262     let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
263     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
264     for src in target_libs {
265         copy_to_folder(&src, &target_lib_dir);
266     }
267 }
268
269 // rules.dist("dist-mingw", "path/to/nowhere")
270 //      .default(true)
271 //      .only_host_build(true)
272 //      .dep(move |s| tool_rust_installer(build, s))
273 //      .run(move |s| {
274 //          if s.target.contains("pc-windows-gnu") {
275 //              dist::mingw(build, s.target)
276 //          }
277 //      });
278
279 #[derive(Serialize)]
280 pub struct Mingw<'a> {
281     host: &'a str,
282 }
283
284 impl<'a> Step<'a> for Mingw<'a> {
285     type Output = ();
286     const DEFAULT: bool = true;
287     const ONLY_BUILD_TARGETS: bool = true;
288
289     fn should_run(_builder: &Builder, _path: &Path) -> bool {
290         false
291     }
292
293     fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
294         builder.ensure(Mingw {
295             host: host,
296         });
297     }
298
299     /// Build the `rust-mingw` installer component.
300     ///
301     /// This contains all the bits and pieces to run the MinGW Windows targets
302     /// without any extra installed software (e.g. we bundle gcc, libraries, etc).
303     fn run(self, builder: &Builder) {
304         let build = builder.build;
305         let host = self.host;
306
307         if !host.contains("pc-windows-gnu") {
308             return;
309         }
310
311         println!("Dist mingw ({})", host);
312         let name = pkgname(build, "rust-mingw");
313         let image = tmpdir(build).join(format!("{}-{}-image", name, host));
314         let _ = fs::remove_dir_all(&image);
315         t!(fs::create_dir_all(&image));
316
317         // The first argument is a "temporary directory" which is just
318         // thrown away (this contains the runtime DLLs included in the rustc package
319         // above) and the second argument is where to place all the MinGW components
320         // (which is what we want).
321         make_win_dist(&tmpdir(build), &image, host, &build);
322
323         let mut cmd = rust_installer(build);
324         cmd.arg("generate")
325            .arg("--product-name=Rust-MinGW")
326            .arg("--rel-manifest-dir=rustlib")
327            .arg("--success-message=Rust-MinGW-is-installed.")
328            .arg("--image-dir").arg(&image)
329            .arg("--work-dir").arg(&tmpdir(build))
330            .arg("--output-dir").arg(&distdir(build))
331            .arg(format!("--package-name={}-{}", name, host))
332            .arg("--component-name=rust-mingw")
333            .arg("--legacy-manifest-dirs=rustlib,cargo");
334         build.run(&mut cmd);
335         t!(fs::remove_dir_all(&image));
336     }
337 }
338
339 // rules.dist("dist-rustc", "src/librustc")
340 //      .dep(move |s| s.name("rustc").host(&build.build))
341 //      .host(true)
342 //      .only_host_build(true)
343 //      .default(true)
344 //      .dep(move |s| tool_rust_installer(build, s))
345 //      .run(move |s| dist::rustc(build, s.stage, s.target));
346
347 #[derive(Serialize)]
348 pub struct Rustc<'a> {
349     stage: u32,
350     host: &'a str,
351 }
352
353 impl<'a> Step<'a> for Rustc<'a> {
354     type Output = ();
355     const DEFAULT: bool = true;
356     const ONLY_HOSTS: bool = true;
357     const ONLY_BUILD_TARGETS: bool = true;
358
359     fn should_run(_builder: &Builder, path: &Path) -> bool {
360         path.ends_with("src/librustc")
361     }
362
363     fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
364         builder.ensure(Rustc {
365             stage: builder.top_stage,
366             host: host,
367         });
368     }
369
370     /// Creates the `rustc` installer component.
371     fn run(self, builder: &builder) {
372         let build = builder.build;
373         let stage = self.stage;
374         let host = self.host;
375         println!("Dist rustc stage{} ({})", stage, host);
376         let name = pkgname(build, "rustc");
377         let image = tmpdir(build).join(format!("{}-{}-image", name, host));
378         let _ = fs::remove_dir_all(&image);
379         let overlay = tmpdir(build).join(format!("{}-{}-overlay", name, host));
380         let _ = fs::remove_dir_all(&overlay);
381
382         // Prepare the rustc "image", what will actually end up getting installed
383         prepare_image(builder, stage, host, &image);
384
385         // Prepare the overlay which is part of the tarball but won't actually be
386         // installed
387         let cp = |file: &str| {
388             install(&build.src.join(file), &overlay, 0o644);
389         };
390         cp("COPYRIGHT");
391         cp("LICENSE-APACHE");
392         cp("LICENSE-MIT");
393         cp("README.md");
394         // tiny morsel of metadata is used by rust-packaging
395         let version = build.rust_version();
396         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
397
398         // On MinGW we've got a few runtime DLL dependencies that we need to
399         // include. The first argument to this script is where to put these DLLs
400         // (the image we're creating), and the second argument is a junk directory
401         // to ignore all other MinGW stuff the script creates.
402         //
403         // On 32-bit MinGW we're always including a DLL which needs some extra
404         // licenses to distribute. On 64-bit MinGW we don't actually distribute
405         // anything requiring us to distribute a license, but it's likely the
406         // install will *also* include the rust-mingw package, which also needs
407         // licenses, so to be safe we just include it here in all MinGW packages.
408         if host.contains("pc-windows-gnu") {
409             make_win_dist(&image, &tmpdir(build), host, build);
410
411             let dst = image.join("share/doc");
412             t!(fs::create_dir_all(&dst));
413             cp_r(&build.src.join("src/etc/third-party"), &dst);
414         }
415
416         // Finally, wrap everything up in a nice tarball!
417         let mut cmd = rust_installer(build);
418         cmd.arg("generate")
419            .arg("--product-name=Rust")
420            .arg("--rel-manifest-dir=rustlib")
421            .arg("--success-message=Rust-is-ready-to-roll.")
422            .arg("--image-dir").arg(&image)
423            .arg("--work-dir").arg(&tmpdir(build))
424            .arg("--output-dir").arg(&distdir(build))
425            .arg("--non-installed-overlay").arg(&overlay)
426            .arg(format!("--package-name={}-{}", name, host))
427            .arg("--component-name=rustc")
428            .arg("--legacy-manifest-dirs=rustlib,cargo");
429         build.run(&mut cmd);
430         t!(fs::remove_dir_all(&image));
431         t!(fs::remove_dir_all(&overlay));
432
433         fn prepare_image(builder: &Builder, stage: u32, host: &str, image: &Path) {
434             let build = builder.build;
435             let src = build.sysroot(builder.compiler(stage, host));
436             let libdir = libdir(host);
437
438             // Copy rustc/rustdoc binaries
439             t!(fs::create_dir_all(image.join("bin")));
440             cp_r(&src.join("bin"), &image.join("bin"));
441
442             // Copy runtime DLLs needed by the compiler
443             if libdir != "bin" {
444                 for entry in t!(src.join(libdir).read_dir()).map(|e| t!(e)) {
445                     let name = entry.file_name();
446                     if let Some(s) = name.to_str() {
447                         if is_dylib(s) {
448                             install(&entry.path(), &image.join(libdir), 0o644);
449                         }
450                     }
451                 }
452             }
453
454             // Man pages
455             t!(fs::create_dir_all(image.join("share/man/man1")));
456             cp_r(&build.src.join("man"), &image.join("share/man/man1"));
457
458             // Debugger scripts
459             builder.ensure(DebuggerScripts {
460                 sysroot: &image,
461                 host: host,
462             });
463
464             // Misc license info
465             let cp = |file: &str| {
466                 install(&build.src.join(file), &image.join("share/doc/rust"), 0o644);
467             };
468             cp("COPYRIGHT");
469             cp("LICENSE-APACHE");
470             cp("LICENSE-MIT");
471             cp("README.md");
472         }
473     }
474 }
475
476 //rules.test("debugger-scripts", "src/etc/lldb_batchmode.py")
477 //     .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()),
478 //                                     s.target));
479
480 #[derive(Serialize)]
481 pub struct DebuggerScripts<'a> {
482     sysroot: &'a Path,
483     host: &'a str,
484 }
485
486 impl<'a> Step<'a> for DebuggerScripts<'a> {
487     type Output = ();
488
489     fn should_run(_builder: &Builder, path: &Path) -> bool {
490         path.ends_with("src/etc/lldb_batchmode.py")
491     }
492
493     fn make_run(builder: &Builder, _path: Option<&Path>, host: &str, _target: &str) {
494         builder.ensure(DebuggerScripts {
495             // FIXME: builder.top_stage is likely wrong in some cases.
496             sysroot: &builder.sysroot(builder.compiler(builder.top_stage, host)),
497             host: host,
498         });
499     }
500
501     /// Copies debugger scripts for `host` into the `sysroot` specified.
502     fn run(self, builder: &Builder) {
503         let build = builder.build;
504         let host = self.host;
505         let sysroot = self.sysroot;
506         let dst = sysroot.join("lib/rustlib/etc");
507         t!(fs::create_dir_all(&dst));
508         let cp_debugger_script = |file: &str| {
509             install(&build.src.join("src/etc/").join(file), &dst, 0o644);
510         };
511         if host.contains("windows-msvc") {
512             // windbg debugger scripts
513             install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
514                 0o755);
515
516             cp_debugger_script("natvis/liballoc.natvis");
517             cp_debugger_script("natvis/libcore.natvis");
518         } else {
519             cp_debugger_script("debugger_pretty_printers_common.py");
520
521             // gdb debugger scripts
522             install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
523                     0o755);
524
525             cp_debugger_script("gdb_load_rust_pretty_printers.py");
526             cp_debugger_script("gdb_rust_pretty_printing.py");
527
528             // lldb debugger scripts
529             install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
530                     0o755);
531
532             cp_debugger_script("lldb_rust_formatters.py");
533         }
534     }
535 }
536
537 // rules.dist("dist-std", "src/libstd")
538 //      .dep(move |s| {
539 //          // We want to package up as many target libraries as possible
540 //          // for the `rust-std` package, so if this is a host target we
541 //          // depend on librustc and otherwise we just depend on libtest.
542 //          if build.config.host.iter().any(|t| t == s.target) {
543 //              s.name("librustc-link")
544 //          } else {
545 //              s.name("libtest-link")
546 //          }
547 //      })
548 //      .default(true)
549 //      .only_host_build(true)
550 //      .dep(move |s| tool_rust_installer(build, s))
551 //      .run(move |s| dist::std(build, &s.compiler(), s.target));
552
553     let name = pkgname(build, "rust-std");
554     let image = tmpdir(build).join(format!("{}-{}-image", name, target));
555     let _ = fs::remove_dir_all(&image);
556
557     let dst = image.join("lib/rustlib").join(target);
558     t!(fs::create_dir_all(&dst));
559     let mut src = build.sysroot_libdir(compiler, target);
560     src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
561     cp_r(&src, &dst);
562
563     let mut cmd = rust_installer(build);
564     cmd.arg("generate")
565        .arg("--product-name=Rust")
566        .arg("--rel-manifest-dir=rustlib")
567        .arg("--success-message=std-is-standing-at-the-ready.")
568        .arg("--image-dir").arg(&image)
569        .arg("--work-dir").arg(&tmpdir(build))
570        .arg("--output-dir").arg(&distdir(build))
571        .arg(format!("--package-name={}-{}", name, target))
572        .arg(format!("--component-name=rust-std-{}", target))
573        .arg("--legacy-manifest-dirs=rustlib,cargo");
574     build.run(&mut cmd);
575     t!(fs::remove_dir_all(&image));
576 }
577
578 /// The path to the complete rustc-src tarball
579 pub fn rust_src_location(build: &Build) -> PathBuf {
580     let plain_name = format!("rustc-{}-src", build.rust_package_vers());
581     distdir(build).join(&format!("{}.tar.gz", plain_name))
582 }
583
584 /// The path to the rust-src component installer
585 pub fn rust_src_installer(build: &Build) -> PathBuf {
586     let name = pkgname(build, "rust-src");
587     distdir(build).join(&format!("{}.tar.gz", name))
588 }
589
590 // rules.dist("dist-analysis", "analysis")
591 //      .default(build.config.extended)
592 //      .dep(|s| s.name("dist-std"))
593 //      .only_host_build(true)
594 //      .dep(move |s| tool_rust_installer(build, s))
595 //      .run(move |s| dist::analysis(build, &s.compiler(), s.target));
596
597 #[derive(Serialize)]
598 pub struct Analysis<'a> {
599     compiler: Compiler<'a>,
600     target: &'a str,
601 }
602
603 impl<'a> Step<'a> for Analysis<'a> {
604     type Output = ();
605     const DEFAULT: bool = true;
606     const ONLY_BUILD_TARGETS: bool = true;
607
608     fn should_run(_builder: &Builder, path: &Path) -> bool {
609         path.ends_with("analysis")
610     }
611
612     fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
613         if path.is_none() && !builder.build.config.extended {
614             return;
615         }
616         builder.ensure(Analysis {
617             compiler: builder.compiler(builder.top_stage, host),
618             target: target,
619         });
620     }
621
622     /// Creates a tarball of save-analysis metadata, if available.
623     fn run(self, builder: &Builder) {
624         let build = builder.build;
625         let compiler = self.compiler;
626         let target = self.target;
627         assert!(build.config.extended);
628         println!("Dist analysis");
629
630         if compiler.host != build.build {
631             println!("\tskipping, not a build host");
632             return;
633         }
634
635         // Package save-analysis from stage1 if not doing a full bootstrap, as the
636         // stage2 artifacts is simply copied from stage1 in that case.
637         let compiler = if build.force_use_stage1(compiler, target) {
638             builder.compiler(1, compiler.host)
639         } else {
640             compiler.clone()
641         };
642
643         let name = pkgname(build, "rust-analysis");
644         let image = tmpdir(build).join(format!("{}-{}-image", name, target));
645
646         let src = build.stage_out(compiler, Mode::Libstd)
647             .join(target).join("release").join("deps");
648
649         let image_src = src.join("save-analysis");
650         let dst = image.join("lib/rustlib").join(target).join("analysis");
651         t!(fs::create_dir_all(&dst));
652         println!("image_src: {:?}, dst: {:?}", image_src, dst);
653         cp_r(&image_src, &dst);
654
655         let mut cmd = rust_installer(build);
656         cmd.arg("generate")
657            .arg("--product-name=Rust")
658            .arg("--rel-manifest-dir=rustlib")
659            .arg("--success-message=save-analysis-saved.")
660            .arg("--image-dir").arg(&image)
661            .arg("--work-dir").arg(&tmpdir(build))
662            .arg("--output-dir").arg(&distdir(build))
663            .arg(format!("--package-name={}-{}", name, target))
664            .arg(format!("--component-name=rust-analysis-{}", target))
665            .arg("--legacy-manifest-dirs=rustlib,cargo");
666         build.run(&mut cmd);
667         t!(fs::remove_dir_all(&image));
668     }
669 }
670
671 fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
672     fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
673         let spath = match path.to_str() {
674             Some(path) => path,
675             None => return false,
676         };
677         if spath.ends_with("~") || spath.ends_with(".pyc") {
678             return false
679         }
680         if (spath.contains("llvm/test") || spath.contains("llvm\\test")) &&
681             (spath.ends_with(".ll") ||
682              spath.ends_with(".td") ||
683              spath.ends_with(".s")) {
684             return false
685         }
686
687         let full_path = Path::new(dir).join(path);
688         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
689             return false;
690         }
691
692         let excludes = [
693             "CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
694             ".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
695             "=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore",
696             ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
697         ];
698         !path.iter()
699              .map(|s| s.to_str().unwrap())
700              .any(|s| excludes.contains(&s))
701     }
702
703     // Copy the directories using our filter
704     for item in src_dirs {
705         let dst = &dst_dir.join(item);
706         t!(fs::create_dir_all(dst));
707         cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
708     }
709 }
710
711 // rules.dist("dist-src", "src")
712 //      .default(true)
713 //      .host(true)
714 //      .only_build(true)
715 //      .only_host_build(true)
716 //      .dep(move |s| tool_rust_installer(build, s))
717 //      .run(move |_| dist::rust_src(build));
718
719 #[derive(Serialize)]
720 pub struct Src;
721
722 impl<'a> Step<'a> for Src {
723     type Output = ();
724     const DEFAULT: bool = true;
725     const ONLY_HOSTS: bool = true;
726     const ONLY_BUILD_TARGETS: bool = true;
727     const ONLY_BUILD: bool = true;
728
729     fn should_run(_builder: &Builder, path: &Path) -> bool {
730         path.ends_with("src")
731     }
732
733     fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
734         builder.ensure(Src);
735     }
736
737     /// Creates the `rust-src` installer component
738     fn run(self, builder: &Builder) {
739         let build = builder.build;
740         println!("Dist src");
741
742         let name = pkgname(build, "rust-src");
743         let image = tmpdir(build).join(format!("{}-image", name));
744         let _ = fs::remove_dir_all(&image);
745
746         let dst = image.join("lib/rustlib/src");
747         let dst_src = dst.join("rust");
748         t!(fs::create_dir_all(&dst_src));
749
750         // This is the reduced set of paths which will become the rust-src component
751         // (essentially libstd and all of its path dependencies)
752         let std_src_dirs = [
753             "src/build_helper",
754             "src/liballoc",
755             "src/liballoc_jemalloc",
756             "src/liballoc_system",
757             "src/libbacktrace",
758             "src/libcollections",
759             "src/libcompiler_builtins",
760             "src/libcore",
761             "src/liblibc",
762             "src/libpanic_abort",
763             "src/libpanic_unwind",
764             "src/librand",
765             "src/librustc_asan",
766             "src/librustc_lsan",
767             "src/librustc_msan",
768             "src/librustc_tsan",
769             "src/libstd",
770             "src/libstd_unicode",
771             "src/libunwind",
772             "src/rustc/compiler_builtins_shim",
773             "src/rustc/libc_shim",
774             "src/libtest",
775             "src/libterm",
776             "src/jemalloc",
777             "src/libprofiler_builtins",
778         ];
779         let std_src_dirs_exclude = [
780             "src/compiler-rt/test",
781             "src/jemalloc/test/unit",
782         ];
783
784         copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
785
786         // Create source tarball in rust-installer format
787         let mut cmd = rust_installer(build);
788         cmd.arg("generate")
789            .arg("--product-name=Rust")
790            .arg("--rel-manifest-dir=rustlib")
791            .arg("--success-message=Awesome-Source.")
792            .arg("--image-dir").arg(&image)
793            .arg("--work-dir").arg(&tmpdir(build))
794            .arg("--output-dir").arg(&distdir(build))
795            .arg(format!("--package-name={}", name))
796            .arg("--component-name=rust-src")
797            .arg("--legacy-manifest-dirs=rustlib,cargo");
798         build.run(&mut cmd);
799
800         t!(fs::remove_dir_all(&image));
801     }
802 }
803
804 const CARGO_VENDOR_VERSION: &str = "0.1.4";
805
806 // rules.dist("dist-plain-source-tarball", "src")
807 //      .default(build.config.rust_dist_src)
808 //      .host(true)
809 //      .only_build(true)
810 //      .only_host_build(true)
811 //      .dep(move |s| tool_rust_installer(build, s))
812 //      .run(move |_| dist::plain_source_tarball(build));
813
814 #[derive(Serialize)]
815 pub struct PlainSourceTarball;
816
817 impl<'a> Step<'a> for PlainSourceTarball {
818     type Output = ();
819     const DEFAULT: bool = true;
820     const ONLY_HOSTS: bool = true;
821     const ONLY_BUILD_TARGETS: bool = true;
822     const ONLY_BUILD: bool = true;
823
824     fn should_run(_builder: &Builder, path: &Path) -> bool {
825         path.ends_with("src")
826     }
827
828     fn make_run(builder: &Builder, path: Option<&Path>, _host: &str, _target: &str) {
829         if path.is_none() && !builder.build.config.rust_dist_src {
830             return;
831         }
832
833         builder.ensure(PlainSourceTarball);
834     }
835
836     /// Creates the plain source tarball
837     fn run(self, builder: &Builder) {
838         let build = builder.build;
839         println!("Create plain source tarball");
840
841         // Make sure that the root folder of tarball has the correct name
842         let plain_name = format!("{}-src", pkgname(build, "rustc"));
843         let plain_dst_src = tmpdir(build).join(&plain_name);
844         let _ = fs::remove_dir_all(&plain_dst_src);
845         t!(fs::create_dir_all(&plain_dst_src));
846
847         // This is the set of root paths which will become part of the source package
848         let src_files = [
849             "COPYRIGHT",
850             "LICENSE-APACHE",
851             "LICENSE-MIT",
852             "CONTRIBUTING.md",
853             "README.md",
854             "RELEASES.md",
855             "configure",
856             "x.py",
857         ];
858         let src_dirs = [
859             "man",
860             "src",
861         ];
862
863         copy_src_dirs(build, &src_dirs[..], &[], &plain_dst_src);
864
865         // Copy the files normally
866         for item in &src_files {
867             copy(&build.src.join(item), &plain_dst_src.join(item));
868         }
869
870         // Create the version file
871         write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
872
873         // If we're building from git sources, we need to vendor a complete distribution.
874         if build.rust_info.is_git() {
875             // Get cargo-vendor installed, if it isn't already.
876             let mut has_cargo_vendor = false;
877             let mut cmd = Command::new(&build.initial_cargo);
878             for line in output(cmd.arg("install").arg("--list")).lines() {
879                 has_cargo_vendor |= line.starts_with("cargo-vendor ");
880             }
881             if !has_cargo_vendor {
882                 let mut cmd = Command::new(&build.initial_cargo);
883                 cmd.arg("install")
884                    .arg("--force")
885                    .arg("--debug")
886                    .arg("--vers").arg(CARGO_VENDOR_VERSION)
887                    .arg("cargo-vendor")
888                    .env("RUSTC", &build.initial_rustc);
889                 build.run(&mut cmd);
890             }
891
892             // Vendor all Cargo dependencies
893             let mut cmd = Command::new(&build.initial_cargo);
894             cmd.arg("vendor")
895                .current_dir(&plain_dst_src.join("src"));
896             build.run(&mut cmd);
897         }
898
899         // Create plain source tarball
900         let mut tarball = rust_src_location(build);
901         tarball.set_extension(""); // strip .gz
902         tarball.set_extension(""); // strip .tar
903         if let Some(dir) = tarball.parent() {
904             t!(fs::create_dir_all(dir));
905         }
906         let mut cmd = rust_installer(build);
907         cmd.arg("tarball")
908            .arg("--input").arg(&plain_name)
909            .arg("--output").arg(&tarball)
910            .arg("--work-dir=.")
911            .current_dir(tmpdir(build));
912         build.run(&mut cmd);
913     }
914 }
915
916 fn install(src: &Path, dstdir: &Path, perms: u32) {
917     let dst = dstdir.join(src.file_name().unwrap());
918     t!(fs::create_dir_all(dstdir));
919     t!(fs::copy(src, &dst));
920     chmod(&dst, perms);
921 }
922
923 #[cfg(unix)]
924 fn chmod(path: &Path, perms: u32) {
925     use std::os::unix::fs::*;
926     t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
927 }
928 #[cfg(windows)]
929 fn chmod(_path: &Path, _perms: u32) {}
930
931 // We have to run a few shell scripts, which choke quite a bit on both `\`
932 // characters and on `C:\` paths, so normalize both of them away.
933 pub fn sanitize_sh(path: &Path) -> String {
934     let path = path.to_str().unwrap().replace("\\", "/");
935     return change_drive(&path).unwrap_or(path);
936
937     fn change_drive(s: &str) -> Option<String> {
938         let mut ch = s.chars();
939         let drive = ch.next().unwrap_or('C');
940         if ch.next() != Some(':') {
941             return None
942         }
943         if ch.next() != Some('/') {
944             return None
945         }
946         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
947     }
948 }
949
950 fn write_file(path: &Path, data: &[u8]) {
951     let mut vf = t!(fs::File::create(path));
952     t!(vf.write_all(data));
953 }
954
955 // rules.dist("dist-cargo", "cargo")
956 //      .host(true)
957 //      .only_host_build(true)
958 //      .dep(|s| s.name("tool-cargo"))
959 //      .dep(move |s| tool_rust_installer(build, s))
960 //      .run(move |s| dist::cargo(build, s.stage, s.target));
961
962 #[derive(Serialize)]
963 pub struct Cargo<'a> {
964     stage: u32,
965     target: &'a str,
966 }
967
968 impl<'a> Step<'a> for Cargo<'a> {
969     type Output = ();
970     const ONLY_BUILD_TARGETS: bool = true;
971     const ONLY_HOSTS: bool = true;
972
973     fn should_run(_builder: &Builder, path: &Path) -> bool {
974         path.ends_with("cargo")
975     }
976
977     fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
978         builder.ensure(Cargo {
979             stage: builder.top_stage,
980             target: target,
981         });
982     }
983
984     fn run(self, builder: &Builder) {
985         let build = builder.build;
986         let stage = self.stage;
987         let target = self.target;
988
989         builder.ensure(tool::Cargo { stage, target });
990
991         println!("Dist cargo stage{} ({})", stage, target);
992         let compiler = builder.compiler(stage, &build.build);
993
994         let src = build.src.join("src/tools/cargo");
995         let etc = src.join("src/etc");
996         let release_num = build.release_num("cargo");
997         let name = pkgname(build, "cargo");
998         let version = build.cargo_info.version(build, &release_num);
999
1000         let tmp = tmpdir(build);
1001         let image = tmp.join("cargo-image");
1002         drop(fs::remove_dir_all(&image));
1003         t!(fs::create_dir_all(&image));
1004
1005         // Prepare the image directory
1006         t!(fs::create_dir_all(image.join("share/zsh/site-functions")));
1007         t!(fs::create_dir_all(image.join("etc/bash_completion.d")));
1008         let cargo = build.cargo_out(&compiler, Mode::Tool, target)
1009                          .join(exe("cargo", target));
1010         install(&cargo, &image.join("bin"), 0o755);
1011         for man in t!(etc.join("man").read_dir()) {
1012             let man = t!(man);
1013             install(&man.path(), &image.join("share/man/man1"), 0o644);
1014         }
1015         install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
1016         copy(&etc.join("cargo.bashcomp.sh"),
1017              &image.join("etc/bash_completion.d/cargo"));
1018         let doc = image.join("share/doc/cargo");
1019         install(&src.join("README.md"), &doc, 0o644);
1020         install(&src.join("LICENSE-MIT"), &doc, 0o644);
1021         install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1022         install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
1023
1024         // Prepare the overlay
1025         let overlay = tmp.join("cargo-overlay");
1026         drop(fs::remove_dir_all(&overlay));
1027         t!(fs::create_dir_all(&overlay));
1028         install(&src.join("README.md"), &overlay, 0o644);
1029         install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1030         install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1031         install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1032         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1033
1034         // Generate the installer tarball
1035         let mut cmd = rust_installer(build);
1036         cmd.arg("generate")
1037            .arg("--product-name=Rust")
1038            .arg("--rel-manifest-dir=rustlib")
1039            .arg("--success-message=Rust-is-ready-to-roll.")
1040            .arg("--image-dir").arg(&image)
1041            .arg("--work-dir").arg(&tmpdir(build))
1042            .arg("--output-dir").arg(&distdir(build))
1043            .arg("--non-installed-overlay").arg(&overlay)
1044            .arg(format!("--package-name={}-{}", name, target))
1045            .arg("--component-name=cargo")
1046            .arg("--legacy-manifest-dirs=rustlib,cargo");
1047         build.run(&mut cmd);
1048     }
1049 }
1050
1051 // rules.dist("dist-rls", "rls")
1052 //      .host(true)
1053 //      .only_host_build(true)
1054 //      .dep(|s| s.name("tool-rls"))
1055 //      .dep(move |s| tool_rust_installer(build, s))
1056 //      .run(move |s| dist::rls(build, s.stage, s.target));
1057 #[derive(Serialize)]
1058 pub struct Rls<'a> {
1059     stage: u32,
1060     target: &'a str,
1061 }
1062
1063 impl<'a> Step<'a> for Rls<'a> {
1064     type Output = ();
1065     const ONLY_BUILD_TARGETS: bool = true;
1066     const ONLY_HOSTS: bool = true;
1067
1068     fn should_run(_builder: &Builder, path: &Path) -> bool {
1069         path.ends_with("rls")
1070     }
1071
1072     fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, target: &str) {
1073         builder.ensure(Rls {
1074             stage: builder.top_stage,
1075             target: target,
1076         });
1077     }
1078
1079     fn run(self, builder: &Builder) {
1080         let build = builder.build;
1081         let stage = self.stage;
1082         let target = self.target;
1083         assert!(build.config.extended);
1084
1085         builder.ensure(tool::Rls { stage, target });
1086
1087         println!("Dist RLS stage{} ({})", stage, target);
1088         let compiler = builder.compiler(stage, &build.build);
1089
1090         let src = build.src.join("src/tools/rls");
1091         let release_num = build.release_num("rls");
1092         let name = pkgname(build, "rls");
1093         let version = build.rls_info.version(build, &release_num);
1094
1095         let tmp = tmpdir(build);
1096         let image = tmp.join("rls-image");
1097         drop(fs::remove_dir_all(&image));
1098         t!(fs::create_dir_all(&image));
1099
1100         // Prepare the image directory
1101         let rls = build.cargo_out(&compiler, Mode::Tool, target)
1102                          .join(exe("rls", target));
1103         install(&rls, &image.join("bin"), 0o755);
1104         let doc = image.join("share/doc/rls");
1105         install(&src.join("README.md"), &doc, 0o644);
1106         install(&src.join("LICENSE-MIT"), &doc, 0o644);
1107         install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1108
1109         // Prepare the overlay
1110         let overlay = tmp.join("rls-overlay");
1111         drop(fs::remove_dir_all(&overlay));
1112         t!(fs::create_dir_all(&overlay));
1113         install(&src.join("README.md"), &overlay, 0o644);
1114         install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1115         install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1116         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1117
1118         // Generate the installer tarball
1119         let mut cmd = rust_installer(build);
1120         cmd.arg("generate")
1121            .arg("--product-name=Rust")
1122            .arg("--rel-manifest-dir=rustlib")
1123            .arg("--success-message=RLS-ready-to-serve.")
1124            .arg("--image-dir").arg(&image)
1125            .arg("--work-dir").arg(&tmpdir(build))
1126            .arg("--output-dir").arg(&distdir(build))
1127            .arg("--non-installed-overlay").arg(&overlay)
1128            .arg(format!("--package-name={}-{}", name, target))
1129            .arg("--component-name=rls")
1130            .arg("--legacy-manifest-dirs=rustlib,cargo");
1131         build.run(&mut cmd);
1132     }
1133 }
1134
1135 // rules.dist("dist-extended", "extended")
1136 //      .default(build.config.extended)
1137 //      .host(true)
1138 //      .only_host_build(true)
1139 //      .dep(|d| d.name("dist-std"))
1140 //      .dep(|d| d.name("dist-rustc"))
1141 //      .dep(|d| d.name("dist-mingw"))
1142 //      .dep(|d| d.name("dist-docs"))
1143 //      .dep(|d| d.name("dist-cargo"))
1144 //      .dep(|d| d.name("dist-rls"))
1145 //      .dep(|d| d.name("dist-analysis"))
1146 //      .dep(move |s| tool_rust_installer(build, s))
1147 //      .run(move |s| dist::extended(build, s.stage, s.target));
1148
1149 #[derive(Serialize)]
1150 pub struct Extended<'a> {
1151     stage: u32,
1152     target: &'a str,
1153 }
1154
1155 impl<'a> Step<'a> for Extended<'a> {
1156     type Output = ();
1157     const DEFAULT: bool = true;
1158     const ONLY_BUILD_TARGETS: bool = true;
1159     const ONLY_HOSTS: bool = true;
1160
1161     fn should_run(_builder: &Builder, path: &Path) -> bool {
1162         path.ends_with("cargo")
1163     }
1164
1165     fn make_run(builder: &Builder, path: Option<&Path>, host: &str, target: &str) {
1166         if path.is_none() && !builder.build.config.extended {
1167             return;
1168         }
1169         builder.ensure(Extended {
1170             compiler: builder.compiler(builder.top_stage, host),
1171             target: target,
1172         });
1173     }
1174
1175     /// Creates a combined installer for the specified target in the provided stage.
1176     fn run(self, builder: &Builder) {
1177         let build = builder.build;
1178         let stage = self.stage;
1179         let target = self.target;
1180         let compiler = builder.compiler(stage, &build.build);
1181
1182         builder.ensure(Std { compiler, target });
1183         builder.ensure(Rustc { stage, host });
1184         builder.ensure(Mingw { host });
1185         builder.ensure(Docs { stage, host });
1186         builder.ensure(Cargo { stage, target });
1187         builder.ensure(Rls { stage, target });
1188         builder.ensure(Analysis { compiler, target });
1189
1190         println!("Dist extended stage{} ({})", stage, target);
1191
1192         let dist = distdir(build);
1193         let rustc_installer = dist.join(format!("{}-{}.tar.gz",
1194                                                 pkgname(build, "rustc"),
1195                                                 target));
1196         let cargo_installer = dist.join(format!("{}-{}.tar.gz",
1197                                                 pkgname(build, "cargo"),
1198                                                 target));
1199         let rls_installer = dist.join(format!("{}-{}.tar.gz",
1200                                                 pkgname(build, "rls"),
1201                                                 target));
1202         let analysis_installer = dist.join(format!("{}-{}.tar.gz",
1203                                                     pkgname(build, "rust-analysis"),
1204                                                     target));
1205         let docs_installer = dist.join(format!("{}-{}.tar.gz",
1206                                                 pkgname(build, "rust-docs"),
1207                                                 target));
1208         let mingw_installer = dist.join(format!("{}-{}.tar.gz",
1209                                                 pkgname(build, "rust-mingw"),
1210                                                 target));
1211         let std_installer = dist.join(format!("{}-{}.tar.gz",
1212                                                 pkgname(build, "rust-std"),
1213                                                 target));
1214
1215         let tmp = tmpdir(build);
1216         let overlay = tmp.join("extended-overlay");
1217         let etc = build.src.join("src/etc/installer");
1218         let work = tmp.join("work");
1219
1220         let _ = fs::remove_dir_all(&overlay);
1221         install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
1222         install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
1223         install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
1224         let version = build.rust_version();
1225         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1226         install(&etc.join("README.md"), &overlay, 0o644);
1227
1228         // When rust-std package split from rustc, we needed to ensure that during
1229         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1230         // the std files during uninstall. To do this ensure that rustc comes
1231         // before rust-std in the list below.
1232         let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
1233                                 analysis_installer, docs_installer, std_installer];
1234         if target.contains("pc-windows-gnu") {
1235             tarballs.push(mingw_installer);
1236         }
1237         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1238         for tarball in &tarballs[1..] {
1239             input_tarballs.push(",");
1240             input_tarballs.push(tarball);
1241         }
1242
1243         let mut cmd = rust_installer(build);
1244         cmd.arg("combine")
1245             .arg("--product-name=Rust")
1246             .arg("--rel-manifest-dir=rustlib")
1247             .arg("--success-message=Rust-is-ready-to-roll.")
1248             .arg("--work-dir").arg(&work)
1249             .arg("--output-dir").arg(&distdir(build))
1250             .arg(format!("--package-name={}-{}", pkgname(build, "rust"), target))
1251             .arg("--legacy-manifest-dirs=rustlib,cargo")
1252             .arg("--input-tarballs").arg(input_tarballs)
1253             .arg("--non-installed-overlay").arg(&overlay);
1254         build.run(&mut cmd);
1255
1256         let mut license = String::new();
1257         t!(t!(File::open(build.src.join("COPYRIGHT"))).read_to_string(&mut license));
1258         license.push_str("\n");
1259         t!(t!(File::open(build.src.join("LICENSE-APACHE"))).read_to_string(&mut license));
1260         license.push_str("\n");
1261         t!(t!(File::open(build.src.join("LICENSE-MIT"))).read_to_string(&mut license));
1262
1263         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1264         let mut rtf = rtf.to_string();
1265         rtf.push_str("\n");
1266         for line in license.lines() {
1267             rtf.push_str(line);
1268             rtf.push_str("\\line ");
1269         }
1270         rtf.push_str("}");
1271
1272         if target.contains("apple-darwin") {
1273             let pkg = tmp.join("pkg");
1274             let _ = fs::remove_dir_all(&pkg);
1275             t!(fs::create_dir_all(pkg.join("rustc")));
1276             t!(fs::create_dir_all(pkg.join("cargo")));
1277             t!(fs::create_dir_all(pkg.join("rust-docs")));
1278             t!(fs::create_dir_all(pkg.join("rust-std")));
1279             t!(fs::create_dir_all(pkg.join("rls")));
1280             t!(fs::create_dir_all(pkg.join("rust-analysis")));
1281
1282             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)),
1283                     &pkg.join("rustc"));
1284             cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)),
1285                     &pkg.join("cargo"));
1286             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)),
1287                     &pkg.join("rust-docs"));
1288             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)),
1289                     &pkg.join("rust-std"));
1290             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)),
1291                     &pkg.join("rls"));
1292             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)),
1293                     &pkg.join("rust-analysis"));
1294
1295             install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755);
1296             install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755);
1297             install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755);
1298             install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755);
1299             install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755);
1300             install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755);
1301
1302             let pkgbuild = |component: &str| {
1303                 let mut cmd = Command::new("pkgbuild");
1304                 cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
1305                     .arg("--scripts").arg(pkg.join(component))
1306                     .arg("--nopayload")
1307                     .arg(pkg.join(component).with_extension("pkg"));
1308                 build.run(&mut cmd);
1309             };
1310             pkgbuild("rustc");
1311             pkgbuild("cargo");
1312             pkgbuild("rust-docs");
1313             pkgbuild("rust-std");
1314             pkgbuild("rls");
1315             pkgbuild("rust-analysis");
1316
1317             // create an 'uninstall' package
1318             install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1319             pkgbuild("uninstall");
1320
1321             t!(fs::create_dir_all(pkg.join("res")));
1322             t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
1323             install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1324             let mut cmd = Command::new("productbuild");
1325             cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml"))
1326                 .arg("--resources").arg(pkg.join("res"))
1327                 .arg(distdir(build).join(format!("{}-{}.pkg",
1328                                                     pkgname(build, "rust"),
1329                                                     target)))
1330                 .arg("--package-path").arg(&pkg);
1331             build.run(&mut cmd);
1332         }
1333
1334         if target.contains("windows") {
1335             let exe = tmp.join("exe");
1336             let _ = fs::remove_dir_all(&exe);
1337             t!(fs::create_dir_all(exe.join("rustc")));
1338             t!(fs::create_dir_all(exe.join("cargo")));
1339             t!(fs::create_dir_all(exe.join("rls")));
1340             t!(fs::create_dir_all(exe.join("rust-analysis")));
1341             t!(fs::create_dir_all(exe.join("rust-docs")));
1342             t!(fs::create_dir_all(exe.join("rust-std")));
1343             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target))
1344                         .join("rustc"),
1345                     &exe.join("rustc"));
1346             cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target))
1347                         .join("cargo"),
1348                     &exe.join("cargo"));
1349             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target))
1350                         .join("rust-docs"),
1351                     &exe.join("rust-docs"));
1352             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
1353                         .join(format!("rust-std-{}", target)),
1354                     &exe.join("rust-std"));
1355             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target))
1356                         .join("rls"),
1357                     &exe.join("rls"));
1358             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
1359                         .join(format!("rust-analysis-{}", target)),
1360                     &exe.join("rust-analysis"));
1361
1362             t!(fs::remove_file(exe.join("rustc/manifest.in")));
1363             t!(fs::remove_file(exe.join("cargo/manifest.in")));
1364             t!(fs::remove_file(exe.join("rust-docs/manifest.in")));
1365             t!(fs::remove_file(exe.join("rust-std/manifest.in")));
1366             t!(fs::remove_file(exe.join("rls/manifest.in")));
1367             t!(fs::remove_file(exe.join("rust-analysis/manifest.in")));
1368
1369             if target.contains("windows-gnu") {
1370                 t!(fs::create_dir_all(exe.join("rust-mingw")));
1371                 cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target))
1372                             .join("rust-mingw"),
1373                         &exe.join("rust-mingw"));
1374                 t!(fs::remove_file(exe.join("rust-mingw/manifest.in")));
1375             }
1376
1377             install(&etc.join("exe/rust.iss"), &exe, 0o644);
1378             install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1379             install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1380             install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1381             t!(t!(File::create(exe.join("LICENSE.txt"))).write_all(license.as_bytes()));
1382
1383             // Generate exe installer
1384             let mut cmd = Command::new("iscc");
1385             cmd.arg("rust.iss")
1386                 .current_dir(&exe);
1387             if target.contains("windows-gnu") {
1388                 cmd.arg("/dMINGW");
1389             }
1390             add_env(build, &mut cmd, target);
1391             build.run(&mut cmd);
1392             install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
1393                     &distdir(build),
1394                     0o755);
1395
1396             // Generate msi installer
1397             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1398             let heat = wix.join("bin/heat.exe");
1399             let candle = wix.join("bin/candle.exe");
1400             let light = wix.join("bin/light.exe");
1401
1402             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1403             build.run(Command::new(&heat)
1404                             .current_dir(&exe)
1405                             .arg("dir")
1406                             .arg("rustc")
1407                             .args(&heat_flags)
1408                             .arg("-cg").arg("RustcGroup")
1409                             .arg("-dr").arg("Rustc")
1410                             .arg("-var").arg("var.RustcDir")
1411                             .arg("-out").arg(exe.join("RustcGroup.wxs")));
1412             build.run(Command::new(&heat)
1413                             .current_dir(&exe)
1414                             .arg("dir")
1415                             .arg("rust-docs")
1416                             .args(&heat_flags)
1417                             .arg("-cg").arg("DocsGroup")
1418                             .arg("-dr").arg("Docs")
1419                             .arg("-var").arg("var.DocsDir")
1420                             .arg("-out").arg(exe.join("DocsGroup.wxs"))
1421                             .arg("-t").arg(etc.join("msi/squash-components.xsl")));
1422             build.run(Command::new(&heat)
1423                             .current_dir(&exe)
1424                             .arg("dir")
1425                             .arg("cargo")
1426                             .args(&heat_flags)
1427                             .arg("-cg").arg("CargoGroup")
1428                             .arg("-dr").arg("Cargo")
1429                             .arg("-var").arg("var.CargoDir")
1430                             .arg("-out").arg(exe.join("CargoGroup.wxs"))
1431                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1432             build.run(Command::new(&heat)
1433                             .current_dir(&exe)
1434                             .arg("dir")
1435                             .arg("rust-std")
1436                             .args(&heat_flags)
1437                             .arg("-cg").arg("StdGroup")
1438                             .arg("-dr").arg("Std")
1439                             .arg("-var").arg("var.StdDir")
1440                             .arg("-out").arg(exe.join("StdGroup.wxs")));
1441             build.run(Command::new(&heat)
1442                             .current_dir(&exe)
1443                             .arg("dir")
1444                             .arg("rls")
1445                             .args(&heat_flags)
1446                             .arg("-cg").arg("RlsGroup")
1447                             .arg("-dr").arg("Rls")
1448                             .arg("-var").arg("var.RlsDir")
1449                             .arg("-out").arg(exe.join("RlsGroup.wxs"))
1450                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1451             build.run(Command::new(&heat)
1452                             .current_dir(&exe)
1453                             .arg("dir")
1454                             .arg("rust-analysis")
1455                             .args(&heat_flags)
1456                             .arg("-cg").arg("AnalysisGroup")
1457                             .arg("-dr").arg("Analysis")
1458                             .arg("-var").arg("var.AnalysisDir")
1459                             .arg("-out").arg(exe.join("AnalysisGroup.wxs"))
1460                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1461             if target.contains("windows-gnu") {
1462                 build.run(Command::new(&heat)
1463                                 .current_dir(&exe)
1464                                 .arg("dir")
1465                                 .arg("rust-mingw")
1466                                 .args(&heat_flags)
1467                                 .arg("-cg").arg("GccGroup")
1468                                 .arg("-dr").arg("Gcc")
1469                                 .arg("-var").arg("var.GccDir")
1470                                 .arg("-out").arg(exe.join("GccGroup.wxs")));
1471             }
1472
1473             let candle = |input: &Path| {
1474                 let output = exe.join(input.file_stem().unwrap())
1475                                 .with_extension("wixobj");
1476                 let arch = if target.contains("x86_64") {"x64"} else {"x86"};
1477                 let mut cmd = Command::new(&candle);
1478                 cmd.current_dir(&exe)
1479                     .arg("-nologo")
1480                     .arg("-dRustcDir=rustc")
1481                     .arg("-dDocsDir=rust-docs")
1482                     .arg("-dCargoDir=cargo")
1483                     .arg("-dStdDir=rust-std")
1484                     .arg("-dRlsDir=rls")
1485                     .arg("-dAnalysisDir=rust-analysis")
1486                     .arg("-arch").arg(&arch)
1487                     .arg("-out").arg(&output)
1488                     .arg(&input);
1489                 add_env(build, &mut cmd, target);
1490
1491                 if target.contains("windows-gnu") {
1492                     cmd.arg("-dGccDir=rust-mingw");
1493                 }
1494                 build.run(&mut cmd);
1495             };
1496             candle(&etc.join("msi/rust.wxs"));
1497             candle(&etc.join("msi/ui.wxs"));
1498             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1499             candle("RustcGroup.wxs".as_ref());
1500             candle("DocsGroup.wxs".as_ref());
1501             candle("CargoGroup.wxs".as_ref());
1502             candle("StdGroup.wxs".as_ref());
1503             candle("RlsGroup.wxs".as_ref());
1504             candle("AnalysisGroup.wxs".as_ref());
1505
1506             if target.contains("windows-gnu") {
1507                 candle("GccGroup.wxs".as_ref());
1508             }
1509
1510             t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes()));
1511             install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1512             install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1513
1514             let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
1515             let mut cmd = Command::new(&light);
1516             cmd.arg("-nologo")
1517                 .arg("-ext").arg("WixUIExtension")
1518                 .arg("-ext").arg("WixUtilExtension")
1519                 .arg("-out").arg(exe.join(&filename))
1520                 .arg("rust.wixobj")
1521                 .arg("ui.wixobj")
1522                 .arg("rustwelcomedlg.wixobj")
1523                 .arg("RustcGroup.wixobj")
1524                 .arg("DocsGroup.wixobj")
1525                 .arg("CargoGroup.wixobj")
1526                 .arg("StdGroup.wixobj")
1527                 .arg("RlsGroup.wixobj")
1528                 .arg("AnalysisGroup.wixobj")
1529                 .current_dir(&exe);
1530
1531             if target.contains("windows-gnu") {
1532                 cmd.arg("GccGroup.wixobj");
1533             }
1534             // ICE57 wrongly complains about the shortcuts
1535             cmd.arg("-sice:ICE57");
1536
1537             build.run(&mut cmd);
1538
1539             t!(fs::rename(exe.join(&filename), distdir(build).join(&filename)));
1540         }
1541     }
1542 }
1543
1544 fn add_env(build: &Build, cmd: &mut Command, target: &str) {
1545     let mut parts = channel::CFG_RELEASE_NUM.split('.');
1546     cmd.env("CFG_RELEASE_INFO", build.rust_version())
1547        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
1548        .env("CFG_RELEASE", build.rust_release())
1549        .env("CFG_PRERELEASE_VERSION", channel::CFG_PRERELEASE_VERSION)
1550        .env("CFG_VER_MAJOR", parts.next().unwrap())
1551        .env("CFG_VER_MINOR", parts.next().unwrap())
1552        .env("CFG_VER_PATCH", parts.next().unwrap())
1553        .env("CFG_VER_BUILD", "0") // just needed to build
1554        .env("CFG_PACKAGE_VERS", build.rust_package_vers())
1555        .env("CFG_PACKAGE_NAME", pkgname(build, "rust"))
1556        .env("CFG_BUILD", target)
1557        .env("CFG_CHANNEL", &build.config.channel);
1558
1559     if target.contains("windows-gnu") {
1560        cmd.env("CFG_MINGW", "1")
1561           .env("CFG_ABI", "GNU");
1562     } else {
1563        cmd.env("CFG_MINGW", "0")
1564           .env("CFG_ABI", "MSVC");
1565     }
1566
1567     if target.contains("x86_64") {
1568        cmd.env("CFG_PLATFORM", "x64");
1569     } else {
1570        cmd.env("CFG_PLATFORM", "x86");
1571     }
1572 }
1573
1574 // rules.dist("dist-sign", "hash-and-sign")
1575 //      .host(true)
1576 //      .only_build(true)
1577 //      .only_host_build(true)
1578 //      .dep(move |s| s.name("tool-build-manifest").target(&build.build).stage(0))
1579 //      .run(move |_| dist::hash_and_sign(build));
1580
1581 #[derive(Serialize)]
1582 pub struct HashSign;
1583
1584 impl<'a> Step<'a> for HashSign {
1585     type Output = ();
1586     const ONLY_BUILD_TARGETS: bool = true;
1587     const ONLY_HOSTS: bool = true;
1588     const ONLY_BUILD: bool = true;
1589
1590     fn should_run(_builder: &Builder, path: &Path) -> bool {
1591         path.ends_with("hash-and-sign")
1592     }
1593
1594     fn make_run(builder: &Builder, _path: Option<&Path>, _host: &str, _target: &str) {
1595         builder.ensure(HashSign);
1596     }
1597
1598     fn run(self, builder: &Builder) {
1599         let build = builder.build;
1600         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
1601         let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
1602             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
1603         });
1604         let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
1605             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
1606         });
1607         let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
1608             panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
1609         });
1610         let mut pass = String::new();
1611         t!(t!(File::open(&file)).read_to_string(&mut pass));
1612
1613         let today = output(Command::new("date").arg("+%Y-%m-%d"));
1614
1615         cmd.arg(sign);
1616         cmd.arg(distdir(build));
1617         cmd.arg(today.trim());
1618         cmd.arg(build.rust_package_vers());
1619         cmd.arg(build.package_vers(&build.release_num("cargo")));
1620         cmd.arg(build.package_vers(&build.release_num("rls")));
1621         cmd.arg(addr);
1622
1623         t!(fs::create_dir_all(distdir(build)));
1624
1625         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
1626         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
1627         let status = t!(child.wait());
1628         assert!(status.success());
1629     }
1630 }