@anysphere/file-service 0.0.0-5d343fb9 → 0.0.0-63cdba18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +3 -0
- package/package.json +7 -7
- package/src/file_utils.rs +4 -5
- package/src/git_utils.rs +146 -19
- package/src/lib.rs +50 -4
- package/src/merkle_tree/local_construction.rs +17 -7
- package/src/merkle_tree/mod.rs +109 -31
- package/src/test.rs +5 -0
package/Cargo.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anysphere/file-service",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-63cdba18",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"version": "napi version"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@anysphere/file-service-win32-x64-msvc": "0.0.0-
|
|
39
|
-
"@anysphere/file-service-darwin-x64": "0.0.0-
|
|
40
|
-
"@anysphere/file-service-linux-x64-gnu": "0.0.0-
|
|
41
|
-
"@anysphere/file-service-darwin-arm64": "0.0.0-
|
|
42
|
-
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-
|
|
43
|
-
"@anysphere/file-service-darwin-universal": "0.0.0-
|
|
38
|
+
"@anysphere/file-service-win32-x64-msvc": "0.0.0-63cdba18",
|
|
39
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-63cdba18",
|
|
40
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-63cdba18",
|
|
41
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-63cdba18",
|
|
42
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-63cdba18",
|
|
43
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-63cdba18"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/file_utils.rs
CHANGED
|
@@ -12,9 +12,8 @@ pub fn is_in_bad_dir(file_path: &Path) -> Result<bool, Error> {
|
|
|
12
12
|
let item_path = file_path
|
|
13
13
|
.to_str()
|
|
14
14
|
.ok_or(anyhow::anyhow!("Failed to convert path to string"))?;
|
|
15
|
-
let is_bad_dir =
|
|
16
|
-
|| item_path.contains(".git")
|
|
17
|
-
&& !(item_path.ends_with(".git") || item_path.ends_with("node_modules"));
|
|
15
|
+
let is_bad_dir =
|
|
16
|
+
item_path.contains("node_modules") || item_path.contains(".git");
|
|
18
17
|
Ok(is_bad_dir)
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -38,14 +37,14 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
38
37
|
|
|
39
38
|
match file_name {
|
|
40
39
|
"package-lock.json" | "pnpm-lock.yaml" | "yarn.lock" | "composer.lock"
|
|
41
|
-
| "Gemfile.lock" => {
|
|
40
|
+
| "Gemfile.lock" | "bun.lockb" => {
|
|
42
41
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
43
42
|
}
|
|
44
43
|
_ => {}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
match extension {
|
|
48
|
-
"lock" | "bak" | "tmp" | "bin" | "exe" | "dll" | "so" => {
|
|
47
|
+
"lock" | "bak" | "tmp" | "bin" | "exe" | "dll" | "so" | "lockb" => {
|
|
49
48
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
50
49
|
}
|
|
51
50
|
_ => {}
|
package/src/git_utils.rs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
use std::collections::HashSet;
|
|
2
|
-
use std::path::PathBuf;
|
|
3
2
|
use std::process::Command;
|
|
4
3
|
|
|
5
4
|
pub fn list_ignored_files(
|
|
6
5
|
workspace_root_path: &str,
|
|
7
|
-
|
|
6
|
+
should_return_absolute_paths: bool,
|
|
7
|
+
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
|
8
8
|
let mut gitignored_files = HashSet::new();
|
|
9
9
|
|
|
10
10
|
let commands = vec![
|
|
@@ -15,12 +15,66 @@ pub fn list_ignored_files(
|
|
|
15
15
|
"--ignored",
|
|
16
16
|
"--exclude-standard",
|
|
17
17
|
],
|
|
18
|
+
// FIXME(sualeh): this is super sketchy and might totally break in like a bazillion ways. i dont like it.
|
|
19
|
+
vec![
|
|
20
|
+
"sh",
|
|
21
|
+
"-c",
|
|
22
|
+
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard | sed \"s|^|$path/|\"'",
|
|
23
|
+
],
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
for command in commands {
|
|
27
|
+
let output = Command::new(&command[0])
|
|
28
|
+
.args(&command[1..])
|
|
29
|
+
.current_dir(workspace_root_path)
|
|
30
|
+
.output()?;
|
|
31
|
+
|
|
32
|
+
if output.status.success() {
|
|
33
|
+
let files = String::from_utf8(output.stdout)?
|
|
34
|
+
.lines()
|
|
35
|
+
.filter(|line| !line.is_empty())
|
|
36
|
+
.map(|line| {
|
|
37
|
+
if should_return_absolute_paths {
|
|
38
|
+
let mut path = std::path::PathBuf::from(workspace_root_path);
|
|
39
|
+
path.push(line);
|
|
40
|
+
|
|
41
|
+
match path.canonicalize() {
|
|
42
|
+
Ok(canonical_path) => {
|
|
43
|
+
canonical_path.to_string_lossy().into_owned()
|
|
44
|
+
}
|
|
45
|
+
Err(_) => String::from(line),
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
String::from(line)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.collect::<HashSet<_>>();
|
|
52
|
+
|
|
53
|
+
gitignored_files.extend(files);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Ok(gitignored_files)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn list_ignored_files_with_absolute_paths(
|
|
61
|
+
workspace_root_path: &str,
|
|
62
|
+
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
|
63
|
+
let mut gitignored_files = HashSet::new();
|
|
64
|
+
|
|
65
|
+
let commands = vec![
|
|
18
66
|
vec![
|
|
19
67
|
"git",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"--
|
|
23
|
-
"
|
|
68
|
+
"ls-files",
|
|
69
|
+
"--others",
|
|
70
|
+
"--ignored",
|
|
71
|
+
"--exclude-standard",
|
|
72
|
+
],
|
|
73
|
+
// FIXME(sualeh): this is super sketchy and might totally break in like a bazillion ways. i dont like it.
|
|
74
|
+
vec![
|
|
75
|
+
"sh",
|
|
76
|
+
"-c",
|
|
77
|
+
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard | sed \"s|^|$path/|\"'",
|
|
24
78
|
],
|
|
25
79
|
];
|
|
26
80
|
|
|
@@ -34,7 +88,7 @@ pub fn list_ignored_files(
|
|
|
34
88
|
let files = String::from_utf8(output.stdout)?
|
|
35
89
|
.lines()
|
|
36
90
|
.filter(|line| !line.is_empty())
|
|
37
|
-
.map(|line|
|
|
91
|
+
.map(|line| String::from(line))
|
|
38
92
|
.collect::<HashSet<_>>();
|
|
39
93
|
|
|
40
94
|
gitignored_files.extend(files);
|
|
@@ -66,7 +120,8 @@ mod tests {
|
|
|
66
120
|
#[test]
|
|
67
121
|
fn test_no_ignored_files() {
|
|
68
122
|
let dir = tempfile::tempdir().unwrap();
|
|
69
|
-
let gitignored_files =
|
|
123
|
+
let gitignored_files =
|
|
124
|
+
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
70
125
|
Command::new("git")
|
|
71
126
|
.args(&["init"])
|
|
72
127
|
.current_dir(dir.path())
|
|
@@ -92,13 +147,14 @@ mod tests {
|
|
|
92
147
|
.current_dir(dir.path())
|
|
93
148
|
.output()
|
|
94
149
|
.unwrap();
|
|
95
|
-
let gitignored_files =
|
|
150
|
+
let gitignored_files =
|
|
151
|
+
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
96
152
|
println!(
|
|
97
153
|
"ignored files for test_one_ignored_file: {:?}",
|
|
98
154
|
gitignored_files
|
|
99
155
|
);
|
|
100
156
|
// assert_eq!(gitignored_files.len(), 1);
|
|
101
|
-
assert!(gitignored_files.contains(&
|
|
157
|
+
assert!(gitignored_files.contains(&String::from("ignored.txt")));
|
|
102
158
|
}
|
|
103
159
|
|
|
104
160
|
#[test]
|
|
@@ -121,19 +177,83 @@ mod tests {
|
|
|
121
177
|
.current_dir(dir.path())
|
|
122
178
|
.output()
|
|
123
179
|
.unwrap();
|
|
124
|
-
let gitignored_files =
|
|
180
|
+
let gitignored_files =
|
|
181
|
+
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
125
182
|
println!(
|
|
126
183
|
"ignored files for test_multiple_ignored_files: {:?}",
|
|
127
184
|
gitignored_files
|
|
128
185
|
);
|
|
129
186
|
// assert_eq!(gitignored_files.len(), 2);
|
|
130
|
-
assert!(gitignored_files.contains(&
|
|
131
|
-
assert!(gitignored_files.contains(&
|
|
187
|
+
assert!(gitignored_files.contains(&String::from("ignored1.txt")));
|
|
188
|
+
assert!(gitignored_files.contains(&String::from("ignored2.txt")));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#[test]
|
|
192
|
+
fn test_git_submodule_ignored_files() {
|
|
193
|
+
let dir = tempfile::tempdir().unwrap();
|
|
194
|
+
let submodule_path = dir.path().join("submodule");
|
|
195
|
+
std::fs::create_dir(&submodule_path).unwrap();
|
|
196
|
+
|
|
197
|
+
let o = Command::new("git")
|
|
198
|
+
.args(&["init"])
|
|
199
|
+
.current_dir(&submodule_path)
|
|
200
|
+
.output()
|
|
201
|
+
.unwrap();
|
|
202
|
+
println!("git init output: {:?}", o);
|
|
203
|
+
|
|
204
|
+
let file_path = submodule_path.join("ignored.txt");
|
|
205
|
+
let mut file = File::create(&file_path).unwrap();
|
|
206
|
+
writeln!(file, "This is an ignored file.").unwrap();
|
|
207
|
+
|
|
208
|
+
let file2 = submodule_path.join("ignored2.txt");
|
|
209
|
+
let mut file = File::create(&file2).unwrap();
|
|
210
|
+
writeln!(file, "This is another ignored file.").unwrap();
|
|
211
|
+
|
|
212
|
+
let gitignore_path = submodule_path.join(".gitignore");
|
|
213
|
+
let mut gitignore = File::create(&gitignore_path).unwrap();
|
|
214
|
+
writeln!(gitignore, "*.txt").unwrap();
|
|
215
|
+
|
|
216
|
+
let o = Command::new("git")
|
|
217
|
+
.args(&["init"])
|
|
218
|
+
.current_dir(dir.path())
|
|
219
|
+
.output()
|
|
220
|
+
.unwrap();
|
|
221
|
+
println!("git init output: {:?}", o);
|
|
222
|
+
|
|
223
|
+
// make a commit in the submodule
|
|
224
|
+
let o = Command::new("git")
|
|
225
|
+
.args(&["add", "."])
|
|
226
|
+
.current_dir(&submodule_path)
|
|
227
|
+
.output()
|
|
228
|
+
.unwrap();
|
|
229
|
+
println!("git add output: {:?}", o);
|
|
230
|
+
let o = Command::new("git")
|
|
231
|
+
.args(&["commit", "-m", "initial commit"])
|
|
232
|
+
.current_dir(&submodule_path)
|
|
233
|
+
.output()
|
|
234
|
+
.unwrap();
|
|
235
|
+
println!("git commit output: {:?}", o);
|
|
236
|
+
|
|
237
|
+
let o = Command::new("git")
|
|
238
|
+
.args(&["submodule", "add", "./submodule"])
|
|
239
|
+
.current_dir(dir.path())
|
|
240
|
+
.output()
|
|
241
|
+
.unwrap();
|
|
242
|
+
println!("git submodule add output: {:?}", o);
|
|
243
|
+
|
|
244
|
+
let gitignored_files =
|
|
245
|
+
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
246
|
+
println!(
|
|
247
|
+
"ignored files for test_git_submodule_ignored_files: {:?}",
|
|
248
|
+
gitignored_files
|
|
249
|
+
);
|
|
250
|
+
assert!(gitignored_files.contains(&String::from("submodule/ignored.txt")));
|
|
251
|
+
assert!(gitignored_files.contains(&String::from("submodule/ignored2.txt")));
|
|
132
252
|
}
|
|
133
253
|
|
|
134
254
|
#[test]
|
|
135
255
|
fn test_multiple_ignored_files_in_current_dir() {
|
|
136
|
-
let gitignored_files = list_ignored_files(".").unwrap();
|
|
256
|
+
let gitignored_files = list_ignored_files(".", false).unwrap();
|
|
137
257
|
assert!(gitignored_files.len() > 1);
|
|
138
258
|
|
|
139
259
|
// print a sample of the ignored files
|
|
@@ -147,7 +267,6 @@ mod tests {
|
|
|
147
267
|
}
|
|
148
268
|
}
|
|
149
269
|
|
|
150
|
-
|
|
151
270
|
#[tokio::test]
|
|
152
271
|
async fn test_file_not_ignored() {
|
|
153
272
|
let dir = tempfile::tempdir().unwrap();
|
|
@@ -160,7 +279,10 @@ mod tests {
|
|
|
160
279
|
.current_dir(dir.path())
|
|
161
280
|
.output()
|
|
162
281
|
.unwrap();
|
|
163
|
-
let is_ignored =
|
|
282
|
+
let is_ignored =
|
|
283
|
+
is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt")
|
|
284
|
+
.await
|
|
285
|
+
.unwrap();
|
|
164
286
|
assert_eq!(is_ignored, false);
|
|
165
287
|
}
|
|
166
288
|
|
|
@@ -180,7 +302,10 @@ mod tests {
|
|
|
180
302
|
.current_dir(dir.path())
|
|
181
303
|
.output()
|
|
182
304
|
.unwrap();
|
|
183
|
-
let is_ignored =
|
|
305
|
+
let is_ignored =
|
|
306
|
+
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
307
|
+
.await
|
|
308
|
+
.unwrap();
|
|
184
309
|
assert_eq!(is_ignored, true);
|
|
185
310
|
}
|
|
186
311
|
|
|
@@ -200,8 +325,10 @@ mod tests {
|
|
|
200
325
|
.current_dir(dir.path())
|
|
201
326
|
.output()
|
|
202
327
|
.unwrap();
|
|
203
|
-
let is_ignored =
|
|
328
|
+
let is_ignored =
|
|
329
|
+
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
330
|
+
.await
|
|
331
|
+
.unwrap();
|
|
204
332
|
assert_eq!(is_ignored, true);
|
|
205
333
|
}
|
|
206
|
-
|
|
207
334
|
}
|
package/src/lib.rs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#![deny(clippy::all)]
|
|
2
|
+
#![deny(unsafe_op_in_unsafe_fn)]
|
|
2
3
|
pub mod file_utils;
|
|
3
4
|
pub mod git_utils;
|
|
4
5
|
pub mod merkle_tree;
|
|
@@ -6,6 +7,9 @@ pub mod merkle_tree;
|
|
|
6
7
|
use std::vec;
|
|
7
8
|
|
|
8
9
|
use merkle_tree::{LocalConstruction, MerkleTree};
|
|
10
|
+
use tracing::{info, Level};
|
|
11
|
+
use tracing_appender::rolling::{RollingFileAppender, Rotation};
|
|
12
|
+
use tracing_subscriber::fmt;
|
|
9
13
|
|
|
10
14
|
#[macro_use]
|
|
11
15
|
extern crate napi_derive;
|
|
@@ -14,15 +18,35 @@ extern crate napi_derive;
|
|
|
14
18
|
pub struct MerkleClient {
|
|
15
19
|
tree: MerkleTree,
|
|
16
20
|
root_directory: String,
|
|
21
|
+
_guard: tracing_appender::non_blocking::WorkerGuard,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub fn init_logger() -> tracing_appender::non_blocking::WorkerGuard {
|
|
25
|
+
let file_appender =
|
|
26
|
+
RollingFileAppender::new(Rotation::NEVER, "./", "rust_log.txt");
|
|
27
|
+
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
|
|
28
|
+
let subscriber = fmt::Subscriber::builder()
|
|
29
|
+
.with_max_level(Level::TRACE)
|
|
30
|
+
.with_writer(non_blocking)
|
|
31
|
+
.with_ansi(false)
|
|
32
|
+
.with_line_number(true)
|
|
33
|
+
.finish();
|
|
34
|
+
|
|
35
|
+
let _ = tracing::subscriber::set_global_default(subscriber);
|
|
36
|
+
|
|
37
|
+
_guard
|
|
17
38
|
}
|
|
18
39
|
|
|
19
40
|
#[napi]
|
|
20
41
|
impl MerkleClient {
|
|
21
42
|
#[napi(constructor)]
|
|
22
43
|
pub fn new(root_directory: String) -> MerkleClient {
|
|
44
|
+
let _guard = init_logger();
|
|
45
|
+
|
|
23
46
|
MerkleClient {
|
|
24
47
|
tree: MerkleTree::empty_tree(),
|
|
25
48
|
root_directory,
|
|
49
|
+
_guard,
|
|
26
50
|
}
|
|
27
51
|
}
|
|
28
52
|
|
|
@@ -31,7 +55,9 @@ impl MerkleClient {
|
|
|
31
55
|
// 1. compute the merkle tree
|
|
32
56
|
// 2. update the backend
|
|
33
57
|
// 3. sync with the remote
|
|
34
|
-
|
|
58
|
+
unsafe {
|
|
59
|
+
self.compute_merkle_tree().await?;
|
|
60
|
+
}
|
|
35
61
|
|
|
36
62
|
Ok(())
|
|
37
63
|
}
|
|
@@ -47,6 +73,17 @@ impl MerkleClient {
|
|
|
47
73
|
let t =
|
|
48
74
|
MerkleTree::construct_merkle_tree(self.root_directory.clone()).await;
|
|
49
75
|
|
|
76
|
+
let files = self.tree.get_all_files().await;
|
|
77
|
+
|
|
78
|
+
match files {
|
|
79
|
+
Ok(files) => {
|
|
80
|
+
info!("files: {:?}", files);
|
|
81
|
+
}
|
|
82
|
+
Err(e) => {
|
|
83
|
+
info!("Error in get_all_files: {:?}", e);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
50
87
|
match t {
|
|
51
88
|
Ok(tree) => {
|
|
52
89
|
self.tree = tree;
|
|
@@ -74,9 +111,13 @@ impl MerkleClient {
|
|
|
74
111
|
&self,
|
|
75
112
|
relative_path: String,
|
|
76
113
|
) -> Result<String, napi::Error> {
|
|
114
|
+
info!("relative_path: {:?}", relative_path);
|
|
77
115
|
let absolute_path =
|
|
78
116
|
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
79
|
-
let
|
|
117
|
+
let canonical_path = absolute_path.canonicalize().unwrap();
|
|
118
|
+
|
|
119
|
+
info!("canonical_path: {:?}", canonical_path);
|
|
120
|
+
let hash = self.tree.get_subtree_hash(canonical_path).await;
|
|
80
121
|
|
|
81
122
|
match hash {
|
|
82
123
|
Ok(hash) => Ok(hash),
|
|
@@ -104,8 +145,10 @@ impl MerkleClient {
|
|
|
104
145
|
&self,
|
|
105
146
|
relative_path: String,
|
|
106
147
|
) -> Result<i32, napi::Error> {
|
|
107
|
-
let absolute_path =
|
|
108
|
-
|
|
148
|
+
let absolute_path = std::path::Path::new(&self.root_directory)
|
|
149
|
+
.join(relative_path)
|
|
150
|
+
.canonicalize()?;
|
|
151
|
+
|
|
109
152
|
let num = self
|
|
110
153
|
.tree
|
|
111
154
|
.get_num_embeddable_files_in_subtree(absolute_path)
|
|
@@ -166,7 +209,10 @@ impl MerkleClient {
|
|
|
166
209
|
// TODO(sualeh): we should assert that the path is ascending up to the path.
|
|
167
210
|
|
|
168
211
|
let ret = vec![file];
|
|
212
|
+
info!("file: {:?}", ret);
|
|
213
|
+
|
|
169
214
|
let ret = ret.into_iter().chain(path.into_iter()).collect::<Vec<_>>();
|
|
215
|
+
info!("ret to js: {:?}", ret);
|
|
170
216
|
|
|
171
217
|
Ok(ret)
|
|
172
218
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
use crate::git_utils;
|
|
1
2
|
use crate::merkle_tree::{
|
|
2
3
|
File, MerkleNode, MerkleNodePtr, NodeType, PinnedFuture,
|
|
3
4
|
};
|
|
4
5
|
|
|
5
6
|
use super::{LocalConstruction, MerkleTree};
|
|
6
|
-
use std::collections::BTreeMap;
|
|
7
|
-
use std::path::PathBuf;
|
|
8
|
-
use std::{collections::HashMap, path::Path, sync::Arc};
|
|
7
|
+
use std::collections::{BTreeMap, HashSet};
|
|
8
|
+
use std::path::{Path, PathBuf};
|
|
9
9
|
use tonic::async_trait;
|
|
10
10
|
|
|
11
11
|
#[async_trait]
|
|
@@ -29,20 +29,30 @@ impl LocalConstruction for MerkleTree {
|
|
|
29
29
|
/// 3. construct merkle tree
|
|
30
30
|
/// 4. return merkle tree
|
|
31
31
|
async fn construct_merkle_tree(
|
|
32
|
-
|
|
32
|
+
absolute_path_to_root_directory: String,
|
|
33
33
|
) -> Result<MerkleTree, anyhow::Error> {
|
|
34
|
-
let path = PathBuf::from(
|
|
34
|
+
let path = PathBuf::from(absolute_path_to_root_directory.clone());
|
|
35
35
|
if !path.exists() {
|
|
36
36
|
// FIXME: we should report this via a good logger.
|
|
37
37
|
panic!("Root directory does not exist!");
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
// 1. get all the gitignored files
|
|
41
|
+
let git_ignored_files = match git_utils::list_ignored_files(
|
|
42
|
+
absolute_path_to_root_directory.as_str(),
|
|
43
|
+
true,
|
|
44
|
+
) {
|
|
45
|
+
Ok(git_ignored) => git_ignored,
|
|
46
|
+
Err(_e) => HashSet::new(),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
let root_node = MerkleNode::new(path, None, &git_ignored_files).await;
|
|
41
50
|
let mut mt = MerkleTree {
|
|
42
51
|
root: root_node,
|
|
43
52
|
files: BTreeMap::new(),
|
|
44
|
-
root_path:
|
|
53
|
+
root_path: absolute_path_to_root_directory,
|
|
45
54
|
cursor: None,
|
|
55
|
+
git_ignored_files,
|
|
46
56
|
};
|
|
47
57
|
|
|
48
58
|
// we now iterate over all the nodes and add them to the hashmap
|
package/src/merkle_tree/mod.rs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
use super::file_utils;
|
|
2
2
|
use sha2::Digest;
|
|
3
|
-
use std::collections::BTreeMap;
|
|
3
|
+
use std::collections::{BTreeMap, HashSet};
|
|
4
4
|
use std::path::PathBuf;
|
|
5
5
|
use std::{fs, path::Path, sync::Arc};
|
|
6
6
|
use tokio::sync::RwLock;
|
|
7
7
|
use tonic::async_trait;
|
|
8
|
+
use tracing::info;
|
|
8
9
|
pub mod local_construction;
|
|
9
10
|
pub mod test;
|
|
10
11
|
|
|
@@ -15,6 +16,7 @@ pub struct MerkleTree {
|
|
|
15
16
|
root: MerkleNodePtr,
|
|
16
17
|
files: BTreeMap<String, File>,
|
|
17
18
|
cursor: Option<usize>,
|
|
19
|
+
git_ignored_files: HashSet<String>,
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
#[derive(Debug)]
|
|
@@ -91,6 +93,7 @@ impl MerkleTree {
|
|
|
91
93
|
files: BTreeMap::new(),
|
|
92
94
|
root_path: "".to_string(),
|
|
93
95
|
cursor: None,
|
|
96
|
+
git_ignored_files: HashSet::new(),
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
@@ -301,26 +304,51 @@ impl MerkleTree {
|
|
|
301
304
|
Ok(files)
|
|
302
305
|
}
|
|
303
306
|
|
|
307
|
+
// TODO(sualeh): i need tests for this!!
|
|
304
308
|
pub async fn get_spline(
|
|
305
309
|
&self,
|
|
306
310
|
absolute_path: &str,
|
|
307
311
|
) -> Result<Vec<String>, anyhow::Error> {
|
|
312
|
+
info!("get_spline called with absolute_path: {}", absolute_path);
|
|
308
313
|
let mut files = Vec::new();
|
|
309
314
|
|
|
310
315
|
let current_node = match self.files.get(absolute_path) {
|
|
311
|
-
Some(node) =>
|
|
312
|
-
|
|
316
|
+
Some(node) => {
|
|
317
|
+
info!("Found node for absolute_path: {}", absolute_path);
|
|
318
|
+
node.node.clone()
|
|
319
|
+
}
|
|
320
|
+
None => {
|
|
321
|
+
info!("File not found for absolute_path: {}", absolute_path);
|
|
322
|
+
return Err(anyhow::anyhow!("File not found: {}", absolute_path));
|
|
323
|
+
}
|
|
313
324
|
};
|
|
325
|
+
|
|
314
326
|
let mut stack = Vec::new();
|
|
315
327
|
stack.push(current_node);
|
|
316
328
|
|
|
317
329
|
while let Some(node) = stack.pop() {
|
|
318
330
|
let parent = node.read().await.parent.clone();
|
|
319
331
|
if let Some(parent) = parent {
|
|
320
|
-
|
|
332
|
+
info!("Adding parent hash to files vector");
|
|
333
|
+
{
|
|
334
|
+
let parent_node = parent.read().await;
|
|
335
|
+
match &parent_node.node_type {
|
|
336
|
+
NodeType::File(file_name) => {
|
|
337
|
+
files.push(file_name.clone());
|
|
338
|
+
}
|
|
339
|
+
NodeType::Branch((branch_name, _)) => {
|
|
340
|
+
files.push(branch_name.clone());
|
|
341
|
+
}
|
|
342
|
+
_ => {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
321
348
|
stack.push(parent);
|
|
322
349
|
}
|
|
323
350
|
}
|
|
351
|
+
info!("Returning files vector with {} elements", files.len());
|
|
324
352
|
Ok(files)
|
|
325
353
|
}
|
|
326
354
|
|
|
@@ -363,8 +391,12 @@ impl MerkleTree {
|
|
|
363
391
|
0 => {
|
|
364
392
|
// this means that the ancestor is the root.
|
|
365
393
|
// we need to create a new node and attach it to the ancestor.
|
|
366
|
-
let new_node =
|
|
367
|
-
|
|
394
|
+
let new_node = MerkleNode::new(
|
|
395
|
+
file_path.clone(),
|
|
396
|
+
Some(ancestor.clone()),
|
|
397
|
+
&self.git_ignored_files,
|
|
398
|
+
)
|
|
399
|
+
.await;
|
|
368
400
|
ancestor.write().await.attach_child(new_node.clone()).await;
|
|
369
401
|
new_node
|
|
370
402
|
}
|
|
@@ -375,9 +407,12 @@ impl MerkleTree {
|
|
|
375
407
|
// UNSURE: not sure this is the correct thing to do but it is the fastest.
|
|
376
408
|
// get the last thing that is not in the tree.
|
|
377
409
|
let first_child_path = path.last().unwrap();
|
|
378
|
-
let first_child =
|
|
379
|
-
|
|
380
|
-
|
|
410
|
+
let first_child = MerkleNode::new(
|
|
411
|
+
first_child_path.clone(),
|
|
412
|
+
Some(ancestor.clone()),
|
|
413
|
+
&self.git_ignored_files,
|
|
414
|
+
)
|
|
415
|
+
.await;
|
|
381
416
|
|
|
382
417
|
// TODO(sualeh): we should do an assertion check that the entire vec is contained here.
|
|
383
418
|
|
|
@@ -654,18 +689,34 @@ use std::future::Future;
|
|
|
654
689
|
use std::pin::Pin;
|
|
655
690
|
|
|
656
691
|
type PinnedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
|
692
|
+
type IgnoredFiles = HashSet<String>;
|
|
657
693
|
|
|
658
694
|
impl MerkleNode {
|
|
659
695
|
/// please be careful using this.
|
|
660
696
|
async fn __new_unchecked(
|
|
661
697
|
file_or_directory: String,
|
|
662
698
|
parent: ParentPtr,
|
|
699
|
+
ignored_files: &IgnoredFiles,
|
|
663
700
|
) -> MerkleNodePtr {
|
|
664
|
-
MerkleNode::construct_node(
|
|
701
|
+
MerkleNode::construct_node(
|
|
702
|
+
Path::new(&file_or_directory),
|
|
703
|
+
parent,
|
|
704
|
+
ignored_files,
|
|
705
|
+
)
|
|
706
|
+
.await
|
|
665
707
|
}
|
|
666
708
|
|
|
667
|
-
async fn new(
|
|
668
|
-
|
|
709
|
+
async fn new(
|
|
710
|
+
absolute_file_or_directory: PathBuf,
|
|
711
|
+
parent: ParentPtr,
|
|
712
|
+
ignored_files: &IgnoredFiles,
|
|
713
|
+
) -> MerkleNodePtr {
|
|
714
|
+
MerkleNode::construct_node(
|
|
715
|
+
Path::new(&absolute_file_or_directory),
|
|
716
|
+
parent,
|
|
717
|
+
ignored_files,
|
|
718
|
+
)
|
|
719
|
+
.await
|
|
669
720
|
}
|
|
670
721
|
|
|
671
722
|
/// NOT added to the tree by default.
|
|
@@ -676,38 +727,40 @@ impl MerkleNode {
|
|
|
676
727
|
// let file_hash = self.files.get_mut(&file_path).unwrap();
|
|
677
728
|
|
|
678
729
|
fn construct_node<'a>(
|
|
679
|
-
|
|
730
|
+
absolute_file_or_directory: &'a Path,
|
|
680
731
|
parent: ParentPtr,
|
|
732
|
+
ignored_files: &'a IgnoredFiles,
|
|
681
733
|
) -> PinnedFuture<'a, MerkleNodePtr> {
|
|
682
734
|
Box::pin(async move {
|
|
683
735
|
// check if it is a file
|
|
684
|
-
let path_str =
|
|
685
|
-
if
|
|
736
|
+
let path_str = absolute_file_or_directory.to_str().unwrap().to_string();
|
|
737
|
+
if absolute_file_or_directory.is_file() {
|
|
686
738
|
return Arc::new(RwLock::new(
|
|
687
739
|
MerkleNode::construct_file_node_or_error_node(
|
|
688
|
-
|
|
740
|
+
absolute_file_or_directory,
|
|
689
741
|
parent,
|
|
742
|
+
ignored_files,
|
|
690
743
|
)
|
|
691
744
|
.await,
|
|
692
745
|
));
|
|
693
746
|
}
|
|
694
747
|
|
|
695
748
|
// check if the directory fails the bad dir test.
|
|
696
|
-
let is_bad_dir = file_utils::is_in_bad_dir(
|
|
749
|
+
let is_bad_dir = file_utils::is_in_bad_dir(absolute_file_or_directory);
|
|
697
750
|
if is_bad_dir.is_err() || is_bad_dir.unwrap_or(false) {
|
|
698
751
|
// println!("skipping directory: {}", path_str);
|
|
699
752
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
700
|
-
Some(
|
|
753
|
+
Some(absolute_file_or_directory),
|
|
701
754
|
Some("Directory is in bad dir!".to_string()),
|
|
702
755
|
)));
|
|
703
756
|
}
|
|
704
757
|
|
|
705
|
-
let entries = fs::read_dir(
|
|
758
|
+
let entries = fs::read_dir(absolute_file_or_directory);
|
|
706
759
|
match entries {
|
|
707
760
|
Ok(_) => (),
|
|
708
761
|
Err(e) => {
|
|
709
762
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
710
|
-
Some(
|
|
763
|
+
Some(absolute_file_or_directory),
|
|
711
764
|
Some(e.to_string()),
|
|
712
765
|
)));
|
|
713
766
|
}
|
|
@@ -727,13 +780,17 @@ impl MerkleNode {
|
|
|
727
780
|
match entry {
|
|
728
781
|
Ok(entry) => {
|
|
729
782
|
children.push(
|
|
730
|
-
MerkleNode::construct_node(
|
|
731
|
-
.
|
|
783
|
+
MerkleNode::construct_node(
|
|
784
|
+
&entry.path(),
|
|
785
|
+
Some(node.clone()),
|
|
786
|
+
ignored_files,
|
|
787
|
+
)
|
|
788
|
+
.await,
|
|
732
789
|
);
|
|
733
790
|
}
|
|
734
791
|
Err(e) => {
|
|
735
792
|
children.push(Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
736
|
-
Some(
|
|
793
|
+
Some(absolute_file_or_directory),
|
|
737
794
|
Some(e.to_string()),
|
|
738
795
|
))));
|
|
739
796
|
}
|
|
@@ -753,23 +810,33 @@ impl MerkleNode {
|
|
|
753
810
|
}
|
|
754
811
|
|
|
755
812
|
async fn construct_file_node(
|
|
756
|
-
|
|
813
|
+
absolute_file_path: &Path,
|
|
757
814
|
parent: ParentPtr,
|
|
815
|
+
ignored_files: &IgnoredFiles,
|
|
758
816
|
) -> Result<MerkleNode, String> {
|
|
759
|
-
let file_str =
|
|
817
|
+
let file_str = absolute_file_path
|
|
760
818
|
.to_str()
|
|
761
819
|
.ok_or("Could not convert file path to string!")?
|
|
762
820
|
.to_string();
|
|
763
821
|
// first see if it passes the
|
|
764
|
-
match file_utils::is_good_file(
|
|
822
|
+
match file_utils::is_good_file(absolute_file_path) {
|
|
765
823
|
Ok(_) => {}
|
|
766
824
|
Err(e) => {
|
|
767
825
|
return Err(format!("File failed runtime checks! {}", e.to_string()));
|
|
768
826
|
}
|
|
769
827
|
}
|
|
770
828
|
|
|
829
|
+
// check if the file is in the git ignore buffer.
|
|
830
|
+
// this is a bug right because we are not checking absoluteness here.
|
|
831
|
+
match ignored_files.contains(&file_str) {
|
|
832
|
+
true => {
|
|
833
|
+
return Err(format!("File is in git ignore buffer!"));
|
|
834
|
+
}
|
|
835
|
+
false => {}
|
|
836
|
+
}
|
|
837
|
+
|
|
771
838
|
// read the file_content to a buffer
|
|
772
|
-
let file_content = match tokio::fs::read(
|
|
839
|
+
let file_content = match tokio::fs::read(absolute_file_path).await {
|
|
773
840
|
Ok(content) => content,
|
|
774
841
|
Err(e) => {
|
|
775
842
|
return Err(format!("Could not read file! {}", e.to_string()));
|
|
@@ -777,7 +844,11 @@ impl MerkleNode {
|
|
|
777
844
|
};
|
|
778
845
|
|
|
779
846
|
// check if the file passes runtime checks.
|
|
780
|
-
match file_utils::is_good_file_runtime_check(
|
|
847
|
+
match file_utils::is_good_file_runtime_check(
|
|
848
|
+
absolute_file_path,
|
|
849
|
+
&file_content,
|
|
850
|
+
)
|
|
851
|
+
.await
|
|
781
852
|
{
|
|
782
853
|
Ok(_) => {}
|
|
783
854
|
Err(e) => {
|
|
@@ -808,15 +879,22 @@ impl MerkleNode {
|
|
|
808
879
|
}
|
|
809
880
|
|
|
810
881
|
async fn construct_file_node_or_error_node(
|
|
811
|
-
|
|
882
|
+
absolute_file_path: &Path,
|
|
812
883
|
parent: ParentPtr,
|
|
884
|
+
ignored_files: &IgnoredFiles,
|
|
813
885
|
) -> MerkleNode {
|
|
814
|
-
let node = match MerkleNode::construct_file_node(
|
|
886
|
+
let node = match MerkleNode::construct_file_node(
|
|
887
|
+
absolute_file_path,
|
|
888
|
+
parent,
|
|
889
|
+
ignored_files,
|
|
890
|
+
)
|
|
891
|
+
.await
|
|
892
|
+
{
|
|
815
893
|
Ok(node) => node,
|
|
816
894
|
Err(e) => {
|
|
817
895
|
// println!("constructing error node. error: {}", e);
|
|
818
896
|
// println!("file_path: {:?}", file_path);
|
|
819
|
-
MerkleNode::empty_node(Some(
|
|
897
|
+
MerkleNode::empty_node(Some(absolute_file_path), Some(e))
|
|
820
898
|
}
|
|
821
899
|
};
|
|
822
900
|
|