From d9196f997f20d30adc39cdbf18e618d354d62400 Mon Sep 17 00:00:00 2001 From: khubo Date: Wed, 20 Oct 2021 08:38:06 +0530 Subject: [PATCH 01/16] change output flag to dir flag --- README.md | 4 ++-- src/cli.rs | 8 ++++---- src/lib.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index db008da..9951f9c 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ ouch decompress a.zip b.tar.gz c.tar ouch d a.zip ``` -You can redirect the decompression results to another folder with the `-o/--output` flag. +You can redirect the decompression results to another folder with the `-d/--dir` flag. ```sh # Decompress 'summer_vacation.zip' inside of new folder 'pictures' -ouch decompress summer_vacation.zip -o pictures +ouch decompress summer_vacation.zip -d pictures ``` ### Compressing diff --git a/src/cli.rs b/src/cli.rs index d507775..aaff61e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -124,7 +124,7 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { ParsedArgs { command, flags } } Some(&"d") | Some(&"decompress") => { - flags_info.push(arg_flag!('o', "output")); + flags_info.push(arg_flag!('d', "dir")); if let Some(first_arg) = args.first() { if is_typo(first_arg) { @@ -138,7 +138,7 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { let (files, flags) = oof::filter_flags(args, &flags_info)?; let files = files.into_iter().map(PathBuf::from).collect(); - let output_folder = flags.arg("output").map(PathBuf::from); + let output_folder = flags.arg("dir").map(PathBuf::from); // TODO: ensure all files are decompressible @@ -203,10 +203,10 @@ mod tests { assert_eq!(test_cli("--version").unwrap().flags, oof::Flags::default()); assert_eq!( - test_cli("decompress foo --yes bar --output folder").unwrap().flags, + test_cli("decompress foo --yes bar --dir folder").unwrap().flags, oof::Flags { boolean_flags: vec!["yes"].into_iter().collect(), - argument_flags: vec![("output", OsString::from("folder"))].into_iter().collect(), + argument_flags: vec![("dir", OsString::from("folder"))].into_iter().collect(), } ); } diff --git a/src/lib.rs b/src/lib.rs index 3c3830d..489ddf3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ fn help_command() { {yellow}--version{reset} Display version information. {cyan}SPECIFIC FLAGS:{reset} - {yellow}-o{reset}, {yellow}--output{reset} FOLDER_PATH When decompressing, to decompress files to + {yellow}-d{reset}, {yellow}--dir{reset} FOLDER_PATH When decompressing, to decompress files to another folder. Visit https://github.com/ouch-org/ouch for more usage examples.", From 7efac2e55da21b32a9ee8a140029321d4c86dd57 Mon Sep 17 00:00:00 2001 From: figsoda Date: Wed, 20 Oct 2021 19:13:25 -0400 Subject: [PATCH 02/16] generate completions --- Cargo.lock | 10 +++++++ Cargo.toml | 4 +++ build.rs | 22 ++++++++++++++++ src/archive/zip.rs | 2 +- src/cli.rs | 45 ++------------------------------ src/commands.rs | 3 +-- src/lib.rs | 6 +++-- src/main.rs | 2 +- src/opts.rs | 44 +++++++++++++++++++++++++++++++ tests/compress_and_decompress.rs | 5 +--- tests/utils.rs | 5 +--- 11 files changed, 91 insertions(+), 57 deletions(-) create mode 100644 build.rs create mode 100644 src/opts.rs diff --git a/Cargo.lock b/Cargo.lock index 68b82c9..758456c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,6 +114,15 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_generate" +version = "3.0.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "097ab5db1c3417442270cd57c8dd39f6c3114d3ce09d595f9efddbb1fcfaa799" +dependencies = [ + "clap", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -283,6 +292,7 @@ dependencies = [ "atty", "bzip2", "clap", + "clap_generate", "flate2", "infer", "libc", diff --git a/Cargo.toml b/Cargo.toml index c42ac8b..e9d9b02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,10 @@ zip = { version = "0.5.13", default-features = false, features = ["defl flate2 = { version = "1.0.22", default-features = false, features = ["zlib"] } zstd = { version = "0.9.0", default-features = false, features = ["thin"] } +[build-dependencies] +clap = "=3.0.0-beta.5" +clap_generate = "=3.0.0-beta.5" + [dev-dependencies] tempfile = "3.2.0" infer = "0.5.0" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..5372154 --- /dev/null +++ b/build.rs @@ -0,0 +1,22 @@ +use clap::{ArgEnum, IntoApp}; +use clap_generate::{generate_to, Shell}; + +use std::{env, fs::create_dir_all, path::Path}; + +include!("src/opts.rs"); + +fn main() { + println!("cargo:rerun-if-env-changed=GEN_COMPLETIONS"); + + if env::var_os("GEN_COMPLETIONS") != Some("1".into()) { + return; + } + + let out = &Path::new(&env::var_os("OUT_DIR").unwrap()).join("completions"); + create_dir_all(out).unwrap(); + let app = &mut Opts::into_app(); + + for shell in Shell::value_variants() { + generate_to(*shell, app, "ouch", out).unwrap(); + } +} diff --git a/src/archive/zip.rs b/src/archive/zip.rs index db35727..f15e650 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -11,7 +11,7 @@ use zip::{self, read::ZipFile, ZipArchive}; use crate::{ info, - utils::{self, dir_is_empty,strip_cur_dir, Bytes}, + utils::{self, dir_is_empty, strip_cur_dir, Bytes}, }; use self::utf8::get_invalid_utf8_paths; diff --git a/src/cli.rs b/src/cli.rs index 7a13aab..bd9a8de 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -5,50 +5,9 @@ use std::{ vec::Vec, }; -use clap::{Parser, ValueHint}; +use clap::Parser; -use crate::Error; - -#[derive(Parser, Debug)] -#[clap(version, about)] -pub struct Opts { - /// Skip overwrite questions positively. - #[clap(short, long, conflicts_with = "no")] - pub yes: bool, - - /// Skip overwrite questions negatively. - #[clap(short, long)] - pub no: bool, - - #[clap(subcommand)] - pub cmd: Subcommand, -} - -#[derive(Parser, PartialEq, Eq, Debug)] -pub enum Subcommand { - /// Compress files. Alias: c - #[clap(alias = "c")] - Compress { - /// Files to be compressed - #[clap(required = true, min_values = 1)] - files: Vec, - - /// The resulting file. Its extensions specify how the files will be compressed and they need to be supported - #[clap(required = true, value_hint = ValueHint::FilePath)] - output: PathBuf, - }, - /// Compress files. Alias: d - #[clap(alias = "d")] - Decompress { - /// Files to be decompressed - #[clap(required = true, min_values = 1)] - files: Vec, - - /// Decompress files in a directory other than the current - #[clap(short, long, value_hint = ValueHint::DirPath)] - output: Option, - }, -} +use crate::{Error, Opts, Subcommand}; impl Opts { /// A helper method that calls `clap::Parser::parse` and then translates relative paths to absolute. diff --git a/src/commands.rs b/src/commands.rs index 6d41347..b4e6fab 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -12,7 +12,6 @@ use utils::colors; use crate::{ archive, - cli::{Opts, Subcommand}, error::FinalError, extension::{ self, @@ -22,7 +21,7 @@ use crate::{ utils::nice_directory_display, utils::to_utf, utils::{self, dir_is_empty}, - Error, + Error, Opts, Subcommand, }; // Used in BufReader and BufWriter to perform less syscalls diff --git a/src/lib.rs b/src/lib.rs index 9a1a795..d0650e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,18 +5,20 @@ //! 2. It's required by some integration tests at tests/ folder. // Public modules -pub mod cli; +pub mod archive; pub mod commands; // Private modules -pub mod archive; +mod cli; mod dialogs; mod error; mod extension; mod macros; +mod opts; mod utils; pub use error::{Error, Result}; +pub use opts::{Opts, Subcommand}; /// The status code ouch has when an error is encountered pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE; diff --git a/src/main.rs b/src/main.rs index 9fc88ec..eb886f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use ouch::{cli::Opts, commands, Result}; +use ouch::{commands, Opts, Result}; fn main() { if let Err(err) = run() { diff --git a/src/opts.rs b/src/opts.rs new file mode 100644 index 0000000..6d414a8 --- /dev/null +++ b/src/opts.rs @@ -0,0 +1,44 @@ +use clap::{Parser, ValueHint}; + +use std::path::PathBuf; + +#[derive(Parser, Debug)] +#[clap(version, about)] +pub struct Opts { + /// Skip overwrite questions positively. + #[clap(short, long, conflicts_with = "no")] + pub yes: bool, + + /// Skip overwrite questions negatively. + #[clap(short, long)] + pub no: bool, + + #[clap(subcommand)] + pub cmd: Subcommand, +} + +#[derive(Parser, PartialEq, Eq, Debug)] +pub enum Subcommand { + /// Compress files. Alias: c + #[clap(alias = "c")] + Compress { + /// Files to be compressed + #[clap(required = true, min_values = 1)] + files: Vec, + + /// The resulting file. Its extensions specify how the files will be compressed and they need to be supported + #[clap(required = true, value_hint = ValueHint::FilePath)] + output: PathBuf, + }, + /// Compress files. Alias: d + #[clap(alias = "d")] + Decompress { + /// Files to be decompressed + #[clap(required = true, min_values = 1)] + files: Vec, + + /// Decompress files in a directory other than the current + #[clap(short, long, value_hint = ValueHint::DirPath)] + output: Option, + }, +} diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 77d929d..71e5d13 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -7,10 +7,7 @@ use std::{ time::Duration, }; -use ouch::{ - cli::{Opts, Subcommand}, - commands::run, -}; +use ouch::{commands::run, Opts, Subcommand}; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use tempfile::NamedTempFile; use utils::*; diff --git a/tests/utils.rs b/tests/utils.rs index 10cc749..ad3bdf4 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -7,10 +7,7 @@ use std::{ path::{Path, PathBuf}, }; -use ouch::{ - cli::{Opts, Subcommand}, - commands::run, -}; +use ouch::{commands::run, Opts, Subcommand}; pub fn create_empty_dir(at: &Path, filename: &str) -> PathBuf { let dirname = Path::new(filename); From bce6ae279741b595286539ab2ac47b60516d3427 Mon Sep 17 00:00:00 2001 From: figsoda Date: Wed, 20 Oct 2021 19:27:18 -0400 Subject: [PATCH 03/16] generate completions and man page in ci --- .github/workflows/build.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f6592f..466dc9f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -104,13 +104,15 @@ jobs: - name: Install dependencies for musl libc run: | sudo apt-get update - sudo apt-get install musl-tools + sudo apt-get install help2man musl-tools - name: Run cargo build uses: actions-rs/cargo@v1 with: command: build args: --release --target x86_64-unknown-linux-musl + env: + GEN_COMPLETIONS: 1 - name: Run cargo test uses: actions-rs/cargo@v1 @@ -118,6 +120,11 @@ jobs: command: test args: --target x86_64-unknown-linux-musl + - name: Build man page and find completions + run: | + help2man target/x86_64-unknown-linux-musl/release/ouch > ouch.1 + cp -r target/x86_64-unknown-linux-musl/release/build/ouch-*/out/completions . + - name: Strip binary run: strip target/x86_64-unknown-linux-musl/release/ouch @@ -127,6 +134,17 @@ jobs: name: 'ouch-x86_64-linux-musl' path: target/x86_64-unknown-linux-musl/release/ouch + - name: Upload completions + uses: actions/upload-artifact@v2 + with: + name: completions + path: completions + + - name: Upload man page + uses: actions/upload-artifact@v2 + with: + name: ouch.1 + path: ouch.1 x86_64_glibc: name: Ubuntu 20.04 (glibc) From 340827de1f4944c99ed0411f382fb388ae9304f7 Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Thu, 21 Oct 2021 19:17:14 +0300 Subject: [PATCH 04/16] Introduce `is_archive_format` method on `CompressionFormat` --- src/extension.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/extension.rs b/src/extension.rs index b1828f0..87efbc6 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -19,6 +19,12 @@ pub enum CompressionFormat { Zip, // .zip } +impl CompressionFormat { + pub fn is_archive_format(&self) -> bool { + matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zstd | Zip) + } +} + impl fmt::Display for CompressionFormat { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( From 0f3bc4f444f66c993802d04a877b9c3f3b315ddd Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:04:08 +0300 Subject: [PATCH 05/16] Use the new method were applicable --- src/commands.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 6d41347..d98d297 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -56,7 +56,9 @@ pub fn run(args: Opts, skip_questions_positively: Option) -> crate::Result return Err(Error::with_reason(reason)); } - if matches!(&formats[0], Bzip | Gzip | Lzma) && represents_several_files(&files) { + if !formats.get(0).map(CompressionFormat::is_archive_format).unwrap_or(false) + && represents_several_files(&files) + { // This piece of code creates a suggestion for compressing multiple files // It says: // Change from file.bz.xz @@ -84,7 +86,7 @@ pub fn run(args: Opts, skip_questions_positively: Option) -> crate::Result return Err(Error::with_reason(reason)); } - if let Some(format) = formats.iter().skip(1).find(|format| matches!(format, Tar | Zip)) { + if let Some(format) = formats.iter().skip(1).find(|format| format.is_archive_format()) { let reason = FinalError::with_title(format!("Cannot compress to '{}'.", to_utf(&output_path))) .detail(format!("Found the format '{}' in an incorrect position.", format)) .detail(format!("'{}' can only be used at the start of the file extension.", format)) From 91a1054c3c8f6c2f42b0ea0fb811a54835c73837 Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:05:38 +0300 Subject: [PATCH 06/16] Remove duplicated if/else branches --- src/commands.rs | 142 +++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 81 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index d98d297..2a627dd 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -188,94 +188,74 @@ pub fn run(args: Opts, skip_questions_positively: Option) -> crate::Result fn compress_files(files: Vec, formats: Vec, output_file: fs::File) -> crate::Result<()> { let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file); - if let [Tar | Tgz | Zip] = *formats.as_slice() { - match formats[0] { - Tar => { - let mut bufwriter = archive::tar::build_archive_from_paths(&files, file_writer)?; - bufwriter.flush()?; - } - Tgz => { - // Wrap it into an gz_decoder, and pass to the tar archive builder - let gz_decoder = flate2::write::GzEncoder::new(file_writer, Default::default()); - let mut bufwriter = archive::tar::build_archive_from_paths(&files, gz_decoder)?; - bufwriter.flush()?; - } - Zip => { - let mut bufwriter = archive::zip::build_archive_from_paths(&files, file_writer)?; - bufwriter.flush()?; + let mut writer: Box = Box::new(file_writer); + + // Grab previous encoder and wrap it inside of a new one + let chain_writer_encoder = |format: &CompressionFormat, encoder: Box| { + let encoder: Box = match format { + Gzip => Box::new(flate2::write::GzEncoder::new(encoder, Default::default())), + Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())), + Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)), + Zstd => { + let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default()); + // Safety: + // Encoder::new() can only fail if `level` is invalid, but Default::default() + // is guaranteed to be valid + Box::new(zstd_encoder.unwrap().auto_finish()) } _ => unreachable!(), }; - } else { - let mut writer: Box = Box::new(file_writer); + encoder + }; - // Grab previous encoder and wrap it inside of a new one - let chain_writer_encoder = |format: &CompressionFormat, encoder: Box| { - let encoder: Box = match format { - Gzip => Box::new(flate2::write::GzEncoder::new(encoder, Default::default())), - Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())), - Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)), - Zstd => { - let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default()); - // Safety: - // Encoder::new() can only fail if `level` is invalid, but Default::default() - // is guaranteed to be valid - Box::new(zstd_encoder.unwrap().auto_finish()) - } - _ => unreachable!(), - }; - encoder - }; + for format in formats.iter().skip(1).rev() { + writer = chain_writer_encoder(format, writer); + } - for format in formats.iter().skip(1).rev() { - writer = chain_writer_encoder(format, writer); + match formats[0] { + Gzip | Bzip | Lzma | Zstd => { + writer = chain_writer_encoder(&formats[0], writer); + let mut reader = fs::File::open(&files[0]).unwrap(); + io::copy(&mut reader, &mut writer)?; } + Tar => { + let mut writer = archive::tar::build_archive_from_paths(&files, writer)?; + writer.flush()?; + } + Tgz => { + let encoder = flate2::write::GzEncoder::new(writer, Default::default()); + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Tbz => { + let encoder = bzip2::write::BzEncoder::new(writer, Default::default()); + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Tlzma => { + let encoder = xz2::write::XzEncoder::new(writer, 6); + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Tzst => { + let encoder = zstd::stream::write::Encoder::new(writer, Default::default())?; + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Zip => { + eprintln!("{yellow}Warning:{reset}", yellow = *colors::YELLOW, reset = *colors::RESET); + eprintln!("\tCompressing .zip entirely in memory."); + eprintln!("\tIf the file is too big, your PC might freeze!"); + eprintln!( + "\tThis is a limitation for formats like '{}'.", + formats.iter().map(|format| format.to_string()).collect::() + ); + eprintln!("\tThe design of .zip makes it impossible to compress via stream."); - match formats[0] { - Gzip | Bzip | Lzma | Zstd => { - writer = chain_writer_encoder(&formats[0], writer); - let mut reader = fs::File::open(&files[0]).unwrap(); - io::copy(&mut reader, &mut writer)?; - } - Tar => { - let mut writer = archive::tar::build_archive_from_paths(&files, writer)?; - writer.flush()?; - } - Tgz => { - let encoder = flate2::write::GzEncoder::new(writer, Default::default()); - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Tbz => { - let encoder = bzip2::write::BzEncoder::new(writer, Default::default()); - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Tlzma => { - let encoder = xz2::write::XzEncoder::new(writer, 6); - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Tzst => { - let encoder = zstd::stream::write::Encoder::new(writer, Default::default())?; - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Zip => { - eprintln!("{yellow}Warning:{reset}", yellow = *colors::YELLOW, reset = *colors::RESET); - eprintln!("\tCompressing .zip entirely in memory."); - eprintln!("\tIf the file is too big, your PC might freeze!"); - eprintln!( - "\tThis is a limitation for formats like '{}'.", - formats.iter().map(|format| format.to_string()).collect::() - ); - eprintln!("\tThe design of .zip makes it impossible to compress via stream."); - - let mut vec_buffer = io::Cursor::new(vec![]); - archive::zip::build_archive_from_paths(&files, &mut vec_buffer)?; - let vec_buffer = vec_buffer.into_inner(); - io::copy(&mut vec_buffer.as_slice(), &mut writer)?; - } + let mut vec_buffer = io::Cursor::new(vec![]); + archive::zip::build_archive_from_paths(&files, &mut vec_buffer)?; + let vec_buffer = vec_buffer.into_inner(); + io::copy(&mut vec_buffer.as_slice(), &mut writer)?; } } From d6054ba3eef7cc11a00afa7749fdc306c5acab83 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 21 Oct 2021 19:05:48 -0400 Subject: [PATCH 07/16] move QuestionPolicy to lib --- src/archive/tar.rs | 3 ++- src/archive/zip.rs | 3 ++- src/cli.rs | 3 +-- src/commands.rs | 6 ++---- src/lib.rs | 1 + tests/compress_and_decompress.rs | 2 +- tests/utils.rs | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/archive/tar.rs b/src/archive/tar.rs index bb52d7e..7106392 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -11,7 +11,8 @@ use walkdir::WalkDir; use crate::{ info, - utils::{self, Bytes, QuestionPolicy}, + utils::{self, Bytes}, + QuestionPolicy, }; pub fn unpack_archive( diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 87d1a17..3cce681 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -11,7 +11,8 @@ use zip::{self, read::ZipFile, ZipArchive}; use crate::{ info, - utils::{self, dir_is_empty, strip_cur_dir, Bytes, QuestionPolicy}, + utils::{self, dir_is_empty, strip_cur_dir, Bytes}, + QuestionPolicy, }; use self::utf8::get_invalid_utf8_paths; diff --git a/src/cli.rs b/src/cli.rs index 256424b..7f57c14 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -7,8 +7,7 @@ use std::{ use clap::Parser; -pub use crate::utils::QuestionPolicy; -use crate::{Error, Opts, Subcommand}; +use crate::{Error, Opts, QuestionPolicy, Subcommand}; impl Opts { /// A helper method that calls `clap::Parser::parse` and then translates relative paths to absolute. diff --git a/src/commands.rs b/src/commands.rs index aa538a9..75de550 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -18,10 +18,8 @@ use crate::{ CompressionFormat::{self, *}, }, info, - utils::nice_directory_display, - utils::to_utf, - utils::{self, dir_is_empty, QuestionPolicy}, - Error, Opts, Subcommand, + utils::{self, dir_is_empty, nice_directory_display, to_utf}, + Error, Opts, QuestionPolicy, Subcommand, }; // Used in BufReader and BufWriter to perform less syscalls diff --git a/src/lib.rs b/src/lib.rs index d0650e0..c6f5a07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ mod utils; pub use error::{Error, Result}; pub use opts::{Opts, Subcommand}; +pub use utils::QuestionPolicy; /// The status code ouch has when an error is encountered pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE; diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index d1344e9..6422953 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -7,7 +7,7 @@ use std::{ time::Duration, }; -use ouch::{cli::QuestionPolicy, commands::run, Opts, Subcommand}; +use ouch::{commands::run, Opts, QuestionPolicy, Subcommand}; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use tempfile::NamedTempFile; use utils::*; diff --git a/tests/utils.rs b/tests/utils.rs index b51de5d..9ee7c7c 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -7,7 +7,7 @@ use std::{ path::{Path, PathBuf}, }; -use ouch::{cli::QuestionPolicy, commands::run, Opts, Subcommand}; +use ouch::{commands::run, Opts, QuestionPolicy, Subcommand}; pub fn create_empty_dir(at: &Path, filename: &str) -> PathBuf { let dirname = Path::new(filename); From 0ed684186598a7e840e87c4c27aa34448c10e99d Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:14:04 +0300 Subject: [PATCH 08/16] Fix tests so they don't use `tar.zst` --- tests/compress_and_decompress.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 77d929d..0a34f47 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -32,7 +32,7 @@ fn sanity_check_through_mime() { let formats = [ "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma", - "tar.xz", "tar.zst", + "tar.xz", "zst", ]; let expected_mimes = [ @@ -79,7 +79,6 @@ fn test_each_format() { test_compressing_and_decompressing_archive("tar.xz"); test_compressing_and_decompressing_archive("tar.lz"); test_compressing_and_decompressing_archive("tar.lzma"); - test_compressing_and_decompressing_archive("tar.zst"); test_compressing_and_decompressing_archive("tgz"); test_compressing_and_decompressing_archive("tbz"); test_compressing_and_decompressing_archive("tbz2"); @@ -97,7 +96,7 @@ fn test_each_format() { // Why not test_compressing_and_decompressing_archive( - "tar.gz.gz.gz.gz.gz.gz.gz.gz.zst.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz", + "tar.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz", ); } From bdf5090844ed267621ab9e3e9bdda6de6a05b68a Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:21:31 +0300 Subject: [PATCH 09/16] zst is not an archive format.. --- src/archive/zip.rs | 2 +- src/extension.rs | 2 +- tests/compress_and_decompress.rs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/archive/zip.rs b/src/archive/zip.rs index db35727..f15e650 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -11,7 +11,7 @@ use zip::{self, read::ZipFile, ZipArchive}; use crate::{ info, - utils::{self, dir_is_empty,strip_cur_dir, Bytes}, + utils::{self, dir_is_empty, strip_cur_dir, Bytes}, }; use self::utf8::get_invalid_utf8_paths; diff --git a/src/extension.rs b/src/extension.rs index 87efbc6..9ff200f 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -21,7 +21,7 @@ pub enum CompressionFormat { impl CompressionFormat { pub fn is_archive_format(&self) -> bool { - matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zstd | Zip) + matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zip) } } diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 0a34f47..77d929d 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -32,7 +32,7 @@ fn sanity_check_through_mime() { let formats = [ "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma", - "tar.xz", "zst", + "tar.xz", "tar.zst", ]; let expected_mimes = [ @@ -79,6 +79,7 @@ fn test_each_format() { test_compressing_and_decompressing_archive("tar.xz"); test_compressing_and_decompressing_archive("tar.lz"); test_compressing_and_decompressing_archive("tar.lzma"); + test_compressing_and_decompressing_archive("tar.zst"); test_compressing_and_decompressing_archive("tgz"); test_compressing_and_decompressing_archive("tbz"); test_compressing_and_decompressing_archive("tbz2"); @@ -96,7 +97,7 @@ fn test_each_format() { // Why not test_compressing_and_decompressing_archive( - "tar.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz", + "tar.gz.gz.gz.gz.gz.gz.gz.gz.zst.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz", ); } From 01b6dc89deddbf638e587c870c453bca6b6bed1f Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Wed, 27 Oct 2021 15:58:31 +0200 Subject: [PATCH 10/16] Check the format with Github Action (#126) * Add cargo fmt to the CI Use a job to check the format of the sourcecode with `cargo fmt` command. The new step does not change any code, but returns an error when `check` does not pass with 0 issues. --- .github/workflows/build.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f6592f..aa0f697 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -274,3 +274,26 @@ jobs: # with: # name: 'ouch-x86_64-pc-windows-gnu' # path: target\x86_64-pc-windows-gnu\release\ouch.exe + + fmt: + name: Check sourcecode format + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + target: x86_64-unknown-linux-musl + components: rustfmt + override: true + + - name: Check format with cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check From 2d84686b25228f06de37128712ef42cfab2b95b4 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Fri, 29 Oct 2021 19:14:16 +0200 Subject: [PATCH 11/16] feat: write only one time the info on stdout --- src/commands.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 2543c67..a73982d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -346,31 +346,25 @@ fn decompress_file( let mut writer = fs::File::create(&output_path)?; io::copy(&mut reader, &mut writer)?; - info!("Successfully decompressed archive in {}.", nice_directory_display(output_path)); } Tar => { let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; - info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); } Tgz => { let reader = chain_reader_decoder(&Gzip, reader)?; let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; - info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); } Tbz => { let reader = chain_reader_decoder(&Bzip, reader)?; let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; - info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); } Tlzma => { let reader = chain_reader_decoder(&Lzma, reader)?; let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; - info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); } Tzst => { let reader = chain_reader_decoder(&Zstd, reader)?; let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; - info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); } Zip => { eprintln!("Compressing first into .zip."); @@ -385,10 +379,10 @@ fn decompress_file( let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?; let _ = crate::archive::zip::unpack_archive(zip_archive, output_folder, question_policy)?; - - info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); } } + info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); + Ok(()) } From 09c28301903f2e6199f43e125dcc234ce474d34d Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Fri, 29 Oct 2021 19:21:17 +0200 Subject: [PATCH 12/16] feat: print number of unpacked files --- src/commands.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index a73982d..5b68ecc 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -338,6 +338,8 @@ fn decompress_file( utils::create_dir_if_non_existent(output_folder)?; + let files_unpacked; + match formats[0] { Gzip | Bzip | Lzma | Zstd => { reader = chain_reader_decoder(&formats[0], reader)?; @@ -346,25 +348,26 @@ fn decompress_file( let mut writer = fs::File::create(&output_path)?; io::copy(&mut reader, &mut writer)?; + files_unpacked = vec![output_path]; } Tar => { - let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; + files_unpacked = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; } Tgz => { let reader = chain_reader_decoder(&Gzip, reader)?; - let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; + files_unpacked = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; } Tbz => { let reader = chain_reader_decoder(&Bzip, reader)?; - let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; + files_unpacked = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; } Tlzma => { let reader = chain_reader_decoder(&Lzma, reader)?; - let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; + files_unpacked = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; } Tzst => { let reader = chain_reader_decoder(&Zstd, reader)?; - let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; + files_unpacked = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?; } Zip => { eprintln!("Compressing first into .zip."); @@ -378,11 +381,12 @@ fn decompress_file( io::copy(&mut reader, &mut vec)?; let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?; - let _ = crate::archive::zip::unpack_archive(zip_archive, output_folder, question_policy)?; + files_unpacked = crate::archive::zip::unpack_archive(zip_archive, output_folder, question_policy)?; } } info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder)); + info!("Files unpacked: {}", files_unpacked.len()); Ok(()) } From 09b050d836596fb6f0ae3e0b2f796812d75b359b Mon Sep 17 00:00:00 2001 From: Gabriel Simonetto Date: Thu, 14 Oct 2021 20:10:07 -0300 Subject: [PATCH 13/16] Introduce fs_err as a replacement for fs --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/archive/tar.rs | 19 ++++++++++++++++--- src/archive/zip.rs | 7 +++++-- src/cli.rs | 4 +++- src/commands.rs | 2 +- src/utils.rs | 5 +++-- tests/compress_and_decompress.rs | 4 +++- tests/utils.rs | 7 +++---- 9 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc1dcff..cf92250 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fs-err" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ebd3504ad6116843b8375ad70df74e7bfe83cac77a1f3fe73200c844d43bfe0" + [[package]] name = "getrandom" version = "0.2.3" @@ -206,6 +212,7 @@ dependencies = [ "atty", "bzip2", "flate2", + "fs-err", "infer", "lazy_static", "libc", diff --git a/Cargo.toml b/Cargo.toml index f1d3a9f..4d8320e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ description = "A command-line utility for easily compressing and decompressing f [dependencies] atty = "0.2.14" +fs-err = "2.6.0" lazy_static = "1.4.0" walkdir = "2.3.2" strsim = "0.10.0" diff --git a/src/archive/tar.rs b/src/archive/tar.rs index a5fa6f0..0536841 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -1,17 +1,19 @@ //! Contains Tar-specific building and unpacking functions use std::{ - env, fs, + env, io::prelude::*, path::{Path, PathBuf}, }; +use fs_err as fs; use tar; use walkdir::WalkDir; use crate::{ + error::FinalError, info, oof, - utils::{self, Bytes}, + utils::{self, to_utf, Bytes}, }; pub fn unpack_archive(reader: Box, output_folder: &Path, flags: &oof::Flags) -> crate::Result> { @@ -58,7 +60,18 @@ where builder.append_dir(path, path)?; } else { let mut file = fs::File::open(path)?; - builder.append_file(path, &mut file)?; + dbg!(&path); + dbg!(&file); + dbg!(&entry); + dbg!(&previous_location); + dbg!(&filename); + + // builder.append_file(path, file.file_mut())?; + builder.append_file(path, file.file_mut()).map_err(|err| { + FinalError::with_title(format!("Could not create archive '{}'", to_utf(path.clone()))) // output_path == writer? da + .detail(format!("Unexpected error while trying to read file '{}'", to_utf(output_path))) + .detail(format!("Error: {}.", err)) + })?; } } env::set_current_dir(previous_location)?; diff --git a/src/archive/zip.rs b/src/archive/zip.rs index be47ea8..1b07c20 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -1,11 +1,13 @@ //! Contains Zip-specific building and unpacking functions use std::{ - env, fs, + env, io::{self, prelude::*}, path::{Path, PathBuf}, }; +use fs_err as fs; + use walkdir::WalkDir; use zip::{self, read::ZipFile, ZipArchive}; @@ -121,10 +123,11 @@ fn check_for_comments(file: &ZipFile) { #[cfg(unix)] fn __unix_set_permissions(file_path: &Path, file: &ZipFile) -> crate::Result<()> { + use std::fs::Permissions; use std::os::unix::fs::PermissionsExt; if let Some(mode) = file.unix_mode() { - fs::set_permissions(file_path, fs::Permissions::from_mode(mode))?; + fs::set_permissions(file_path, Permissions::from_mode(mode))?; } Ok(()) diff --git a/src/cli.rs b/src/cli.rs index 9ff64c6..8d93c01 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,6 +9,8 @@ use std::{ vec::Vec, }; +use fs_err as fs; + use strsim::normalized_damerau_levenshtein; use crate::{arg_flag, flag, oof, Error}; @@ -73,7 +75,7 @@ fn is_typo(path: impl AsRef) -> bool { } fn canonicalize(path: impl AsRef) -> crate::Result { - match std::fs::canonicalize(&path.as_ref()) { + match fs::canonicalize(&path.as_ref()) { Ok(abs_path) => Ok(abs_path), Err(io_err) => { if !path.as_ref().exists() { diff --git a/src/commands.rs b/src/commands.rs index bf278b6..b97338c 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3,11 +3,11 @@ //! Also, where correctly call functions based on the detected `Command`. use std::{ - fs, io::{self, BufReader, BufWriter, Read, Write}, path::{Path, PathBuf}, }; +use fs_err as fs; use utils::colors; use crate::{ diff --git a/src/utils.rs b/src/utils.rs index a03d227..6c2b214 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,15 +1,16 @@ use std::{ cmp, env, ffi::OsStr, - fs::{self, ReadDir}, path::{Path, PathBuf}, }; +use fs_err as fs; + use crate::{dialogs::Confirmation, info, oof}; /// Checks if the given path represents an empty directory. pub fn dir_is_empty(dir_path: &Path) -> bool { - let is_empty = |mut rd: ReadDir| rd.next().is_none(); + let is_empty = |mut rd: std::fs::ReadDir| rd.next().is_none(); dir_path.read_dir().ok().map(is_empty).unwrap_or_default() } diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 22b99fc..3879e2b 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -1,12 +1,14 @@ mod utils; use std::{ - env, fs, + env, io::prelude::*, path::{Path, PathBuf}, time::Duration, }; +use fs_err as fs; + use ouch::{cli::Command, commands::run, oof}; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use tempfile::NamedTempFile; diff --git a/tests/utils.rs b/tests/utils.rs index 3ab9831..60d1ea3 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -2,10 +2,9 @@ #![allow(dead_code)] -use std::{ - fs, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; + +use fs_err as fs; use ouch::{cli::Command, commands::run, oof}; From 6c6f721f352e708f199f6aad6f8d40aaada2db9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20M=2E=20Bezerra?= Date: Fri, 29 Oct 2021 17:27:48 -0300 Subject: [PATCH 14/16] Solved FinalError compile errors --- src/archive/tar.rs | 14 ++++---------- src/error.rs | 6 ++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 0536841..e92c31d 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -13,7 +13,7 @@ use walkdir::WalkDir; use crate::{ error::FinalError, info, oof, - utils::{self, to_utf, Bytes}, + utils::{self, Bytes}, }; pub fn unpack_archive(reader: Box, output_folder: &Path, flags: &oof::Flags) -> crate::Result> { @@ -60,17 +60,11 @@ where builder.append_dir(path, path)?; } else { let mut file = fs::File::open(path)?; - dbg!(&path); - dbg!(&file); - dbg!(&entry); - dbg!(&previous_location); - dbg!(&filename); - - // builder.append_file(path, file.file_mut())?; builder.append_file(path, file.file_mut()).map_err(|err| { - FinalError::with_title(format!("Could not create archive '{}'", to_utf(path.clone()))) // output_path == writer? da - .detail(format!("Unexpected error while trying to read file '{}'", to_utf(output_path))) + FinalError::with_title("Could not create archive") + .detail("Unexpected error while trying to read file") .detail(format!("Error: {}.", err)) + .into_owned() })?; } } diff --git a/src/error.rs b/src/error.rs index 3792bfb..b84220a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -205,3 +205,9 @@ impl From for Error { Self::OofError(err) } } + +impl From for Error { + fn from(err: FinalError) -> Self { + Self::Custom { reason: err } + } +} From d1c905cda489275afc8ba13da9a1da5fab6af705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20M=2E=20Bezerra?= Date: Fri, 29 Oct 2021 17:35:53 -0300 Subject: [PATCH 15/16] Improving permission denied error message --- src/error.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index b84220a..090c2ec 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,7 +21,7 @@ pub enum Error { FileNotFound(PathBuf), AlreadyExists, InvalidZipArchive(&'static str), - PermissionDenied, + PermissionDenied { error_title: String }, UnsupportedZipArchive(&'static str), InternalError, OofError(oof::OofError), @@ -156,7 +156,9 @@ impl fmt::Display for Error { Error::UnknownExtensionError(_) => todo!(), Error::AlreadyExists => todo!(), Error::InvalidZipArchive(_) => todo!(), - Error::PermissionDenied => todo!(), + Error::PermissionDenied { error_title } => { + FinalError::with_title(error_title).detail("Permission denied").to_owned() + } Error::UnsupportedZipArchive(_) => todo!(), Error::Custom { reason } => reason.clone(), }; @@ -174,8 +176,8 @@ impl Error { impl From for Error { fn from(err: std::io::Error) -> Self { match err.kind() { - std::io::ErrorKind::NotFound => panic!("{}", err), - std::io::ErrorKind::PermissionDenied => Self::PermissionDenied, + std::io::ErrorKind::NotFound => todo!(), + std::io::ErrorKind::PermissionDenied => Self::PermissionDenied { error_title: err.to_string() }, std::io::ErrorKind::AlreadyExists => Self::AlreadyExists, _other => Self::IoError { reason: err.to_string() }, } From 038da118ecc0d9fc844bac5d1921528035e2b862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Marcos=20Bezerra?= Date: Sun, 31 Oct 2021 02:15:40 -0300 Subject: [PATCH 16/16] Update CONTRIBUTING.md (#132) --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 67be18c..1bf3f44 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,12 +4,12 @@ Feel free to open an issue anytime you wish to ask a question, suggest a feature # Requirements -1. Be kind, considerate and respectfull. -2. If editing .rs files, run `rustfmt` on them before commiting. +1. Be nice to other people. +2. If editing the Rust source code, remember to run `rustfmt` (otherwise, CI will warn you the code was not properly formatted). -Note that we are using `unstable` features of `rustfmt`, so you will need to change your toolchain to nightly. +Note: we are using `unstable` features of `rustfmt`! Nightly toolchain is required (will likely be installed automatically, cause the toolchain was specified in the project root). # Suggestions -1. Ask for some guidance before solving an error if you feel like it. -2. If editing Rust code, run `clippy` before commiting. +1. If you wish to, you can ask for some guidance before solving an issue. +2. Run `cargo clippy` too.