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