@anysphere/file-service 0.0.0-94b0c7a7 → 0.0.0-a0aa43e6
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 +0 -3
- package/package.json +7 -7
- package/src/file_utils.rs +5 -4
- package/src/git_utils.rs +19 -146
- package/src/lib.rs +14 -59
- package/src/merkle_tree/local_construction.rs +7 -17
- package/src/merkle_tree/mod.rs +101 -163
- package/src/test.rs +0 -5
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-a0aa43e6",
|
|
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-a0aa43e6",
|
|
39
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-a0aa43e6",
|
|
40
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-a0aa43e6",
|
|
41
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-a0aa43e6",
|
|
42
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-a0aa43e6",
|
|
43
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-a0aa43e6"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/file_utils.rs
CHANGED
|
@@ -12,8 +12,9 @@ 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
|
-
|
|
15
|
+
let is_bad_dir = (item_path.contains("node_modules")
|
|
16
|
+
|| item_path.contains(".git"))
|
|
17
|
+
&& !(item_path.ends_with(".git") || item_path.ends_with("node_modules"));
|
|
17
18
|
Ok(is_bad_dir)
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -37,14 +38,14 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
37
38
|
|
|
38
39
|
match file_name {
|
|
39
40
|
"package-lock.json" | "pnpm-lock.yaml" | "yarn.lock" | "composer.lock"
|
|
40
|
-
| "Gemfile.lock"
|
|
41
|
+
| "Gemfile.lock" => {
|
|
41
42
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
42
43
|
}
|
|
43
44
|
_ => {}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
match extension {
|
|
47
|
-
"lock" | "bak" | "tmp" | "bin" | "exe" | "dll" | "so"
|
|
48
|
+
"lock" | "bak" | "tmp" | "bin" | "exe" | "dll" | "so" => {
|
|
48
49
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
49
50
|
}
|
|
50
51
|
_ => {}
|
package/src/git_utils.rs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
use std::collections::HashSet;
|
|
2
|
+
use std::path::PathBuf;
|
|
2
3
|
use std::process::Command;
|
|
3
4
|
|
|
4
5
|
pub fn list_ignored_files(
|
|
5
6
|
workspace_root_path: &str,
|
|
6
|
-
|
|
7
|
-
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
|
7
|
+
) -> Result<HashSet<PathBuf>, Box<dyn std::error::Error>> {
|
|
8
8
|
let mut gitignored_files = HashSet::new();
|
|
9
9
|
|
|
10
10
|
let commands = vec![
|
|
@@ -15,66 +15,12 @@ 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![
|
|
66
18
|
vec![
|
|
67
19
|
"git",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"--
|
|
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/|\"'",
|
|
20
|
+
"submodule",
|
|
21
|
+
"foreach",
|
|
22
|
+
"--quiet",
|
|
23
|
+
"git ls-files --others --ignored --exclude-standard | sed 's|^|$path/|'",
|
|
78
24
|
],
|
|
79
25
|
];
|
|
80
26
|
|
|
@@ -88,7 +34,7 @@ pub fn list_ignored_files_with_absolute_paths(
|
|
|
88
34
|
let files = String::from_utf8(output.stdout)?
|
|
89
35
|
.lines()
|
|
90
36
|
.filter(|line| !line.is_empty())
|
|
91
|
-
.map(|line|
|
|
37
|
+
.map(|line| PathBuf::from(line))
|
|
92
38
|
.collect::<HashSet<_>>();
|
|
93
39
|
|
|
94
40
|
gitignored_files.extend(files);
|
|
@@ -120,8 +66,7 @@ mod tests {
|
|
|
120
66
|
#[test]
|
|
121
67
|
fn test_no_ignored_files() {
|
|
122
68
|
let dir = tempfile::tempdir().unwrap();
|
|
123
|
-
let gitignored_files =
|
|
124
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
69
|
+
let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
|
|
125
70
|
Command::new("git")
|
|
126
71
|
.args(&["init"])
|
|
127
72
|
.current_dir(dir.path())
|
|
@@ -147,14 +92,13 @@ mod tests {
|
|
|
147
92
|
.current_dir(dir.path())
|
|
148
93
|
.output()
|
|
149
94
|
.unwrap();
|
|
150
|
-
let gitignored_files =
|
|
151
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
95
|
+
let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
|
|
152
96
|
println!(
|
|
153
97
|
"ignored files for test_one_ignored_file: {:?}",
|
|
154
98
|
gitignored_files
|
|
155
99
|
);
|
|
156
100
|
// assert_eq!(gitignored_files.len(), 1);
|
|
157
|
-
assert!(gitignored_files.contains(&
|
|
101
|
+
assert!(gitignored_files.contains(&PathBuf::from("ignored.txt")));
|
|
158
102
|
}
|
|
159
103
|
|
|
160
104
|
#[test]
|
|
@@ -177,83 +121,19 @@ mod tests {
|
|
|
177
121
|
.current_dir(dir.path())
|
|
178
122
|
.output()
|
|
179
123
|
.unwrap();
|
|
180
|
-
let gitignored_files =
|
|
181
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
124
|
+
let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
|
|
182
125
|
println!(
|
|
183
126
|
"ignored files for test_multiple_ignored_files: {:?}",
|
|
184
127
|
gitignored_files
|
|
185
128
|
);
|
|
186
129
|
// assert_eq!(gitignored_files.len(), 2);
|
|
187
|
-
assert!(gitignored_files.contains(&
|
|
188
|
-
assert!(gitignored_files.contains(&
|
|
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")));
|
|
130
|
+
assert!(gitignored_files.contains(&PathBuf::from("ignored1.txt")));
|
|
131
|
+
assert!(gitignored_files.contains(&PathBuf::from("ignored2.txt")));
|
|
252
132
|
}
|
|
253
133
|
|
|
254
134
|
#[test]
|
|
255
135
|
fn test_multiple_ignored_files_in_current_dir() {
|
|
256
|
-
let gitignored_files = list_ignored_files("."
|
|
136
|
+
let gitignored_files = list_ignored_files(".").unwrap();
|
|
257
137
|
assert!(gitignored_files.len() > 1);
|
|
258
138
|
|
|
259
139
|
// print a sample of the ignored files
|
|
@@ -267,6 +147,7 @@ mod tests {
|
|
|
267
147
|
}
|
|
268
148
|
}
|
|
269
149
|
|
|
150
|
+
|
|
270
151
|
#[tokio::test]
|
|
271
152
|
async fn test_file_not_ignored() {
|
|
272
153
|
let dir = tempfile::tempdir().unwrap();
|
|
@@ -279,10 +160,7 @@ mod tests {
|
|
|
279
160
|
.current_dir(dir.path())
|
|
280
161
|
.output()
|
|
281
162
|
.unwrap();
|
|
282
|
-
let is_ignored =
|
|
283
|
-
is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt")
|
|
284
|
-
.await
|
|
285
|
-
.unwrap();
|
|
163
|
+
let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt").await.unwrap();
|
|
286
164
|
assert_eq!(is_ignored, false);
|
|
287
165
|
}
|
|
288
166
|
|
|
@@ -302,10 +180,7 @@ mod tests {
|
|
|
302
180
|
.current_dir(dir.path())
|
|
303
181
|
.output()
|
|
304
182
|
.unwrap();
|
|
305
|
-
let is_ignored =
|
|
306
|
-
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
307
|
-
.await
|
|
308
|
-
.unwrap();
|
|
183
|
+
let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt").await.unwrap();
|
|
309
184
|
assert_eq!(is_ignored, true);
|
|
310
185
|
}
|
|
311
186
|
|
|
@@ -325,10 +200,8 @@ mod tests {
|
|
|
325
200
|
.current_dir(dir.path())
|
|
326
201
|
.output()
|
|
327
202
|
.unwrap();
|
|
328
|
-
let is_ignored =
|
|
329
|
-
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
330
|
-
.await
|
|
331
|
-
.unwrap();
|
|
203
|
+
let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt").await.unwrap();
|
|
332
204
|
assert_eq!(is_ignored, true);
|
|
333
205
|
}
|
|
206
|
+
|
|
334
207
|
}
|
package/src/lib.rs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#![deny(clippy::all)]
|
|
2
|
-
#![deny(unsafe_op_in_unsafe_fn)]
|
|
3
2
|
pub mod file_utils;
|
|
4
3
|
pub mod git_utils;
|
|
5
4
|
pub mod merkle_tree;
|
|
@@ -7,9 +6,6 @@ pub mod merkle_tree;
|
|
|
7
6
|
use std::vec;
|
|
8
7
|
|
|
9
8
|
use merkle_tree::{LocalConstruction, MerkleTree};
|
|
10
|
-
use tracing::{info, Level};
|
|
11
|
-
use tracing_appender::rolling::{RollingFileAppender, Rotation};
|
|
12
|
-
use tracing_subscriber::fmt;
|
|
13
9
|
|
|
14
10
|
#[macro_use]
|
|
15
11
|
extern crate napi_derive;
|
|
@@ -18,35 +14,15 @@ extern crate napi_derive;
|
|
|
18
14
|
pub struct MerkleClient {
|
|
19
15
|
tree: MerkleTree,
|
|
20
16
|
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
|
|
38
17
|
}
|
|
39
18
|
|
|
40
19
|
#[napi]
|
|
41
20
|
impl MerkleClient {
|
|
42
21
|
#[napi(constructor)]
|
|
43
22
|
pub fn new(root_directory: String) -> MerkleClient {
|
|
44
|
-
let _guard = init_logger();
|
|
45
|
-
|
|
46
23
|
MerkleClient {
|
|
47
24
|
tree: MerkleTree::empty_tree(),
|
|
48
25
|
root_directory,
|
|
49
|
-
_guard,
|
|
50
26
|
}
|
|
51
27
|
}
|
|
52
28
|
|
|
@@ -55,9 +31,7 @@ impl MerkleClient {
|
|
|
55
31
|
// 1. compute the merkle tree
|
|
56
32
|
// 2. update the backend
|
|
57
33
|
// 3. sync with the remote
|
|
58
|
-
|
|
59
|
-
self.compute_merkle_tree().await?;
|
|
60
|
-
}
|
|
34
|
+
self.compute_merkle_tree().await?;
|
|
61
35
|
|
|
62
36
|
Ok(())
|
|
63
37
|
}
|
|
@@ -73,17 +47,6 @@ impl MerkleClient {
|
|
|
73
47
|
let t =
|
|
74
48
|
MerkleTree::construct_merkle_tree(self.root_directory.clone()).await;
|
|
75
49
|
|
|
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
|
-
|
|
87
50
|
match t {
|
|
88
51
|
Ok(tree) => {
|
|
89
52
|
self.tree = tree;
|
|
@@ -111,13 +74,9 @@ impl MerkleClient {
|
|
|
111
74
|
&self,
|
|
112
75
|
relative_path: String,
|
|
113
76
|
) -> Result<String, napi::Error> {
|
|
114
|
-
info!("relative_path: {:?}", relative_path);
|
|
115
77
|
let absolute_path =
|
|
116
78
|
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
info!("canonical_path: {:?}", canonical_path);
|
|
120
|
-
let hash = self.tree.get_subtree_hash(canonical_path).await;
|
|
79
|
+
let hash = self.tree.get_subtree_hash(absolute_path).await;
|
|
121
80
|
|
|
122
81
|
match hash {
|
|
123
82
|
Ok(hash) => Ok(hash),
|
|
@@ -145,10 +104,8 @@ impl MerkleClient {
|
|
|
145
104
|
&self,
|
|
146
105
|
relative_path: String,
|
|
147
106
|
) -> Result<i32, napi::Error> {
|
|
148
|
-
let absolute_path =
|
|
149
|
-
.join(relative_path)
|
|
150
|
-
.canonicalize()?;
|
|
151
|
-
|
|
107
|
+
let absolute_path =
|
|
108
|
+
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
152
109
|
let num = self
|
|
153
110
|
.tree
|
|
154
111
|
.get_num_embeddable_files_in_subtree(absolute_path)
|
|
@@ -209,10 +166,7 @@ impl MerkleClient {
|
|
|
209
166
|
// TODO(sualeh): we should assert that the path is ascending up to the path.
|
|
210
167
|
|
|
211
168
|
let ret = vec![file];
|
|
212
|
-
info!("file: {:?}", ret);
|
|
213
|
-
|
|
214
169
|
let ret = ret.into_iter().chain(path.into_iter()).collect::<Vec<_>>();
|
|
215
|
-
info!("ret to js: {:?}", ret);
|
|
216
170
|
|
|
217
171
|
Ok(ret)
|
|
218
172
|
}
|
|
@@ -229,16 +183,17 @@ impl MerkleClient {
|
|
|
229
183
|
&self,
|
|
230
184
|
absolute_file_path: String,
|
|
231
185
|
) -> Result<Vec<String>, napi::Error> {
|
|
232
|
-
let
|
|
233
|
-
let spline = self.tree.get_spline(absolute_path_str).await;
|
|
186
|
+
// let spline = self.tree.get_spline(absolute_file_path).await;
|
|
234
187
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
188
|
+
return Ok(vec![]);
|
|
189
|
+
|
|
190
|
+
// match spline {
|
|
191
|
+
// Ok(spline) => Ok(spline),
|
|
192
|
+
// Err(e) => Err(napi::Error::new(
|
|
193
|
+
// napi::Status::Unknown,
|
|
194
|
+
// format!("Error in get_spline: {:?}", e),
|
|
195
|
+
// )),
|
|
196
|
+
// }
|
|
242
197
|
}
|
|
243
198
|
|
|
244
199
|
#[napi]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
use crate::git_utils;
|
|
2
1
|
use crate::merkle_tree::{
|
|
3
2
|
File, MerkleNode, MerkleNodePtr, NodeType, PinnedFuture,
|
|
4
3
|
};
|
|
5
4
|
|
|
6
5
|
use super::{LocalConstruction, MerkleTree};
|
|
7
|
-
use std::collections::
|
|
8
|
-
use std::path::
|
|
6
|
+
use std::collections::BTreeMap;
|
|
7
|
+
use std::path::PathBuf;
|
|
8
|
+
use std::{collections::HashMap, path::Path, sync::Arc};
|
|
9
9
|
use tonic::async_trait;
|
|
10
10
|
|
|
11
11
|
#[async_trait]
|
|
@@ -29,30 +29,20 @@ 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
|
+
root_directory: String,
|
|
33
33
|
) -> Result<MerkleTree, anyhow::Error> {
|
|
34
|
-
let path = PathBuf::from(
|
|
34
|
+
let path = PathBuf::from(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
|
-
|
|
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;
|
|
40
|
+
let root_node = MerkleNode::new(path, None).await;
|
|
50
41
|
let mut mt = MerkleTree {
|
|
51
42
|
root: root_node,
|
|
52
43
|
files: BTreeMap::new(),
|
|
53
|
-
root_path:
|
|
44
|
+
root_path: root_directory,
|
|
54
45
|
cursor: None,
|
|
55
|
-
git_ignored_files,
|
|
56
46
|
};
|
|
57
47
|
|
|
58
48
|
// we now iterate over all the nodes and add them to the hashmap
|
package/src/merkle_tree/mod.rs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
use super::file_utils;
|
|
2
2
|
use sha2::Digest;
|
|
3
|
-
use std::collections::
|
|
3
|
+
use std::collections::BTreeMap;
|
|
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;
|
|
9
8
|
pub mod local_construction;
|
|
10
9
|
pub mod test;
|
|
11
10
|
|
|
@@ -15,8 +14,7 @@ pub struct MerkleTree {
|
|
|
15
14
|
root_path: String,
|
|
16
15
|
root: MerkleNodePtr,
|
|
17
16
|
files: BTreeMap<String, File>,
|
|
18
|
-
cursor: Option<
|
|
19
|
-
git_ignored_files: HashSet<String>,
|
|
17
|
+
cursor: Option<MerkleNodePtr>,
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
#[derive(Debug)]
|
|
@@ -93,7 +91,6 @@ impl MerkleTree {
|
|
|
93
91
|
files: BTreeMap::new(),
|
|
94
92
|
root_path: "".to_string(),
|
|
95
93
|
cursor: None,
|
|
96
|
-
git_ignored_files: HashSet::new(),
|
|
97
94
|
}
|
|
98
95
|
}
|
|
99
96
|
|
|
@@ -159,7 +156,7 @@ impl MerkleTree {
|
|
|
159
156
|
}
|
|
160
157
|
};
|
|
161
158
|
|
|
162
|
-
// TODO(sualeh): worth keeping this list sorted.
|
|
159
|
+
// TODO(sualeh): worth keeping this list sorted.
|
|
163
160
|
|
|
164
161
|
for (_, file) in &self.files {
|
|
165
162
|
let file_reader = file.node.read().await;
|
|
@@ -237,44 +234,83 @@ impl MerkleTree {
|
|
|
237
234
|
pub async fn get_next_file_to_embed(
|
|
238
235
|
&mut self,
|
|
239
236
|
) -> Result<(String, Vec<String>), anyhow::Error> {
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
237
|
+
// the plan is to do an in-order traversal of the tree.
|
|
238
|
+
|
|
239
|
+
// first the edge case to deal with:
|
|
240
|
+
// cursor == None
|
|
241
|
+
if self.cursor.is_none() {
|
|
242
|
+
// If the root is a file, return its name.
|
|
243
|
+
if let NodeType::File(file_path) = &self.root.read().await.node_type {
|
|
244
|
+
return Ok((file_path.clone(), vec![]));
|
|
246
245
|
}
|
|
247
|
-
};
|
|
248
246
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
247
|
+
// if the path is not empty, we can iterate till we find the first child.
|
|
248
|
+
let mut potential_first_child = self.root.clone();
|
|
249
|
+
let mut is_branch = true;
|
|
250
|
+
let mut path = Vec::new();
|
|
251
|
+
|
|
252
|
+
while is_branch {
|
|
253
|
+
let node = {
|
|
254
|
+
let potential_first_child_reader = potential_first_child.read().await;
|
|
255
|
+
match &potential_first_child_reader.node_type {
|
|
256
|
+
NodeType::Branch(branch) => branch.clone(),
|
|
257
|
+
NodeType::File(_) => {
|
|
258
|
+
return Err(anyhow::anyhow!(
|
|
259
|
+
"get_next_file_to_embed: This should not happen! the branch happened to be file."
|
|
260
|
+
));
|
|
261
|
+
}
|
|
262
|
+
NodeType::ErrorNode(_) => {
|
|
263
|
+
return Err(anyhow::anyhow!("Cursor is an error node!"));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
259
267
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
let current_node_name = &node.0;
|
|
269
|
+
let child_list = &node.1;
|
|
270
|
+
|
|
271
|
+
if let Some(c) = child_list.first() {
|
|
272
|
+
let c_reader = c.read().await;
|
|
273
|
+
|
|
274
|
+
match &c_reader.node_type {
|
|
275
|
+
NodeType::File(file_path) => {
|
|
276
|
+
// must set the cursor!
|
|
277
|
+
self.cursor = Some(c.clone());
|
|
278
|
+
|
|
279
|
+
return Ok((file_path.clone(), path));
|
|
280
|
+
}
|
|
281
|
+
NodeType::Branch(_) => {
|
|
282
|
+
potential_first_child = c.clone();
|
|
283
|
+
is_branch = true;
|
|
284
|
+
|
|
285
|
+
// add the path to the current node.
|
|
286
|
+
path.push(current_node_name.clone());
|
|
287
|
+
}
|
|
288
|
+
NodeType::ErrorNode(_) => {
|
|
289
|
+
return Err(anyhow::anyhow!("Cursor is an error node!"));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
// If the root has no children, return an error.
|
|
294
|
+
return Err(anyhow::anyhow!("Root has no children!"));
|
|
275
295
|
}
|
|
276
296
|
}
|
|
277
297
|
}
|
|
298
|
+
|
|
299
|
+
// THE DEFAULT CASE:
|
|
300
|
+
// we already have a cursor at a file.
|
|
301
|
+
|
|
302
|
+
// UNWRAP checked and fine. see the none case above.
|
|
303
|
+
let cursor_name = self.cursor.as_ref().unwrap();
|
|
304
|
+
let cursor_reader = cursor_name.read().await;
|
|
305
|
+
|
|
306
|
+
// invariant: you must be a file!!
|
|
307
|
+
|
|
308
|
+
// everytime we get to a child list, we will add all the children to a fifo, and then pull from it as long as we need it.
|
|
309
|
+
|
|
310
|
+
// algorithm:
|
|
311
|
+
// 1.
|
|
312
|
+
|
|
313
|
+
Err(anyhow::anyhow!("Could not find file to embed!"))
|
|
278
314
|
}
|
|
279
315
|
|
|
280
316
|
pub async fn get_all_dir_files_to_embed(
|
|
@@ -304,54 +340,6 @@ impl MerkleTree {
|
|
|
304
340
|
Ok(files)
|
|
305
341
|
}
|
|
306
342
|
|
|
307
|
-
// TODO(sualeh): i need tests for this!!
|
|
308
|
-
pub async fn get_spline(
|
|
309
|
-
&self,
|
|
310
|
-
absolute_path: &str,
|
|
311
|
-
) -> Result<Vec<String>, anyhow::Error> {
|
|
312
|
-
info!("get_spline called with absolute_path: {}", absolute_path);
|
|
313
|
-
let mut files = Vec::new();
|
|
314
|
-
|
|
315
|
-
let current_node = match self.files.get(absolute_path) {
|
|
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
|
-
}
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
let mut stack = Vec::new();
|
|
327
|
-
stack.push(current_node);
|
|
328
|
-
|
|
329
|
-
while let Some(node) = stack.pop() {
|
|
330
|
-
let parent = node.read().await.parent.clone();
|
|
331
|
-
if let Some(parent) = parent {
|
|
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
|
-
|
|
348
|
-
stack.push(parent);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
info!("Returning files vector with {} elements", files.len());
|
|
352
|
-
Ok(files)
|
|
353
|
-
}
|
|
354
|
-
|
|
355
343
|
/// creates a new node and attaches it to the current tree.
|
|
356
344
|
/// SPEC:
|
|
357
345
|
/// - you are allowed to create a file with a node such that the
|
|
@@ -391,12 +379,8 @@ impl MerkleTree {
|
|
|
391
379
|
0 => {
|
|
392
380
|
// this means that the ancestor is the root.
|
|
393
381
|
// we need to create a new node and attach it to the ancestor.
|
|
394
|
-
let new_node =
|
|
395
|
-
file_path.clone(),
|
|
396
|
-
Some(ancestor.clone()),
|
|
397
|
-
&self.git_ignored_files,
|
|
398
|
-
)
|
|
399
|
-
.await;
|
|
382
|
+
let new_node =
|
|
383
|
+
MerkleNode::new(file_path.clone(), Some(ancestor.clone())).await;
|
|
400
384
|
ancestor.write().await.attach_child(new_node.clone()).await;
|
|
401
385
|
new_node
|
|
402
386
|
}
|
|
@@ -407,12 +391,9 @@ impl MerkleTree {
|
|
|
407
391
|
// UNSURE: not sure this is the correct thing to do but it is the fastest.
|
|
408
392
|
// get the last thing that is not in the tree.
|
|
409
393
|
let first_child_path = path.last().unwrap();
|
|
410
|
-
let first_child =
|
|
411
|
-
first_child_path.clone(),
|
|
412
|
-
|
|
413
|
-
&self.git_ignored_files,
|
|
414
|
-
)
|
|
415
|
-
.await;
|
|
394
|
+
let first_child =
|
|
395
|
+
MerkleNode::new(first_child_path.clone(), Some(ancestor.clone()))
|
|
396
|
+
.await;
|
|
416
397
|
|
|
417
398
|
// TODO(sualeh): we should do an assertion check that the entire vec is contained here.
|
|
418
399
|
|
|
@@ -689,34 +670,18 @@ use std::future::Future;
|
|
|
689
670
|
use std::pin::Pin;
|
|
690
671
|
|
|
691
672
|
type PinnedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
|
692
|
-
type IgnoredFiles = HashSet<String>;
|
|
693
673
|
|
|
694
674
|
impl MerkleNode {
|
|
695
675
|
/// please be careful using this.
|
|
696
676
|
async fn __new_unchecked(
|
|
697
677
|
file_or_directory: String,
|
|
698
678
|
parent: ParentPtr,
|
|
699
|
-
ignored_files: &IgnoredFiles,
|
|
700
679
|
) -> MerkleNodePtr {
|
|
701
|
-
MerkleNode::construct_node(
|
|
702
|
-
Path::new(&file_or_directory),
|
|
703
|
-
parent,
|
|
704
|
-
ignored_files,
|
|
705
|
-
)
|
|
706
|
-
.await
|
|
680
|
+
MerkleNode::construct_node(Path::new(&file_or_directory), parent).await
|
|
707
681
|
}
|
|
708
682
|
|
|
709
|
-
async fn new(
|
|
710
|
-
|
|
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
|
|
683
|
+
async fn new(file_or_directory: PathBuf, parent: ParentPtr) -> MerkleNodePtr {
|
|
684
|
+
MerkleNode::construct_node(Path::new(&file_or_directory), parent).await
|
|
720
685
|
}
|
|
721
686
|
|
|
722
687
|
/// NOT added to the tree by default.
|
|
@@ -727,40 +692,38 @@ impl MerkleNode {
|
|
|
727
692
|
// let file_hash = self.files.get_mut(&file_path).unwrap();
|
|
728
693
|
|
|
729
694
|
fn construct_node<'a>(
|
|
730
|
-
|
|
695
|
+
file_or_directory: &'a Path,
|
|
731
696
|
parent: ParentPtr,
|
|
732
|
-
ignored_files: &'a IgnoredFiles,
|
|
733
697
|
) -> PinnedFuture<'a, MerkleNodePtr> {
|
|
734
698
|
Box::pin(async move {
|
|
735
699
|
// check if it is a file
|
|
736
|
-
let path_str =
|
|
737
|
-
if
|
|
700
|
+
let path_str = file_or_directory.to_str().unwrap().to_string();
|
|
701
|
+
if file_or_directory.is_file() {
|
|
738
702
|
return Arc::new(RwLock::new(
|
|
739
703
|
MerkleNode::construct_file_node_or_error_node(
|
|
740
|
-
|
|
704
|
+
file_or_directory,
|
|
741
705
|
parent,
|
|
742
|
-
ignored_files,
|
|
743
706
|
)
|
|
744
707
|
.await,
|
|
745
708
|
));
|
|
746
709
|
}
|
|
747
710
|
|
|
748
711
|
// check if the directory fails the bad dir test.
|
|
749
|
-
let is_bad_dir = file_utils::is_in_bad_dir(
|
|
712
|
+
let is_bad_dir = file_utils::is_in_bad_dir(file_or_directory);
|
|
750
713
|
if is_bad_dir.is_err() || is_bad_dir.unwrap_or(false) {
|
|
751
714
|
// println!("skipping directory: {}", path_str);
|
|
752
715
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
753
|
-
Some(
|
|
716
|
+
Some(file_or_directory),
|
|
754
717
|
Some("Directory is in bad dir!".to_string()),
|
|
755
718
|
)));
|
|
756
719
|
}
|
|
757
720
|
|
|
758
|
-
let entries = fs::read_dir(
|
|
721
|
+
let entries = fs::read_dir(file_or_directory);
|
|
759
722
|
match entries {
|
|
760
723
|
Ok(_) => (),
|
|
761
724
|
Err(e) => {
|
|
762
725
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
763
|
-
Some(
|
|
726
|
+
Some(file_or_directory),
|
|
764
727
|
Some(e.to_string()),
|
|
765
728
|
)));
|
|
766
729
|
}
|
|
@@ -780,17 +743,13 @@ impl MerkleNode {
|
|
|
780
743
|
match entry {
|
|
781
744
|
Ok(entry) => {
|
|
782
745
|
children.push(
|
|
783
|
-
MerkleNode::construct_node(
|
|
784
|
-
|
|
785
|
-
Some(node.clone()),
|
|
786
|
-
ignored_files,
|
|
787
|
-
)
|
|
788
|
-
.await,
|
|
746
|
+
MerkleNode::construct_node(&entry.path(), Some(node.clone()))
|
|
747
|
+
.await,
|
|
789
748
|
);
|
|
790
749
|
}
|
|
791
750
|
Err(e) => {
|
|
792
751
|
children.push(Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
793
|
-
Some(
|
|
752
|
+
Some(file_or_directory),
|
|
794
753
|
Some(e.to_string()),
|
|
795
754
|
))));
|
|
796
755
|
}
|
|
@@ -810,33 +769,23 @@ impl MerkleNode {
|
|
|
810
769
|
}
|
|
811
770
|
|
|
812
771
|
async fn construct_file_node(
|
|
813
|
-
|
|
772
|
+
file_path: &Path,
|
|
814
773
|
parent: ParentPtr,
|
|
815
|
-
ignored_files: &IgnoredFiles,
|
|
816
774
|
) -> Result<MerkleNode, String> {
|
|
817
|
-
let file_str =
|
|
775
|
+
let file_str = file_path
|
|
818
776
|
.to_str()
|
|
819
777
|
.ok_or("Could not convert file path to string!")?
|
|
820
778
|
.to_string();
|
|
821
779
|
// first see if it passes the
|
|
822
|
-
match file_utils::is_good_file(
|
|
780
|
+
match file_utils::is_good_file(file_path) {
|
|
823
781
|
Ok(_) => {}
|
|
824
782
|
Err(e) => {
|
|
825
783
|
return Err(format!("File failed runtime checks! {}", e.to_string()));
|
|
826
784
|
}
|
|
827
785
|
}
|
|
828
786
|
|
|
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
|
-
|
|
838
787
|
// read the file_content to a buffer
|
|
839
|
-
let file_content = match tokio::fs::read(
|
|
788
|
+
let file_content = match tokio::fs::read(file_path).await {
|
|
840
789
|
Ok(content) => content,
|
|
841
790
|
Err(e) => {
|
|
842
791
|
return Err(format!("Could not read file! {}", e.to_string()));
|
|
@@ -844,11 +793,7 @@ impl MerkleNode {
|
|
|
844
793
|
};
|
|
845
794
|
|
|
846
795
|
// check if the file passes runtime checks.
|
|
847
|
-
match file_utils::is_good_file_runtime_check(
|
|
848
|
-
absolute_file_path,
|
|
849
|
-
&file_content,
|
|
850
|
-
)
|
|
851
|
-
.await
|
|
796
|
+
match file_utils::is_good_file_runtime_check(file_path, &file_content).await
|
|
852
797
|
{
|
|
853
798
|
Ok(_) => {}
|
|
854
799
|
Err(e) => {
|
|
@@ -879,22 +824,15 @@ impl MerkleNode {
|
|
|
879
824
|
}
|
|
880
825
|
|
|
881
826
|
async fn construct_file_node_or_error_node(
|
|
882
|
-
|
|
827
|
+
file_path: &Path,
|
|
883
828
|
parent: ParentPtr,
|
|
884
|
-
ignored_files: &IgnoredFiles,
|
|
885
829
|
) -> MerkleNode {
|
|
886
|
-
let node = match MerkleNode::construct_file_node(
|
|
887
|
-
absolute_file_path,
|
|
888
|
-
parent,
|
|
889
|
-
ignored_files,
|
|
890
|
-
)
|
|
891
|
-
.await
|
|
892
|
-
{
|
|
830
|
+
let node = match MerkleNode::construct_file_node(file_path, parent).await {
|
|
893
831
|
Ok(node) => node,
|
|
894
832
|
Err(e) => {
|
|
895
833
|
// println!("constructing error node. error: {}", e);
|
|
896
834
|
// println!("file_path: {:?}", file_path);
|
|
897
|
-
MerkleNode::empty_node(Some(
|
|
835
|
+
MerkleNode::empty_node(Some(file_path), Some(e))
|
|
898
836
|
}
|
|
899
837
|
};
|
|
900
838
|
|