dkdc_files/
lib.rs

1use anyhow::Result;
2use dkdc_lake::Lake;
3use std::fs;
4use std::path::Path;
5
6pub fn list_files(path: &str) -> Result<()> {
7    let lake = Lake::new()?;
8    let files = lake.list_files(path)?;
9
10    for file in files {
11        println!("{}", file);
12    }
13
14    Ok(())
15}
16
17pub fn add_file(file: &str, path: Option<&str>) -> Result<()> {
18    let file_path = Path::new(file);
19
20    if !file_path.exists() {
21        anyhow::bail!("File not found: '{}'", file);
22    }
23
24    if !file_path.is_file() {
25        anyhow::bail!("'{}' is not a file", file);
26    }
27
28    let filename = file_path
29        .file_name()
30        .and_then(|n| n.to_str())
31        .ok_or_else(|| anyhow::anyhow!("Invalid filename"))?;
32
33    let data = fs::read(file_path)?;
34    let lake = Lake::new()?;
35    let filepath = path.unwrap_or("./files");
36
37    lake.add_file(filepath, filename, &data)?;
38
39    // Just output the filename that was added, Unix style
40    println!("{}", filename);
41
42    Ok(())
43}
44
45pub fn open_file(name: &str, path: &str) -> Result<()> {
46    use tempfile::Builder;
47    
48    let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vim".to_string());
49    let lake = Lake::new()?;
50    
51    // Get existing file content if it exists
52    let existing_content = lake.get_file(path, name)?;
53    let initial_content = existing_content
54        .as_ref()
55        .map(|f| f.filedata.as_slice())
56        .unwrap_or(b"");
57    
58    // Extract file extension from name
59    let extension = Path::new(name)
60        .extension()
61        .and_then(|ext| ext.to_str())
62        .map(|ext| format!(".{}", ext))
63        .unwrap_or_default();
64    
65    // Create temporary file with same extension for syntax highlighting
66    let mut temp_file = Builder::new()
67        .prefix("dkdc_")
68        .suffix(&extension)
69        .tempfile()?;
70    
71    use std::io::Write;
72    temp_file.write_all(initial_content)?;
73    
74    // Get the path before we lose ownership
75    let temp_path = temp_file.path().to_owned();
76    
77    // Keep the file alive while editing
78    let _temp_file = temp_file.persist(&temp_path)?;
79    
80    // Open in editor
81    let status = std::process::Command::new(&editor)
82        .arg(&temp_path)
83        .status()?;
84    
85    if !status.success() {
86        anyhow::bail!("Editor exited with error");
87    }
88    
89    // Read the edited content
90    let final_content = fs::read(&temp_path)?;
91    
92    // Save if changed or new
93    if existing_content.is_none() && !final_content.is_empty() {
94        lake.add_file(path, name, &final_content)?;
95    } else if existing_content.is_some() && final_content != initial_content {
96        lake.add_file(path, name, &final_content)?;
97    }
98    
99    // Clean up the temporary file
100    fs::remove_file(temp_path)?;
101    
102    Ok(())
103}
104
105pub fn dump_files(output: &str) -> Result<()> {
106    let output_path = Path::new(output);
107    fs::create_dir_all(output_path)?;
108
109    let lake = Lake::new()?;
110    let files = lake.list_files("./files")?;
111
112    for filename in &files {
113        if let Some(file) = lake.get_file("./files", filename)? {
114            let file_path = output_path.join(filename);
115            fs::write(&file_path, &file.filedata)?;
116            // Output each file as it's dumped
117            println!("{}", file_path.display());
118        }
119    }
120
121    Ok(())
122}
123
124pub fn restore_files(directory: &str) -> Result<()> {
125    let restore_path = Path::new(directory);
126
127    if !restore_path.exists() {
128        anyhow::bail!("Directory not found: {}", directory);
129    }
130
131    if !restore_path.is_dir() {
132        anyhow::bail!("Not a directory: {}", directory);
133    }
134
135    let lake = Lake::new()?;
136
137    for entry in fs::read_dir(restore_path)? {
138        let entry = entry?;
139        let path = entry.path();
140
141        if path.is_file() {
142            if let Some(filename) = path.file_name().and_then(|n| n.to_str()) {
143                let data = fs::read(&path)?;
144                lake.add_file("./files", filename, &data)?;
145                // Output each file as it's restored
146                println!("{}", filename);
147            }
148        }
149    }
150
151    Ok(())
152}