165 lines
5.5 KiB
Plaintext
165 lines
5.5 KiB
Plaintext
#!/usr/bin/env nu
|
|
# Backup KOGRAL graphs to archive
|
|
#
|
|
# Usage: nu kogral-backup.nu [--output <path>] [--format <tar|zip>] [--compress]
|
|
|
|
def main [
|
|
--output: string = "kogral-backup" # Output filename (without extension)
|
|
--format: string = "tar" # Archive format: tar or zip
|
|
--compress # Compress the archive
|
|
--kogral-dir: string = ".kogral" # KOGRAL directory
|
|
--include-metadata # Include .git and other metadata
|
|
] {
|
|
print $"(ansi green_bold)KOGRAL Backup(ansi reset)"
|
|
print $"KOGRAL Directory: ($kogral-dir)"
|
|
print $"Format: ($format)"
|
|
print $"Compress: ($compress)"
|
|
|
|
# Check if .kogral directory exists
|
|
if not ($kogral-dir | path exists) {
|
|
print $"(ansi red)Error: KOGRAL directory not found: ($kogral-dir)(ansi reset)"
|
|
exit 1
|
|
}
|
|
|
|
# Generate timestamp
|
|
let timestamp = date now | format date "%Y%m%d_%H%M%S"
|
|
let backup_name = $"($output)_($timestamp)"
|
|
|
|
# Determine file extension
|
|
let extension = if $compress {
|
|
if $format == "tar" { ".tar.gz" } else { ".zip" }
|
|
} else {
|
|
if $format == "tar" { ".tar" } else { ".zip" }
|
|
}
|
|
|
|
let backup_file = $"($backup_name)($extension)"
|
|
|
|
print $"\n(ansi cyan_bold)Preparing backup...(ansi reset)"
|
|
print $"Output file: ($backup_file)"
|
|
|
|
# Count files
|
|
let stats = get_kogral_stats $kogral_dir
|
|
|
|
print $"\n(ansi cyan_bold)Files to backup:(ansi reset)"
|
|
print $" Notes: ($stats.notes)"
|
|
print $" Decisions: ($stats.decisions)"
|
|
print $" Guidelines: ($stats.guidelines)"
|
|
print $" Patterns: ($stats.patterns)"
|
|
print $" Journal: ($stats.journal)"
|
|
print $" Config: ($stats.config)"
|
|
print $" Total: ($stats.total)"
|
|
|
|
# Create backup
|
|
print $"\n(ansi cyan_bold)Creating backup...(ansi reset)"
|
|
|
|
match $format {
|
|
"tar" => {
|
|
create_tar_backup $kogral_dir $backup_file $compress $include_metadata
|
|
},
|
|
"zip" => {
|
|
create_zip_backup $kogral_dir $backup_file $include_metadata
|
|
},
|
|
_ => {
|
|
print $"(ansi red)Error: Invalid format. Use: tar or zip(ansi reset)"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Verify backup
|
|
if ($backup_file | path exists) {
|
|
let size = ls $backup_file | get size | first
|
|
print $"\n(ansi green_bold)✓ Backup created successfully(ansi reset)"
|
|
print $"File: ($backup_file)"
|
|
print $"Size: ($size)"
|
|
} else {
|
|
print $"\n(ansi red)✗ Backup creation failed(ansi reset)"
|
|
exit 1
|
|
}
|
|
|
|
# Generate manifest
|
|
print $"\n(ansi cyan_bold)Generating manifest...(ansi reset)"
|
|
let manifest = generate_manifest $kogral_dir $backup_file $stats $timestamp
|
|
let manifest_file = $"($backup_name).manifest.json"
|
|
$manifest | to json | save $manifest_file
|
|
print $"Manifest saved: ($manifest_file)"
|
|
|
|
print $"\n(ansi green_bold)✓ Backup completed(ansi reset)"
|
|
}
|
|
|
|
def get_kogral_stats [kogral_dir: string] -> record {
|
|
let notes = (glob $"($kogral_dir)/notes/**/*.md" | length)
|
|
let decisions = (glob $"($kogral_dir)/decisions/**/*.md" | length)
|
|
let guidelines = (glob $"($kogral_dir)/guidelines/**/*.md" | length)
|
|
let patterns = (glob $"($kogral_dir)/patterns/**/*.md" | length)
|
|
let journal = (glob $"($kogral_dir)/journal/**/*.md" | length)
|
|
let config = if ($"($kogral_dir)/config.toml" | path exists) { 1 } else { 0 }
|
|
|
|
{
|
|
notes: $notes,
|
|
decisions: $decisions,
|
|
guidelines: $guidelines,
|
|
patterns: $patterns,
|
|
journal: $journal,
|
|
config: $config,
|
|
total: ($notes + $decisions + $guidelines + $patterns + $journal + $config)
|
|
}
|
|
}
|
|
|
|
def create_tar_backup [kogral_dir: string, output: string, compress: bool, include_metadata: bool] {
|
|
let compress_flag = if $compress { "z" } else { "" }
|
|
let exclude_flags = if not $include_metadata {
|
|
["--exclude=.git", "--exclude=.DS_Store"]
|
|
} else {
|
|
[]
|
|
}
|
|
|
|
print $" Creating tar archive..."
|
|
|
|
# Use tar command
|
|
let tar_cmd = if $compress {
|
|
$"tar -c($compress_flag)f ($output) ($exclude_flags | str join ' ') ($kogral_dir)"
|
|
} else {
|
|
$"tar -cf ($output) ($exclude_flags | str join ' ') ($kogral_dir)"
|
|
}
|
|
|
|
try {
|
|
bash -c $tar_cmd
|
|
print $" (ansi green)✓ Tar archive created(ansi reset)"
|
|
} catch {
|
|
print $" (ansi red)✗ Tar archive creation failed(ansi reset)"
|
|
}
|
|
}
|
|
|
|
def create_zip_backup [kogral_dir: string, output: string, include_metadata: bool] {
|
|
print $" Creating zip archive..."
|
|
|
|
let exclude_pattern = if not $include_metadata { "*.git* */.DS_Store" } else { "" }
|
|
|
|
try {
|
|
bash -c $"zip -r ($output) ($kogral_dir) -x ($exclude_pattern)"
|
|
print $" (ansi green)✓ Zip archive created(ansi reset)"
|
|
} catch {
|
|
print $" (ansi red)✗ Zip archive creation failed(ansi reset)"
|
|
}
|
|
}
|
|
|
|
def generate_manifest [kogral_dir: string, backup_file: string, stats: record, timestamp: string] -> record {
|
|
let config_path = $"($kogral_dir)/config.toml"
|
|
let config = if ($config_path | path exists) {
|
|
open $config_path | from toml
|
|
} else {
|
|
{ graph: { name: "unknown", version: "unknown" } }
|
|
}
|
|
|
|
{
|
|
backup_timestamp: $timestamp,
|
|
backup_file: $backup_file,
|
|
kogral_directory: $kogral_dir,
|
|
graph_name: $config.graph.name,
|
|
graph_version: $config.graph.version,
|
|
statistics: $stats,
|
|
created_by: "kogral-backup.nu",
|
|
version: "1.0.0"
|
|
}
|
|
}
|