@anysphere/file-service 0.0.0-bff0125b → 0.0.0-c2b75b32
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 +2 -0
- package/index.d.ts +1 -1
- package/package.json +10 -8
- package/src/file_utils.rs +8 -9
- package/src/git_utils.rs +14 -7
- package/src/lib.rs +51 -35
- package/src/merkle_tree/local_construction.rs +21 -11
- package/src/merkle_tree/mod.rs +58 -33
package/Cargo.toml
CHANGED
package/index.d.ts
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-c2b75b32",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"additional": [
|
|
10
10
|
"aarch64-apple-darwin",
|
|
11
11
|
"aarch64-pc-windows-msvc",
|
|
12
|
-
"universal-apple-darwin"
|
|
12
|
+
"universal-apple-darwin",
|
|
13
|
+
"aarch64-unknown-linux-gnu"
|
|
13
14
|
]
|
|
14
15
|
}
|
|
15
16
|
},
|
|
@@ -35,11 +36,12 @@
|
|
|
35
36
|
"version": "napi version"
|
|
36
37
|
},
|
|
37
38
|
"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-
|
|
39
|
+
"@anysphere/file-service-win32-x64-msvc": "0.0.0-c2b75b32",
|
|
40
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-c2b75b32",
|
|
41
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-c2b75b32",
|
|
42
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-c2b75b32",
|
|
43
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-c2b75b32",
|
|
44
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-c2b75b32",
|
|
45
|
+
"@anysphere/file-service-linux-arm64-gnu": "0.0.0-c2b75b32"
|
|
44
46
|
}
|
|
45
47
|
}
|
package/src/file_utils.rs
CHANGED
|
@@ -62,7 +62,7 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
62
62
|
Some(extension) => match extension.to_str() {
|
|
63
63
|
Some(ext_str) => {
|
|
64
64
|
if bad_extensions.contains(&ext_str) {
|
|
65
|
-
return Err(anyhow::anyhow!("
|
|
65
|
+
return Err(anyhow::anyhow!("Binary file excluded from indexing."));
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
None => {
|
|
@@ -88,10 +88,12 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
88
88
|
Ok(())
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
// use binaryornot::is_binary;
|
|
92
|
+
// use anyhow::Context;
|
|
91
93
|
// implement the buffer above:
|
|
92
94
|
pub async fn is_good_file_runtime_check(
|
|
93
95
|
file_path: &Path,
|
|
94
|
-
|
|
96
|
+
_buffer: &[u8],
|
|
95
97
|
) -> Result<(), Error> {
|
|
96
98
|
match get_file_size(file_path).await {
|
|
97
99
|
Ok(size) if size > 2 * 1024 * 1024 => {
|
|
@@ -101,13 +103,10 @@ pub async fn is_good_file_runtime_check(
|
|
|
101
103
|
_ => {}
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return Err(anyhow::anyhow!("File is not a valid UTF-8 string"));
|
|
109
|
-
}
|
|
110
|
-
}
|
|
106
|
+
// if is_binary(file_path).context("Failed to check if file is binary")? {
|
|
107
|
+
// return Err(anyhow::anyhow!("File is binary"));
|
|
108
|
+
// }
|
|
109
|
+
|
|
111
110
|
Ok(())
|
|
112
111
|
}
|
|
113
112
|
|
package/src/git_utils.rs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use std::collections::HashSet;
|
|
2
2
|
use std::process::Command;
|
|
3
3
|
|
|
4
|
-
pub fn
|
|
4
|
+
pub fn list_ignored_files_and_directories(
|
|
5
5
|
workspace_root_path: &str,
|
|
6
6
|
should_return_absolute_paths: bool,
|
|
7
7
|
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
|
@@ -14,12 +14,14 @@ pub fn list_ignored_files(
|
|
|
14
14
|
"--others",
|
|
15
15
|
"--ignored",
|
|
16
16
|
"--exclude-standard",
|
|
17
|
+
"--directory",
|
|
18
|
+
"--no-empty-directory"
|
|
17
19
|
],
|
|
18
20
|
// FIXME(sualeh): this is super sketchy and might totally break in like a bazillion ways. i dont like it.
|
|
19
21
|
vec![
|
|
20
22
|
"sh",
|
|
21
23
|
"-c",
|
|
22
|
-
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard | sed \"s|^|$path/|\"'",
|
|
24
|
+
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard --directory --no-empty-directory | sed \"s|^|$path/|\"'",
|
|
23
25
|
],
|
|
24
26
|
];
|
|
25
27
|
|
|
@@ -133,7 +135,8 @@ mod tests {
|
|
|
133
135
|
fn test_no_ignored_files() {
|
|
134
136
|
let dir = tempfile::tempdir().unwrap();
|
|
135
137
|
let gitignored_files =
|
|
136
|
-
|
|
138
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
139
|
+
.unwrap();
|
|
137
140
|
Command::new("git")
|
|
138
141
|
.args(&["init"])
|
|
139
142
|
.current_dir(dir.path())
|
|
@@ -160,7 +163,8 @@ mod tests {
|
|
|
160
163
|
.output()
|
|
161
164
|
.unwrap();
|
|
162
165
|
let gitignored_files =
|
|
163
|
-
|
|
166
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
167
|
+
.unwrap();
|
|
164
168
|
println!(
|
|
165
169
|
"ignored files for test_one_ignored_file: {:?}",
|
|
166
170
|
gitignored_files
|
|
@@ -190,7 +194,8 @@ mod tests {
|
|
|
190
194
|
.output()
|
|
191
195
|
.unwrap();
|
|
192
196
|
let gitignored_files =
|
|
193
|
-
|
|
197
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
198
|
+
.unwrap();
|
|
194
199
|
println!(
|
|
195
200
|
"ignored files for test_multiple_ignored_files: {:?}",
|
|
196
201
|
gitignored_files
|
|
@@ -254,7 +259,8 @@ mod tests {
|
|
|
254
259
|
println!("git submodule add output: {:?}", o);
|
|
255
260
|
|
|
256
261
|
let gitignored_files =
|
|
257
|
-
|
|
262
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
263
|
+
.unwrap();
|
|
258
264
|
println!(
|
|
259
265
|
"ignored files for test_git_submodule_ignored_files: {:?}",
|
|
260
266
|
gitignored_files
|
|
@@ -265,7 +271,8 @@ mod tests {
|
|
|
265
271
|
|
|
266
272
|
#[test]
|
|
267
273
|
fn test_multiple_ignored_files_in_current_dir() {
|
|
268
|
-
let gitignored_files =
|
|
274
|
+
let gitignored_files =
|
|
275
|
+
list_ignored_files_and_directories(".", false).unwrap();
|
|
269
276
|
assert!(gitignored_files.len() > 1);
|
|
270
277
|
|
|
271
278
|
// print a sample of the ignored files
|
package/src/lib.rs
CHANGED
|
@@ -10,6 +10,7 @@ use merkle_tree::{LocalConstruction, MerkleTree};
|
|
|
10
10
|
use tracing::{info, Level};
|
|
11
11
|
use tracing_appender::rolling::{RollingFileAppender, Rotation};
|
|
12
12
|
use tracing_subscriber::fmt;
|
|
13
|
+
use anyhow::Context;
|
|
13
14
|
|
|
14
15
|
#[macro_use]
|
|
15
16
|
extern crate napi_derive;
|
|
@@ -17,7 +18,7 @@ extern crate napi_derive;
|
|
|
17
18
|
#[napi]
|
|
18
19
|
pub struct MerkleClient {
|
|
19
20
|
tree: MerkleTree,
|
|
20
|
-
|
|
21
|
+
absolute_root_directory: String,
|
|
21
22
|
_guard: tracing_appender::non_blocking::WorkerGuard,
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -40,12 +41,22 @@ pub fn init_logger() -> tracing_appender::non_blocking::WorkerGuard {
|
|
|
40
41
|
#[napi]
|
|
41
42
|
impl MerkleClient {
|
|
42
43
|
#[napi(constructor)]
|
|
43
|
-
pub fn new(
|
|
44
|
+
pub fn new(absolute_root_directory: String) -> MerkleClient {
|
|
44
45
|
let _guard = init_logger();
|
|
45
46
|
|
|
47
|
+
// let canonical_root_directory = std::path::Path::new(&absolute_root_directory);
|
|
48
|
+
// use dunce::canonicalize;
|
|
49
|
+
// let canonical_root_directory = match dunce::canonicalize(&canonical_root_directory) {
|
|
50
|
+
// Ok(path) => path.to_str().unwrap_or(&absolute_root_directory).to_string().to_lowercase(),
|
|
51
|
+
// Err(e) => {
|
|
52
|
+
// info!("Error in canonicalizing path: path: {:?}, error {:?}", canonical_root_directory, e);
|
|
53
|
+
// absolute_root_directory
|
|
54
|
+
// }
|
|
55
|
+
// };
|
|
56
|
+
|
|
46
57
|
MerkleClient {
|
|
47
58
|
tree: MerkleTree::empty_tree(),
|
|
48
|
-
|
|
59
|
+
absolute_root_directory,
|
|
49
60
|
_guard,
|
|
50
61
|
}
|
|
51
62
|
}
|
|
@@ -55,6 +66,7 @@ impl MerkleClient {
|
|
|
55
66
|
// 1. compute the merkle tree
|
|
56
67
|
// 2. update the backend
|
|
57
68
|
// 3. sync with the remote
|
|
69
|
+
info!("Merkle tree compute started!");
|
|
58
70
|
unsafe {
|
|
59
71
|
self.compute_merkle_tree().await?;
|
|
60
72
|
}
|
|
@@ -71,18 +83,7 @@ impl MerkleClient {
|
|
|
71
83
|
&mut self,
|
|
72
84
|
) -> Result<(), napi::Error> {
|
|
73
85
|
let t =
|
|
74
|
-
MerkleTree::construct_merkle_tree(self.
|
|
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
|
+
MerkleTree::construct_merkle_tree(self.absolute_root_directory.clone()).await;
|
|
86
87
|
|
|
87
88
|
match t {
|
|
88
89
|
Ok(tree) => {
|
|
@@ -111,19 +112,35 @@ impl MerkleClient {
|
|
|
111
112
|
&self,
|
|
112
113
|
relative_path: String,
|
|
113
114
|
) -> Result<String, napi::Error> {
|
|
114
|
-
info!("relative_path: {:?}", relative_path);
|
|
115
|
-
let absolute_path =
|
|
116
|
-
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
117
|
-
let canonical_path = absolute_path.canonicalize().unwrap();
|
|
118
115
|
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
let relative_path_without_leading_slash = match relative_path.strip_prefix('.') {
|
|
117
|
+
Some(path) => path.strip_prefix(std::path::MAIN_SEPARATOR).unwrap_or(""),
|
|
118
|
+
None => relative_path.as_str(),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
let absolute_path = if !relative_path_without_leading_slash.is_empty() {
|
|
122
|
+
std::path::Path::new(&self.absolute_root_directory).join(relative_path_without_leading_slash)
|
|
123
|
+
} else {
|
|
124
|
+
std::path::Path::new(&self.absolute_root_directory).to_path_buf()
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
let absolute_path_string = match absolute_path.to_str() {
|
|
128
|
+
Some(path) => path.to_string(),
|
|
129
|
+
None => {
|
|
130
|
+
return Err(napi::Error::new(
|
|
131
|
+
napi::Status::Unknown,
|
|
132
|
+
format!("some string error")
|
|
133
|
+
))
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
let hash = self.tree.get_subtree_hash(absolute_path_string.as_str()).await;
|
|
121
138
|
|
|
122
139
|
match hash {
|
|
123
140
|
Ok(hash) => Ok(hash),
|
|
124
141
|
Err(e) => Err(napi::Error::new(
|
|
125
142
|
napi::Status::Unknown,
|
|
126
|
-
format!("Error in get_subtree_hash: {:?}", e)
|
|
143
|
+
format!("Error in get_subtree_hash. \nRelative path: {:?}, \nAbsolute path: {:?}, \nRoot directory: {:?}\nError: {:?}", &relative_path, absolute_path, self.absolute_root_directory, e)
|
|
127
144
|
)),
|
|
128
145
|
}
|
|
129
146
|
}
|
|
@@ -136,7 +153,7 @@ impl MerkleClient {
|
|
|
136
153
|
Ok(num) => Ok(num),
|
|
137
154
|
Err(e) => Err(napi::Error::new(
|
|
138
155
|
napi::Status::Unknown,
|
|
139
|
-
format!("Error in get_num_embeddable_files: {:?}", e)
|
|
156
|
+
format!("Error in get_num_embeddable_files: {:?}", e)
|
|
140
157
|
)),
|
|
141
158
|
}
|
|
142
159
|
}
|
|
@@ -145,7 +162,7 @@ impl MerkleClient {
|
|
|
145
162
|
&self,
|
|
146
163
|
relative_path: String,
|
|
147
164
|
) -> Result<i32, napi::Error> {
|
|
148
|
-
let absolute_path = std::path::Path::new(&self.
|
|
165
|
+
let absolute_path = std::path::Path::new(&self.absolute_root_directory)
|
|
149
166
|
.join(relative_path)
|
|
150
167
|
.canonicalize()?;
|
|
151
168
|
|
|
@@ -158,7 +175,7 @@ impl MerkleClient {
|
|
|
158
175
|
Ok(num) => Ok(num),
|
|
159
176
|
Err(e) => Err(napi::Error::new(
|
|
160
177
|
napi::Status::Unknown,
|
|
161
|
-
format!("Error in get_num_embeddable_files_in_subtree: {:?}", e)
|
|
178
|
+
format!("Error in get_num_embeddable_files_in_subtree: {:?}", e)
|
|
162
179
|
)),
|
|
163
180
|
}
|
|
164
181
|
}
|
|
@@ -171,7 +188,7 @@ impl MerkleClient {
|
|
|
171
188
|
Ok(files) => Ok(files),
|
|
172
189
|
Err(e) => Err(napi::Error::new(
|
|
173
190
|
napi::Status::Unknown,
|
|
174
|
-
format!("Error in get_all_files: {:?}", e)
|
|
191
|
+
format!("Error in get_all_files: {:?}", e)
|
|
175
192
|
)),
|
|
176
193
|
}
|
|
177
194
|
}
|
|
@@ -181,10 +198,12 @@ impl MerkleClient {
|
|
|
181
198
|
&self,
|
|
182
199
|
absolute_file_path: String,
|
|
183
200
|
) -> Result<Vec<String>, napi::Error> {
|
|
184
|
-
let
|
|
201
|
+
// let absolute_path = absolute_file_path.to_lowercase();
|
|
202
|
+
// let absolute_path_str = absolute_path.as_str();
|
|
203
|
+
|
|
185
204
|
let files = self
|
|
186
205
|
.tree
|
|
187
|
-
.get_all_dir_files_to_embed(
|
|
206
|
+
.get_all_dir_files_to_embed(absolute_file_path.as_str())
|
|
188
207
|
.await;
|
|
189
208
|
|
|
190
209
|
match files {
|
|
@@ -209,11 +228,7 @@ impl MerkleClient {
|
|
|
209
228
|
// TODO(sualeh): we should assert that the path is ascending up to the path.
|
|
210
229
|
|
|
211
230
|
let ret = vec![file];
|
|
212
|
-
info!("file: {:?}", ret);
|
|
213
|
-
|
|
214
231
|
let ret = ret.into_iter().chain(path.into_iter()).collect::<Vec<_>>();
|
|
215
|
-
info!("ret to js: {:?}", ret);
|
|
216
|
-
|
|
217
232
|
Ok(ret)
|
|
218
233
|
}
|
|
219
234
|
Err(e) => Err(napi::Error::new(
|
|
@@ -229,8 +244,9 @@ impl MerkleClient {
|
|
|
229
244
|
&self,
|
|
230
245
|
absolute_file_path: String,
|
|
231
246
|
) -> Result<Vec<String>, napi::Error> {
|
|
232
|
-
let
|
|
233
|
-
let
|
|
247
|
+
// let absolute_path = absolute_file_path.to_lowercase();
|
|
248
|
+
// let absolute_path_str = absolute_path.as_str();
|
|
249
|
+
let spline = self.tree.get_spline(absolute_file_path.as_str()).await;
|
|
234
250
|
|
|
235
251
|
match spline {
|
|
236
252
|
Ok(spline) => Ok(spline),
|
|
@@ -259,6 +275,6 @@ impl MerkleClient {
|
|
|
259
275
|
|
|
260
276
|
#[napi]
|
|
261
277
|
pub fn update_root_directory(&mut self, root_directory: String) {
|
|
262
|
-
self.
|
|
278
|
+
self.absolute_root_directory = root_directory;
|
|
263
279
|
}
|
|
264
280
|
}
|
|
@@ -38,20 +38,19 @@ impl LocalConstruction for MerkleTree {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// 1. get all the gitignored files
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
tracing::info!("git_ignored_files: {:?}", git_ignored_files);
|
|
41
|
+
let git_ignored_files_and_dirs =
|
|
42
|
+
match git_utils::list_ignored_files_and_directories(
|
|
43
|
+
absolute_path_to_root_directory.as_str(),
|
|
44
|
+
true,
|
|
45
|
+
) {
|
|
46
|
+
Ok(git_ignored) => git_ignored,
|
|
47
|
+
Err(_e) => HashSet::new(),
|
|
48
|
+
};
|
|
50
49
|
|
|
51
50
|
let root_node = MerkleNode::new(
|
|
52
51
|
path,
|
|
53
52
|
None,
|
|
54
|
-
&
|
|
53
|
+
&git_ignored_files_and_dirs,
|
|
55
54
|
absolute_path_to_root_directory.as_str(),
|
|
56
55
|
)
|
|
57
56
|
.await;
|
|
@@ -60,7 +59,7 @@ impl LocalConstruction for MerkleTree {
|
|
|
60
59
|
files: BTreeMap::new(),
|
|
61
60
|
root_path: absolute_path_to_root_directory,
|
|
62
61
|
cursor: None,
|
|
63
|
-
|
|
62
|
+
git_ignored_files_and_dirs: git_ignored_files_and_dirs,
|
|
64
63
|
};
|
|
65
64
|
|
|
66
65
|
// we now iterate over all the nodes and add them to the hashmap
|
|
@@ -73,6 +72,7 @@ impl LocalConstruction for MerkleTree {
|
|
|
73
72
|
let node_reader = node.read().await;
|
|
74
73
|
match &node_reader.node_type {
|
|
75
74
|
NodeType::Branch(n) => {
|
|
75
|
+
tracing::info!("Branch: {:?}", n.0);
|
|
76
76
|
let children = &n.1;
|
|
77
77
|
files.insert(n.0.clone(), File { node: node.clone() });
|
|
78
78
|
for child in children {
|
|
@@ -81,6 +81,13 @@ impl LocalConstruction for MerkleTree {
|
|
|
81
81
|
}
|
|
82
82
|
NodeType::File(file_name) => {
|
|
83
83
|
let f = File { node: node.clone() };
|
|
84
|
+
|
|
85
|
+
// i dont reallly like this :(((
|
|
86
|
+
// let canonical_file_name = match dunce::canonicalize(file_name) {
|
|
87
|
+
// Ok(path) => path.to_str().unwrap_or(file_name).to_string(),
|
|
88
|
+
// Err(_) => file_name.clone(),
|
|
89
|
+
// };
|
|
90
|
+
|
|
84
91
|
files.insert(file_name.clone(), f);
|
|
85
92
|
}
|
|
86
93
|
NodeType::ErrorNode(_) => {
|
|
@@ -92,6 +99,9 @@ impl LocalConstruction for MerkleTree {
|
|
|
92
99
|
|
|
93
100
|
add_nodes_to_hashmap(&mt.root, &mut mt.files).await;
|
|
94
101
|
|
|
102
|
+
tracing::info!("Merkle tree compute finished!");
|
|
103
|
+
tracing::info!("Merkle tree: {}", mt);
|
|
104
|
+
|
|
95
105
|
Ok(mt)
|
|
96
106
|
}
|
|
97
107
|
|
package/src/merkle_tree/mod.rs
CHANGED
|
@@ -4,6 +4,7 @@ use super::file_utils;
|
|
|
4
4
|
use sha2::Digest;
|
|
5
5
|
use std::collections::{BTreeMap, HashSet};
|
|
6
6
|
use std::path::PathBuf;
|
|
7
|
+
use std::vec;
|
|
7
8
|
use std::{fs, path::Path, sync::Arc};
|
|
8
9
|
use tokio::sync::RwLock;
|
|
9
10
|
use tonic::async_trait;
|
|
@@ -18,7 +19,7 @@ pub struct MerkleTree {
|
|
|
18
19
|
root: MerkleNodePtr,
|
|
19
20
|
files: BTreeMap<String, File>,
|
|
20
21
|
cursor: Option<usize>,
|
|
21
|
-
|
|
22
|
+
git_ignored_files_and_dirs: HashSet<String>,
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
#[derive(Debug)]
|
|
@@ -95,33 +96,34 @@ impl MerkleTree {
|
|
|
95
96
|
files: BTreeMap::new(),
|
|
96
97
|
root_path: "".to_string(),
|
|
97
98
|
cursor: None,
|
|
98
|
-
|
|
99
|
+
git_ignored_files_and_dirs: HashSet::new(),
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
pub async fn get_subtree_hash(
|
|
103
104
|
&self,
|
|
104
|
-
absolute_path:
|
|
105
|
+
absolute_path: &str,
|
|
105
106
|
) -> Result<String, anyhow::Error> {
|
|
106
|
-
let
|
|
107
|
-
Some(s) => s.to_string(),
|
|
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) {
|
|
107
|
+
let node = match self.files.get(absolute_path) {
|
|
116
108
|
Some(file) => file.node.clone(),
|
|
117
109
|
None => {
|
|
118
|
-
|
|
110
|
+
let all_files: Vec<String> = self.files.keys().cloned().collect();
|
|
111
|
+
return Err(anyhow::anyhow!(
|
|
112
|
+
"Could not find file in tree! Looking for: {}. All files: {:?}",
|
|
113
|
+
absolute_path,
|
|
114
|
+
all_files
|
|
115
|
+
));
|
|
119
116
|
}
|
|
120
117
|
};
|
|
121
118
|
|
|
122
119
|
let node_reader = node.read().await;
|
|
123
120
|
let node_hash = node_reader.hash.clone();
|
|
124
121
|
|
|
122
|
+
info!(
|
|
123
|
+
"get_subtree_hash for path: {}, node_hash: {}",
|
|
124
|
+
absolute_path, node_hash
|
|
125
|
+
);
|
|
126
|
+
|
|
125
127
|
Ok(node_hash)
|
|
126
128
|
}
|
|
127
129
|
|
|
@@ -397,7 +399,7 @@ impl MerkleTree {
|
|
|
397
399
|
let new_node = MerkleNode::new(
|
|
398
400
|
file_path.clone(),
|
|
399
401
|
Some(ancestor.clone()),
|
|
400
|
-
&self.
|
|
402
|
+
&self.git_ignored_files_and_dirs,
|
|
401
403
|
&absolute_root_path.as_str(),
|
|
402
404
|
)
|
|
403
405
|
.await;
|
|
@@ -414,7 +416,7 @@ impl MerkleTree {
|
|
|
414
416
|
let first_child = MerkleNode::new(
|
|
415
417
|
first_child_path.clone(),
|
|
416
418
|
Some(ancestor.clone()),
|
|
417
|
-
&self.
|
|
419
|
+
&self.git_ignored_files_and_dirs,
|
|
418
420
|
&absolute_root_path.as_str(),
|
|
419
421
|
)
|
|
420
422
|
.await;
|
|
@@ -790,22 +792,9 @@ impl MerkleNode {
|
|
|
790
792
|
)));
|
|
791
793
|
}
|
|
792
794
|
|
|
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
|
-
};
|
|
795
|
+
let is_git_ignored_dir = ignored_files.contains(&path_str);
|
|
806
796
|
|
|
807
|
-
if
|
|
808
|
-
// println!("skipping directory: {}", path_str);
|
|
797
|
+
if is_git_ignored_dir && !bypass_git {
|
|
809
798
|
return Arc::new(RwLock::new(MerkleNode::empty_node(
|
|
810
799
|
Some(absolute_file_or_directory),
|
|
811
800
|
Some("Directory is git ignored!".to_string()),
|
|
@@ -979,15 +968,51 @@ impl MerkleNode {
|
|
|
979
968
|
|
|
980
969
|
async fn compute_branch_hash(children: &[MerkleNodePtr]) -> String {
|
|
981
970
|
let mut hasher = sha2::Sha256::new();
|
|
971
|
+
let mut names_and_hashes = vec![];
|
|
972
|
+
let mut non_zero_children = 0;
|
|
973
|
+
|
|
982
974
|
for child in children {
|
|
983
975
|
// check if it is an error node
|
|
984
976
|
let child_reader = child.read().await;
|
|
985
|
-
|
|
977
|
+
|
|
978
|
+
match &child_reader.node_type {
|
|
979
|
+
NodeType::File(file_name) => {
|
|
980
|
+
non_zero_children += 1;
|
|
981
|
+
names_and_hashes.push((file_name.clone(), child_reader.hash.clone()));
|
|
982
|
+
}
|
|
983
|
+
NodeType::Branch((file_name, _)) => {
|
|
984
|
+
let hash = child_reader.hash.clone();
|
|
985
|
+
if hash == "" {
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
non_zero_children += 1;
|
|
990
|
+
names_and_hashes.push((file_name.clone(), hash));
|
|
991
|
+
}
|
|
992
|
+
NodeType::ErrorNode(_) => {
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// sort the list of names and hashes by the hashes!!
|
|
999
|
+
names_and_hashes
|
|
1000
|
+
.sort_by(|a, b| a.1.to_lowercase().cmp(&b.1.to_lowercase()));
|
|
1001
|
+
|
|
1002
|
+
for (name, hash) in names_and_hashes {
|
|
1003
|
+
if hash == "" {
|
|
986
1004
|
continue;
|
|
987
1005
|
}
|
|
1006
|
+
info!("name: {}, hash: {}", name, hash);
|
|
1007
|
+
hasher.update(hash);
|
|
1008
|
+
}
|
|
988
1009
|
|
|
989
|
-
|
|
1010
|
+
if non_zero_children == 0 {
|
|
1011
|
+
// this means that the branch is empty.
|
|
1012
|
+
// we should return an empty string.
|
|
1013
|
+
return "".to_string();
|
|
990
1014
|
}
|
|
1015
|
+
|
|
991
1016
|
let result = hasher.finalize();
|
|
992
1017
|
format!("{:x}", result)
|
|
993
1018
|
}
|