Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rustdoc] Generate redirect map file #81223

Merged
merged 4 commits into from
Mar 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,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 @@ -586,6 +588,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 @@ -643,6 +646,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>>>>,
jyn514 marked this conversation as resolved.
Show resolved Hide resolved
/// 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 @@ -405,6 +409,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
static_root_path,
generate_search_filter,
unstable_features,
generate_redirect_map,
..
} = options;

Expand Down Expand Up @@ -510,6 +515,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 @@ -588,6 +594,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 @@ -676,9 +691,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 @@ -423,6 +423,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
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
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 {
() => {}
}