Skip to content

Commit

Permalink
[feat] Add command substitute and general cleanup
Browse files Browse the repository at this point in the history
Signed-off-by: Shinyzenith <[email protected]>
  • Loading branch information
Shinyzenith committed Oct 15, 2022
1 parent 6a1d5ca commit 23291ad
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 41 deletions.
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ build:

clean:
@cargo clean
@rm ./docs/*.gz
@$(RM) -f ./docs/*.gz
@$(RM) -f ./docs/*.out

install:
@find ./docs -type f -iname "*.1.gz" -exec cp {} $(MAN1_DIR) \;
Expand All @@ -22,8 +23,8 @@ install:
@chmod +x $(TARGET_DIR)/$(BINARY)

uninstall:
@rm $(TARGET_DIR)/$(BINARY)
@rm /usr/share/man/man1/$(BINARY).1.gz
@rm /usr/share/man/man5/$(BINARY).5.gz
@$(RM) -f $(TARGET_DIR)/$(BINARY)
@$(RM) -f /usr/share/man/man1/$(BINARY).1.gz
@$(RM) -f /usr/share/man/man5/$(BINARY).5.gz

.PHONY: build install uninstall
4 changes: 2 additions & 2 deletions docs/sniff.5.scd
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ Sniff uses the JSON file format. Configuration files should always be named *sni
All JSON keys apart from the following are treated as patterns to check for file changes:
- _sniff_ignore_dir_ (Make sniff ignore directories.)
- _sniff_ignore_file_ (Make sniff ignore files.)
- _sniff_cooldown_ (State the cooldown between consecutive build commands.)
- _sniff_cooldown_ (State the cooldown between consecutive build commands. Default is 650 ms.)

Each pattern check can either be an object or an array.
- If the pattern check if an array then the commands in it are executed.
- If the pattern check is an object then the following keys are searched for:
- "commands": The array of commands to execute.
- "commands": The array of commands to execute. "%sniff_file_name%" is a reserved term which is substituted with the file name.
- "relative_dir": The directory relative to which the commands should be executed.

# EXAMPLE
Expand Down
105 changes: 70 additions & 35 deletions src/sniff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ use std::{
struct Ignore {
sniff_ignore_dir: Vec<String>,
sniff_ignore_file: Vec<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
struct Cooldown {
sniff_cooldown: u128,
}

Expand All @@ -40,12 +44,34 @@ fn main() {
env_logger::init();
log::trace!("Logger initialized.");

let config_file = fetch_sniff_config_file();
let json: serde_json::Value =
serde_json::from_str(config_file.as_str()).expect("JSON not well-formatted");
let config_file = match fetch_sniff_config() {
Some(cfg) => cfg,
None => {
log::error!("Failed to read sniff config file. Either it does not exist or the required permissions for reading the file are not available!");
exit(1);
}
};

let json: serde_json::Value = match serde_json::from_str(config_file.as_str()) {
Ok(cfg) => cfg,
Err(e) => {
log::error!("Failed to marshal input string to JSON: {:#?}", e);
exit(1);
}
};

let ignore_list: Option<Ignore> = match serde_json::from_str(config_file.as_str()) {
Ok(ign) => Some(ign),
Err(..) => {
log::debug!("No ignore directives found.");
None
}
};

let ignore_list: Ignore =
serde_json::from_str(config_file.as_str()).expect("JSON not well-formatted");
let cooldown: u128 = match serde_json::from_str(config_file.as_str()) {
Ok(cooldown) => cooldown,
Err(..) => 650,
};

if let Ok(current_dir) = env::current_dir() {
let (tx, rx) = channel();
Expand All @@ -66,6 +92,7 @@ fn main() {
path.to_str().unwrap(),
json.clone(),
ignore_list.clone(),
cooldown,
&mut last_run,
);
}
Expand All @@ -80,33 +107,33 @@ fn main() {
}
}

fn fetch_sniff_config_file() -> String {
fn fetch_sniff_config() -> Option<String> {
let config_file_path = Path::new("./sniff.json");
if config_file_path.exists() {
return fs::read_to_string(config_file_path).unwrap();
return Some(fs::read_to_string(config_file_path).unwrap());
}

let config_file_path = match env::var("XDG_CONFIG_HOME") {
Ok(val) => {
log::debug!("XDG_CONFIG_HOME exists: {:#?}", val);
Path::new(&val).join("sniff/sniff.json")
}
Err(_) => {
Err(..) => {
log::error!(
"XDG_CONFIG_HOME has not been set. Falling back to ~/.config/sniff/sniff.json"
);
Path::new("~/.config/sniff/sniff.json").to_path_buf()
}
};

if !config_file_path.exists() {
log::error!("Config file doesn't exist.");
exit(1);
return None;
}

if Path::new(&config_file_path).exists() {
fs::read_to_string(config_file_path).unwrap()
return Some(fs::read_to_string(config_file_path).unwrap());
} else {
log::error!("Config file not found!");
exit(1);
return None;
}
}

Expand All @@ -115,6 +142,8 @@ fn run_system_command(command_dir_pairs: Vec<(Vec<String>, Option<PathBuf>)>) {
let mut status = WNOHANG;
wait(&mut status);
}

log::info!("************* Initializing Command Runners! *************");
for (commands, relative_dir) in command_dir_pairs {
for command in commands {
// We need to split the arg apart because it returns a temporary pointer that is free'd after
Expand All @@ -130,8 +159,6 @@ fn run_system_command(command_dir_pairs: Vec<(Vec<String>, Option<PathBuf>)>) {
if let Err(e) = cmd.spawn() {
log::error!("Failed to execute {}", command);
log::error!("Error, {}", e);
} else {
log::info!("Ran {:#?}", command);
}
}
}
Expand All @@ -140,31 +167,34 @@ fn run_system_command(command_dir_pairs: Vec<(Vec<String>, Option<PathBuf>)>) {
fn check_and_run(
file_path: &str,
json: serde_json::Value,
ignore_list: Ignore,
ignore_list: Option<Ignore>,
cooldown: u128,
last_run: &mut Instant,
) {
// Cooldown check.
if Instant::now().duration_since(*last_run).as_millis() < ignore_list.sniff_cooldown {
if Instant::now().duration_since(*last_run).as_millis() < cooldown {
log::debug!("In cooldown.");
return;
}

// First the file check.
for ignore_file in ignore_list.sniff_ignore_file {
if ignore_file[..] == file_path[file_path.rfind('/').unwrap() + 1..] {
log::debug!("Ignoring {} as it's in the ingored file list.", file_path);
return;
if let Some(ignore_list) = ignore_list {
// First the file check.
for ignore_file in ignore_list.sniff_ignore_file {
if ignore_file[..] == file_path[file_path.rfind('/').unwrap() + 1..] {
log::debug!("Ignoring {} as it's in the ingored file list.", file_path);
return;
}
}
}

// Now the dir check.
for ignore_dir in ignore_list.sniff_ignore_dir {
if file_path[0..file_path.rfind('/').unwrap()].contains(ignore_dir.as_str()) {
log::debug!(
"Ignoring {} as it's in the ingored directory list.",
file_path
);
return;
// Now the dir check.
for ignore_dir in ignore_list.sniff_ignore_dir {
if file_path[0..file_path.rfind('/').unwrap()].contains(ignore_dir.as_str()) {
log::debug!(
"Ignoring {} as it's in the ingored directory list.",
file_path
);
return;
}
}
}

Expand All @@ -180,11 +210,13 @@ fn check_and_run(
}
},
None => {
log::error!("Failed to get file name from absolute path!");
exit(1);
log::error!(
"{:#?} had no extension. Skipping instruction search.",
file_path
);
return;
}
};
dbg!(file_name);
match json {
serde_json::Value::Object(map) => {
for (pattern, instructions) in map.iter() {
Expand All @@ -210,7 +242,10 @@ fn check_and_run(
for command in commands {
match command {
serde_json::Value::String(command) => {
command_strs.push(command.to_string());
command_strs.push(command.replace(
"%sniff_file_name%",
file_path,
));
}
_ => {
log::error!("Command wasn't a string.");
Expand Down

0 comments on commit 23291ad

Please sign in to comment.