Skip to main content

xtask/tasks/fmt/lints/
package_info.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Checks to ensure that the `[package]` sections of Cargo.toml files do not
5//! contain `authors` or `version` fields, and that rust-version, edition, and
6//! fields are properly workspaced.
7//!
8//! Eliding the [version][] sets the version to "0.0.0", which is fine. More
9//! importantly, it means the module cannot be published to crates.io
10//! (equivalent to publish = false), which is what we want for our internal
11//! crates. And removing the meaningless version also eliminates more questions
12//! from newcomers (does the version field mean anything? do we use it for
13//! semver internally?).
14//!
15//! The [authors][] field is optional, is not really used anywhere anymore, and
16//! just creates confusion.
17//!
18//! [version]:
19//!     <https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field>
20//! [authors]:
21//!     <https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field>
22
23use super::Lint;
24use super::LintCtx;
25use super::Lintable;
26use toml_edit::DocumentMut;
27use toml_edit::Item;
28use toml_edit::Table;
29
30/// List of packages that are allowed to have a version
31static VERSION_EXCEPTIONS: &[&str] = &["vmgstool"];
32
33pub struct PackageInfo;
34
35impl Lint for PackageInfo {
36    fn new(_ctx: &LintCtx) -> Self {
37        PackageInfo
38    }
39
40    fn enter_workspace(&mut self, _content: &Lintable<DocumentMut>) {}
41    fn enter_crate(&mut self, _content: &Lintable<DocumentMut>) {}
42    fn visit_file(&mut self, _content: &mut Lintable<String>) {}
43
44    fn exit_crate(&mut self, content: &mut Lintable<DocumentMut>) {
45        let package = content["package"].as_table().unwrap();
46        let excluded_from_workspace = package
47            .get("metadata")
48            .and_then(|x| x.get("xtask"))
49            .and_then(|x| x.get("house-rules"))
50            .and_then(|x| x.get("excluded-from-workspace"))
51            .and_then(|v| v.as_bool())
52            .unwrap_or(false);
53
54        let package_name = package["name"].as_str().unwrap();
55        let check_version = !VERSION_EXCEPTIONS.contains(&package_name);
56
57        let mut lints_table = Table::new();
58        lints_table.insert("workspace", Item::Value(true.into()));
59
60        let mut rust_version_field = Table::new();
61        rust_version_field.set_dotted(true);
62        rust_version_field.insert("workspace", Item::Value(true.into()));
63
64        let mut edition_field = Table::new();
65        edition_field.set_dotted(true);
66        edition_field.insert("workspace", Item::Value(true.into()));
67
68        let has_authors = package.contains_key("authors");
69        let has_version = check_version && package.contains_key("version");
70        let needs_lints_fix = !excluded_from_workspace
71            && content.get("lints").map(|o| o.to_string()).as_deref()
72                != Some(&lints_table.to_string());
73        let needs_rust_version_fix = !excluded_from_workspace
74            && package
75                .get("rust-version")
76                .map(|o| o.to_string())
77                .as_deref()
78                != Some(&rust_version_field.to_string());
79        let needs_edition_fix = !excluded_from_workspace
80            && package.get("edition").map(|o| o.to_string()).as_deref()
81                != Some(&edition_field.to_string());
82
83        if has_authors {
84            content.fix("package should not have authors field", |doc| {
85                doc["package"].as_table_mut().unwrap().remove("authors");
86            });
87        }
88
89        if has_version {
90            content.fix("package should not have version field", |doc| {
91                doc["package"].as_table_mut().unwrap().remove("version");
92            });
93        }
94
95        if needs_lints_fix {
96            content.fix("lints should be workspaced", |doc| {
97                doc.insert("lints", Item::Table(lints_table));
98            });
99        }
100
101        if needs_rust_version_fix {
102            content.fix("rust-version should be workspaced", |doc| {
103                doc["package"]
104                    .as_table_mut()
105                    .unwrap()
106                    .insert("rust-version", Item::Table(rust_version_field));
107            });
108        }
109
110        if needs_edition_fix {
111            content.fix("edition should be workspaced", |doc| {
112                doc["package"]
113                    .as_table_mut()
114                    .unwrap()
115                    .insert("edition", Item::Table(edition_field));
116            });
117        }
118    }
119
120    fn exit_workspace(&mut self, _content: &mut Lintable<DocumentMut>) {}
121}