Skip to content

Commit 97b01ab

Browse files
committed
Auto merge of #41991 - GuillaumeGomez:rustdoc-html-diff, r=nrc
Add warnings when rustdoc html rendering differs
2 parents 890c87b + b501d00 commit 97b01ab

File tree

9 files changed

+406
-56
lines changed

9 files changed

+406
-56
lines changed

Diff for: src/Cargo.lock

+290-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/librustdoc/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ path = "lib.rs"
1212
env_logger = { version = "0.4", default-features = false }
1313
log = "0.3"
1414
pulldown-cmark = { version = "0.0.14", default-features = false }
15+
html-diff = "0.0.3"
1516

1617
[build-dependencies]
1718
build_helper = { path = "../build_helper" }

Diff for: src/librustdoc/html/render.rs

+31-2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ use html::item_type::ItemType;
7575
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType};
7676
use html::{highlight, layout};
7777

78+
use html_diff;
79+
7880
/// A pair of name and its optional document.
7981
pub type NameDoc = (String, Option<String>);
8082

@@ -1643,6 +1645,33 @@ fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Re
16431645
Ok(())
16441646
}
16451647

1648+
fn get_html_diff(w: &mut fmt::Formatter, md_text: &str, render_type: RenderType,
1649+
prefix: &str) -> fmt::Result {
1650+
let output = format!("{}", Markdown(md_text, render_type));
1651+
let old = format!("{}", Markdown(md_text, match render_type {
1652+
RenderType::Hoedown => RenderType::Pulldown,
1653+
RenderType::Pulldown => RenderType::Hoedown,
1654+
}));
1655+
let differences = html_diff::get_differences(&output, &old);
1656+
if !differences.is_empty() {
1657+
println!("Differences spotted in {:?}:\n{}",
1658+
md_text,
1659+
differences.iter()
1660+
.filter_map(|s| {
1661+
match *s {
1662+
html_diff::Difference::NodeText { ref elem_text,
1663+
ref opposite_elem_text,
1664+
.. }
1665+
if elem_text.trim() == opposite_elem_text.trim() => None,
1666+
_ => Some(format!("=> {}", s.to_string())),
1667+
}
1668+
})
1669+
.collect::<Vec<String>>()
1670+
.join("\n"));
1671+
}
1672+
write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
1673+
}
1674+
16461675
fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
16471676
render_type: RenderType, prefix: &str) -> fmt::Result {
16481677
if let Some(s) = item.doc_value() {
@@ -1652,7 +1681,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
16521681
} else {
16531682
format!("{}", &plain_summary_line(Some(s)))
16541683
};
1655-
write!(w, "<div class='docblock'>{}{}</div>", prefix, Markdown(&markdown, render_type))?;
1684+
get_html_diff(w, &markdown, render_type, prefix)?;
16561685
} else if !prefix.is_empty() {
16571686
write!(w, "<div class='docblock'>{}</div>", prefix)?;
16581687
}
@@ -1676,7 +1705,7 @@ fn render_assoc_const_value(item: &clean::Item) -> String {
16761705
fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
16771706
render_type: RenderType, prefix: &str) -> fmt::Result {
16781707
if let Some(s) = item.doc_value() {
1679-
write!(w, "<div class='docblock'>{}{}</div>", prefix, Markdown(s, render_type))?;
1708+
get_html_diff(w, s, render_type, prefix)?;
16801709
} else if !prefix.is_empty() {
16811710
write!(w, "<div class='docblock'>{}</div>", prefix)?;
16821711
}

Diff for: src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
extern crate arena;
2929
extern crate getopts;
3030
extern crate env_logger;
31+
extern crate html_diff;
3132
extern crate libc;
3233
extern crate rustc;
3334
extern crate rustc_data_structures;

Diff for: src/libstd/io/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
//! # }
213213
//! ```
214214
//!
215-
//! [functions-list]: #functions-1
215+
//! [functions-list]: #functions-2
216216
//!
217217
//! ## io::Result
218218
//!
+2-35
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,2 @@
1-
-include ../tools.mk
2-
3-
# This is a whitelist of files which are stable crates or simply are not crates,
4-
# we don't check for the instability of these crates as they're all stable!
5-
STABLE_CRATES := \
6-
std \
7-
core \
8-
proc_macro \
9-
rsbegin.o \
10-
rsend.o \
11-
dllcrt2.o \
12-
crt2.o \
13-
clang_rt.%_dynamic.dylib
14-
15-
# Generate a list of all crates in the sysroot. To do this we list all files in
16-
# rustc's sysroot, look at the filename, strip everything after the `-`, and
17-
# strip the leading `lib` (if present)
18-
SYSROOT := $(shell $(RUSTC) --print sysroot)
19-
LIBS := $(wildcard $(SYSROOT)/lib/rustlib/$(TARGET)/lib/*)
20-
LIBS := $(foreach lib,$(LIBS),$(notdir $(lib)))
21-
LIBS := $(foreach lib,$(LIBS),$(word 1,$(subst -, ,$(lib))))
22-
LIBS := $(foreach lib,$(LIBS),$(patsubst lib%,%,$(lib)))
23-
LIBS := $(filter-out $(STABLE_CRATES),$(LIBS))
24-
25-
all: $(foreach lib,$(LIBS),check-crate-$(lib)-is-unstable)
26-
27-
check-crate-%-is-unstable:
28-
@echo verifying $* is an unstable crate
29-
@echo 'extern crate $*;' | \
30-
$(RUSTC) - --crate-type rlib 2>&1 | cat > $(TMPDIR)/$*; \
31-
true
32-
@grep -q 'use of unstable library feature' $(TMPDIR)/$* || \
33-
(echo crate $* is not unstable && \
34-
cat $(TMPDIR)/$* && \
35-
false)
1+
all:
2+
python2.7 test.py
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright 2015 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+
import sys
12+
import os
13+
from os import listdir
14+
from os.path import isfile, join
15+
from subprocess import PIPE, Popen
16+
17+
18+
# This is a whitelist of files which are stable crates or simply are not crates,
19+
# we don't check for the instability of these crates as they're all stable!
20+
STABLE_CRATES = ['std', 'core', 'proc_macro', 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o',
21+
'clang_rt']
22+
23+
24+
def convert_to_string(s):
25+
if s.__class__.__name__ == 'bytes':
26+
return s.decode('utf-8')
27+
return s
28+
29+
30+
def exec_command(command, to_input=None):
31+
child = None
32+
if to_input is None:
33+
child = Popen(command, stdout=PIPE, stderr=PIPE)
34+
else:
35+
child = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
36+
stdout, stderr = child.communicate(input=to_input)
37+
return (convert_to_string(stdout), convert_to_string(stderr))
38+
39+
40+
def check_lib(lib):
41+
if lib['name'] in STABLE_CRATES:
42+
return True
43+
print('verifying if {} is an unstable crate'.format(lib['name']))
44+
stdout, stderr = exec_command([os.environ['RUSTC'], '-', '--crate-type', 'rlib',
45+
'--extern', '{}={}'.format(lib['name'], lib['path'])],
46+
to_input='extern crate {};'.format(lib['name']))
47+
if not 'use of unstable library feature' in '{}{}'.format(stdout, stderr):
48+
print('crate {} "{}" is not unstable'.format(lib['name'], lib['path']))
49+
print('{}{}'.format(stdout, stderr))
50+
print('')
51+
return False
52+
return True
53+
54+
# Generate a list of all crates in the sysroot. To do this we list all files in
55+
# rustc's sysroot, look at the filename, strip everything after the `-`, and
56+
# strip the leading `lib` (if present)
57+
def get_all_libs(dir_path):
58+
return [{ 'path': join(dir_path, f), 'name': f[3:].split('-')[0] }
59+
for f in listdir(dir_path)
60+
if isfile(join(dir_path, f)) and f.endswith('.rlib') and f not in STABLE_CRATES]
61+
62+
63+
sysroot = exec_command([os.environ['RUSTC'], '--print', 'sysroot'])[0].replace('\n', '')
64+
libs = get_all_libs(join(sysroot, 'lib/rustlib/{}/lib'.format(os.environ['TARGET'])))
65+
66+
ret = 0
67+
for lib in libs:
68+
if not check_lib(lib):
69+
# We continue so users can see all the not unstable crates.
70+
ret = 1
71+
sys.exit(ret)

Diff for: src/test/rustdoc/issue-29449.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ impl Foo {
1818
/// # Panics
1919
pub fn bar() {}
2020

21-
// @has - '//*[@id="examples-1"]//a' 'Examples'
21+
// @has - '//*[@id="examples-2"]//a' 'Examples'
2222
/// # Examples
2323
pub fn bar_1() {}
2424

25-
// @has - '//*[@id="examples-2"]//a' 'Examples'
26-
// @has - '//*[@id="panics-1"]//a' 'Panics'
25+
// @has - '//*[@id="examples-4"]//a' 'Examples'
26+
// @has - '//*[@id="panics-2"]//a' 'Panics'
2727
/// # Examples
2828
/// # Panics
2929
pub fn bar_2() {}

Diff for: src/tools/tidy/src/deps.rs

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ static EXCEPTIONS: &'static [&'static str] = &[
3333
"openssl", // BSD+advertising clause, cargo, mdbook
3434
"pest", // MPL2, mdbook via handlebars
3535
"thread-id", // Apache-2.0, mdbook
36+
"cssparser", // MPL-2.0, rustdoc
37+
"smallvec", // MPL-2.0, rustdoc
38+
"magenta-sys", // BSD-3-Clause, rustdoc
39+
"magenta", // BSD-3-Clause, rustdoc
40+
"cssparser-macros", // MPL-2.0, rustdoc
41+
"selectors", // MPL-2.0, rustdoc
3642
];
3743

3844
pub fn check(path: &Path, bad: &mut bool) {

0 commit comments

Comments
 (0)