Skip to content

Commit 7ca5fa6

Browse files
authored
Rollup merge of rust-lang#81223 - GuillaumeGomez:generate-redirect-map, r=jyn514
[rustdoc] Generate redirect map file Fixes rust-lang#81134. So with this code: ```rust #![crate_name = "foo"] pub use private::Quz; pub use hidden::Bar; mod private { pub struct Quz; } #[doc(hidden)] pub mod hidden { pub struct Bar; } #[macro_export] macro_rules! foo { () => {} } ``` It generates: ```json { "foo/macro.foo!.html": "foo/macro.foo.html", "foo/private/struct.Quz.html": "foo/struct.Quz.html", "foo/hidden/struct.Bar.html": "foo/struct.Bar.html" } ``` Do the pathes look as you expected ``@pietroalbini?`` r? ``@jyn514``
2 parents 2158634 + 41fc58b commit 7ca5fa6

File tree

9 files changed

+150
-10
lines changed

9 files changed

+150
-10
lines changed

src/librustdoc/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ crate struct RenderOptions {
263263
crate document_private: bool,
264264
/// Document items that have `doc(hidden)`.
265265
crate document_hidden: bool,
266+
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
267+
crate generate_redirect_map: bool,
266268
crate unstable_features: rustc_feature::UnstableFeatures,
267269
}
268270

@@ -570,6 +572,7 @@ impl Options {
570572
let document_private = matches.opt_present("document-private-items");
571573
let document_hidden = matches.opt_present("document-hidden-items");
572574
let run_check = matches.opt_present("check");
575+
let generate_redirect_map = matches.opt_present("generate-redirect-map");
573576

574577
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
575578

@@ -627,6 +630,7 @@ impl Options {
627630
generate_search_filter,
628631
document_private,
629632
document_hidden,
633+
generate_redirect_map,
630634
unstable_features: rustc_feature::UnstableFeatures::from_environment(
631635
crate_name.as_deref(),
632636
),

src/librustdoc/html/render/mod.rs

+43-10
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ crate struct Context<'tcx> {
111111
/// real location of an item. This is used to allow external links to
112112
/// publicly reused items to redirect to the right location.
113113
crate render_redirect_pages: bool,
114+
/// `None` by default, depends on the `generate-redirect-map` option flag. If this field is set
115+
/// to `Some(...)`, it'll store redirections and then generate a JSON file at the top level of
116+
/// the crate.
117+
crate redirections: Option<Rc<RefCell<FxHashMap<String, String>>>>,
114118
/// The map used to ensure all generated 'id=' attributes are unique.
115119
id_map: Rc<RefCell<IdMap>>,
116120
/// Tracks section IDs for `Deref` targets so they match in both the main
@@ -404,6 +408,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
404408
static_root_path,
405409
generate_search_filter,
406410
unstable_features,
411+
generate_redirect_map,
407412
..
408413
} = options;
409414

@@ -509,6 +514,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
509514
all: Rc::new(RefCell::new(AllTypes::new())),
510515
errors: Rc::new(receiver),
511516
cache: Rc::new(cache),
517+
redirections: if generate_redirect_map { Some(Default::default()) } else { None },
512518
};
513519

514520
CURRENT_DEPTH.with(|s| s.set(0));
@@ -587,6 +593,15 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
587593
&style_files,
588594
);
589595
self.shared.fs.write(&settings_file, v.as_bytes())?;
596+
if let Some(redirections) = self.redirections.take() {
597+
if !redirections.borrow().is_empty() {
598+
let redirect_map_path =
599+
self.dst.join(&*krate.name.as_str()).join("redirect-map.json");
600+
let paths = serde_json::to_string(&*redirections.borrow()).unwrap();
601+
self.shared.ensure_dir(&self.dst.join(&*krate.name.as_str()))?;
602+
self.shared.fs.write(&redirect_map_path, paths.as_bytes())?;
603+
}
604+
}
590605

591606
// Flush pending errors.
592607
Arc::get_mut(&mut self.shared).unwrap().fs.close();
@@ -675,9 +690,17 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
675690
// to the new one (without).
676691
if item_type == ItemType::Macro {
677692
let redir_name = format!("{}.{}!.html", item_type, name);
678-
let redir_dst = self.dst.join(redir_name);
679-
let v = layout::redirect(file_name);
680-
self.shared.fs.write(&redir_dst, v.as_bytes())?;
693+
if let Some(ref redirections) = self.redirections {
694+
let crate_name = &self.shared.layout.krate;
695+
redirections.borrow_mut().insert(
696+
format!("{}/{}", crate_name, redir_name),
697+
format!("{}/{}", crate_name, file_name),
698+
);
699+
} else {
700+
let v = layout::redirect(file_name);
701+
let redir_dst = self.dst.join(redir_name);
702+
self.shared.fs.write(&redir_dst, v.as_bytes())?;
703+
}
681704
}
682705
}
683706
Ok(())
@@ -1588,17 +1611,27 @@ impl Context<'_> {
15881611
&self.shared.style_files,
15891612
)
15901613
} else {
1591-
let mut url = self.root_path();
15921614
if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
1615+
let mut path = String::new();
15931616
for name in &names[..names.len() - 1] {
1594-
url.push_str(name);
1595-
url.push('/');
1617+
path.push_str(name);
1618+
path.push('/');
1619+
}
1620+
path.push_str(&item_path(ty, names.last().unwrap()));
1621+
match self.redirections {
1622+
Some(ref redirections) => {
1623+
let mut current_path = String::new();
1624+
for name in &self.current {
1625+
current_path.push_str(name);
1626+
current_path.push('/');
1627+
}
1628+
current_path.push_str(&item_path(ty, names.last().unwrap()));
1629+
redirections.borrow_mut().insert(current_path, path);
1630+
}
1631+
None => return layout::redirect(&format!("{}{}", self.root_path(), path)),
15961632
}
1597-
url.push_str(&item_path(ty, names.last().unwrap()));
1598-
layout::redirect(&url)
1599-
} else {
1600-
String::new()
16011633
}
1634+
String::new()
16021635
}
16031636
}
16041637

src/librustdoc/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,13 @@ fn opts() -> Vec<RustcOptGroup> {
499499
o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
500500
}),
501501
unstable("check", |o| o.optflag("", "check", "Run rustdoc checks")),
502+
unstable("generate-redirect-map", |o| {
503+
o.optflag(
504+
"",
505+
"generate-redirect-map",
506+
"Generate JSON file at the top level instead of generating HTML redirection files",
507+
)
508+
}),
502509
]
503510
}
504511

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTDOC) -Z unstable-options --generate-redirect-map foo.rs -o "$(TMPDIR)/out"
5+
"$(PYTHON)" validate_json.py "$(TMPDIR)/out"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"foo/macro.foo!.html": "foo/macro.foo.html",
3+
"foo/private/struct.Quz.html": "foo/struct.Quz.html",
4+
"foo/hidden/struct.Bar.html": "foo/struct.Bar.html"
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pub use private::Quz;
2+
pub use hidden::Bar;
3+
4+
mod private {
5+
pub struct Quz;
6+
}
7+
8+
#[doc(hidden)]
9+
pub mod hidden {
10+
pub struct Bar;
11+
}
12+
13+
#[macro_export]
14+
macro_rules! foo {
15+
() => {}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python
2+
3+
import os
4+
import sys
5+
import json
6+
7+
8+
def find_redirect_map_file(folder, errors):
9+
for root, dirs, files in os.walk(folder):
10+
for name in files:
11+
if not name.endswith("redirect-map.json"):
12+
continue
13+
with open(os.path.join(root, name)) as f:
14+
data = json.load(f)
15+
with open("expected.json") as f:
16+
expected = json.load(f)
17+
for key in expected:
18+
if expected[key] != data.get(key):
19+
errors.append("Expected `{}` for key `{}`, found: `{}`".format(
20+
expected[key], key, data.get(key)))
21+
else:
22+
del data[key]
23+
for key in data:
24+
errors.append("Extra data not expected: key: `{}`, data: `{}`".format(
25+
key, data[key]))
26+
return True
27+
return False
28+
29+
30+
if len(sys.argv) != 2:
31+
print("Expected doc directory to check!")
32+
sys.exit(1)
33+
34+
errors = []
35+
if not find_redirect_map_file(sys.argv[1], errors):
36+
print("Didn't find the map file in `{}`...".format(sys.argv[1]))
37+
sys.exit(1)
38+
for err in errors:
39+
print("=> {}".format(err))
40+
if len(errors) != 0:
41+
sys.exit(1)
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// compile-flags: -Z unstable-options --generate-redirect-map
2+
3+
#![crate_name = "foo"]
4+
5+
// @!has foo/redirect-map.json
6+
pub struct Foo;

src/test/rustdoc/redirect-map.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// compile-flags: -Z unstable-options --generate-redirect-map
2+
3+
#![crate_name = "foo"]
4+
5+
// @!has foo/private/struct.Quz.html
6+
// @!has foo/hidden/struct.Bar.html
7+
// @has foo/redirect-map.json
8+
pub use private::Quz;
9+
pub use hidden::Bar;
10+
11+
mod private {
12+
pub struct Quz;
13+
}
14+
15+
#[doc(hidden)]
16+
pub mod hidden {
17+
pub struct Bar;
18+
}
19+
20+
#[macro_export]
21+
macro_rules! foo {
22+
() => {}
23+
}

0 commit comments

Comments
 (0)