Skip to content

Commit

Permalink
Rollup merge of #81223 - GuillaumeGomez:generate-redirect-map, r=jyn514
Browse files Browse the repository at this point in the history
[rustdoc] Generate redirect map file

Fixes #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````
  • Loading branch information
JohnTitor authored Mar 3, 2021
2 parents 35dbef2 + 41fc58b commit 9a827d9
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 10 deletions.
4 changes: 4 additions & 0 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ crate struct RenderOptions {
crate document_private: bool,
/// Document items that have `doc(hidden)`.
crate document_hidden: bool,
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
crate generate_redirect_map: bool,
crate unstable_features: rustc_feature::UnstableFeatures,
}

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

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

Expand Down Expand Up @@ -627,6 +630,7 @@ impl Options {
generate_search_filter,
document_private,
document_hidden,
generate_redirect_map,
unstable_features: rustc_feature::UnstableFeatures::from_environment(
crate_name.as_deref(),
),
Expand Down
53 changes: 43 additions & 10 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ crate struct Context<'tcx> {
/// real location of an item. This is used to allow external links to
/// publicly reused items to redirect to the right location.
crate render_redirect_pages: bool,
/// `None` by default, depends on the `generate-redirect-map` option flag. If this field is set
/// to `Some(...)`, it'll store redirections and then generate a JSON file at the top level of
/// the crate.
crate redirections: Option<Rc<RefCell<FxHashMap<String, String>>>>,
/// The map used to ensure all generated 'id=' attributes are unique.
id_map: Rc<RefCell<IdMap>>,
/// Tracks section IDs for `Deref` targets so they match in both the main
Expand Down Expand Up @@ -404,6 +408,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
static_root_path,
generate_search_filter,
unstable_features,
generate_redirect_map,
..
} = options;

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

CURRENT_DEPTH.with(|s| s.set(0));
Expand Down Expand Up @@ -587,6 +593,15 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
&style_files,
);
self.shared.fs.write(&settings_file, v.as_bytes())?;
if let Some(redirections) = self.redirections.take() {
if !redirections.borrow().is_empty() {
let redirect_map_path =
self.dst.join(&*krate.name.as_str()).join("redirect-map.json");
let paths = serde_json::to_string(&*redirections.borrow()).unwrap();
self.shared.ensure_dir(&self.dst.join(&*krate.name.as_str()))?;
self.shared.fs.write(&redirect_map_path, paths.as_bytes())?;
}
}

// Flush pending errors.
Arc::get_mut(&mut self.shared).unwrap().fs.close();
Expand Down Expand Up @@ -675,9 +690,17 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
// to the new one (without).
if item_type == ItemType::Macro {
let redir_name = format!("{}.{}!.html", item_type, name);
let redir_dst = self.dst.join(redir_name);
let v = layout::redirect(file_name);
self.shared.fs.write(&redir_dst, v.as_bytes())?;
if let Some(ref redirections) = self.redirections {
let crate_name = &self.shared.layout.krate;
redirections.borrow_mut().insert(
format!("{}/{}", crate_name, redir_name),
format!("{}/{}", crate_name, file_name),
);
} else {
let v = layout::redirect(file_name);
let redir_dst = self.dst.join(redir_name);
self.shared.fs.write(&redir_dst, v.as_bytes())?;
}
}
}
Ok(())
Expand Down Expand Up @@ -1588,17 +1611,27 @@ impl Context<'_> {
&self.shared.style_files,
)
} else {
let mut url = self.root_path();
if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
let mut path = String::new();
for name in &names[..names.len() - 1] {
url.push_str(name);
url.push('/');
path.push_str(name);
path.push('/');
}
path.push_str(&item_path(ty, names.last().unwrap()));
match self.redirections {
Some(ref redirections) => {
let mut current_path = String::new();
for name in &self.current {
current_path.push_str(name);
current_path.push('/');
}
current_path.push_str(&item_path(ty, names.last().unwrap()));
redirections.borrow_mut().insert(current_path, path);
}
None => return layout::redirect(&format!("{}{}", self.root_path(), path)),
}
url.push_str(&item_path(ty, names.last().unwrap()));
layout::redirect(&url)
} else {
String::new()
}
String::new()
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,13 @@ fn opts() -> Vec<RustcOptGroup> {
o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
}),
unstable("check", |o| o.optflag("", "check", "Run rustdoc checks")),
unstable("generate-redirect-map", |o| {
o.optflag(
"",
"generate-redirect-map",
"Generate JSON file at the top level instead of generating HTML redirection files",
)
}),
]
}

Expand Down
5 changes: 5 additions & 0 deletions src/test/run-make-fulldeps/rustdoc-map-file/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-include ../tools.mk

all:
$(RUSTDOC) -Z unstable-options --generate-redirect-map foo.rs -o "$(TMPDIR)/out"
"$(PYTHON)" validate_json.py "$(TMPDIR)/out"
5 changes: 5 additions & 0 deletions src/test/run-make-fulldeps/rustdoc-map-file/expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"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"
}
16 changes: 16 additions & 0 deletions src/test/run-make-fulldeps/rustdoc-map-file/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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 {
() => {}
}
41 changes: 41 additions & 0 deletions src/test/run-make-fulldeps/rustdoc-map-file/validate_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python

import os
import sys
import json


def find_redirect_map_file(folder, errors):
for root, dirs, files in os.walk(folder):
for name in files:
if not name.endswith("redirect-map.json"):
continue
with open(os.path.join(root, name)) as f:
data = json.load(f)
with open("expected.json") as f:
expected = json.load(f)
for key in expected:
if expected[key] != data.get(key):
errors.append("Expected `{}` for key `{}`, found: `{}`".format(
expected[key], key, data.get(key)))
else:
del data[key]
for key in data:
errors.append("Extra data not expected: key: `{}`, data: `{}`".format(
key, data[key]))
return True
return False


if len(sys.argv) != 2:
print("Expected doc directory to check!")
sys.exit(1)

errors = []
if not find_redirect_map_file(sys.argv[1], errors):
print("Didn't find the map file in `{}`...".format(sys.argv[1]))
sys.exit(1)
for err in errors:
print("=> {}".format(err))
if len(errors) != 0:
sys.exit(1)
6 changes: 6 additions & 0 deletions src/test/rustdoc/redirect-map-empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// compile-flags: -Z unstable-options --generate-redirect-map

#![crate_name = "foo"]

// @!has foo/redirect-map.json
pub struct Foo;
23 changes: 23 additions & 0 deletions src/test/rustdoc/redirect-map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// compile-flags: -Z unstable-options --generate-redirect-map

#![crate_name = "foo"]

// @!has foo/private/struct.Quz.html
// @!has foo/hidden/struct.Bar.html
// @has foo/redirect-map.json
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 {
() => {}
}

0 comments on commit 9a827d9

Please sign in to comment.