@anysphere/file-service 0.0.0-dbd43428 → 0.0.0-e3fdf62d
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/index.d.ts +1 -5
- package/package.json +7 -7
- package/src/file_utils.rs +5 -4
- package/src/git_utils.rs +19 -158
- package/src/lib.rs +5 -111
- package/src/merkle_tree/local_construction.rs +8 -27
- package/src/merkle_tree/mod.rs +98 -292
- package/src/test.rs +0 -5
package/Cargo.toml
CHANGED
package/index.d.ts
CHANGED
|
@@ -6,15 +6,11 @@
|
|
|
6
6
|
export class MerkleClient {
|
|
7
7
|
constructor(rootDirectory: string)
|
|
8
8
|
init(): Promise<void>
|
|
9
|
-
computeMerkleTree(): Promise<void>
|
|
10
9
|
updateFile(filePath: string): Promise<void>
|
|
11
10
|
deleteFile(filePath: string): Promise<void>
|
|
12
|
-
getSubtreeHash(
|
|
11
|
+
getSubtreeHash(path: string): Promise<string>
|
|
13
12
|
getNumEmbeddableFiles(): Promise<number>
|
|
14
13
|
getAllFiles(): Promise<Array<string>>
|
|
15
|
-
getAllDirFilesToEmbed(absoluteFilePath: string): Promise<Array<string>>
|
|
16
14
|
getNextFileToEmbed(): Promise<Array<string>>
|
|
17
|
-
getSpline(absoluteFilePath: string): Promise<Array<string>>
|
|
18
15
|
getHashesForFiles(files: Array<string>): Promise<Array<string>>
|
|
19
|
-
updateRootDirectory(rootDirectory: string): void
|
|
20
16
|
}
|
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-e3fdf62d",
|
|
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-e3fdf62d",
|
|
39
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-e3fdf62d",
|
|
40
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-e3fdf62d",
|
|
41
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-e3fdf62d",
|
|
42
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-e3fdf62d",
|
|
43
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-e3fdf62d"
|
|
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);
|
|
@@ -111,18 +57,6 @@ pub async fn is_git_ignored(
|
|
|
111
57
|
Ok(output.status.success())
|
|
112
58
|
}
|
|
113
59
|
|
|
114
|
-
pub async fn is_git_directory(
|
|
115
|
-
workspace_root_path: &str,
|
|
116
|
-
) -> Result<bool, anyhow::Error> {
|
|
117
|
-
let output = tokio::process::Command::new("git")
|
|
118
|
-
.args(&["rev-parse", "--is-inside-work-tree"])
|
|
119
|
-
.current_dir(workspace_root_path)
|
|
120
|
-
.output()
|
|
121
|
-
.await?;
|
|
122
|
-
|
|
123
|
-
Ok(output.status.success())
|
|
124
|
-
}
|
|
125
|
-
|
|
126
60
|
#[cfg(test)]
|
|
127
61
|
mod tests {
|
|
128
62
|
use super::*;
|
|
@@ -132,8 +66,7 @@ mod tests {
|
|
|
132
66
|
#[test]
|
|
133
67
|
fn test_no_ignored_files() {
|
|
134
68
|
let dir = tempfile::tempdir().unwrap();
|
|
135
|
-
let gitignored_files =
|
|
136
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
69
|
+
let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
|
|
137
70
|
Command::new("git")
|
|
138
71
|
.args(&["init"])
|
|
139
72
|
.current_dir(dir.path())
|
|
@@ -159,14 +92,13 @@ mod tests {
|
|
|
159
92
|
.current_dir(dir.path())
|
|
160
93
|
.output()
|
|
161
94
|
.unwrap();
|
|
162
|
-
let gitignored_files =
|
|
163
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
95
|
+
let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
|
|
164
96
|
println!(
|
|
165
97
|
"ignored files for test_one_ignored_file: {:?}",
|
|
166
98
|
gitignored_files
|
|
167
99
|
);
|
|
168
100
|
// assert_eq!(gitignored_files.len(), 1);
|
|
169
|
-
assert!(gitignored_files.contains(&
|
|
101
|
+
assert!(gitignored_files.contains(&PathBuf::from("ignored.txt")));
|
|
170
102
|
}
|
|
171
103
|
|
|
172
104
|
#[test]
|
|
@@ -189,83 +121,19 @@ mod tests {
|
|
|
189
121
|
.current_dir(dir.path())
|
|
190
122
|
.output()
|
|
191
123
|
.unwrap();
|
|
192
|
-
let gitignored_files =
|
|
193
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
124
|
+
let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
|
|
194
125
|
println!(
|
|
195
126
|
"ignored files for test_multiple_ignored_files: {:?}",
|
|
196
127
|
gitignored_files
|
|
197
128
|
);
|
|
198
129
|
// assert_eq!(gitignored_files.len(), 2);
|
|
199
|
-
assert!(gitignored_files.contains(&
|
|
200
|
-
assert!(gitignored_files.contains(&
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
#[test]
|
|
204
|
-
fn test_git_submodule_ignored_files() {
|
|
205
|
-
let dir = tempfile::tempdir().unwrap();
|
|
206
|
-
let submodule_path = dir.path().join("submodule");
|
|
207
|
-
std::fs::create_dir(&submodule_path).unwrap();
|
|
208
|
-
|
|
209
|
-
let o = Command::new("git")
|
|
210
|
-
.args(&["init"])
|
|
211
|
-
.current_dir(&submodule_path)
|
|
212
|
-
.output()
|
|
213
|
-
.unwrap();
|
|
214
|
-
println!("git init output: {:?}", o);
|
|
215
|
-
|
|
216
|
-
let file_path = submodule_path.join("ignored.txt");
|
|
217
|
-
let mut file = File::create(&file_path).unwrap();
|
|
218
|
-
writeln!(file, "This is an ignored file.").unwrap();
|
|
219
|
-
|
|
220
|
-
let file2 = submodule_path.join("ignored2.txt");
|
|
221
|
-
let mut file = File::create(&file2).unwrap();
|
|
222
|
-
writeln!(file, "This is another ignored file.").unwrap();
|
|
223
|
-
|
|
224
|
-
let gitignore_path = submodule_path.join(".gitignore");
|
|
225
|
-
let mut gitignore = File::create(&gitignore_path).unwrap();
|
|
226
|
-
writeln!(gitignore, "*.txt").unwrap();
|
|
227
|
-
|
|
228
|
-
let o = Command::new("git")
|
|
229
|
-
.args(&["init"])
|
|
230
|
-
.current_dir(dir.path())
|
|
231
|
-
.output()
|
|
232
|
-
.unwrap();
|
|
233
|
-
println!("git init output: {:?}", o);
|
|
234
|
-
|
|
235
|
-
// make a commit in the submodule
|
|
236
|
-
let o = Command::new("git")
|
|
237
|
-
.args(&["add", "."])
|
|
238
|
-
.current_dir(&submodule_path)
|
|
239
|
-
.output()
|
|
240
|
-
.unwrap();
|
|
241
|
-
println!("git add output: {:?}", o);
|
|
242
|
-
let o = Command::new("git")
|
|
243
|
-
.args(&["commit", "-m", "initial commit"])
|
|
244
|
-
.current_dir(&submodule_path)
|
|
245
|
-
.output()
|
|
246
|
-
.unwrap();
|
|
247
|
-
println!("git commit output: {:?}", o);
|
|
248
|
-
|
|
249
|
-
let o = Command::new("git")
|
|
250
|
-
.args(&["submodule", "add", "./submodule"])
|
|
251
|
-
.current_dir(dir.path())
|
|
252
|
-
.output()
|
|
253
|
-
.unwrap();
|
|
254
|
-
println!("git submodule add output: {:?}", o);
|
|
255
|
-
|
|
256
|
-
let gitignored_files =
|
|
257
|
-
list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
|
|
258
|
-
println!(
|
|
259
|
-
"ignored files for test_git_submodule_ignored_files: {:?}",
|
|
260
|
-
gitignored_files
|
|
261
|
-
);
|
|
262
|
-
assert!(gitignored_files.contains(&String::from("submodule/ignored.txt")));
|
|
263
|
-
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")));
|
|
264
132
|
}
|
|
265
133
|
|
|
266
134
|
#[test]
|
|
267
135
|
fn test_multiple_ignored_files_in_current_dir() {
|
|
268
|
-
let gitignored_files = list_ignored_files("."
|
|
136
|
+
let gitignored_files = list_ignored_files(".").unwrap();
|
|
269
137
|
assert!(gitignored_files.len() > 1);
|
|
270
138
|
|
|
271
139
|
// print a sample of the ignored files
|
|
@@ -279,6 +147,7 @@ mod tests {
|
|
|
279
147
|
}
|
|
280
148
|
}
|
|
281
149
|
|
|
150
|
+
|
|
282
151
|
#[tokio::test]
|
|
283
152
|
async fn test_file_not_ignored() {
|
|
284
153
|
let dir = tempfile::tempdir().unwrap();
|
|
@@ -291,10 +160,7 @@ mod tests {
|
|
|
291
160
|
.current_dir(dir.path())
|
|
292
161
|
.output()
|
|
293
162
|
.unwrap();
|
|
294
|
-
let is_ignored =
|
|
295
|
-
is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt")
|
|
296
|
-
.await
|
|
297
|
-
.unwrap();
|
|
163
|
+
let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt").await.unwrap();
|
|
298
164
|
assert_eq!(is_ignored, false);
|
|
299
165
|
}
|
|
300
166
|
|
|
@@ -314,10 +180,7 @@ mod tests {
|
|
|
314
180
|
.current_dir(dir.path())
|
|
315
181
|
.output()
|
|
316
182
|
.unwrap();
|
|
317
|
-
let is_ignored =
|
|
318
|
-
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
319
|
-
.await
|
|
320
|
-
.unwrap();
|
|
183
|
+
let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt").await.unwrap();
|
|
321
184
|
assert_eq!(is_ignored, true);
|
|
322
185
|
}
|
|
323
186
|
|
|
@@ -337,10 +200,8 @@ mod tests {
|
|
|
337
200
|
.current_dir(dir.path())
|
|
338
201
|
.output()
|
|
339
202
|
.unwrap();
|
|
340
|
-
let is_ignored =
|
|
341
|
-
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
342
|
-
.await
|
|
343
|
-
.unwrap();
|
|
203
|
+
let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt").await.unwrap();
|
|
344
204
|
assert_eq!(is_ignored, true);
|
|
345
205
|
}
|
|
206
|
+
|
|
346
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
|
}
|
|
@@ -66,24 +40,13 @@ impl MerkleClient {
|
|
|
66
40
|
unimplemented!("Interrupt is not implemented yet");
|
|
67
41
|
}
|
|
68
42
|
|
|
69
|
-
#[napi]
|
|
43
|
+
// #[napi]
|
|
70
44
|
pub async unsafe fn compute_merkle_tree(
|
|
71
45
|
&mut self,
|
|
72
46
|
) -> Result<(), napi::Error> {
|
|
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;
|
|
@@ -109,15 +72,9 @@ impl MerkleClient {
|
|
|
109
72
|
#[napi]
|
|
110
73
|
pub async fn get_subtree_hash(
|
|
111
74
|
&self,
|
|
112
|
-
|
|
75
|
+
path: String,
|
|
113
76
|
) -> Result<String, napi::Error> {
|
|
114
|
-
|
|
115
|
-
let absolute_path =
|
|
116
|
-
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
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;
|
|
77
|
+
let hash = self.tree.get_subtree_hash(path).await;
|
|
121
78
|
|
|
122
79
|
match hash {
|
|
123
80
|
Ok(hash) => Ok(hash),
|
|
@@ -141,28 +98,6 @@ impl MerkleClient {
|
|
|
141
98
|
}
|
|
142
99
|
}
|
|
143
100
|
|
|
144
|
-
pub async fn get_num_embeddable_files_in_subtree(
|
|
145
|
-
&self,
|
|
146
|
-
relative_path: String,
|
|
147
|
-
) -> Result<i32, napi::Error> {
|
|
148
|
-
let absolute_path = std::path::Path::new(&self.root_directory)
|
|
149
|
-
.join(relative_path)
|
|
150
|
-
.canonicalize()?;
|
|
151
|
-
|
|
152
|
-
let num = self
|
|
153
|
-
.tree
|
|
154
|
-
.get_num_embeddable_files_in_subtree(absolute_path)
|
|
155
|
-
.await;
|
|
156
|
-
|
|
157
|
-
match num {
|
|
158
|
-
Ok(num) => Ok(num),
|
|
159
|
-
Err(e) => Err(napi::Error::new(
|
|
160
|
-
napi::Status::Unknown,
|
|
161
|
-
format!("Error in get_num_embeddable_files_in_subtree: {:?}", e),
|
|
162
|
-
)),
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
101
|
#[napi]
|
|
167
102
|
pub async fn get_all_files(&self) -> Result<Vec<String>, napi::Error> {
|
|
168
103
|
let files = self.tree.get_all_files().await;
|
|
@@ -176,26 +111,6 @@ impl MerkleClient {
|
|
|
176
111
|
}
|
|
177
112
|
}
|
|
178
113
|
|
|
179
|
-
#[napi]
|
|
180
|
-
pub async fn get_all_dir_files_to_embed(
|
|
181
|
-
&self,
|
|
182
|
-
absolute_file_path: String,
|
|
183
|
-
) -> Result<Vec<String>, napi::Error> {
|
|
184
|
-
let absolute_path_str = absolute_file_path.as_str();
|
|
185
|
-
let files = self
|
|
186
|
-
.tree
|
|
187
|
-
.get_all_dir_files_to_embed(absolute_path_str)
|
|
188
|
-
.await;
|
|
189
|
-
|
|
190
|
-
match files {
|
|
191
|
-
Ok(files) => Ok(files),
|
|
192
|
-
Err(e) => Err(napi::Error::new(
|
|
193
|
-
napi::Status::Unknown,
|
|
194
|
-
format!("Error in get_all_dir_files_to_embed: {:?}", e),
|
|
195
|
-
)),
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
114
|
#[napi]
|
|
200
115
|
pub async unsafe fn get_next_file_to_embed(
|
|
201
116
|
&mut self,
|
|
@@ -209,10 +124,7 @@ impl MerkleClient {
|
|
|
209
124
|
// TODO(sualeh): we should assert that the path is ascending up to the path.
|
|
210
125
|
|
|
211
126
|
let ret = vec![file];
|
|
212
|
-
info!("file: {:?}", ret);
|
|
213
|
-
|
|
214
127
|
let ret = ret.into_iter().chain(path.into_iter()).collect::<Vec<_>>();
|
|
215
|
-
info!("ret to js: {:?}", ret);
|
|
216
128
|
|
|
217
129
|
Ok(ret)
|
|
218
130
|
}
|
|
@@ -223,24 +135,6 @@ impl MerkleClient {
|
|
|
223
135
|
}
|
|
224
136
|
}
|
|
225
137
|
|
|
226
|
-
// FIXME(sualeh): get_spline
|
|
227
|
-
#[napi]
|
|
228
|
-
pub async fn get_spline(
|
|
229
|
-
&self,
|
|
230
|
-
absolute_file_path: String,
|
|
231
|
-
) -> Result<Vec<String>, napi::Error> {
|
|
232
|
-
let absolute_path_str = absolute_file_path.as_str();
|
|
233
|
-
let spline = self.tree.get_spline(absolute_path_str).await;
|
|
234
|
-
|
|
235
|
-
match spline {
|
|
236
|
-
Ok(spline) => Ok(spline),
|
|
237
|
-
Err(e) => Err(napi::Error::new(
|
|
238
|
-
napi::Status::Unknown,
|
|
239
|
-
format!("Error in get_spline: {:?}", e),
|
|
240
|
-
)),
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
138
|
#[napi]
|
|
245
139
|
pub async fn get_hashes_for_files(
|
|
246
140
|
&self,
|
|
@@ -257,7 +151,7 @@ impl MerkleClient {
|
|
|
257
151
|
}
|
|
258
152
|
}
|
|
259
153
|
|
|
260
|
-
#[napi]
|
|
154
|
+
// #[napi]
|
|
261
155
|
pub fn update_root_directory(&mut self, root_directory: String) {
|
|
262
156
|
self.root_directory = root_directory;
|
|
263
157
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
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::
|
|
8
|
-
use std::path::
|
|
6
|
+
use std::path::PathBuf;
|
|
7
|
+
use std::{collections::HashMap, path::Path, sync::Arc};
|
|
9
8
|
use tonic::async_trait;
|
|
10
9
|
|
|
11
10
|
#[async_trait]
|
|
@@ -29,45 +28,27 @@ impl LocalConstruction for MerkleTree {
|
|
|
29
28
|
/// 3. construct merkle tree
|
|
30
29
|
/// 4. return merkle tree
|
|
31
30
|
async fn construct_merkle_tree(
|
|
32
|
-
|
|
31
|
+
root_directory: String,
|
|
33
32
|
) -> Result<MerkleTree, anyhow::Error> {
|
|
34
|
-
let path = PathBuf::from(
|
|
33
|
+
let path = PathBuf::from(root_directory.clone());
|
|
35
34
|
if !path.exists() {
|
|
36
35
|
// FIXME: we should report this via a good logger.
|
|
37
36
|
panic!("Root directory does not exist!");
|
|
38
37
|
}
|
|
39
38
|
|
|
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
|
-
tracing::info!("git_ignored_files: {:?}", git_ignored_files);
|
|
50
|
-
|
|
51
|
-
let root_node = MerkleNode::new(
|
|
52
|
-
path,
|
|
53
|
-
None,
|
|
54
|
-
&git_ignored_files,
|
|
55
|
-
absolute_path_to_root_directory.as_str(),
|
|
56
|
-
)
|
|
57
|
-
.await;
|
|
39
|
+
let root_node = MerkleNode::new(path, None).await;
|
|
58
40
|
let mut mt = MerkleTree {
|
|
59
41
|
root: root_node,
|
|
60
|
-
files:
|
|
61
|
-
root_path:
|
|
42
|
+
files: HashMap::new(),
|
|
43
|
+
root_path: root_directory,
|
|
62
44
|
cursor: None,
|
|
63
|
-
git_ignored_files,
|
|
64
45
|
};
|
|
65
46
|
|
|
66
47
|
// we now iterate over all the nodes and add them to the hashmap
|
|
67
48
|
// TODO(later): i can make this parallel.
|
|
68
49
|
fn add_nodes_to_hashmap<'a>(
|
|
69
50
|
node: &'a MerkleNodePtr,
|
|
70
|
-
files: &'a mut
|
|
51
|
+
files: &'a mut HashMap<String, File>,
|
|
71
52
|
) -> PinnedFuture<'a, ()> {
|
|
72
53
|
Box::pin(async move {
|
|
73
54
|
let node_reader = node.read().await;
|
package/src/merkle_tree/mod.rs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
use crate::git_utils;
|
|
2
|
-
|
|
3
1
|
use super::file_utils;
|
|
4
2
|
use sha2::Digest;
|
|
5
|
-
use std::collections::{BTreeMap, HashSet};
|
|
6
3
|
use std::path::PathBuf;
|
|
7
|
-
use std::{fs, path::Path, sync::Arc};
|
|
4
|
+
use std::{collections::HashMap, fs, path::Path, sync::Arc};
|
|
8
5
|
use tokio::sync::RwLock;
|
|
9
6
|
use tonic::async_trait;
|
|
10
|
-
use tracing::info;
|
|
11
7
|
pub mod local_construction;
|
|
12
8
|
pub mod test;
|
|
13
9
|
|
|
@@ -16,9 +12,8 @@ pub type MerkleNodePtr = Arc<RwLock<MerkleNode>>;
|
|
|
16
12
|
pub struct MerkleTree {
|
|
17
13
|
root_path: String,
|
|
18
14
|
root: MerkleNodePtr,
|
|
19
|
-
files:
|
|
20
|
-
cursor: Option<
|
|
21
|
-
git_ignored_files: HashSet<String>,
|
|
15
|
+
files: HashMap<String, File>,
|
|
16
|
+
cursor: Option<MerkleNodePtr>,
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
#[derive(Debug)]
|
|
@@ -92,27 +87,18 @@ impl MerkleTree {
|
|
|
92
87
|
pub fn empty_tree() -> MerkleTree {
|
|
93
88
|
MerkleTree {
|
|
94
89
|
root: Arc::new(RwLock::new(MerkleNode::empty_node(None, None))),
|
|
95
|
-
files:
|
|
90
|
+
files: HashMap::new(),
|
|
96
91
|
root_path: "".to_string(),
|
|
97
92
|
cursor: None,
|
|
98
|
-
git_ignored_files: HashSet::new(),
|
|
99
93
|
}
|
|
100
94
|
}
|
|
101
95
|
|
|
102
96
|
pub async fn get_subtree_hash(
|
|
103
97
|
&self,
|
|
104
|
-
|
|
98
|
+
path: String,
|
|
105
99
|
) -> Result<String, anyhow::Error> {
|
|
106
|
-
let
|
|
107
|
-
|
|
108
|
-
None => {
|
|
109
|
-
return Err(anyhow::anyhow!(
|
|
110
|
-
"get_subtree_hash: Failed to convert path to string"
|
|
111
|
-
))
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
let node = match self.files.get(&abs_string) {
|
|
100
|
+
let path = PathBuf::from(path);
|
|
101
|
+
let node = match self.files.get(path.to_str().unwrap()) {
|
|
116
102
|
Some(file) => file.node.clone(),
|
|
117
103
|
None => {
|
|
118
104
|
return Err(anyhow::anyhow!("Could not find file in tree!"));
|
|
@@ -146,43 +132,6 @@ impl MerkleTree {
|
|
|
146
132
|
Ok(count)
|
|
147
133
|
}
|
|
148
134
|
|
|
149
|
-
pub async fn get_num_embeddable_files_in_subtree(
|
|
150
|
-
&self,
|
|
151
|
-
absolute_path: PathBuf,
|
|
152
|
-
) -> Result<i32, anyhow::Error> {
|
|
153
|
-
let mut count = 0;
|
|
154
|
-
|
|
155
|
-
let absolute_path = match absolute_path.to_str() {
|
|
156
|
-
Some(s) => s.to_string(),
|
|
157
|
-
None => {
|
|
158
|
-
return Err(anyhow::anyhow!(
|
|
159
|
-
"get_num_embeddable_files_in_subtree: Failed to convert path to string"
|
|
160
|
-
))
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// TODO(sualeh): worth keeping this list sorted. its now a btree
|
|
165
|
-
|
|
166
|
-
for (_, file) in &self.files {
|
|
167
|
-
let file_reader = file.node.read().await;
|
|
168
|
-
match &file_reader.node_type {
|
|
169
|
-
NodeType::File(file_name) => {
|
|
170
|
-
if file_name.contains(&absolute_path) {
|
|
171
|
-
count += 1;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
NodeType::Branch(_) => {
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
NodeType::ErrorNode(_) => {
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
Ok(count)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
135
|
pub async fn get_all_files(&self) -> Result<Vec<String>, anyhow::Error> {
|
|
187
136
|
let mut files = Vec::new();
|
|
188
137
|
|
|
@@ -239,119 +188,83 @@ impl MerkleTree {
|
|
|
239
188
|
pub async fn get_next_file_to_embed(
|
|
240
189
|
&mut self,
|
|
241
190
|
) -> Result<(String, Vec<String>), anyhow::Error> {
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
191
|
+
// the plan is to do an in-order traversal of the tree.
|
|
192
|
+
|
|
193
|
+
// first the edge case to deal with:
|
|
194
|
+
// cursor == None
|
|
195
|
+
if self.cursor.is_none() {
|
|
196
|
+
// If the root is a file, return its name.
|
|
197
|
+
if let NodeType::File(file_path) = &self.root.read().await.node_type {
|
|
198
|
+
return Ok((file_path.clone(), vec![]));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// if the path is not empty, we can iterate till we find the first child.
|
|
202
|
+
let mut potential_first_child = self.root.clone();
|
|
203
|
+
let mut is_branch = true;
|
|
204
|
+
let mut path = Vec::new();
|
|
205
|
+
|
|
206
|
+
while is_branch {
|
|
207
|
+
let node = {
|
|
208
|
+
let potential_first_child_reader = potential_first_child.read().await;
|
|
209
|
+
match &potential_first_child_reader.node_type {
|
|
210
|
+
NodeType::Branch(branch) => branch.clone(),
|
|
211
|
+
NodeType::File(_) => {
|
|
212
|
+
return Err(anyhow::anyhow!(
|
|
213
|
+
"get_next_file_to_embed: This should not happen! the branch happened to be file."
|
|
214
|
+
));
|
|
215
|
+
}
|
|
216
|
+
NodeType::ErrorNode(_) => {
|
|
217
|
+
return Err(anyhow::anyhow!("Cursor is an error node!"));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
250
221
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
loop {
|
|
254
|
-
// O(log n)
|
|
255
|
-
let file = match self.files.values().nth(cursor) {
|
|
256
|
-
Some(file) => file,
|
|
257
|
-
None => {
|
|
258
|
-
return Err(anyhow::anyhow!("Could not find file to embed!"));
|
|
259
|
-
}
|
|
260
|
-
};
|
|
222
|
+
let current_node_name = &node.0;
|
|
223
|
+
let child_list = &node.1;
|
|
261
224
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
NodeType::File(f) => {
|
|
265
|
-
// update the cursor.
|
|
266
|
-
self.cursor = Some(cursor + 1);
|
|
267
|
-
let spline = self.get_spline(f).await?;
|
|
268
|
-
return Ok((f.clone(), spline));
|
|
269
|
-
}
|
|
270
|
-
NodeType::Branch(_) => {
|
|
271
|
-
cursor += 1;
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
NodeType::ErrorNode(_) => {
|
|
275
|
-
cursor += 1;
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
225
|
+
if let Some(c) = child_list.first() {
|
|
226
|
+
let c_reader = c.read().await;
|
|
281
227
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
let mut files = Vec::new();
|
|
228
|
+
match &c_reader.node_type {
|
|
229
|
+
NodeType::File(file_path) => {
|
|
230
|
+
// must set the cursor!
|
|
231
|
+
self.cursor = Some(c.clone());
|
|
287
232
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
233
|
+
return Ok((file_path.clone(), path));
|
|
234
|
+
}
|
|
235
|
+
NodeType::Branch(_) => {
|
|
236
|
+
potential_first_child = c.clone();
|
|
237
|
+
is_branch = true;
|
|
292
238
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
239
|
+
// add the path to the current node.
|
|
240
|
+
path.push(current_node_name.clone());
|
|
241
|
+
}
|
|
242
|
+
NodeType::ErrorNode(_) => {
|
|
243
|
+
return Err(anyhow::anyhow!("Cursor is an error node!"));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
// If the root has no children, return an error.
|
|
248
|
+
return Err(anyhow::anyhow!("Root has no children!"));
|
|
302
249
|
}
|
|
303
250
|
}
|
|
304
251
|
}
|
|
305
252
|
|
|
306
|
-
|
|
307
|
-
|
|
253
|
+
// THE DEFAULT CASE:
|
|
254
|
+
// we already have a cursor at a file.
|
|
308
255
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
absolute_path: &str,
|
|
313
|
-
) -> Result<Vec<String>, anyhow::Error> {
|
|
314
|
-
info!("get_spline called with absolute_path: {}", absolute_path);
|
|
315
|
-
let mut files = Vec::new();
|
|
256
|
+
// UNWRAP checked and fine. see the none case above.
|
|
257
|
+
let cursor_name = self.cursor.as_ref().unwrap();
|
|
258
|
+
let cursor_reader = cursor_name.read().await;
|
|
316
259
|
|
|
317
|
-
|
|
318
|
-
Some(node) => {
|
|
319
|
-
info!("Found node for absolute_path: {}", absolute_path);
|
|
320
|
-
node.node.clone()
|
|
321
|
-
}
|
|
322
|
-
None => {
|
|
323
|
-
info!("File not found for absolute_path: {}", absolute_path);
|
|
324
|
-
return Err(anyhow::anyhow!("File not found: {}", absolute_path));
|
|
325
|
-
}
|
|
326
|
-
};
|
|
260
|
+
// invariant: you must be a file!!
|
|
327
261
|
|
|
328
|
-
|
|
329
|
-
stack.push(current_node);
|
|
330
|
-
|
|
331
|
-
while let Some(node) = stack.pop() {
|
|
332
|
-
let parent = node.read().await.parent.clone();
|
|
333
|
-
if let Some(parent) = parent {
|
|
334
|
-
info!("Adding parent hash to files vector");
|
|
335
|
-
{
|
|
336
|
-
let parent_node = parent.read().await;
|
|
337
|
-
match &parent_node.node_type {
|
|
338
|
-
NodeType::File(file_name) => {
|
|
339
|
-
files.push(file_name.clone());
|
|
340
|
-
}
|
|
341
|
-
NodeType::Branch((branch_name, _)) => {
|
|
342
|
-
files.push(branch_name.clone());
|
|
343
|
-
}
|
|
344
|
-
_ => {
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
262
|
+
// 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.
|
|
349
263
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
Ok(files)
|
|
264
|
+
// algorithm:
|
|
265
|
+
// 1.
|
|
266
|
+
|
|
267
|
+
Err(anyhow::anyhow!("Could not find file to embed!"))
|
|
355
268
|
}
|
|
356
269
|
|
|
357
270
|
/// creates a new node and attaches it to the current tree.
|
|
@@ -389,18 +302,12 @@ impl MerkleTree {
|
|
|
389
302
|
// 1. the path is empty. this means that the ancestor is the root.
|
|
390
303
|
// 2. the path is non-empty. that means there exist a non-empty element btwn till the root.
|
|
391
304
|
|
|
392
|
-
let absolute_root_path = self.root_path.clone();
|
|
393
305
|
let new_node = match path.len() {
|
|
394
306
|
0 => {
|
|
395
307
|
// this means that the ancestor is the root.
|
|
396
308
|
// we need to create a new node and attach it to the ancestor.
|
|
397
|
-
let new_node =
|
|
398
|
-
file_path.clone(),
|
|
399
|
-
Some(ancestor.clone()),
|
|
400
|
-
&self.git_ignored_files,
|
|
401
|
-
&absolute_root_path.as_str(),
|
|
402
|
-
)
|
|
403
|
-
.await;
|
|
309
|
+
let new_node =
|
|
310
|
+
MerkleNode::new(file_path.clone(), Some(ancestor.clone())).await;
|
|
404
311
|
ancestor.write().await.attach_child(new_node.clone()).await;
|
|
405
312
|
new_node
|
|
406
313
|
}
|
|
@@ -411,13 +318,9 @@ impl MerkleTree {
|
|
|
411
318
|
// UNSURE: not sure this is the correct thing to do but it is the fastest.
|
|
412
319
|
// get the last thing that is not in the tree.
|
|
413
320
|
let first_child_path = path.last().unwrap();
|
|
414
|
-
let first_child =
|
|
415
|
-
first_child_path.clone(),
|
|
416
|
-
|
|
417
|
-
&self.git_ignored_files,
|
|
418
|
-
&absolute_root_path.as_str(),
|
|
419
|
-
)
|
|
420
|
-
.await;
|
|
321
|
+
let first_child =
|
|
322
|
+
MerkleNode::new(first_child_path.clone(), Some(ancestor.clone()))
|
|
323
|
+
.await;
|
|
421
324
|
|
|
422
325
|
// TODO(sualeh): we should do an assertion check that the entire vec is contained here.
|
|
423
326
|
|
|
@@ -694,62 +597,18 @@ use std::future::Future;
|
|
|
694
597
|
use std::pin::Pin;
|
|
695
598
|
|
|
696
599
|
type PinnedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
|
697
|
-
type IgnoredFiles = HashSet<String>;
|
|
698
600
|
|
|
699
601
|
impl MerkleNode {
|
|
700
602
|
/// please be careful using this.
|
|
701
603
|
async fn __new_unchecked(
|
|
702
604
|
file_or_directory: String,
|
|
703
605
|
parent: ParentPtr,
|
|
704
|
-
ignored_files: &IgnoredFiles,
|
|
705
|
-
absolute_root_path: &str,
|
|
706
606
|
) -> MerkleNodePtr {
|
|
707
|
-
|
|
708
|
-
let is_git_repo =
|
|
709
|
-
match git_utils::is_git_directory(absolute_root_path).await {
|
|
710
|
-
Ok(is_git_repo) => is_git_repo,
|
|
711
|
-
Err(e) => false,
|
|
712
|
-
};
|
|
713
|
-
let bypass_git = !is_git_repo;
|
|
714
|
-
|
|
715
|
-
MerkleNode::construct_node(
|
|
716
|
-
Path::new(&file_or_directory),
|
|
717
|
-
parent,
|
|
718
|
-
ignored_files,
|
|
719
|
-
absolute_root_path,
|
|
720
|
-
bypass_git,
|
|
721
|
-
)
|
|
722
|
-
.await
|
|
607
|
+
MerkleNode::construct_node(Path::new(&file_or_directory), parent).await
|
|
723
608
|
}
|
|
724
609
|
|
|
725
|
-
async fn new(
|
|
726
|
-
|
|
727
|
-
parent: ParentPtr,
|
|
728
|
-
ignored_files: &IgnoredFiles,
|
|
729
|
-
absolute_root_path: &str,
|
|
730
|
-
) -> MerkleNodePtr {
|
|
731
|
-
// check if the root is a git directory.
|
|
732
|
-
let is_git_repo =
|
|
733
|
-
match git_utils::is_git_directory(absolute_root_path).await {
|
|
734
|
-
Ok(is_git_repo) => is_git_repo,
|
|
735
|
-
Err(_e) => false,
|
|
736
|
-
};
|
|
737
|
-
let bypass_git = !is_git_repo;
|
|
738
|
-
|
|
739
|
-
info!(
|
|
740
|
-
"constructing node for absolute_file_or_directory: {:?}",
|
|
741
|
-
absolute_file_or_directory
|
|
742
|
-
);
|
|
743
|
-
info!("bypass_git: {}, is_git_repo: {}", bypass_git, is_git_repo);
|
|
744
|
-
|
|
745
|
-
MerkleNode::construct_node(
|
|
746
|
-
Path::new(&absolute_file_or_directory),
|
|
747
|
-
parent,
|
|
748
|
-
ignored_files,
|
|
749
|
-
absolute_root_path,
|
|
750
|
-
bypass_git,
|
|
751
|
-
)
|
|
752
|
-
.await
|
|
610
|
+
async fn new(file_or_directory: PathBuf, parent: ParentPtr) -> MerkleNodePtr {
|
|
611
|
+
MerkleNode::construct_node(Path::new(&file_or_directory), parent).await
|
|
753
612
|
}
|
|
754
613
|
|
|
755
614
|
/// NOT added to the tree by default.
|
|
@@ -760,64 +619,38 @@ impl MerkleNode {
|
|
|
760
619
|
// let file_hash = self.files.get_mut(&file_path).unwrap();
|
|
761
620
|
|
|
762
621
|
fn construct_node<'a>(
|
|
763
|
-
|
|
622
|
+
file_or_directory: &'a Path,
|
|
764
623
|
parent: ParentPtr,
|
|
765
|
-
ignored_files: &'a IgnoredFiles,
|
|
766
|
-
absolute_root_path: &'a str,
|
|
767
|
-
bypass_git: bool,
|
|
768
624
|
) -> PinnedFuture<'a, MerkleNodePtr> {
|
|
769
625
|
Box::pin(async move {
|
|
770
626
|
// check if it is a file
|
|
771
|
-
let path_str =
|
|
772
|
-
if
|
|
627
|
+
let path_str = file_or_directory.to_str().unwrap().to_string();
|
|
628
|
+
if file_or_directory.is_file() {
|
|
773
629
|
return Arc::new(RwLock::new(
|
|
774
630
|
MerkleNode::construct_file_node_or_error_node(
|
|
775
|
-
|
|
631
|
+
file_or_directory,
|
|
776
632
|
parent,
|
|
777
|
-
ignored_files,
|
|
778
633
|
)
|
|
779
634
|
.await,
|
|
780
635
|
));
|
|
781
636
|
}
|
|
782
637
|
|
|
783
638
|
// check if the directory fails the bad dir test.
|
|
784
|
-
let is_bad_dir = file_utils::is_in_bad_dir(
|
|
639
|
+
let is_bad_dir = file_utils::is_in_bad_dir(file_or_directory);
|
|
785
640
|
if is_bad_dir.is_err() || is_bad_dir.unwrap_or(false) {
|
|
786
641
|
// println!("skipping directory: {}", path_str);
|
|
787
642
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
788
|
-
Some(
|
|
643
|
+
Some(file_or_directory),
|
|
789
644
|
Some("Directory is in bad dir!".to_string()),
|
|
790
645
|
)));
|
|
791
646
|
}
|
|
792
647
|
|
|
793
|
-
|
|
794
|
-
let is_git_ignored =
|
|
795
|
-
match git_utils::is_git_ignored(absolute_root_path, path_str.as_str())
|
|
796
|
-
.await
|
|
797
|
-
{
|
|
798
|
-
Ok(is_git_ignored) => is_git_ignored,
|
|
799
|
-
Err(e) => {
|
|
800
|
-
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
801
|
-
Some(absolute_file_or_directory),
|
|
802
|
-
Some(e.to_string()),
|
|
803
|
-
)));
|
|
804
|
-
}
|
|
805
|
-
};
|
|
806
|
-
|
|
807
|
-
if is_git_ignored && !bypass_git {
|
|
808
|
-
// println!("skipping directory: {}", path_str);
|
|
809
|
-
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
810
|
-
Some(absolute_file_or_directory),
|
|
811
|
-
Some("Directory is git ignored!".to_string()),
|
|
812
|
-
)));
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
let entries = fs::read_dir(absolute_file_or_directory);
|
|
648
|
+
let entries = fs::read_dir(file_or_directory);
|
|
816
649
|
match entries {
|
|
817
650
|
Ok(_) => (),
|
|
818
651
|
Err(e) => {
|
|
819
652
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
820
|
-
Some(
|
|
653
|
+
Some(file_or_directory),
|
|
821
654
|
Some(e.to_string()),
|
|
822
655
|
)));
|
|
823
656
|
}
|
|
@@ -837,19 +670,13 @@ impl MerkleNode {
|
|
|
837
670
|
match entry {
|
|
838
671
|
Ok(entry) => {
|
|
839
672
|
children.push(
|
|
840
|
-
MerkleNode::construct_node(
|
|
841
|
-
|
|
842
|
-
Some(node.clone()),
|
|
843
|
-
ignored_files,
|
|
844
|
-
absolute_root_path,
|
|
845
|
-
bypass_git,
|
|
846
|
-
)
|
|
847
|
-
.await,
|
|
673
|
+
MerkleNode::construct_node(&entry.path(), Some(node.clone()))
|
|
674
|
+
.await,
|
|
848
675
|
);
|
|
849
676
|
}
|
|
850
677
|
Err(e) => {
|
|
851
678
|
children.push(Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
852
|
-
Some(
|
|
679
|
+
Some(file_or_directory),
|
|
853
680
|
Some(e.to_string()),
|
|
854
681
|
))));
|
|
855
682
|
}
|
|
@@ -869,33 +696,23 @@ impl MerkleNode {
|
|
|
869
696
|
}
|
|
870
697
|
|
|
871
698
|
async fn construct_file_node(
|
|
872
|
-
|
|
699
|
+
file_path: &Path,
|
|
873
700
|
parent: ParentPtr,
|
|
874
|
-
ignored_files: &IgnoredFiles,
|
|
875
701
|
) -> Result<MerkleNode, String> {
|
|
876
|
-
let file_str =
|
|
702
|
+
let file_str = file_path
|
|
877
703
|
.to_str()
|
|
878
704
|
.ok_or("Could not convert file path to string!")?
|
|
879
705
|
.to_string();
|
|
880
706
|
// first see if it passes the
|
|
881
|
-
match file_utils::is_good_file(
|
|
707
|
+
match file_utils::is_good_file(file_path) {
|
|
882
708
|
Ok(_) => {}
|
|
883
709
|
Err(e) => {
|
|
884
710
|
return Err(format!("File failed runtime checks! {}", e.to_string()));
|
|
885
711
|
}
|
|
886
712
|
}
|
|
887
713
|
|
|
888
|
-
// check if the file is in the git ignore buffer.
|
|
889
|
-
// this is a bug right because we are not checking absoluteness here.
|
|
890
|
-
match ignored_files.contains(&file_str) {
|
|
891
|
-
true => {
|
|
892
|
-
return Err(format!("File is in git ignore buffer!"));
|
|
893
|
-
}
|
|
894
|
-
false => {}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
714
|
// read the file_content to a buffer
|
|
898
|
-
let file_content = match tokio::fs::read(
|
|
715
|
+
let file_content = match tokio::fs::read(file_path).await {
|
|
899
716
|
Ok(content) => content,
|
|
900
717
|
Err(e) => {
|
|
901
718
|
return Err(format!("Could not read file! {}", e.to_string()));
|
|
@@ -903,11 +720,7 @@ impl MerkleNode {
|
|
|
903
720
|
};
|
|
904
721
|
|
|
905
722
|
// check if the file passes runtime checks.
|
|
906
|
-
match file_utils::is_good_file_runtime_check(
|
|
907
|
-
absolute_file_path,
|
|
908
|
-
&file_content,
|
|
909
|
-
)
|
|
910
|
-
.await
|
|
723
|
+
match file_utils::is_good_file_runtime_check(file_path, &file_content).await
|
|
911
724
|
{
|
|
912
725
|
Ok(_) => {}
|
|
913
726
|
Err(e) => {
|
|
@@ -938,22 +751,15 @@ impl MerkleNode {
|
|
|
938
751
|
}
|
|
939
752
|
|
|
940
753
|
async fn construct_file_node_or_error_node(
|
|
941
|
-
|
|
754
|
+
file_path: &Path,
|
|
942
755
|
parent: ParentPtr,
|
|
943
|
-
ignored_files: &IgnoredFiles,
|
|
944
756
|
) -> MerkleNode {
|
|
945
|
-
let node = match MerkleNode::construct_file_node(
|
|
946
|
-
absolute_file_path,
|
|
947
|
-
parent,
|
|
948
|
-
ignored_files,
|
|
949
|
-
)
|
|
950
|
-
.await
|
|
951
|
-
{
|
|
757
|
+
let node = match MerkleNode::construct_file_node(file_path, parent).await {
|
|
952
758
|
Ok(node) => node,
|
|
953
759
|
Err(e) => {
|
|
954
760
|
// println!("constructing error node. error: {}", e);
|
|
955
761
|
// println!("file_path: {:?}", file_path);
|
|
956
|
-
MerkleNode::empty_node(Some(
|
|
762
|
+
MerkleNode::empty_node(Some(file_path), Some(e))
|
|
957
763
|
}
|
|
958
764
|
};
|
|
959
765
|
|