Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update(history): update history file format to handler multiple task runner like pnpm, yarn, e.t.c. #315 #324

Merged
merged 36 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
788bb4b
empty commit
kyu08 Nov 11, 2024
f73d90a
wip
kyu08 Nov 13, 2024
769f6d6
wip
kyu08 Nov 14, 2024
46c2bdd
wip
kyu08 Nov 14, 2024
b463c4c
wip
kyu08 Nov 17, 2024
1ac8e26
wip
kyu08 Nov 18, 2024
1eca854
wip
kyu08 Nov 18, 2024
0cdff02
wip
kyu08 Nov 22, 2024
d497772
read history
kyu08 Nov 23, 2024
1528c7b
write history
kyu08 Nov 23, 2024
be28765
append_history
kyu08 Nov 23, 2024
1b892af
delete unnecessary code
kyu08 Nov 23, 2024
d2e452a
specify_makefile_name: receive current_dir as an argument instead of …
kyu08 Nov 23, 2024
3e64452
delete unnecessary code
kyu08 Nov 23, 2024
4e3fb73
fix comment
kyu08 Nov 23, 2024
3a27495
use command.runner_type.to_runner instead of s.runners[0]
kyu08 Nov 23, 2024
c3901ac
SelectTargetState.histories: Add comment
kyu08 Nov 24, 2024
73ce55e
add pretty_assertions
kyu08 Nov 24, 2024
efaebab
rename
kyu08 Nov 24, 2024
4152334
histories.append
kyu08 Nov 24, 2024
bc61ca9
history.append
kyu08 Nov 24, 2024
43bf4da
comment in tests temporary disabled
kyu08 Nov 24, 2024
d9a71bd
rename: target -> command
kyu08 Nov 24, 2024
7af110f
Add a comment tells that the the commands are sorted by executed time…
kyu08 Nov 24, 2024
067a1af
format import statements
kyu08 Nov 24, 2024
a5acdc6
remove unnecessary comment
kyu08 Nov 24, 2024
4687b7e
make `content_to_include_file_paths` private
kyu08 Nov 24, 2024
9f46fae
delete unnecessary path specification
kyu08 Nov 24, 2024
b19cddc
make.rs: rename create_makefile to new, new to new_internal
kyu08 Nov 24, 2024
8ed1f59
change format to display command: (runner_type) name -> [runner_type]…
kyu08 Nov 24, 2024
b056ea2
model/histories.rs: fix comment
kyu08 Nov 24, 2024
50a85c5
make some methods private
kyu08 Nov 24, 2024
0e206e9
rename var name
kyu08 Nov 24, 2024
c655f91
rename: store_history -> create_or_update_history_file
kyu08 Nov 24, 2024
27cfea5
delete unnecessary code
kyu08 Nov 24, 2024
424bfa8
reoder import block
kyu08 Nov 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -1093,3 +1093,30 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================================

rust-pretty-assertions
https://github.com/rust-pretty-assertions/rust-pretty-assertions/tree/main
----------------------------------------------------------------

The MIT License (MIT)

Copyright (c) 2016 rust-derive-builder contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ tui-textarea = "0.6.0"
toml = "0.8.19"
serde = {version = "1.0.204", features = ["derive"]}
simple-home-dir = "0.4.0"
pretty_assertions = "1.4.1"
225 changes: 179 additions & 46 deletions src/file/toml.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,154 @@
use super::path_to_content;
use crate::model::{
histories::{self},
runner_type,
};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use simple_home_dir::home_dir;
use std::{
env,
fs::{self, File},
io::Write,
path::PathBuf,
};

#[derive(Debug, Serialize, Deserialize)]
struct Histories {
history: Vec<History>,
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
pub struct Histories {
histories: Vec<History>,
}

impl Histories {
fn from(histories: Vec<(PathBuf, Vec<String>)>) -> Self {
pub fn get_history() -> Histories {
match history_file_path() {
Some((history_file_dir, history_file_name)) => {
match path_to_content::path_to_content(history_file_dir.join(history_file_name)) {
// TODO: Show error message on message pane if parsing history file failed. https://github.com/kyu08/fzf-make/issues/152
Ok(c) => match parse_history(c.to_string()) {
Ok(h) => h,
Err(_) => Histories { histories: vec![] },
},
Err(_) => Histories { histories: vec![] },
}
}
None => Histories { histories: vec![] },
}
}

fn from(histories: histories::Histories) -> Self {
let mut result: Vec<History> = vec![];
for h in histories {
result.push(History {
path: h.0.to_str().unwrap().to_string(),
executed_targets: h.1,
});
for h in histories.histories {
result.push(History::from(h));
}
Histories { history: result }
Self { histories: result }
}

pub fn into(self) -> histories::Histories {
let mut result: Vec<histories::History> = vec![];
for h in self.histories {
result.push(History::into(h));
}
histories::Histories { histories: result }
}
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
struct History {
path: String,
executed_targets: Vec<String>,
path: PathBuf,
commands: Vec<HistoryCommand>,
}

pub fn parse_history(content: String) -> Result<Vec<(PathBuf, Vec<String>)>> {
let histories: Histories = toml::from_str(&content)?;
impl History {
fn from(history: histories::History) -> Self {
let mut commands: Vec<HistoryCommand> = vec![];
for h in history.commands {
commands.push(HistoryCommand::from(h));
}

History {
path: history.path,
commands,
}
}

let mut result: Vec<(PathBuf, Vec<String>)> = Vec::new();
fn into(self) -> histories::History {
let mut commands: Vec<histories::HistoryCommand> = vec![];
for h in self.commands {
commands.push(HistoryCommand::into(h));
}

for history in histories.history {
result.push((PathBuf::from(history.path), history.executed_targets));
histories::History {
path: self.path,
commands,
}
}
Ok(result)
}

#[allow(dead_code)] // TODO(#321): remove
/// toml representation of histories::HistoryCommand.
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
struct HistoryCommand {
runner_type: runner_type::RunnerType,
name: String,
}

impl HistoryCommand {
fn from(command: histories::HistoryCommand) -> Self {
Self {
runner_type: command.runner_type,
name: command.name.clone(),
}
}

fn into(self) -> histories::HistoryCommand {
histories::HistoryCommand {
runner_type: self.runner_type,
name: self.name,
}
}
}

// TODO: should return Result not Option(returns when it fails to get the home dir)
Copy link
Owner Author

@kyu08 kyu08 Nov 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wont fix in this PR

pub fn history_file_path() -> Option<(PathBuf, String)> {
const HISTORY_FILE_NAME: &str = "history.toml";

match env::var("FZF_MAKE_IS_TESTING") {
Ok(_) => {
// When testing
let cwd = std::env::current_dir().unwrap();
Some((
cwd.join(PathBuf::from("test_dir")),
HISTORY_FILE_NAME.to_string(),
))
}
_ => home_dir().map(|home_dir| {
(
home_dir.join(PathBuf::from(".config/fzf-make")),
HISTORY_FILE_NAME.to_string(),
)
}),
}
}

pub fn parse_history(content: String) -> Result<Histories> {
let histories = toml::from_str(&content)?;
Ok(histories)
}

pub fn store_history(
history_directory_path: PathBuf,
history_file_name: String,
histories_tuple: Vec<(PathBuf, Vec<String>)>,
new_history: histories::Histories,
) -> Result<()> {
let histories = Histories::from(histories_tuple);

if !history_directory_path.is_dir() {
fs::create_dir_all(history_directory_path.clone())?;
}

let mut history_file = File::create(history_directory_path.join(history_file_name))?;
history_file.write_all(toml::to_string(&histories).unwrap().as_bytes())?;
history_file.write_all(
toml::to_string(&Histories::from(new_history))
.unwrap()
.as_bytes(),
)?;
history_file.flush()?;

Ok(())
Expand All @@ -64,49 +157,89 @@ pub fn store_history(
#[cfg(test)]
mod test {
use super::*;
use crate::model::runner_type;
use anyhow::Result;
use pretty_assertions::assert_eq;

#[test]
fn parse_history_test() {
struct Case {
title: &'static str,
content: String,
expect: Result<Vec<(PathBuf, Vec<String>)>>,
expect: Result<Histories>,
}
let cases = vec![
Case {
title: "Success",
content: r#"
[[history]]
[[histories]]
path = "/Users/user/code/fzf-make"
executed-targets = ["test", "check", "spell-check"]

[[history]]
[[histories.commands]]
runner-type = "make"
name = "test"

[[histories.commands]]
runner-type = "make"
name = "check"

[[histories.commands]]
runner-type = "make"
name = "spell-check"

[[histories]]
path = "/Users/user/code/golang/go-playground"
executed-targets = ["run", "echo1"]

[[histories.commands]]
runner-type = "make"
name = "run"

[[histories.commands]]
runner-type = "make"
name = "echo1"
"#
.to_string(),
expect: Ok(vec![
(
PathBuf::from("/Users/user/code/fzf-make".to_string()),
vec![
"test".to_string(),
"check".to_string(),
"spell-check".to_string(),
],
),
(
PathBuf::from("/Users/user/code/golang/go-playground".to_string()),
vec!["run".to_string(), "echo1".to_string()],
),
]),
expect: Ok(Histories {
histories: vec![
History {
path: PathBuf::from("/Users/user/code/fzf-make"),
commands: vec![
HistoryCommand {
runner_type: runner_type::RunnerType::Make,
name: "test".to_string(),
},
HistoryCommand {
runner_type: runner_type::RunnerType::Make,
name: "check".to_string(),
},
HistoryCommand {
runner_type: runner_type::RunnerType::Make,
name: "spell-check".to_string(),
},
],
},
History {
path: PathBuf::from("/Users/user/code/golang/go-playground"),
commands: vec![
HistoryCommand {
runner_type: runner_type::RunnerType::Make,
name: "run".to_string(),
},
HistoryCommand {
runner_type: runner_type::RunnerType::Make,
name: "echo1".to_string(),
},
],
},
],
}),
},
Case {
title: "Error",
content: r#"
"#
.to_string(),
expect: Err(anyhow::anyhow!("TOML parse error at line 1, column 1\n |\n1 | \n | ^\nmissing field `history`\n")),
expect: Err(anyhow::anyhow!("TOML parse error at line 1, column 1\n |\n1 | \n | ^\nmissing field `histories`\n")),
},
];

Expand Down
2 changes: 1 addition & 1 deletion src/model/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{fmt, path::PathBuf};

use super::runner_type;

#[derive(PartialEq, Debug, Clone)]
#[derive(PartialEq, Clone, Debug)]
pub struct Command {
pub runner_type: runner_type::RunnerType,
pub name: String,
Expand Down
Loading