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

10 feature create new citrus core crate #11

Merged
merged 4 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 5 additions & 7 deletions crates/citrus-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
[package]
name = "citrus-cli"
version = "0.1.4"
edition = "2021"
license = "MIT"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
description = "A simple task managing tool that can be configured with YAML files"
repository = "https://github.com/davidkurilla/citrus"
readme = "../../README.md"
readme = "../../docs/README.md"

[dependencies]
clap = "3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
toml = "0.8.13"
citrus-core = "0.1.0"
190 changes: 5 additions & 185 deletions crates/citrus-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,4 @@
use clap::{App, Arg, SubCommand};
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use std::process::{Command, exit};
use toml::Value;

#[derive(Debug, Serialize, Deserialize)]
struct Job {
name: String,
command: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct Task {
name: String,
jobs: Vec<Job>,
}

fn main() {
let matches = App::new("citrus")
Expand Down Expand Up @@ -72,189 +54,27 @@ fn main() {
match matches.subcommand() {
Some(("run", sub_m)) => {
let name = sub_m.value_of("name").unwrap();
run_task(name);
citrus_core::run_task(name);
}
Some(("create", sub_m)) => {
let name = sub_m.value_of("name").unwrap();
let yaml_path = sub_m.value_of("yaml").unwrap();
create_task(name, yaml_path);
citrus_core::create_task(name, yaml_path);
}
Some(("list", _)) => {
list_tasks();
citrus_core::list_tasks();
}
Some(("delete", sub_m)) => {
let name = sub_m.value_of("name").unwrap();
delete_task(name);
citrus_core::delete_task(name);
}
Some(("update", sub_m)) => {
let name = sub_m.value_of("name").unwrap();
let yaml_path = sub_m.value_of("yaml").unwrap();
update_task(name, yaml_path);
citrus_core::update_task(name, yaml_path);
}
_ => {
println!("Welcome to citrus!");
}
}
}

fn run_task(name: &str) {
// Load the task from the JSON file
let output_directory = match get_config_file() {
Ok(dir) => dir,
Err(e) => {
eprintln!("Error getting config file: {}", e);
return;
}
};
let file_path = format!("{}/{}.json", output_directory, name);
let mut file = match File::open(&file_path) {
Ok(file) => file,
Err(err) => {
eprintln!("Error: Unable to open task file '{}'. Error: {}", file_path, err);
exit(1);
}
};
let mut contents = String::new();
file.read_to_string(&mut contents).expect("Unable to read task file");
let task: Task = serde_json::from_str(&contents).expect("Unable to parse task file");

for job in task.jobs {
println!("Executing job: {}", job.name);
let mut parts = job.command.split_whitespace();
let command = parts.next().expect("Invalid command");
let args: Vec<&str> = parts.collect();

let status = Command::new(command)
.args(&args)
.status()
.expect("Failed to execute command");

if !status.success() {
eprintln!("Error: Job '{}' failed with exit code {}", job.name, status);
exit(1);
}
}
println!("Task '{}' completed successfully.", task.name);
}

fn create_task(name: &str, yaml_path: &str) {
let mut file = File::open(yaml_path).expect("Unable to open YAML file");
let mut contents = String::new();
file.read_to_string(&mut contents).expect("Unable to read YAML file");
let jobs: Vec<Job> = serde_yaml::from_str(&contents).expect("Unable to parse YAML file");

let task = Task {
name: name.to_string(),
jobs,
};

let output_directory = match get_config_file() {
Ok(dir) => dir,
Err(e) => {
eprintln!("Error getting config file: {}", e);
return;
}
};

let file_path = format!("{}/{}.json", output_directory, name);
save_task(&file_path, &task);

println!("Created task: {:?}", task);
}

fn save_task(file_path: &str, task: &Task) {
let content = serde_json::to_string_pretty(task).expect("Unable to serialize task");
let mut file = File::create(file_path).expect("Unable to create file");
file.write_all(content.as_bytes()).expect("Unable to write file");
}

fn delete_task(name: &str) {
let output_directory = match get_config_file() {
Ok(dir) => dir,
Err(e) => {
eprintln!("Error getting config file: {}", e);
return;
}
};
let file_path = format!("{}/{}.json", output_directory, name);

if Path::new(&file_path).exists() {
match fs::remove_file(&file_path) {
Ok(_) => println!("Task '{}' deleted successfully.", name),
Err(err) => eprintln!("Error: Unable to delete task file '{}'. Error: {}", file_path, err),
}
} else {
eprintln!("Error: Task '{}' does not exist.", name);
}
}

fn list_tasks() {
let output_directory = match get_config_file() {
Ok(dir) => dir,
Err(e) => {
eprintln!("Error getting config file: {}", e);
return;
}
};
let paths = fs::read_dir(output_directory).expect("Unable to read directory");

let mut tasks = Vec::new();
for path in paths {
let path = path.expect("Unable to read path").path();
if path.extension().and_then(|s| s.to_str()) == Some("json") {
if let Some(task_name) = path.file_stem().and_then(|s| s.to_str()) {
tasks.push(task_name.to_string());
}
}
}

if tasks.is_empty() {
println!("No tasks found.");
} else {
println!("Tasks:");
for task in tasks {
println!("- {}", task);
}
}
}

fn update_task(name: &str, yaml_path: &str) {
let output_directory = match get_config_file() {
Ok(dir) => dir,
Err(e) => {
eprintln!("Error getting config file: {}", e);
return;
}
};
let file_path = format!("{}/{}.json", output_directory, name);
if !Path::new(&file_path).exists() {
eprintln!("Error: Task '{}' does not exist.", name);
exit(1);
}

let mut file = File::open(yaml_path).expect("Unable to open YAML file");
let mut contents = String::new();
file.read_to_string(&mut contents).expect("Unable to read YAML file");
let jobs: Vec<Job> = serde_yaml::from_str(&contents).expect("Unable to parse YAML file");

let task = Task {
name: name.to_string(),
jobs,
};

save_task(&file_path, &task);

println!("Updated task: {:?}", task);
}

fn get_config_file() -> Result<String, &'static str> {
let mut config_file = File::open("citrus-config.toml").expect("Could not locate 'citrus-config.toml' in the current directory");
let mut contents = String::new();
config_file.read_to_string(&mut contents).expect("Could not read file!");
let value: Value = toml::from_str(&contents).expect("Could not parse TOML file!");
if let Some(task_directory) = value.get("config").and_then(|config| config.get("task_directory")).and_then(|v| v.as_str()) {
Ok(task_directory.to_string())
} else {
Err("Could not find 'task_directory' key in TOML file or it is not a string")
}
}
15 changes: 15 additions & 0 deletions crates/citrus-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "citrus-core"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
description = "A library of simple task managing functions."
repository = "https://github.com/davidkurilla/citrus"
readme = "../../docs/README.md"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
toml = "0.8.13"
Loading