adding working directory option on prjfmt.toml for each formatter (#59)

* adding working directory option on prjfmt.toml for each formatter

* rename workdir into work_dir

* switch from xshell into process::Command

* fix unordered command_context by changing to BTreeMap
This commit is contained in:
Andika Demas Riyandi 2021-02-19 23:02:33 +07:00 committed by GitHub
parent f53c70d5ac
commit 3ad67a3851
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 58 additions and 36 deletions

View File

@ -1,4 +1,4 @@
{
"nixEnvSelector.nixShellConfig": "${workspaceRoot}/shell.nix",
"files.trimFinalNewlines": true
"files.trimFinalNewlines": true,
"nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix"
}

16
Cargo.lock generated
View File

@ -610,7 +610,6 @@ dependencies = [
"structopt",
"toml",
"which",
"xshell",
]
[[package]]
@ -700,18 +699,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xshell"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed373ede30cea03e8c0af22f48ee1ba80efbf06fec8b4746977e6ee703878de0"
dependencies = [
"xshell-macros",
]
[[package]]
name = "xshell-macros"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6af9f8119104697b0105989a73c578ce33f922d9d6f3dae0e8ae3d538db321"

View File

@ -21,5 +21,4 @@ serde_json = "1.0"
sha-1 = "0.9.2"
structopt = "0.3"
toml = "0.5"
xshell = "0.1"
which = "4.0.2"

View File

@ -12,10 +12,11 @@ A formatter MUST adhere to the following interface:
```
Where
* `<command>` is the name of the formatter.
* `[options]` is any number of flags and options that the formatter wants to
provide.
* `[...<files>]` is one or more files that the formatter should process.
- `<command>` is the name of the formatter.
- `[options]` is any number of flags and options that the formatter wants to
provide.
- `[...<files>]` is one or more files that the formatter should process.
Whenever the program is invoked with the list of files, it MUST only process all the files that are passed and format them. Files that are not passed should never be formatted.

View File

@ -1,8 +1,6 @@
# A list of known formatters
| name | files as argument | write-in-place | update-mtime |
|-----------|-------------------|----------------|----------------------|
| --------- | ----------------- | -------------- | -------------------- |
| gofmt | yes | yes | keeps the same mtime |
| cargo fmt | no | yes | yes |

View File

@ -2,4 +2,4 @@
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.
- First version. Released on an unsuspecting world.

View File

@ -2,4 +2,4 @@
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.
- First version. Released on an unsuspecting world.

View File

@ -20,6 +20,8 @@ pub struct Root {
pub struct FmtConfig {
/// Command formatter to run
pub command: String,
/// Working directory for formatter
pub work_dir: Option<String>,
/// Argument for formatter
#[serde(default)]
pub options: Vec<String>,

View File

@ -9,8 +9,8 @@ use std::collections::BTreeSet;
use std::fs::metadata;
use std::iter::Iterator;
use std::path::PathBuf;
use std::process::Command;
use which::which;
use xshell::cmd;
/// Make sure that formatter binary exists. This also for other formatter
pub fn check_bin(command: &str) -> Result<()> {
@ -61,6 +61,10 @@ pub fn run_treefmt(cwd: PathBuf, cache_dir: PathBuf) -> anyhow::Result<()> {
for c in context {
if !c.metadata.is_empty() {
println!("Command: {}", c.command);
println!(
"Working Directory: {}",
c.work_dir.clone().unwrap_or("".to_string())
);
println!("Files:");
for m in &c.metadata {
let path = &m.path;
@ -71,17 +75,29 @@ pub fn run_treefmt(cwd: PathBuf, cache_dir: PathBuf) -> anyhow::Result<()> {
}
// TODO: report errors (both Err(_), and Ok(bad status))
let _outputs: Vec<xshell::Result<std::process::Output>> = context
let _outputs: Vec<std::io::Result<std::process::Output>> = context
.par_iter()
.map(|c| {
let arg = &c.options;
let cmd_arg = &c.command;
let mut cmd_arg = Command::new(&c.command);
let work_dir = match c.work_dir.clone() {
Some(x) => x,
None => String::new(),
};
let paths = c.metadata.iter().map(|f| &f.path);
cmd!("{cmd_arg} {arg...} {paths...}").output()
if !work_dir.is_empty() {
let _x = std::env::set_current_dir(work_dir);
cmd_arg.args(arg).args(paths).output()
} else {
let _x = std::env::set_current_dir(cwd.clone());
cmd_arg.args(arg).args(paths).output()
}
})
.collect();
if mfst.manifest.is_empty() || ctxs.is_empty() {
if mfst.manifest.is_empty() && ctxs.is_empty() {
CLOG.info("First time running treefmt");
CLOG.info("capturing formatted file's state...");
create_manifest(treefmt_toml, cache_dir, old_ctx)?;
} else {
// Read the current status of files and insert into the manifest.
@ -161,6 +177,7 @@ pub fn create_command_context(
Ok(CmdContext {
command: config.command.clone(),
options: config.options.clone(),
work_dir: config.work_dir.clone(),
metadata: path_to_filemeta(list_files)?,
})
})

View File

@ -30,6 +30,7 @@ pub fn create_manifest(
let treefmt = cmd.command;
let manifest = CmdContext {
command: treefmt.to_string(),
work_dir: cmd.work_dir,
options: cmd.options,
metadata: cmd.metadata,
};
@ -102,15 +103,32 @@ pub fn check_treefmt(
cache: &RootManifest,
) -> Result<Vec<CmdContext>> {
let cache_context = cache.manifest.values();
let results = cmd_context.iter().zip(cache_context);
let map_ctx: BTreeMap<String, CmdContext> = cmd_context
.into_iter()
.map(|cmd| {
let treefmt = cmd.command.clone();
let ctx = CmdContext {
command: treefmt.to_string(),
work_dir: cmd.work_dir.clone(),
options: cmd.options.clone(),
metadata: cmd.metadata.clone(),
};
(treefmt, ctx)
})
.collect();
let new_cmd_ctx = map_ctx.values();
let results = new_cmd_ctx.clone().into_iter().zip(cache_context);
let cache_context: Vec<CmdContext> = results
.clone()
.map(|(new, old)| {
Ok(CmdContext {
command: new.command.clone(),
work_dir: new.work_dir.clone(),
options: new.options.clone(),
metadata: if new.command != old.command || new.options != old.options {
metadata: if new.command != old.command
|| new.options != old.options
|| new.work_dir != old.work_dir
{
// If either the command or the options have changed, invalidate old entries
new.metadata.clone()
} else {

View File

@ -21,6 +21,8 @@ pub static CLOG: CustomLogOutput = CustomLogOutput::new();
pub struct CmdContext {
/// formatter command to run
pub command: String,
/// formatter work_dir
pub work_dir: Option<String>,
/// formatter arguments or flags
pub options: Vec<String>,
/// formatter target path
@ -30,6 +32,7 @@ pub struct CmdContext {
impl PartialEq for CmdContext {
fn eq(&self, other: &Self) -> bool {
self.command == other.command
&& self.work_dir == other.work_dir
&& self.options == other.options
&& self.metadata == other.metadata
}