feat: open source vibecoding example project
This commit is contained in:
commit
b370f462f2
34 changed files with 7744 additions and 0 deletions
152
src/main.rs
Normal file
152
src/main.rs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// json-archive is a tool for tracking JSON file changes over time
|
||||
// Copyright (C) 2025 Peoples Grocers LLC
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
// To purchase a license under different terms contact admin@peoplesgrocers.com
|
||||
// To request changes, report bugs, or give user feedback contact
|
||||
// marxism@peoplesgrocers.com
|
||||
//
|
||||
|
||||
use json_archive::{
|
||||
append_to_archive, create_archive_from_files, default_output_filename, is_json_archive, Diagnostic,
|
||||
DiagnosticCode, DiagnosticLevel,
|
||||
};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
mod cmd;
|
||||
mod flags;
|
||||
|
||||
fn main() {
|
||||
let flags = flags::JsonArchive::from_env_or_exit();
|
||||
|
||||
let diagnostics = run(flags);
|
||||
|
||||
for diagnostic in &diagnostics {
|
||||
eprintln!("{}", diagnostic);
|
||||
}
|
||||
|
||||
let has_fatal = diagnostics.iter().any(|d| d.is_fatal());
|
||||
if has_fatal {
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn run(flags: flags::JsonArchive) -> Vec<Diagnostic> {
|
||||
match flags.subcommand {
|
||||
flags::JsonArchiveCmd::Create(create_flags) => create_archive(&create_flags),
|
||||
flags::JsonArchiveCmd::Info(info_flags) => cmd::info::run(&info_flags),
|
||||
flags::JsonArchiveCmd::State(state_flags) => cmd::state::run(&state_flags),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_archive(flags: &flags::Create) -> Vec<Diagnostic> {
|
||||
if flags.inputs.is_empty() {
|
||||
return vec![Diagnostic::new(
|
||||
DiagnosticLevel::Fatal,
|
||||
DiagnosticCode::MissingHeaderField,
|
||||
"I need at least one JSON file to create an archive, but you didn't provide any."
|
||||
.to_string(),
|
||||
)
|
||||
.with_advice(
|
||||
"Usage: json-archive <file1.json> [file2.json ...]\n\n\
|
||||
The first file will be used as the initial state, and subsequent files \
|
||||
will be compared to generate change events."
|
||||
.to_string(),
|
||||
)];
|
||||
}
|
||||
|
||||
let output_path = match &flags.output {
|
||||
Some(path) => path.clone(),
|
||||
None => default_output_filename(&flags.inputs[0]),
|
||||
};
|
||||
|
||||
let mut diagnostics = Vec::new();
|
||||
for input_path in &flags.inputs {
|
||||
if !Path::new(input_path).exists() {
|
||||
diagnostics.push(
|
||||
Diagnostic::new(
|
||||
DiagnosticLevel::Fatal,
|
||||
DiagnosticCode::PathNotFound,
|
||||
format!("I couldn't find the input file: {}", input_path.display()),
|
||||
)
|
||||
.with_advice(
|
||||
"Make sure the file path is correct and the file exists. \
|
||||
Check for typos in the filename."
|
||||
.to_string(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !diagnostics.is_empty() {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
let first_is_archive = match is_json_archive(&flags.inputs[0]) {
|
||||
Ok(is_archive) => is_archive,
|
||||
Err(e) => {
|
||||
return vec![Diagnostic::new(
|
||||
DiagnosticLevel::Fatal,
|
||||
DiagnosticCode::PathNotFound,
|
||||
format!("I couldn't check if the first file is an archive: {}", e),
|
||||
)];
|
||||
}
|
||||
};
|
||||
|
||||
if first_is_archive {
|
||||
println!("First input appears to be a JSON archive file");
|
||||
if flags.inputs.len() == 1 {
|
||||
return vec![
|
||||
Diagnostic::new(
|
||||
DiagnosticLevel::Fatal,
|
||||
DiagnosticCode::MissingHeaderField,
|
||||
"I found that the first input is already an archive file, but you didn't provide any additional JSON files to append.".to_string()
|
||||
)
|
||||
.with_advice(
|
||||
"If you want to append to an archive, provide additional JSON files:\n\
|
||||
json-archive existing.json.archive new1.json new2.json"
|
||||
.to_string()
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
return append_to_archive(&flags.inputs[0], &flags.inputs[1..], &output_path, flags.source.clone(), flags.snapshot_interval);
|
||||
}
|
||||
|
||||
println!("Creating archive: {}", output_path.display());
|
||||
println!("Input files: {:?}", flags.inputs);
|
||||
|
||||
if let Some(interval) = flags.snapshot_interval {
|
||||
println!("Snapshot interval: every {} observations", interval);
|
||||
}
|
||||
|
||||
if let Some(ref source) = flags.source {
|
||||
println!("Source: {}", source);
|
||||
}
|
||||
|
||||
match create_archive_from_files(
|
||||
&flags.inputs,
|
||||
output_path.clone(),
|
||||
flags.source.clone(),
|
||||
flags.snapshot_interval,
|
||||
) {
|
||||
Ok(()) => {
|
||||
println!("Archive created successfully: {}", output_path.display());
|
||||
Vec::new()
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue