Skip to content

Commit 59247ac

Browse files
authored
Compile dylints when compiling the contract (#703)
* Don't build dylint driver * Run dylint by patching manifest * Switch injection to master branch
1 parent cc69f67 commit 59247ac

29 files changed

+85
-2777
lines changed

.github/workflows/macos.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
with:
4141
profile: minimal
4242
toolchain: ${{ matrix.toolchain }}
43-
components: rust-src, rustc-dev, llvm-tools-preview
43+
components: rust-src
4444

4545
- name: Install cargo-dylint
4646
uses: baptiste0928/cargo-install@v1

.github/workflows/windows.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
uses: dtolnay/rust-toolchain@stable
4343
with:
4444
toolchain: ${{ matrix.toolchain }}
45-
components: rust-src, rustc-dev, llvm-tools-preview
45+
components: rust-src
4646

4747
- name: Install cargo-dylint
4848
uses: baptiste0928/cargo-install@v1

.gitlab-ci.yml

+1-24
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ workflow:
5050
name: "${CI_IMAGE}"
5151
before_script:
5252
- rustup default stable
53-
- rustup component add rustfmt clippy rust-src rustc-dev llvm-tools-preview
53+
- rustup component add rustfmt clippy rust-src
5454
- cargo -vV
5555
- rustc -vV
5656
- rustup show
@@ -105,29 +105,6 @@ clippy:
105105

106106
#### stage: test (all features)
107107

108-
test-dylint:
109-
stage: test
110-
<<: *docker-env
111-
script:
112-
# We need to fix this test to a toolchain because of the UI tests
113-
# We can't use stable here because the UI tests freak out if there are dots in the drivers file name
114-
- rustup default nightly-2022-06-30
115-
- rustup component add rustfmt clippy rust-src rustc-dev llvm-tools-preview
116-
117-
- rusty-cachier snapshot create
118-
- cd ink_linting/
119-
- mv _Cargo.toml Cargo.toml
120-
121-
- cargo check --verbose
122-
- cargo +nightly fmt --verbose --all -- --check
123-
- cargo clippy --verbose -- -D warnings;
124-
125-
# Needed until https://github.com/mozilla/sccache/issues/1000 is fixed.
126-
- unset RUSTC_WRAPPER
127-
128-
- cargo test --verbose --all-features
129-
- rusty-cachier cache upload
130-
131108
test:
132109
stage: test
133110
<<: *docker-env

Cargo.toml

-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ keywords = ["wasm", "parity", "webassembly", "blockchain", "edsl"]
1818
categories = ["command-line-utilities", "development-tools::build-utils", "development-tools::cargo-plugins"]
1919
include = [
2020
"Cargo.toml", "src/**/*.rs", "README.md", "LICENSE", "build.rs", "templates", "src/**/*.scale",
21-
# We need to include `ink_linting` in the releases, so that the dylint driver which
22-
# is contained in that crate is build locally as part of the installation.
23-
"ink_linting", "!ink_linting/target/", "!ink_linting/ui/"
2421
]
2522

2623
[dependencies]

build.rs

+1-282
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn main() {
5353
let out_dir: PathBuf = env::var("OUT_DIR")
5454
.expect("OUT_DIR should be set by cargo")
5555
.into();
56-
let res = zip_template_and_build_dylint_driver(manifest_dir, out_dir);
56+
let res = zip_template(&manifest_dir, &out_dir);
5757

5858
match res {
5959
Ok(()) => std::process::exit(0),
@@ -64,58 +64,6 @@ fn main() {
6464
}
6565
}
6666

67-
/// This method:
68-
/// * Creates a zip archive of the `new` project template.
69-
/// * Builds the `dylint` driver found in `ink_linting`, the compiled
70-
/// driver is put into a zip archive as well.
71-
fn zip_template_and_build_dylint_driver(
72-
manifest_dir: PathBuf,
73-
out_dir: PathBuf,
74-
) -> Result<()> {
75-
zip_template(&manifest_dir, &out_dir)?;
76-
77-
check_dylint_link_installed()?;
78-
79-
// This zip file will contain the `dylint` driver, this is one file named in the form of
80-
// `libink_linting@nightly-2021-11-04-x86_64-unknown-linux-gnu.so`. This file is obtained
81-
// by building the crate in `ink_linting/`.
82-
let dylint_driver_dst_file = out_dir.join("ink-dylint-driver.zip");
83-
84-
let ink_dylint_driver_dir = manifest_dir.join("ink_linting");
85-
let ink_dylint_driver_dir = ink_dylint_driver_dir.canonicalize().map_err(|err| {
86-
anyhow::anyhow!(
87-
"Unable to canonicalize '{:?}': {:?}\nDoes the folder exist? {}",
88-
ink_dylint_driver_dir,
89-
err,
90-
ink_dylint_driver_dir.exists()
91-
)
92-
})?;
93-
94-
// The `ink_linting/Cargo.toml` file is named `_Cargo.toml` in the repository.
95-
// This is because we need to have the `ink_linting` folder part of the release,
96-
// so that when somebody installs `cargo-contract` the `ink_linting` crate is
97-
// build locally as part of that installation process.
98-
// But if the file were named `Cargo.toml` then `cargo publish` would ignore
99-
// the whole `ink_linting` folder and we wouldn't be able to specify the folder
100-
// in the `cargo-contract/Cargo.toml` section of `[include]`.
101-
//
102-
// This is intended behavior:
103-
//
104-
// > Regardless of whether exclude or include is specified, the following files are always excluded:
105-
// > * Any sub-packages will be skipped (any subdirectory that contains a Cargo.toml file).
106-
//
107-
// (from https://doc.rust-lang.org/cargo/reference/manifest.html#the-exclude-and-include-fields)
108-
let original_name = ink_dylint_driver_dir.join("_Cargo.toml");
109-
110-
// After the build process of `ink_linting` happened we need to remove the `Cargo.toml` file.
111-
// Otherwise the directory would be "dirty" and `cargo publish` would fail with `Source
112-
// directory was modified by build.rs during cargo publish`.
113-
let tmp_name = ink_dylint_driver_dir.join("Cargo.toml");
114-
let _guard = tmp_file_guard::FileGuard::new(original_name, tmp_name);
115-
116-
build_and_zip_dylint_driver(ink_dylint_driver_dir, out_dir, dylint_driver_dst_file)
117-
}
118-
11967
/// Creates a zip archive `template.zip` of the `new` project template in `out_dir`.
12068
fn zip_template(manifest_dir: &Path, out_dir: &Path) -> Result<()> {
12169
let template_dir = manifest_dir.join("templates").join("new");
@@ -134,128 +82,6 @@ fn zip_template(manifest_dir: &Path, out_dir: &Path) -> Result<()> {
13482
})
13583
}
13684

137-
/// Builds the crate in `ink_linting/`. This crate contains the `dylint` driver with ink! specific
138-
/// linting rules.
139-
#[cfg(feature = "cargo-clippy")]
140-
fn build_and_zip_dylint_driver(
141-
_ink_dylint_driver_dir: PathBuf,
142-
_out_dir: PathBuf,
143-
dylint_driver_dst_file: PathBuf,
144-
) -> Result<()> {
145-
// For `clippy` runs it is not necessary to build the `dylint` driver.
146-
// Furthermore the fixed Rust nightly specified in `ink_linting/rust-toolchain`
147-
// contains a bug that results in an `error[E0786]: found invalid metadata files` ICE.
148-
//
149-
// We still have to create an empty file though, due to the `include_bytes!` macro.
150-
File::create(dylint_driver_dst_file)
151-
.map_err(|err| {
152-
anyhow::anyhow!(
153-
"Failed creating an empty ink-dylint-driver.zip file: {:?}",
154-
err
155-
)
156-
})
157-
.map(|_| ())
158-
}
159-
160-
/// Builds the crate in `ink_linting/`. This crate contains the `dylint` driver with ink! specific
161-
/// linting rules.
162-
#[cfg(not(feature = "cargo-clippy"))]
163-
fn build_and_zip_dylint_driver(
164-
ink_dylint_driver_dir: PathBuf,
165-
out_dir: PathBuf,
166-
dylint_driver_dst_file: PathBuf,
167-
) -> Result<()> {
168-
let mut cmd = Command::new("cargo");
169-
#[cfg(windows)]
170-
{
171-
// copied workaround from dylint for https://github.com/rust-lang/rustup/pull/2978
172-
let cargo_home = match env::var("CARGO_HOME") {
173-
Ok(value) => Ok(PathBuf::from(value)),
174-
Err(error) => {
175-
dirs::home_dir()
176-
.map(|path| path.join(".cargo"))
177-
.ok_or(error)
178-
}
179-
}?;
180-
let old_path = crate::env::var("PATH")?;
181-
let new_path = std::env::join_paths(
182-
std::iter::once(Path::new(&cargo_home).join("bin"))
183-
.chain(std::env::split_paths(&old_path)),
184-
)?;
185-
cmd.envs(vec![("PATH", new_path)]);
186-
}
187-
188-
let manifest_arg = format!(
189-
"--manifest-path={}",
190-
ink_dylint_driver_dir.join("Cargo.toml").display()
191-
);
192-
let target_dir = format!("--target-dir={}", out_dir.display());
193-
cmd.args(vec![
194-
"build",
195-
"--release",
196-
"--locked",
197-
&target_dir,
198-
&manifest_arg,
199-
]);
200-
201-
// There are generally problems with having a custom `rustc` wrapper, while
202-
// executing `dylint` (which has a custom linker). Especially for `sccache`
203-
// there is this bug: https://github.com/mozilla/sccache/issues/1000.
204-
// Until we have a justification for leaving the wrapper we should unset it.
205-
cmd.env_remove("RUSTC_WRAPPER");
206-
207-
// We need to remove those environment variables because `dylint` uses a
208-
// fixed Rust toolchain via the `ink_linting/rust-toolchain` file. By removing
209-
// these env variables we avoid issues with different Rust toolchains
210-
// interfering with each other.
211-
cmd.env_remove("RUSTUP_TOOLCHAIN");
212-
cmd.env_remove("CARGO_TARGET_DIR");
213-
214-
// Dylint drivers need unstable features. Allow them on a stable toolchain.
215-
cmd.env("RUSTC_BOOTSTRAP", "1");
216-
217-
println!(
218-
"Setting cargo working dir to '{}'",
219-
ink_dylint_driver_dir.display()
220-
);
221-
cmd.current_dir(ink_dylint_driver_dir.clone());
222-
223-
println!("Invoking cargo: {:?}", cmd);
224-
225-
let child = cmd
226-
// Capture the stdout to return from this function as bytes
227-
.stdout(std::process::Stdio::piped())
228-
.spawn()?;
229-
let output = child.wait_with_output()?;
230-
231-
if !output.status.success() {
232-
anyhow::bail!(
233-
"`{:?}` failed with exit code: {:?}",
234-
cmd,
235-
output.status.code()
236-
);
237-
}
238-
239-
println!(
240-
"Creating ink-dylint-driver.zip: destination archive '{}'",
241-
dylint_driver_dst_file.display()
242-
);
243-
244-
zip_dylint_driver(
245-
&out_dir.join("release"),
246-
&dylint_driver_dst_file,
247-
CompressionMethod::Stored,
248-
)
249-
.map(|_| {
250-
println!(
251-
"Done: {} written to {}",
252-
ink_dylint_driver_dir.display(),
253-
dylint_driver_dst_file.display()
254-
);
255-
()
256-
})
257-
}
258-
25985
/// Creates a zip archive at `dst_file` with the content of the `src_dir`.
26086
fn zip_dir(src_dir: &Path, dst_file: &Path, method: CompressionMethod) -> Result<()> {
26187
if !src_dir.exists() {
@@ -303,66 +129,6 @@ fn zip_dir(src_dir: &Path, dst_file: &Path, method: CompressionMethod) -> Result
303129
Ok(())
304130
}
305131

306-
/// Creates a zip archive at `dst_file` with the `dylint` driver found in `src_dir`.
307-
///
308-
/// `dylint` drivers have a file name of the form `libink_linting@toolchain.[so,dll]`.
309-
#[cfg(not(feature = "cargo-clippy"))]
310-
fn zip_dylint_driver(
311-
src_dir: &Path,
312-
dst_file: &Path,
313-
method: CompressionMethod,
314-
) -> Result<()> {
315-
if !src_dir.exists() {
316-
anyhow::bail!("src_dir '{}' does not exist", src_dir.display());
317-
}
318-
if !src_dir.is_dir() {
319-
anyhow::bail!("src_dir '{}' is not a directory", src_dir.display());
320-
}
321-
322-
let file = File::create(dst_file)?;
323-
324-
let mut zip = ZipWriter::new(file);
325-
let options = FileOptions::default()
326-
.compression_method(method)
327-
.unix_permissions(DEFAULT_UNIX_PERMISSIONS);
328-
329-
let mut buffer = Vec::new();
330-
331-
let walkdir = WalkDir::new(src_dir);
332-
let it = walkdir.into_iter().filter_map(|e| e.ok());
333-
let regex = regex::Regex::new(r#"(lib)?ink_linting@.+\.(dll|so|dylib)"#)
334-
.expect("Regex is correct; qed");
335-
let mut lib_found = false;
336-
337-
for entry in it {
338-
let path = entry.path();
339-
let name = path.strip_prefix(&src_dir)?.to_path_buf();
340-
let file_path = name.as_os_str().to_string_lossy();
341-
342-
if path.is_file() && regex.is_match(&path.display().to_string()) {
343-
zip.start_file(file_path, options)?;
344-
let mut f = File::open(path)?;
345-
346-
f.read_to_end(&mut buffer)?;
347-
zip.write_all(&*buffer)?;
348-
buffer.clear();
349-
350-
zip.finish()?;
351-
lib_found = true;
352-
break
353-
}
354-
}
355-
356-
if !lib_found {
357-
anyhow::bail!(
358-
"Couldn't find compiled lint. Is your architecture ({}) defined in ./ink_linting/.cargo/config.toml?",
359-
std::env::var("TARGET").unwrap(),
360-
);
361-
}
362-
363-
Ok(())
364-
}
365-
366132
/// Generate the `cargo:` key output
367133
fn generate_cargo_keys() {
368134
let output = Command::new("git")
@@ -401,50 +167,3 @@ fn get_version(impl_commit: &str) -> String {
401167
current_platform::CURRENT_PLATFORM,
402168
)
403169
}
404-
405-
/// Checks if `dylint-link` is installed, i.e. if the `dylint-link` executable
406-
/// can be executed with a `--version` argument.
407-
fn check_dylint_link_installed() -> Result<()> {
408-
let which = which::which("dylint-link");
409-
if which.is_err() {
410-
anyhow::bail!(
411-
"dylint-link was not found!\n\
412-
Make sure it is installed and the binary is in your PATH environment.\n\n\
413-
You can install it by executing `cargo install dylint-link`."
414-
);
415-
}
416-
Ok(())
417-
}
418-
419-
mod tmp_file_guard {
420-
use std::path::PathBuf;
421-
422-
/// Holds the path to a file meant to be temporary.
423-
pub struct FileGuard {
424-
path: PathBuf,
425-
}
426-
427-
impl FileGuard {
428-
/// Create a new new file guard.
429-
///
430-
/// Once the object instance is dropped the file will be removed automatically.
431-
pub fn new(original_name: PathBuf, tmp_path: PathBuf) -> Self {
432-
std::fs::copy(&original_name, &tmp_path).unwrap_or_else(|err| {
433-
panic!(
434-
"Failed copying '{:?}' to '{:?}': {:?}",
435-
original_name, tmp_path, err
436-
)
437-
});
438-
Self { path: tmp_path }
439-
}
440-
}
441-
442-
impl Drop for FileGuard {
443-
// Once the struct instance is dropped we remove the file.
444-
fn drop(&mut self) {
445-
std::fs::remove_file(&self.path).unwrap_or_else(|err| {
446-
panic!("Failed removing '{:?}': {:?}", self.path, err)
447-
})
448-
}
449-
}
450-
}

0 commit comments

Comments
 (0)