1use std::path::{Path, PathBuf};
6use std::collections::HashMap;
7use std::fs;
8use serde::{Serialize, Deserialize};
9use anyhow::{Result, anyhow};
10
11use crate::vcs::{ObjectId, ObjectStore, ShoveId};
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15pub enum PileStatus {
16 Added,
17 Modified,
18 Deleted,
19 Renamed(PathBuf),
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct PileEntry {
25 pub status: PileStatus,
26 pub object_id: ObjectId,
27 pub original_path: PathBuf,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Pile {
33 pub base_shove: Option<ShoveId>,
35
36 pub entries: HashMap<PathBuf, PileEntry>,
38}
39
40impl Pile {
41 pub fn new() -> Self {
43 Self {
44 base_shove: None,
45 entries: HashMap::new(),
46 }
47 }
48
49 pub fn load(path: &Path) -> Result<Self> {
51 if !path.exists() {
52 return Ok(Self::new());
53 }
54
55 let content = fs::read_to_string(path)?;
56 let pile: Self = toml::from_str(&content)?;
57 Ok(pile)
58 }
59
60 pub fn save(&self, path: &Path) -> Result<()> {
62 let content = toml::to_string_pretty(self)?;
63 fs::write(path, content)?;
64 Ok(())
65 }
66
67 pub fn add_path(&mut self, path: &Path, object_store: &ObjectStore) -> Result<()> {
69 let object_id = object_store.store_file(path)?;
71
72 let entry = PileEntry {
74 status: PileStatus::Added, object_id,
76 original_path: path.to_path_buf(),
77 };
78
79 self.entries.insert(path.to_path_buf(), entry);
80 Ok(())
81 }
82
83 pub fn remove_path(&mut self, path: &Path) -> Result<()> {
85 if !self.entries.contains_key(path) {
86 return Err(anyhow!("Path not in pile: {}", path.display()));
87 }
88
89 self.entries.remove(path);
90 Ok(())
91 }
92
93 pub fn clear(&mut self) -> Result<()> {
95 self.entries.clear();
96 Ok(())
97 }
98
99 pub fn is_empty(&self) -> bool {
101 self.entries.is_empty()
102 }
103
104 pub fn len(&self) -> usize {
106 self.entries.len()
107 }
108
109 }