Rollup merge of #81223 - GuillaumeGomez:generate-redirect-map, r=jyn514
[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````
This commit is contained in:
@@ -263,6 +263,8 @@ crate struct RenderOptions {
|
|||||||
crate document_private: bool,
|
crate document_private: bool,
|
||||||
/// Document items that have `doc(hidden)`.
|
/// Document items that have `doc(hidden)`.
|
||||||
crate document_hidden: bool,
|
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,
|
crate unstable_features: rustc_feature::UnstableFeatures,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,6 +572,7 @@ impl Options {
|
|||||||
let document_private = matches.opt_present("document-private-items");
|
let document_private = matches.opt_present("document-private-items");
|
||||||
let document_hidden = matches.opt_present("document-hidden-items");
|
let document_hidden = matches.opt_present("document-hidden-items");
|
||||||
let run_check = matches.opt_present("check");
|
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);
|
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
|
||||||
|
|
||||||
@@ -627,6 +630,7 @@ impl Options {
|
|||||||
generate_search_filter,
|
generate_search_filter,
|
||||||
document_private,
|
document_private,
|
||||||
document_hidden,
|
document_hidden,
|
||||||
|
generate_redirect_map,
|
||||||
unstable_features: rustc_feature::UnstableFeatures::from_environment(
|
unstable_features: rustc_feature::UnstableFeatures::from_environment(
|
||||||
crate_name.as_deref(),
|
crate_name.as_deref(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -111,6 +111,10 @@ crate struct Context<'tcx> {
|
|||||||
/// real location of an item. This is used to allow external links to
|
/// real location of an item. This is used to allow external links to
|
||||||
/// publicly reused items to redirect to the right location.
|
/// publicly reused items to redirect to the right location.
|
||||||
crate render_redirect_pages: bool,
|
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.
|
/// The map used to ensure all generated 'id=' attributes are unique.
|
||||||
id_map: Rc<RefCell<IdMap>>,
|
id_map: Rc<RefCell<IdMap>>,
|
||||||
/// Tracks section IDs for `Deref` targets so they match in both the main
|
/// Tracks section IDs for `Deref` targets so they match in both the main
|
||||||
@@ -404,6 +408,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||||||
static_root_path,
|
static_root_path,
|
||||||
generate_search_filter,
|
generate_search_filter,
|
||||||
unstable_features,
|
unstable_features,
|
||||||
|
generate_redirect_map,
|
||||||
..
|
..
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
@@ -509,6 +514,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||||||
all: Rc::new(RefCell::new(AllTypes::new())),
|
all: Rc::new(RefCell::new(AllTypes::new())),
|
||||||
errors: Rc::new(receiver),
|
errors: Rc::new(receiver),
|
||||||
cache: Rc::new(cache),
|
cache: Rc::new(cache),
|
||||||
|
redirections: if generate_redirect_map { Some(Default::default()) } else { None },
|
||||||
};
|
};
|
||||||
|
|
||||||
CURRENT_DEPTH.with(|s| s.set(0));
|
CURRENT_DEPTH.with(|s| s.set(0));
|
||||||
@@ -587,6 +593,15 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||||||
&style_files,
|
&style_files,
|
||||||
);
|
);
|
||||||
self.shared.fs.write(&settings_file, v.as_bytes())?;
|
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.
|
// Flush pending errors.
|
||||||
Arc::get_mut(&mut self.shared).unwrap().fs.close();
|
Arc::get_mut(&mut self.shared).unwrap().fs.close();
|
||||||
@@ -675,11 +690,19 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||||||
// to the new one (without).
|
// to the new one (without).
|
||||||
if item_type == ItemType::Macro {
|
if item_type == ItemType::Macro {
|
||||||
let redir_name = format!("{}.{}!.html", item_type, name);
|
let redir_name = format!("{}.{}!.html", item_type, name);
|
||||||
let redir_dst = self.dst.join(redir_name);
|
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 v = layout::redirect(file_name);
|
||||||
|
let redir_dst = self.dst.join(redir_name);
|
||||||
self.shared.fs.write(&redir_dst, v.as_bytes())?;
|
self.shared.fs.write(&redir_dst, v.as_bytes())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1588,19 +1611,29 @@ impl Context<'_> {
|
|||||||
&self.shared.style_files,
|
&self.shared.style_files,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let mut url = self.root_path();
|
|
||||||
if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
|
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] {
|
for name in &names[..names.len() - 1] {
|
||||||
url.push_str(name);
|
path.push_str(name);
|
||||||
url.push('/');
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a map of items shown in the sidebar to a plain-text summary of their docs.
|
/// Construct a map of items shown in the sidebar to a plain-text summary of their docs.
|
||||||
fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
|
fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
|
||||||
|
|||||||
@@ -497,6 +497,13 @@ fn opts() -> Vec<RustcOptGroup> {
|
|||||||
o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
|
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("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",
|
||||||
|
)
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
src/test/run-make-fulldeps/rustdoc-map-file/Makefile
Normal file
5
src/test/run-make-fulldeps/rustdoc-map-file/Makefile
Normal file
@@ -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"
|
||||||
@@ -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
src/test/run-make-fulldeps/rustdoc-map-file/foo.rs
Normal file
16
src/test/run-make-fulldeps/rustdoc-map-file/foo.rs
Normal file
@@ -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
src/test/run-make-fulldeps/rustdoc-map-file/validate_json.py
Executable file
41
src/test/run-make-fulldeps/rustdoc-map-file/validate_json.py
Executable file
@@ -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
src/test/rustdoc/redirect-map-empty.rs
Normal file
6
src/test/rustdoc/redirect-map-empty.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// compile-flags: -Z unstable-options --generate-redirect-map
|
||||||
|
|
||||||
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
|
// @!has foo/redirect-map.json
|
||||||
|
pub struct Foo;
|
||||||
23
src/test/rustdoc/redirect-map.rs
Normal file
23
src/test/rustdoc/redirect-map.rs
Normal file
@@ -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 {
|
||||||
|
() => {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user