cargo_resolvediff/
toml_edit.rs1use color_eyre::Result;
6use std::fs;
7use std::path::{Path, PathBuf};
8use toml_edit::{DocumentMut, Item};
9
10pub struct MutableTomlFile {
15 dirty: bool,
16 path: PathBuf,
17 previous_contents: String,
18 document: DocumentMut,
19}
20
21impl MutableTomlFile {
22 pub fn open(path: impl Into<PathBuf>) -> Result<Self> {
23 let path = path.into();
24 let contents = fs::read_to_string(&path)?;
25 let document = contents.parse::<DocumentMut>()?;
26 Ok(MutableTomlFile {
27 dirty: false,
28 path,
29 previous_contents: contents,
30 document,
31 })
32 }
33
34 pub fn path(&self) -> &Path {
35 &self.path
36 }
37
38 pub fn document(&self) -> &toml_edit::DocumentMut {
39 &self.document
40 }
41
42 pub fn document_mut(&mut self) -> &mut toml_edit::DocumentMut {
43 self.dirty = true;
44 &mut self.document
45 }
46
47 fn write_back_inner(&self, data: &str) -> Result<()> {
48 let tmp_path = self.path.with_file_name(".Cargo.toml.update");
49 fs::write(&tmp_path, data)?;
50 fs::rename(&tmp_path, &self.path)?;
51 Ok(())
52 }
53
54 pub fn write_back(&mut self) -> Result<()> {
56 if self.dirty {
57 self.write_back_inner(&self.document.to_string())?;
58 self.dirty = false;
59 }
60
61 Ok(())
62 }
63
64 pub fn roll_back(&mut self) -> Result<()> {
66 self.document = self.previous_contents.parse()?;
67 self.write_back_inner(&self.previous_contents)?;
68 self.dirty = false;
69 Ok(())
70 }
71
72 pub fn commit(&mut self) -> Result<()> {
74 self.write_back()?;
75 self.previous_contents = self.document.to_string();
76 Ok(())
77 }
78}
79
80pub trait TomlPathLookup {
84 fn path_lookup(&self, path: impl IntoIterator<Item: AsRef<str>>) -> Option<&Item>;
85 fn path_lookup_mut(&mut self, path: impl IntoIterator<Item: AsRef<str>>) -> Option<&mut Item>;
86}
87
88impl TomlPathLookup for toml_edit::Item {
89 fn path_lookup(&self, path: impl IntoIterator<Item: AsRef<str>>) -> Option<&Item> {
90 let mut item = self;
91 for i in path {
92 item = item.get(i.as_ref())?;
93 }
94
95 Some(item)
96 }
97
98 fn path_lookup_mut(&mut self, path: impl IntoIterator<Item: AsRef<str>>) -> Option<&mut Item> {
99 let mut item = self;
100 for i in path {
101 item = item.get_mut(i.as_ref())?;
102 }
103
104 Some(item)
105 }
106}
107
108impl TomlPathLookup for MutableTomlFile {
109 fn path_lookup(&self, path: impl IntoIterator<Item: AsRef<str>>) -> Option<&Item> {
110 self.document().as_item().path_lookup(path)
111 }
112
113 fn path_lookup_mut(&mut self, path: impl IntoIterator<Item: AsRef<str>>) -> Option<&mut Item> {
114 self.document_mut().as_item_mut().path_lookup_mut(path)
115 }
116}