Skip to content

Commit 2b16f74

Browse files
authored
Merge pull request rust-lang#80 from gnzlbg/soft
Add flag --api-guidelines to silence non-technical breaking changes.
2 parents edc3141 + fa51b61 commit 2b16f74

File tree

7 files changed

+75
-13
lines changed

7 files changed

+75
-13
lines changed

src/bin/cargo_semver.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,21 @@ fn do_main(config: &Config, matches: &Matches, explain: bool) -> CargoResult<()>
252252
child.args(&["--target", &target]);
253253
}
254254

255-
let mut child = child
255+
let child = child
256256
.arg("-")
257257
.stdin(Stdio::piped())
258258
.env("RUST_SEMVER_CRATE_VERSION", stable_version)
259259
.env("RUST_SEMVER_VERBOSE", format!("{}", explain))
260+
.env(
261+
"RUST_SEMVER_API_GUIDELINES",
262+
if matches.opt_present("a") {
263+
"true"
264+
} else {
265+
"false"
266+
},
267+
);
268+
269+
let mut child = child
260270
.spawn()
261271
.map_err(|e| Error(format!("could not spawn rustc: {}", e)))?;
262272

@@ -311,6 +321,11 @@ fn main() {
311321
opts.optflag("V", "version", "print version information and exit");
312322
opts.optflag("e", "explain", "print detailed error explanations");
313323
opts.optflag("d", "debug", "print command to debug and exit");
324+
opts.optflag(
325+
"a",
326+
"api-guidelines",
327+
"report only changes that are breaking according to the API-guidelines",
328+
);
314329
opts.optopt(
315330
"s",
316331
"stable-path",

src/bin/rust_semverver.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use std::{
3232
use syntax::{ast, source_map::Pos};
3333

3434
/// After the typechecker has finished it's work, perform our checks.
35-
fn callback(state: &driver::CompileState, version: &str, verbose: bool) {
35+
fn callback(state: &driver::CompileState, version: &str, verbose: bool, api_guidelines: bool) {
3636
let tcx = state.tcx.unwrap();
3737

3838
// To select the old and new crates we look at the position of the declaration in the
@@ -62,8 +62,7 @@ fn callback(state: &driver::CompileState, version: &str, verbose: bool) {
6262
if let [(_, old_def_id), (_, new_def_id)] = *crates.as_slice() {
6363
debug!("running semver analysis");
6464
let changes = run_analysis(tcx, old_def_id, new_def_id);
65-
66-
changes.output(tcx.sess, version, verbose);
65+
changes.output(tcx.sess, version, verbose, api_guidelines);
6766
} else {
6867
tcx.sess.err("could not find crate old and new crates");
6968
}
@@ -77,15 +76,18 @@ struct SemVerVerCompilerCalls {
7776
version: String,
7877
/// The output mode.
7978
verbose: bool,
79+
/// Output only changes that are breaking according to the API guidelines.
80+
api_guidelines: bool,
8081
}
8182

8283
impl SemVerVerCompilerCalls {
8384
/// Construct a new compilation wrapper, given a version string.
84-
pub fn new(version: String, verbose: bool) -> Box<Self> {
85+
pub fn new(version: String, verbose: bool, api_guidelines: bool) -> Box<Self> {
8586
Box::new(Self {
8687
default: Box::new(RustcDefaultCalls),
8788
version,
8889
verbose,
90+
api_guidelines,
8991
})
9092
}
9193

@@ -96,6 +98,10 @@ impl SemVerVerCompilerCalls {
9698
pub fn get_version(&self) -> &String {
9799
&self.version
98100
}
101+
102+
pub fn get_api_guidelines(&self) -> bool {
103+
self.api_guidelines
104+
}
99105
}
100106

101107
impl<'a> CompilerCalls<'a> for SemVerVerCompilerCalls {
@@ -148,13 +154,14 @@ impl<'a> CompilerCalls<'a> for SemVerVerCompilerCalls {
148154
) -> driver::CompileController<'a> {
149155
let default = self.get_default();
150156
let version = self.get_version().clone();
157+
let api_guidelines = self.get_api_guidelines();
151158
let Self { verbose, .. } = *self;
152159
let mut controller = CompilerCalls::build_controller(default, sess, matches);
153160
let old_callback = std::mem::replace(&mut controller.after_analysis.callback, box |_| {});
154161

155162
controller.after_analysis.callback = box move |state| {
156163
debug!("running rust-semverver after_analysis callback");
157-
callback(state, &version, verbose);
164+
callback(state, &version, verbose, api_guidelines);
158165
debug!("running other after_analysis callback");
159166
old_callback(state);
160167
};
@@ -217,8 +224,9 @@ fn main() {
217224
};
218225

219226
let verbose = std::env::var("RUST_SEMVER_VERBOSE") == Ok("true".to_string());
227+
let api_guidelines = std::env::var("RUST_SEMVER_API_GUIDELINES") == Ok("true".to_string());
220228

221-
let cc = SemVerVerCompilerCalls::new(version, verbose);
229+
let cc = SemVerVerCompilerCalls::new(version, verbose, api_guidelines);
222230
rustc_driver::run_compiler(&args, cc, None, None)
223231
});
224232

src/semcheck/changes.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ impl<'tcx> ChangeSet<'tcx> {
879879
}
880880

881881
/// Format the contents of a change set for user output.
882-
pub fn output(&self, session: &Session, version: &str, verbose: bool) {
882+
pub fn output(&self, session: &Session, version: &str, verbose: bool, api_guidelines: bool) {
883883
if let Ok(mut new_version) = Version::parse(version) {
884884
if new_version.major == 0 {
885885
new_version.increment_patch();
@@ -901,11 +901,25 @@ impl<'tcx> ChangeSet<'tcx> {
901901

902902
for key in self.spans.values() {
903903
if let Some(change) = self.path_changes.get(key) {
904-
change.report(session);
904+
if api_guidelines {
905+
match change.to_category() {
906+
Patch | Breaking => change.report(session),
907+
_ => (),
908+
}
909+
} else {
910+
change.report(session);
911+
}
905912
}
906913

907914
if let Some(change) = self.changes.get(key) {
908-
change.report(session, verbose);
915+
if api_guidelines {
916+
match change.to_category() {
917+
Patch | Breaking => change.report(session, verbose),
918+
_ => (),
919+
}
920+
} else {
921+
change.report(session, verbose);
922+
}
909923
}
910924
}
911925
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version bump: 1.0.0 -> (technically breaking) -> 1.1.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version bump: 1.0.0 -> (technically breaking) -> 1.1.0
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
version bump: 1.0.0 -> (breaking) -> 2.0.0
2+
error: breaking changes in `Def`
3+
--> $REPO_PATH/tests/cases/addition_use/new.rs:5:1
4+
|
5+
5 | / pub struct Def<'a> {
6+
6 | | pub field1: Abc,
7+
7 | | pub field2: &'a Bcd,
8+
8 | | }
9+
| |_^
10+
|
11+
= warning: type error: expected (), found struct `new::Abc` (breaking)
12+
= warning: type error: expected (), found trait new::Bcd (breaking)
13+
14+
error: aborting due to previous error
15+

tests/examples.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ mod features {
55
process::{Command, Stdio},
66
};
77

8-
fn test_example(path: &Path) {
8+
fn test_example(path: &Path, out_file: &Path) {
99
let mut success = true;
1010

11-
let out_file = path.join("stdout");
1211
let old_rlib = path.join("libold.rlib").to_str().unwrap().to_owned();
1312
let new_rlib = path.join("libnew.rlib").to_str().unwrap().to_owned();
1413

@@ -78,6 +77,10 @@ mod features {
7877
cmd.args(target_args);
7978
}
8079

80+
if out_file.to_str().unwrap().contains("stdout_api_guidelines") {
81+
cmd.env("RUST_SEMVER_API_GUIDELINES", "true");
82+
}
83+
8184
success &= cmd
8285
.status()
8386
.expect("could not run rust-semverver")
@@ -144,7 +147,12 @@ mod features {
144147
#[test]
145148
fn $name() {
146149
let path = Path::new("tests").join("cases").join(stringify!($name));
147-
test_example(&path);
150+
test_example(&path, &path.join("stdout"));
151+
152+
if path.join("stdout_api_guidelines").exists() {
153+
eprintln!("api-guidelines");
154+
test_example(&path, &path.join("stdout_api_guidelines"));
155+
}
148156
}
149157
};
150158
($($name:ident),*) => {

0 commit comments

Comments
 (0)