1use crate::error::Result;
4use crate::paths::Paths;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Tap {
11 pub name: String,
13 pub url: String,
15 #[serde(default)]
17 pub pinned: bool,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct TapManager {
23 #[serde(default)]
24 taps: HashMap<String, Tap>,
25}
26
27impl Default for TapManager {
28 fn default() -> Self {
29 let mut taps = HashMap::new();
30
31 taps.insert(
33 "neul-labs/stout-index".to_string(),
34 Tap {
35 name: "neul-labs/stout-index".to_string(),
36 url: "https://raw.githubusercontent.com/neul-labs/stout-index/main".to_string(),
37 pinned: false,
38 },
39 );
40
41 Self { taps }
42 }
43}
44
45impl TapManager {
46 pub fn load(paths: &Paths) -> Result<Self> {
48 let taps_file = paths.stout_dir.join("taps.toml");
49
50 if taps_file.exists() {
51 let contents = std::fs::read_to_string(&taps_file)?;
52 let manager: TapManager = toml::from_str(&contents)?;
53 Ok(manager)
54 } else {
55 Ok(Self::default())
56 }
57 }
58
59 pub fn save(&self, paths: &Paths) -> Result<()> {
61 let taps_file = paths.stout_dir.join("taps.toml");
62
63 if let Some(parent) = taps_file.parent() {
64 std::fs::create_dir_all(parent)?;
65 }
66
67 let contents = toml::to_string_pretty(self)?;
68 std::fs::write(&taps_file, contents)?;
69 Ok(())
70 }
71
72 pub fn add(&mut self, tap: Tap) {
74 self.taps.insert(tap.name.clone(), tap);
75 }
76
77 pub fn remove(&mut self, name: &str) {
79 self.taps.remove(name);
80 }
81
82 pub fn get(&self, name: &str) -> Option<&Tap> {
84 self.taps.get(name)
85 }
86
87 pub fn list(&self) -> Vec<&Tap> {
89 let mut taps: Vec<_> = self.taps.values().collect();
90 taps.sort_by(|a, b| a.name.cmp(&b.name));
91 taps
92 }
93
94 pub fn urls(&self) -> Vec<(&str, &str)> {
96 self.taps
97 .iter()
98 .map(|(name, tap)| (name.as_str(), tap.url.as_str()))
99 .collect()
100 }
101
102 pub fn contains(&self, name: &str) -> bool {
104 self.taps.contains_key(name)
105 }
106
107 pub fn pin(&mut self, name: &str) -> bool {
109 if let Some(tap) = self.taps.get_mut(name) {
110 tap.pinned = true;
111 true
112 } else {
113 false
114 }
115 }
116
117 pub fn unpin(&mut self, name: &str) -> bool {
119 if let Some(tap) = self.taps.get_mut(name) {
120 tap.pinned = false;
121 true
122 } else {
123 false
124 }
125 }
126}