]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/doc.rs
16e8ee182bd8ea106ccc594fd373868411b2dc94
[rust.git] / src / bootstrap / doc.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 //! Documentation generation for rustbuild.
12 //!
13 //! This module implements generation for all bits and pieces of documentation
14 //! for the Rust project. This notably includes suites like the rust book, the
15 //! nomicon, standalone documentation, etc.
16 //!
17 //! Everything here is basically just a shim around calling either `rustbook` or
18 //! `rustdoc`.
19
20 use std::fs::{self, File};
21 use std::io::prelude::*;
22 use std::io;
23 use std::path::{PathBuf, Path};
24
25 use Mode;
26 use build_helper::up_to_date;
27
28 use util::{cp_r, symlink_dir};
29 use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
30 use tool::Tool;
31 use compile;
32 use cache::{INTERNER, Interned};
33
34 macro_rules! book {
35     ($($name:ident, $path:expr, $book_name:expr;)+) => {
36         $(
37             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
38         pub struct $name {
39             target: Interned<String>,
40         }
41
42         impl Step for $name {
43             type Output = ();
44             const DEFAULT: bool = true;
45
46             fn should_run(run: ShouldRun) -> ShouldRun {
47                 let builder = run.builder;
48                 run.path($path).default_condition(builder.build.config.docs)
49             }
50
51             fn make_run(run: RunConfig) {
52                 run.builder.ensure($name {
53                     target: run.target,
54                 });
55             }
56
57             fn run(self, builder: &Builder) {
58                 builder.ensure(Rustbook {
59                     target: self.target,
60                     name: INTERNER.intern_str($book_name),
61                 })
62             }
63         }
64         )+
65     }
66 }
67
68 book!(
69     Nomicon, "src/doc/nomicon", "nomicon";
70     Reference, "src/doc/reference", "reference";
71     Rustdoc, "src/doc/rustdoc", "rustdoc";
72 );
73
74 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
75 struct Rustbook {
76     target: Interned<String>,
77     name: Interned<String>,
78 }
79
80 impl Step for Rustbook {
81     type Output = ();
82
83     // rustbook is never directly called, and only serves as a shim for the nomicon and the
84     // reference.
85     fn should_run(run: ShouldRun) -> ShouldRun {
86         run.never()
87     }
88
89     /// Invoke `rustbook` for `target` for the doc book `name`.
90     ///
91     /// This will not actually generate any documentation if the documentation has
92     /// already been generated.
93     fn run(self, builder: &Builder) {
94         let src = builder.build.src.join("src/doc");
95         builder.ensure(RustbookSrc {
96             target: self.target,
97             name: self.name,
98             src: INTERNER.intern_path(src),
99         });
100     }
101 }
102
103 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
104 pub struct UnstableBook {
105     target: Interned<String>,
106 }
107
108 impl Step for UnstableBook {
109     type Output = ();
110     const DEFAULT: bool = true;
111
112     fn should_run(run: ShouldRun) -> ShouldRun {
113         let builder = run.builder;
114         run.path("src/doc/unstable-book").default_condition(builder.build.config.docs)
115     }
116
117     fn make_run(run: RunConfig) {
118         run.builder.ensure(UnstableBook {
119             target: run.target,
120         });
121     }
122
123     fn run(self, builder: &Builder) {
124         builder.ensure(UnstableBookGen {
125             target: self.target,
126         });
127         builder.ensure(RustbookSrc {
128             target: self.target,
129             name: INTERNER.intern_str("unstable-book"),
130             src: builder.build.md_doc_out(self.target),
131         })
132     }
133 }
134
135 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
136 struct RustbookSrc {
137     target: Interned<String>,
138     name: Interned<String>,
139     src: Interned<PathBuf>,
140 }
141
142 impl Step for RustbookSrc {
143     type Output = ();
144
145     fn should_run(run: ShouldRun) -> ShouldRun {
146         run.never()
147     }
148
149     /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path.
150     ///
151     /// This will not actually generate any documentation if the documentation has
152     /// already been generated.
153     fn run(self, builder: &Builder) {
154         let build = builder.build;
155         let target = self.target;
156         let name = self.name;
157         let src = self.src;
158         let out = build.doc_out(target);
159         t!(fs::create_dir_all(&out));
160
161         let out = out.join(name);
162         let src = src.join(name);
163         let index = out.join("index.html");
164         let rustbook = builder.tool_exe(Tool::Rustbook);
165         if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
166             return
167         }
168         println!("Rustbook ({}) - {}", target, name);
169         let _ = fs::remove_dir_all(&out);
170         build.run(builder.tool_cmd(Tool::Rustbook)
171                        .arg("build")
172                        .arg(&src)
173                        .arg("-d")
174                        .arg(out));
175     }
176 }
177
178 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
179 pub struct TheBook {
180     compiler: Compiler,
181     target: Interned<String>,
182     name: &'static str,
183 }
184
185 impl Step for TheBook {
186     type Output = ();
187     const DEFAULT: bool = true;
188
189     fn should_run(run: ShouldRun) -> ShouldRun {
190         let builder = run.builder;
191         run.path("src/doc/book").default_condition(builder.build.config.docs)
192     }
193
194     fn make_run(run: RunConfig) {
195         run.builder.ensure(TheBook {
196             compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
197             target: run.target,
198             name: "book",
199         });
200     }
201
202     /// Build the book and associated stuff.
203     ///
204     /// We need to build:
205     ///
206     /// * Book (first edition)
207     /// * Book (second edition)
208     /// * Index page
209     /// * Redirect pages
210     fn run(self, builder: &Builder) {
211         let build = builder.build;
212         let target = self.target;
213         let name = self.name;
214         // build book first edition
215         builder.ensure(Rustbook {
216             target,
217             name: INTERNER.intern_string(format!("{}/first-edition", name)),
218         });
219
220         // build book second edition
221         builder.ensure(Rustbook {
222             target,
223             name: INTERNER.intern_string(format!("{}/second-edition", name)),
224         });
225
226         // build the index page
227         let index = format!("{}/index.md", name);
228         println!("Documenting book index ({})", target);
229         invoke_rustdoc(builder, self.compiler, target, &index);
230
231         // build the redirect pages
232         println!("Documenting book redirect pages ({})", target);
233         for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) {
234             let file = t!(file);
235             let path = file.path();
236             let path = path.to_str().unwrap();
237
238             invoke_rustdoc(builder, self.compiler, target, path);
239         }
240     }
241 }
242
243 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
244 pub struct CargoBook {
245     target: Interned<String>,
246 }
247
248 impl Step for CargoBook {
249     type Output = ();
250     const DEFAULT: bool = true;
251
252     fn should_run(run: ShouldRun) -> ShouldRun {
253         let builder = run.builder;
254         run.path("src/doc/cargo").default_condition(builder.build.config.docs)
255     }
256
257     fn make_run(run: RunConfig) {
258         run.builder.ensure(CargoBook {
259             target: run.target,
260         });
261     }
262
263     /// Create a placeholder for the cargo documentation so that doc.rust-lang.org/cargo will
264     /// redirect to doc.crates.io. We want to publish doc.rust-lang.org/cargo in the paper
265     /// version of the book, but we don't want to rush the process of switching cargo's docs
266     /// over to mdbook and deploying them. When the cargo book is ready, this implementation
267     /// should build the mdbook instead of this redirect page.
268     fn run(self, builder: &Builder) {
269         let build = builder.build;
270         let out = build.doc_out(self.target);
271
272         let cargo_dir = out.join("cargo");
273         t!(fs::create_dir_all(&cargo_dir));
274
275         let index = cargo_dir.join("index.html");
276         let redirect_html = r#"
277             <html>
278                 <head>
279                     <meta http-equiv="refresh" content="0; URL='http://doc.crates.io'" />
280                 </head>
281             </html>"#;
282
283         println!("Creating cargo book redirect page");
284         t!(t!(File::create(&index)).write_all(redirect_html.as_bytes()));
285     }
286 }
287
288 fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) {
289     let build = builder.build;
290     let out = build.doc_out(target);
291
292     let path = build.src.join("src/doc").join(markdown);
293
294     let favicon = build.src.join("src/doc/favicon.inc");
295     let footer = build.src.join("src/doc/footer.inc");
296
297     let version_input = build.src.join("src/doc/version_info.html.template");
298     let version_info = out.join("version_info.html");
299
300     if !up_to_date(&version_input, &version_info) {
301         let mut info = String::new();
302         t!(t!(File::open(&version_input)).read_to_string(&mut info));
303         let info = info.replace("VERSION", &build.rust_release())
304                        .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or(""))
305                        .replace("STAMP", build.rust_info.sha().unwrap_or(""));
306         t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
307     }
308
309     let mut cmd = builder.rustdoc_cmd(compiler.host);
310
311     let out = out.join("book");
312
313     t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));
314
315     cmd.arg("--html-after-content").arg(&footer)
316         .arg("--html-before-content").arg(&version_info)
317         .arg("--html-in-header").arg(&favicon)
318         .arg("--markdown-playground-url")
319         .arg("https://play.rust-lang.org/")
320         .arg("-o").arg(&out)
321         .arg(&path)
322         .arg("--markdown-css")
323         .arg("rust.css");
324
325     build.run(&mut cmd);
326 }
327
328 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
329 pub struct Standalone {
330     compiler: Compiler,
331     target: Interned<String>,
332 }
333
334 impl Step for Standalone {
335     type Output = ();
336     const DEFAULT: bool = true;
337
338     fn should_run(run: ShouldRun) -> ShouldRun {
339         let builder = run.builder;
340         run.path("src/doc").default_condition(builder.build.config.docs)
341     }
342
343     fn make_run(run: RunConfig) {
344         run.builder.ensure(Standalone {
345             compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
346             target: run.target,
347         });
348     }
349
350     /// Generates all standalone documentation as compiled by the rustdoc in `stage`
351     /// for the `target` into `out`.
352     ///
353     /// This will list all of `src/doc` looking for markdown files and appropriately
354     /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
355     /// `STAMP` along with providing the various header/footer HTML we've customized.
356     ///
357     /// In the end, this is just a glorified wrapper around rustdoc!
358     fn run(self, builder: &Builder) {
359         let build = builder.build;
360         let target = self.target;
361         let compiler = self.compiler;
362         println!("Documenting standalone ({})", target);
363         let out = build.doc_out(target);
364         t!(fs::create_dir_all(&out));
365
366         let favicon = build.src.join("src/doc/favicon.inc");
367         let footer = build.src.join("src/doc/footer.inc");
368         let full_toc = build.src.join("src/doc/full-toc.inc");
369         t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));
370
371         let version_input = build.src.join("src/doc/version_info.html.template");
372         let version_info = out.join("version_info.html");
373
374         if !up_to_date(&version_input, &version_info) {
375             let mut info = String::new();
376             t!(t!(File::open(&version_input)).read_to_string(&mut info));
377             let info = info.replace("VERSION", &build.rust_release())
378                            .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or(""))
379                            .replace("STAMP", build.rust_info.sha().unwrap_or(""));
380             t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
381         }
382
383         for file in t!(fs::read_dir(build.src.join("src/doc"))) {
384             let file = t!(file);
385             let path = file.path();
386             let filename = path.file_name().unwrap().to_str().unwrap();
387             if !filename.ends_with(".md") || filename == "README.md" {
388                 continue
389             }
390
391             let html = out.join(filename).with_extension("html");
392             let rustdoc = builder.rustdoc(compiler.host);
393             if up_to_date(&path, &html) &&
394                up_to_date(&footer, &html) &&
395                up_to_date(&favicon, &html) &&
396                up_to_date(&full_toc, &html) &&
397                up_to_date(&version_info, &html) &&
398                up_to_date(&rustdoc, &html) {
399                 continue
400             }
401
402             let mut cmd = builder.rustdoc_cmd(compiler.host);
403             cmd.arg("--html-after-content").arg(&footer)
404                .arg("--html-before-content").arg(&version_info)
405                .arg("--html-in-header").arg(&favicon)
406                .arg("--markdown-playground-url")
407                .arg("https://play.rust-lang.org/")
408                .arg("-o").arg(&out)
409                .arg(&path);
410
411             if filename == "not_found.md" {
412                 cmd.arg("--markdown-no-toc")
413                    .arg("--markdown-css")
414                    .arg("https://doc.rust-lang.org/rust.css");
415             } else {
416                 cmd.arg("--markdown-css").arg("rust.css");
417             }
418             build.run(&mut cmd);
419         }
420     }
421 }
422
423 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
424 pub struct Std {
425     stage: u32,
426     target: Interned<String>,
427 }
428
429 impl Step for Std {
430     type Output = ();
431     const DEFAULT: bool = true;
432
433     fn should_run(run: ShouldRun) -> ShouldRun {
434         let builder = run.builder;
435         run.krate("std").default_condition(builder.build.config.docs)
436     }
437
438     fn make_run(run: RunConfig) {
439         run.builder.ensure(Std {
440             stage: run.builder.top_stage,
441             target: run.target
442         });
443     }
444
445     /// Compile all standard library documentation.
446     ///
447     /// This will generate all documentation for the standard library and its
448     /// dependencies. This is largely just a wrapper around `cargo doc`.
449     fn run(self, builder: &Builder) {
450         let build = builder.build;
451         let stage = self.stage;
452         let target = self.target;
453         println!("Documenting stage{} std ({})", stage, target);
454         let out = build.doc_out(target);
455         t!(fs::create_dir_all(&out));
456         let compiler = builder.compiler(stage, build.build);
457         let rustdoc = builder.rustdoc(compiler.host);
458         let compiler = if build.force_use_stage1(compiler, target) {
459             builder.compiler(1, compiler.host)
460         } else {
461             compiler
462         };
463
464         builder.ensure(compile::Std { compiler, target });
465         let out_dir = build.stage_out(compiler, Mode::Libstd)
466                            .join(target).join("doc");
467
468         // Here what we're doing is creating a *symlink* (directory junction on
469         // Windows) to the final output location. This is not done as an
470         // optimization but rather for correctness. We've got three trees of
471         // documentation, one for std, one for test, and one for rustc. It's then
472         // our job to merge them all together.
473         //
474         // Unfortunately rustbuild doesn't know nearly as well how to merge doc
475         // trees as rustdoc does itself, so instead of actually having three
476         // separate trees we just have rustdoc output to the same location across
477         // all of them.
478         //
479         // This way rustdoc generates output directly into the output, and rustdoc
480         // will also directly handle merging.
481         let my_out = build.crate_doc_out(target);
482         build.clear_if_dirty(&my_out, &rustdoc);
483         t!(symlink_dir_force(&my_out, &out_dir));
484
485         let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
486         compile::std_cargo(build, &compiler, target, &mut cargo);
487
488         // We don't want to build docs for internal std dependencies unless
489         // in compiler-docs mode. When not in that mode, we whitelist the crates
490         // for which docs must be built.
491         if !build.config.compiler_docs {
492             cargo.arg("--no-deps");
493             for krate in &["alloc", "core", "std", "std_unicode"] {
494                 cargo.arg("-p").arg(krate);
495                 // Create all crate output directories first to make sure rustdoc uses
496                 // relative links.
497                 // FIXME: Cargo should probably do this itself.
498                 t!(fs::create_dir_all(out_dir.join(krate)));
499             }
500         }
501
502
503         build.run(&mut cargo);
504         cp_r(&my_out, &out);
505     }
506 }
507
508 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
509 pub struct Test {
510     stage: u32,
511     target: Interned<String>,
512 }
513
514 impl Step for Test {
515     type Output = ();
516     const DEFAULT: bool = true;
517
518     fn should_run(run: ShouldRun) -> ShouldRun {
519         let builder = run.builder;
520         run.krate("test").default_condition(builder.config.compiler_docs)
521     }
522
523     fn make_run(run: RunConfig) {
524         run.builder.ensure(Test {
525             stage: run.builder.top_stage,
526             target: run.target,
527         });
528     }
529
530     /// Compile all libtest documentation.
531     ///
532     /// This will generate all documentation for libtest and its dependencies. This
533     /// is largely just a wrapper around `cargo doc`.
534     fn run(self, builder: &Builder) {
535         let build = builder.build;
536         let stage = self.stage;
537         let target = self.target;
538         println!("Documenting stage{} test ({})", stage, target);
539         let out = build.doc_out(target);
540         t!(fs::create_dir_all(&out));
541         let compiler = builder.compiler(stage, build.build);
542         let rustdoc = builder.rustdoc(compiler.host);
543         let compiler = if build.force_use_stage1(compiler, target) {
544             builder.compiler(1, compiler.host)
545         } else {
546             compiler
547         };
548
549         // Build libstd docs so that we generate relative links
550         builder.ensure(Std { stage, target });
551
552         builder.ensure(compile::Test { compiler, target });
553         let out_dir = build.stage_out(compiler, Mode::Libtest)
554                            .join(target).join("doc");
555
556         // See docs in std above for why we symlink
557         let my_out = build.crate_doc_out(target);
558         build.clear_if_dirty(&my_out, &rustdoc);
559         t!(symlink_dir_force(&my_out, &out_dir));
560
561         let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
562         compile::test_cargo(build, &compiler, target, &mut cargo);
563         build.run(&mut cargo);
564         cp_r(&my_out, &out);
565     }
566 }
567
568 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
569 pub struct Rustc {
570     stage: u32,
571     target: Interned<String>,
572 }
573
574 impl Step for Rustc {
575     type Output = ();
576     const DEFAULT: bool = true;
577     const ONLY_HOSTS: bool = true;
578
579     fn should_run(run: ShouldRun) -> ShouldRun {
580         let builder = run.builder;
581         run.krate("rustc-main").default_condition(builder.build.config.docs)
582     }
583
584     fn make_run(run: RunConfig) {
585         run.builder.ensure(Rustc {
586             stage: run.builder.top_stage,
587             target: run.target,
588         });
589     }
590
591     /// Generate all compiler documentation.
592     ///
593     /// This will generate all documentation for the compiler libraries and their
594     /// dependencies. This is largely just a wrapper around `cargo doc`.
595     fn run(self, builder: &Builder) {
596         let build = builder.build;
597         let stage = self.stage;
598         let target = self.target;
599         println!("Documenting stage{} compiler ({})", stage, target);
600         let out = build.doc_out(target);
601         t!(fs::create_dir_all(&out));
602         let compiler = builder.compiler(stage, build.build);
603         let rustdoc = builder.rustdoc(compiler.host);
604         let compiler = if build.force_use_stage1(compiler, target) {
605             builder.compiler(1, compiler.host)
606         } else {
607             compiler
608         };
609
610         // Build libstd docs so that we generate relative links
611         builder.ensure(Std { stage, target });
612
613         builder.ensure(compile::Rustc { compiler, target });
614         let out_dir = build.stage_out(compiler, Mode::Librustc)
615                            .join(target).join("doc");
616
617         // See docs in std above for why we symlink
618         let my_out = build.crate_doc_out(target);
619         build.clear_if_dirty(&my_out, &rustdoc);
620         t!(symlink_dir_force(&my_out, &out_dir));
621
622         let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
623         compile::rustc_cargo(build, &compiler, target, &mut cargo);
624
625         if build.config.compiler_docs {
626             // src/rustc/Cargo.toml contains a bin crate called rustc which
627             // would otherwise overwrite the docs for the real rustc lib crate.
628             cargo.arg("-p").arg("rustc_driver");
629         } else {
630             // Like with libstd above if compiler docs aren't enabled then we're not
631             // documenting internal dependencies, so we have a whitelist.
632             cargo.arg("--no-deps");
633             for krate in &["proc_macro"] {
634                 cargo.arg("-p").arg(krate);
635             }
636         }
637
638         build.run(&mut cargo);
639         cp_r(&my_out, &out);
640     }
641 }
642
643 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
644 pub struct ErrorIndex {
645     target: Interned<String>,
646 }
647
648 impl Step for ErrorIndex {
649     type Output = ();
650     const DEFAULT: bool = true;
651     const ONLY_HOSTS: bool = true;
652
653     fn should_run(run: ShouldRun) -> ShouldRun {
654         let builder = run.builder;
655         run.path("src/tools/error_index_generator").default_condition(builder.build.config.docs)
656     }
657
658     fn make_run(run: RunConfig) {
659         run.builder.ensure(ErrorIndex {
660             target: run.target,
661         });
662     }
663
664     /// Generates the HTML rendered error-index by running the
665     /// `error_index_generator` tool.
666     fn run(self, builder: &Builder) {
667         let build = builder.build;
668         let target = self.target;
669
670         println!("Documenting error index ({})", target);
671         let out = build.doc_out(target);
672         t!(fs::create_dir_all(&out));
673         let mut index = builder.tool_cmd(Tool::ErrorIndex);
674         index.arg("html");
675         index.arg(out.join("error-index.html"));
676
677         // FIXME: shouldn't have to pass this env var
678         index.env("CFG_BUILD", &build.build);
679
680         build.run(&mut index);
681     }
682 }
683
684 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
685 pub struct UnstableBookGen {
686     target: Interned<String>,
687 }
688
689 impl Step for UnstableBookGen {
690     type Output = ();
691     const DEFAULT: bool = true;
692     const ONLY_HOSTS: bool = true;
693
694     fn should_run(run: ShouldRun) -> ShouldRun {
695         let builder = run.builder;
696         run.path("src/tools/unstable-book-gen").default_condition(builder.build.config.docs)
697     }
698
699     fn make_run(run: RunConfig) {
700         run.builder.ensure(UnstableBookGen {
701             target: run.target,
702         });
703     }
704
705     fn run(self, builder: &Builder) {
706         let build = builder.build;
707         let target = self.target;
708
709         builder.ensure(compile::Std {
710             compiler: builder.compiler(builder.top_stage, build.build),
711             target,
712         });
713
714         println!("Generating unstable book md files ({})", target);
715         let out = build.md_doc_out(target).join("unstable-book");
716         t!(fs::create_dir_all(&out));
717         t!(fs::remove_dir_all(&out));
718         let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
719         cmd.arg(build.src.join("src"));
720         cmd.arg(out);
721
722         build.run(&mut cmd);
723     }
724 }
725
726 fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
727     if let Ok(m) = fs::symlink_metadata(dst) {
728         if m.file_type().is_dir() {
729             try!(fs::remove_dir_all(dst));
730         } else {
731             // handle directory junctions on windows by falling back to
732             // `remove_dir`.
733             try!(fs::remove_file(dst).or_else(|_| {
734                 fs::remove_dir(dst)
735             }));
736         }
737     }
738
739     symlink_dir(src, dst)
740 }