@anysphere/file-service 0.0.0-fcf7dd4f → 0.0.0-fd010bd5
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 +6 -0
- package/build.rs +2 -0
- package/index.d.ts +2 -2
- package/package.json +8 -8
- package/src/file_utils.rs +134 -18
- package/src/git_utils.rs +6 -4
- package/src/lib.rs +54 -29
- package/src/merkle_tree/local_construction.rs +18 -10
- package/src/merkle_tree/mod.rs +30 -32
- package/src/merkle_tree/test.rs +2 -1
package/Cargo.toml
CHANGED
|
@@ -6,6 +6,10 @@ version = "0.0.0"
|
|
|
6
6
|
[lib]
|
|
7
7
|
crate-type = ["cdylib"]
|
|
8
8
|
|
|
9
|
+
[features]
|
|
10
|
+
default = ["windows-subsystem"]
|
|
11
|
+
windows-subsystem = []
|
|
12
|
+
|
|
9
13
|
[dependencies]
|
|
10
14
|
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
|
11
15
|
napi = { version = "2.12.2", default-features = false, features = ["napi4", "async", "tokio_rt"] }
|
|
@@ -22,6 +26,7 @@ tracing-subscriber = "0.3.17"
|
|
|
22
26
|
tracing-appender = "0.2.2"
|
|
23
27
|
binaryornot = "1.0.0"
|
|
24
28
|
dunce = "1.0.1"
|
|
29
|
+
encoding_rs = "0.8.33"
|
|
25
30
|
|
|
26
31
|
[build-dependencies]
|
|
27
32
|
napi-build = "2.0.1"
|
|
@@ -29,5 +34,6 @@ tonic-build = "0.9.2"
|
|
|
29
34
|
anyhow = "1.0.75"
|
|
30
35
|
glob = "0.3.0"
|
|
31
36
|
|
|
37
|
+
|
|
32
38
|
[profile.release]
|
|
33
39
|
lto = true
|
package/build.rs
CHANGED
package/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
export class MerkleClient {
|
|
7
7
|
constructor(absoluteRootDirectory: string)
|
|
8
|
-
init(): Promise<void>
|
|
9
|
-
computeMerkleTree(): Promise<void>
|
|
8
|
+
init(gitIgnoredFiles: Array<string>, isGitRepo: boolean): Promise<void>
|
|
9
|
+
computeMerkleTree(gitIgnoredFiles: Array<string>, isGitRepo: boolean): Promise<void>
|
|
10
10
|
updateFile(filePath: string): Promise<void>
|
|
11
11
|
deleteFile(filePath: string): Promise<void>
|
|
12
12
|
getSubtreeHash(relativePath: string): Promise<string>
|
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-fd010bd5",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
"version": "napi version"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@anysphere/file-service-win32-x64-msvc": "0.0.0-
|
|
40
|
-
"@anysphere/file-service-darwin-x64": "0.0.0-
|
|
41
|
-
"@anysphere/file-service-linux-x64-gnu": "0.0.0-
|
|
42
|
-
"@anysphere/file-service-darwin-arm64": "0.0.0-
|
|
43
|
-
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-
|
|
44
|
-
"@anysphere/file-service-darwin-universal": "0.0.0-
|
|
45
|
-
"@anysphere/file-service-linux-arm64-gnu": "0.0.0-
|
|
39
|
+
"@anysphere/file-service-win32-x64-msvc": "0.0.0-fd010bd5",
|
|
40
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-fd010bd5",
|
|
41
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-fd010bd5",
|
|
42
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-fd010bd5",
|
|
43
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-fd010bd5",
|
|
44
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-fd010bd5",
|
|
45
|
+
"@anysphere/file-service-linux-arm64-gnu": "0.0.0-fd010bd5"
|
|
46
46
|
}
|
|
47
47
|
}
|
package/src/file_utils.rs
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// 4. vscode.fs.stat
|
|
6
6
|
|
|
7
7
|
use anyhow::Error;
|
|
8
|
+
use encoding_rs::UTF_8;
|
|
8
9
|
use std::path::Path;
|
|
9
10
|
use tokio::fs;
|
|
10
11
|
|
|
@@ -43,8 +44,90 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
43
44
|
_ => {}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
"lock"
|
|
47
|
+
let bad_extensions = vec![
|
|
48
|
+
"lock",
|
|
49
|
+
"bak",
|
|
50
|
+
"tmp",
|
|
51
|
+
"bin",
|
|
52
|
+
"exe",
|
|
53
|
+
"dll",
|
|
54
|
+
"so",
|
|
55
|
+
"lockb",
|
|
56
|
+
"qwoff",
|
|
57
|
+
"isl",
|
|
58
|
+
"csv",
|
|
59
|
+
"pdf",
|
|
60
|
+
// add ms word, excel, powerpoint, etc.
|
|
61
|
+
"doc",
|
|
62
|
+
"docx",
|
|
63
|
+
"xls",
|
|
64
|
+
"xlsx",
|
|
65
|
+
"ppt",
|
|
66
|
+
"pptx",
|
|
67
|
+
"odt",
|
|
68
|
+
"ods",
|
|
69
|
+
"odp",
|
|
70
|
+
"odg",
|
|
71
|
+
"odf",
|
|
72
|
+
"sxw",
|
|
73
|
+
"sxc",
|
|
74
|
+
"sxi",
|
|
75
|
+
"sxd",
|
|
76
|
+
"sdc",
|
|
77
|
+
// add images
|
|
78
|
+
"jpg",
|
|
79
|
+
"jpeg",
|
|
80
|
+
"png",
|
|
81
|
+
"gif",
|
|
82
|
+
"bmp",
|
|
83
|
+
"tif",
|
|
84
|
+
// add audio
|
|
85
|
+
"mp3",
|
|
86
|
+
"wav",
|
|
87
|
+
"wma",
|
|
88
|
+
"ogg",
|
|
89
|
+
"flac",
|
|
90
|
+
"aac",
|
|
91
|
+
// add video
|
|
92
|
+
"mp4",
|
|
93
|
+
"mov",
|
|
94
|
+
"wmv",
|
|
95
|
+
"flv",
|
|
96
|
+
"avi",
|
|
97
|
+
// add archives
|
|
98
|
+
"zip",
|
|
99
|
+
"tar",
|
|
100
|
+
"gz",
|
|
101
|
+
"7z",
|
|
102
|
+
"rar",
|
|
103
|
+
"tgz",
|
|
104
|
+
"dmg",
|
|
105
|
+
"iso",
|
|
106
|
+
"cue",
|
|
107
|
+
"mdf",
|
|
108
|
+
"mds",
|
|
109
|
+
"vcd",
|
|
110
|
+
"toast",
|
|
111
|
+
"img",
|
|
112
|
+
"apk",
|
|
113
|
+
"msi",
|
|
114
|
+
"cab",
|
|
115
|
+
"tar.gz",
|
|
116
|
+
"tar.xz",
|
|
117
|
+
"tar.bz2",
|
|
118
|
+
"tar.lzma",
|
|
119
|
+
"tar.Z",
|
|
120
|
+
"tar.sz",
|
|
121
|
+
"lzma",
|
|
122
|
+
// add fonts
|
|
123
|
+
"ttf",
|
|
124
|
+
"otf",
|
|
125
|
+
"woff",
|
|
126
|
+
"woff2",
|
|
127
|
+
"eot",
|
|
128
|
+
];
|
|
129
|
+
match bad_extensions.contains(&extension) {
|
|
130
|
+
true => {
|
|
48
131
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
49
132
|
}
|
|
50
133
|
_ => {}
|
|
@@ -93,7 +176,7 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
93
176
|
// implement the buffer above:
|
|
94
177
|
pub async fn is_good_file_runtime_check(
|
|
95
178
|
file_path: &Path,
|
|
96
|
-
_buffer: &[u8],
|
|
179
|
+
// _buffer: &[u8],
|
|
97
180
|
) -> Result<(), Error> {
|
|
98
181
|
match get_file_size(file_path).await {
|
|
99
182
|
Ok(size) if size > 2 * 1024 * 1024 => {
|
|
@@ -103,13 +186,31 @@ pub async fn is_good_file_runtime_check(
|
|
|
103
186
|
_ => {}
|
|
104
187
|
}
|
|
105
188
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
189
|
+
// if is_binary(file_path).context("Failed to check if file is binary")? {
|
|
190
|
+
// return Err(anyhow::anyhow!("File is binary"));
|
|
191
|
+
// }
|
|
109
192
|
|
|
110
193
|
Ok(())
|
|
111
194
|
}
|
|
112
195
|
|
|
196
|
+
pub async fn read_string_without_bom(
|
|
197
|
+
file_path: &Path,
|
|
198
|
+
) -> Result<String, Error> {
|
|
199
|
+
let file_buffer = match fs::read(file_path).await {
|
|
200
|
+
Ok(buffer) => buffer,
|
|
201
|
+
Err(e) => {
|
|
202
|
+
return Err(anyhow::anyhow!(
|
|
203
|
+
"Failed to read file buffer: {}",
|
|
204
|
+
e.to_string()
|
|
205
|
+
))
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
let (cow, _) = UTF_8.decode_with_bom_removal(&file_buffer);
|
|
210
|
+
|
|
211
|
+
Ok(cow.to_string())
|
|
212
|
+
}
|
|
213
|
+
|
|
113
214
|
pub fn as_relative_path(
|
|
114
215
|
base_path: &Path,
|
|
115
216
|
file_path: &Path,
|
|
@@ -167,25 +268,40 @@ mod tests {
|
|
|
167
268
|
temp_file.write_all(b"Hello, world!").await.unwrap();
|
|
168
269
|
let buffer = fs::read(&temp_file_path).await.unwrap();
|
|
169
270
|
assert_eq!(
|
|
170
|
-
is_good_file_runtime_check(&temp_file_path,
|
|
171
|
-
.await
|
|
172
|
-
.is_ok(),
|
|
271
|
+
is_good_file_runtime_check(&temp_file_path).await.is_ok(),
|
|
173
272
|
true
|
|
174
273
|
);
|
|
175
274
|
temp_dir.close().unwrap();
|
|
176
275
|
|
|
276
|
+
// let temp_dir = tempfile::tempdir().unwrap();
|
|
277
|
+
// let temp_file_path = temp_dir.path().join("test_file");
|
|
278
|
+
// let mut temp_file = fs::File::create(&temp_file_path).await.unwrap();
|
|
279
|
+
// temp_file.write_all(&[0, 159, 146, 150]).await.unwrap(); // Invalid UTF-8 sequence
|
|
280
|
+
// let buffer = fs::read(&temp_file_path).await.unwrap();
|
|
281
|
+
// assert_eq!(
|
|
282
|
+
// is_good_file_runtime_check(&temp_file_path).await.is_err(),
|
|
283
|
+
// true
|
|
284
|
+
// );
|
|
285
|
+
// temp_dir.close().unwrap();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
#[tokio::test]
|
|
289
|
+
async fn test_bom_file() {
|
|
290
|
+
const BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
|
|
291
|
+
const CONTENT: &str = "Hello, world!";
|
|
292
|
+
|
|
293
|
+
// Write this to a temp file
|
|
177
294
|
let temp_dir = tempfile::tempdir().unwrap();
|
|
178
295
|
let temp_file_path = temp_dir.path().join("test_file");
|
|
179
296
|
let mut temp_file = fs::File::create(&temp_file_path).await.unwrap();
|
|
180
|
-
temp_file.write_all(&
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
188
|
-
temp_dir.close().unwrap();
|
|
297
|
+
temp_file.write_all(&BOM).await.unwrap();
|
|
298
|
+
temp_file.write_all(CONTENT.as_bytes()).await.unwrap();
|
|
299
|
+
|
|
300
|
+
// expect that we read the file with tokio as the CONTENT
|
|
301
|
+
let file_contents = read_string_without_bom(&temp_file_path).await.unwrap();
|
|
302
|
+
|
|
303
|
+
// Check string equality of CONTENT (&str) to file_contents (String)
|
|
304
|
+
assert_eq!(CONTENT, file_contents);
|
|
189
305
|
}
|
|
190
306
|
|
|
191
307
|
#[test]
|
package/src/git_utils.rs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use std::collections::HashSet;
|
|
2
|
+
use std::path::MAIN_SEPARATOR_STR;
|
|
2
3
|
use std::process::Command;
|
|
3
4
|
|
|
4
5
|
pub fn list_ignored_files_and_directories(
|
|
@@ -19,9 +20,7 @@ pub fn list_ignored_files_and_directories(
|
|
|
19
20
|
],
|
|
20
21
|
// FIXME(sualeh): this is super sketchy and might totally break in like a bazillion ways. i dont like it.
|
|
21
22
|
vec![
|
|
22
|
-
"
|
|
23
|
-
"-c",
|
|
24
|
-
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard --directory --no-empty-directory | sed \"s|^|$path/|\"'",
|
|
23
|
+
"git submodule foreach --quiet 'git -C $toplevel/$path ls-files --others --ignored --exclude-standard --directory --no-empty-directory | (while read line; do echo $path/$line; done)'",
|
|
25
24
|
],
|
|
26
25
|
];
|
|
27
26
|
|
|
@@ -36,9 +35,12 @@ pub fn list_ignored_files_and_directories(
|
|
|
36
35
|
.lines()
|
|
37
36
|
.filter(|line| !line.is_empty())
|
|
38
37
|
.map(|line| {
|
|
38
|
+
let line = line.replace("/", MAIN_SEPARATOR_STR);
|
|
39
|
+
|
|
39
40
|
if should_return_absolute_paths {
|
|
40
41
|
let mut path = std::path::PathBuf::from(workspace_root_path);
|
|
41
|
-
|
|
42
|
+
|
|
43
|
+
path.push(line.clone());
|
|
42
44
|
|
|
43
45
|
match path.canonicalize() {
|
|
44
46
|
Ok(canonical_path) => {
|
package/src/lib.rs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
#![windows_subsystem = "windows"]
|
|
1
2
|
#![deny(clippy::all)]
|
|
2
3
|
#![deny(unsafe_op_in_unsafe_fn)]
|
|
3
4
|
pub mod file_utils;
|
|
4
|
-
pub mod git_utils;
|
|
5
5
|
pub mod merkle_tree;
|
|
6
6
|
|
|
7
|
-
use std::vec;
|
|
7
|
+
use std::{collections::HashSet, vec};
|
|
8
8
|
|
|
9
|
+
use anyhow::Context;
|
|
9
10
|
use merkle_tree::{LocalConstruction, MerkleTree};
|
|
10
11
|
use tracing::{info, Level};
|
|
11
12
|
use tracing_appender::rolling::{RollingFileAppender, Rotation};
|
|
12
13
|
use tracing_subscriber::fmt;
|
|
13
|
-
use anyhow::Context;
|
|
14
14
|
|
|
15
15
|
#[macro_use]
|
|
16
16
|
extern crate napi_derive;
|
|
@@ -19,22 +19,27 @@ extern crate napi_derive;
|
|
|
19
19
|
pub struct MerkleClient {
|
|
20
20
|
tree: MerkleTree,
|
|
21
21
|
absolute_root_directory: String,
|
|
22
|
-
_guard: tracing_appender::non_blocking::WorkerGuard
|
|
22
|
+
_guard: Option<tracing_appender::non_blocking::WorkerGuard>,
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
pub fn init_logger() -> tracing_appender::non_blocking::WorkerGuard {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
pub fn init_logger() -> Option<tracing_appender::non_blocking::WorkerGuard> {
|
|
26
|
+
#[cfg(feature = "debugfile")]
|
|
27
|
+
let _guard = {
|
|
28
|
+
let file_appender =
|
|
29
|
+
RollingFileAppender::new(Rotation::NEVER, "./", "rust_log.txt");
|
|
30
|
+
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
|
|
31
|
+
let subscriber = fmt::Subscriber::builder()
|
|
32
|
+
.with_max_level(Level::TRACE)
|
|
33
|
+
.with_writer(non_blocking)
|
|
34
|
+
.with_ansi(false)
|
|
35
|
+
.with_line_number(true)
|
|
36
|
+
.finish();
|
|
37
|
+
|
|
38
|
+
let _ = tracing::subscriber::set_global_default(subscriber);
|
|
39
|
+
_guard
|
|
40
|
+
};
|
|
41
|
+
#[cfg(not(feature = "debugfile"))]
|
|
42
|
+
let _guard = { None };
|
|
38
43
|
_guard
|
|
39
44
|
}
|
|
40
45
|
|
|
@@ -62,13 +67,19 @@ impl MerkleClient {
|
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
#[napi]
|
|
65
|
-
pub async unsafe fn init(
|
|
70
|
+
pub async unsafe fn init(
|
|
71
|
+
&mut self,
|
|
72
|
+
git_ignored_files: Vec<String>,
|
|
73
|
+
is_git_repo: bool,
|
|
74
|
+
) -> Result<(), napi::Error> {
|
|
66
75
|
// 1. compute the merkle tree
|
|
67
76
|
// 2. update the backend
|
|
68
77
|
// 3. sync with the remote
|
|
69
78
|
info!("Merkle tree compute started!");
|
|
70
79
|
unsafe {
|
|
71
|
-
self
|
|
80
|
+
self
|
|
81
|
+
.compute_merkle_tree(git_ignored_files, is_git_repo)
|
|
82
|
+
.await?;
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
Ok(())
|
|
@@ -81,9 +92,18 @@ impl MerkleClient {
|
|
|
81
92
|
#[napi]
|
|
82
93
|
pub async unsafe fn compute_merkle_tree(
|
|
83
94
|
&mut self,
|
|
95
|
+
git_ignored_files: Vec<String>,
|
|
96
|
+
is_git_repo: bool,
|
|
84
97
|
) -> Result<(), napi::Error> {
|
|
85
|
-
|
|
86
|
-
|
|
98
|
+
// make the git ignored files into a hash set
|
|
99
|
+
let git_ignored_set = HashSet::from_iter(git_ignored_files.into_iter());
|
|
100
|
+
|
|
101
|
+
let t = MerkleTree::construct_merkle_tree(
|
|
102
|
+
self.absolute_root_directory.clone(),
|
|
103
|
+
git_ignored_set,
|
|
104
|
+
is_git_repo,
|
|
105
|
+
)
|
|
106
|
+
.await;
|
|
87
107
|
|
|
88
108
|
match t {
|
|
89
109
|
Ok(tree) => {
|
|
@@ -112,14 +132,16 @@ impl MerkleClient {
|
|
|
112
132
|
&self,
|
|
113
133
|
relative_path: String,
|
|
114
134
|
) -> Result<String, napi::Error> {
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
let relative_path_without_leading_slash = match relative_path
|
|
136
|
+
.strip_prefix('.')
|
|
137
|
+
{
|
|
117
138
|
Some(path) => path.strip_prefix(std::path::MAIN_SEPARATOR).unwrap_or(""),
|
|
118
139
|
None => relative_path.as_str(),
|
|
119
140
|
};
|
|
120
141
|
|
|
121
142
|
let absolute_path = if !relative_path_without_leading_slash.is_empty() {
|
|
122
|
-
std::path::Path::new(&self.absolute_root_directory)
|
|
143
|
+
std::path::Path::new(&self.absolute_root_directory)
|
|
144
|
+
.join(relative_path_without_leading_slash)
|
|
123
145
|
} else {
|
|
124
146
|
std::path::Path::new(&self.absolute_root_directory).to_path_buf()
|
|
125
147
|
};
|
|
@@ -129,12 +151,15 @@ impl MerkleClient {
|
|
|
129
151
|
None => {
|
|
130
152
|
return Err(napi::Error::new(
|
|
131
153
|
napi::Status::Unknown,
|
|
132
|
-
format!("some string error")
|
|
154
|
+
format!("some string error"),
|
|
133
155
|
))
|
|
134
156
|
}
|
|
135
157
|
};
|
|
136
158
|
|
|
137
|
-
let hash = self
|
|
159
|
+
let hash = self
|
|
160
|
+
.tree
|
|
161
|
+
.get_subtree_hash(absolute_path_string.as_str())
|
|
162
|
+
.await;
|
|
138
163
|
|
|
139
164
|
match hash {
|
|
140
165
|
Ok(hash) => Ok(hash),
|
|
@@ -153,7 +178,7 @@ impl MerkleClient {
|
|
|
153
178
|
Ok(num) => Ok(num),
|
|
154
179
|
Err(e) => Err(napi::Error::new(
|
|
155
180
|
napi::Status::Unknown,
|
|
156
|
-
format!("Error in get_num_embeddable_files: {:?}", e)
|
|
181
|
+
format!("Error in get_num_embeddable_files: {:?}", e),
|
|
157
182
|
)),
|
|
158
183
|
}
|
|
159
184
|
}
|
|
@@ -175,7 +200,7 @@ impl MerkleClient {
|
|
|
175
200
|
Ok(num) => Ok(num),
|
|
176
201
|
Err(e) => Err(napi::Error::new(
|
|
177
202
|
napi::Status::Unknown,
|
|
178
|
-
format!("Error in get_num_embeddable_files_in_subtree: {:?}", e)
|
|
203
|
+
format!("Error in get_num_embeddable_files_in_subtree: {:?}", e),
|
|
179
204
|
)),
|
|
180
205
|
}
|
|
181
206
|
}
|
|
@@ -188,7 +213,7 @@ impl MerkleClient {
|
|
|
188
213
|
Ok(files) => Ok(files),
|
|
189
214
|
Err(e) => Err(napi::Error::new(
|
|
190
215
|
napi::Status::Unknown,
|
|
191
|
-
format!("Error in get_all_files: {:?}", e)
|
|
216
|
+
format!("Error in get_all_files: {:?}", e),
|
|
192
217
|
)),
|
|
193
218
|
}
|
|
194
219
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
use crate::git_utils;
|
|
2
1
|
use crate::merkle_tree::{
|
|
3
2
|
File, MerkleNode, MerkleNodePtr, NodeType, PinnedFuture,
|
|
4
3
|
};
|
|
@@ -13,8 +12,13 @@ impl LocalConstruction for MerkleTree {
|
|
|
13
12
|
async fn new(
|
|
14
13
|
root_directory: Option<String>,
|
|
15
14
|
) -> Result<MerkleTree, anyhow::Error> {
|
|
15
|
+
let git_ignored_files = HashSet::<String>::new();
|
|
16
16
|
if let Some(root_directory) = root_directory {
|
|
17
|
-
let n = MerkleTree::construct_merkle_tree(
|
|
17
|
+
let n = MerkleTree::construct_merkle_tree(
|
|
18
|
+
root_directory,
|
|
19
|
+
git_ignored_files,
|
|
20
|
+
false
|
|
21
|
+
).await;
|
|
18
22
|
return n;
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -30,6 +34,8 @@ impl LocalConstruction for MerkleTree {
|
|
|
30
34
|
/// 4. return merkle tree
|
|
31
35
|
async fn construct_merkle_tree(
|
|
32
36
|
absolute_path_to_root_directory: String,
|
|
37
|
+
git_ignored_files_and_dirs: HashSet<String>,
|
|
38
|
+
is_git_repo: bool
|
|
33
39
|
) -> Result<MerkleTree, anyhow::Error> {
|
|
34
40
|
let path = PathBuf::from(absolute_path_to_root_directory.clone());
|
|
35
41
|
if !path.exists() {
|
|
@@ -38,20 +44,21 @@ impl LocalConstruction for MerkleTree {
|
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
// 1. get all the gitignored files
|
|
41
|
-
let git_ignored_files_and_dirs =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
// let git_ignored_files_and_dirs =
|
|
48
|
+
// match git_utils::list_ignored_files_and_directories(
|
|
49
|
+
// absolute_path_to_root_directory.as_str(),
|
|
50
|
+
// true,
|
|
51
|
+
// ) {
|
|
52
|
+
// Ok(git_ignored) => git_ignored,
|
|
53
|
+
// Err(_e) => HashSet::new(),
|
|
54
|
+
// };
|
|
49
55
|
|
|
50
56
|
let root_node = MerkleNode::new(
|
|
51
57
|
path,
|
|
52
58
|
None,
|
|
53
59
|
&git_ignored_files_and_dirs,
|
|
54
60
|
absolute_path_to_root_directory.as_str(),
|
|
61
|
+
is_git_repo
|
|
55
62
|
)
|
|
56
63
|
.await;
|
|
57
64
|
let mut mt = MerkleTree {
|
|
@@ -60,6 +67,7 @@ impl LocalConstruction for MerkleTree {
|
|
|
60
67
|
root_path: absolute_path_to_root_directory,
|
|
61
68
|
cursor: None,
|
|
62
69
|
git_ignored_files_and_dirs: git_ignored_files_and_dirs,
|
|
70
|
+
is_git_repo
|
|
63
71
|
};
|
|
64
72
|
|
|
65
73
|
// we now iterate over all the nodes and add them to the hashmap
|
package/src/merkle_tree/mod.rs
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
use crate::git_utils;
|
|
2
|
-
|
|
3
1
|
use super::file_utils;
|
|
4
2
|
use sha2::Digest;
|
|
5
3
|
use std::collections::{BTreeMap, HashSet};
|
|
@@ -9,6 +7,7 @@ use std::{fs, path::Path, sync::Arc};
|
|
|
9
7
|
use tokio::sync::RwLock;
|
|
10
8
|
use tonic::async_trait;
|
|
11
9
|
use tracing::info;
|
|
10
|
+
|
|
12
11
|
pub mod local_construction;
|
|
13
12
|
pub mod test;
|
|
14
13
|
|
|
@@ -20,6 +19,7 @@ pub struct MerkleTree {
|
|
|
20
19
|
files: BTreeMap<String, File>,
|
|
21
20
|
cursor: Option<usize>,
|
|
22
21
|
git_ignored_files_and_dirs: HashSet<String>,
|
|
22
|
+
is_git_repo: bool,
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
#[derive(Debug)]
|
|
@@ -63,6 +63,8 @@ pub trait LocalConstruction {
|
|
|
63
63
|
|
|
64
64
|
async fn construct_merkle_tree(
|
|
65
65
|
root_directory: String,
|
|
66
|
+
git_ignored_files_and_dirs: HashSet<String>,
|
|
67
|
+
is_git_repo: bool
|
|
66
68
|
) -> Result<MerkleTree, anyhow::Error>;
|
|
67
69
|
|
|
68
70
|
async fn update_file(
|
|
@@ -97,6 +99,7 @@ impl MerkleTree {
|
|
|
97
99
|
root_path: "".to_string(),
|
|
98
100
|
cursor: None,
|
|
99
101
|
git_ignored_files_and_dirs: HashSet::new(),
|
|
102
|
+
is_git_repo: false
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -287,6 +290,12 @@ impl MerkleTree {
|
|
|
287
290
|
) -> Result<Vec<String>, anyhow::Error> {
|
|
288
291
|
let mut files = Vec::new();
|
|
289
292
|
|
|
293
|
+
// 1. should check that this absolute path is actually a directory.
|
|
294
|
+
let file_node = self.files.get(absolute_path);
|
|
295
|
+
if file_node.is_none() {
|
|
296
|
+
return Err(anyhow::anyhow!("Could not find directory the in tree!"));
|
|
297
|
+
}
|
|
298
|
+
|
|
290
299
|
for (file_path, f) in &self.files {
|
|
291
300
|
if !file_path.contains(absolute_path) {
|
|
292
301
|
continue;
|
|
@@ -401,6 +410,7 @@ impl MerkleTree {
|
|
|
401
410
|
Some(ancestor.clone()),
|
|
402
411
|
&self.git_ignored_files_and_dirs,
|
|
403
412
|
&absolute_root_path.as_str(),
|
|
413
|
+
self.is_git_repo
|
|
404
414
|
)
|
|
405
415
|
.await;
|
|
406
416
|
ancestor.write().await.attach_child(new_node.clone()).await;
|
|
@@ -418,6 +428,7 @@ impl MerkleTree {
|
|
|
418
428
|
Some(ancestor.clone()),
|
|
419
429
|
&self.git_ignored_files_and_dirs,
|
|
420
430
|
&absolute_root_path.as_str(),
|
|
431
|
+
self.is_git_repo
|
|
421
432
|
)
|
|
422
433
|
.await;
|
|
423
434
|
|
|
@@ -705,13 +716,14 @@ impl MerkleNode {
|
|
|
705
716
|
parent: ParentPtr,
|
|
706
717
|
ignored_files: &IgnoredFiles,
|
|
707
718
|
absolute_root_path: &str,
|
|
719
|
+
is_git_repo: bool,
|
|
708
720
|
) -> MerkleNodePtr {
|
|
709
|
-
// check if the root is a git directory.
|
|
710
|
-
let is_git_repo =
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
721
|
+
// // check if the root is a git directory.
|
|
722
|
+
// let is_git_repo =
|
|
723
|
+
// match git_utils::is_git_directory(absolute_root_path).await {
|
|
724
|
+
// Ok(is_git_repo) => is_git_repo,
|
|
725
|
+
// Err(_e) => false,
|
|
726
|
+
// };
|
|
715
727
|
let bypass_git = !is_git_repo;
|
|
716
728
|
|
|
717
729
|
MerkleNode::construct_node(
|
|
@@ -729,13 +741,8 @@ impl MerkleNode {
|
|
|
729
741
|
parent: ParentPtr,
|
|
730
742
|
ignored_files: &IgnoredFiles,
|
|
731
743
|
absolute_root_path: &str,
|
|
744
|
+
is_git_repo: bool,
|
|
732
745
|
) -> MerkleNodePtr {
|
|
733
|
-
// check if the root is a git directory.
|
|
734
|
-
let is_git_repo =
|
|
735
|
-
match git_utils::is_git_directory(absolute_root_path).await {
|
|
736
|
-
Ok(is_git_repo) => is_git_repo,
|
|
737
|
-
Err(_e) => false,
|
|
738
|
-
};
|
|
739
746
|
let bypass_git = !is_git_repo;
|
|
740
747
|
|
|
741
748
|
info!(
|
|
@@ -883,18 +890,10 @@ impl MerkleNode {
|
|
|
883
890
|
false => {}
|
|
884
891
|
}
|
|
885
892
|
|
|
886
|
-
// read the file_content to a buffer
|
|
887
|
-
let file_content = match tokio::fs::read(absolute_file_path).await {
|
|
888
|
-
Ok(content) => content,
|
|
889
|
-
Err(e) => {
|
|
890
|
-
return Err(format!("Could not read file! {}", e.to_string()));
|
|
891
|
-
}
|
|
892
|
-
};
|
|
893
|
-
|
|
894
893
|
// check if the file passes runtime checks.
|
|
895
894
|
match file_utils::is_good_file_runtime_check(
|
|
896
895
|
absolute_file_path,
|
|
897
|
-
&file_content,
|
|
896
|
+
// &file_content,
|
|
898
897
|
)
|
|
899
898
|
.await
|
|
900
899
|
{
|
|
@@ -904,15 +903,14 @@ impl MerkleNode {
|
|
|
904
903
|
}
|
|
905
904
|
}
|
|
906
905
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
e.to_string()
|
|
913
|
-
|
|
914
|
-
}
|
|
915
|
-
};
|
|
906
|
+
// read the file_content to a buffer
|
|
907
|
+
let file_content =
|
|
908
|
+
match file_utils::read_string_without_bom(absolute_file_path).await {
|
|
909
|
+
Ok(content) => content,
|
|
910
|
+
Err(e) => {
|
|
911
|
+
return Err(format!("Could not read file! {}", e.to_string()));
|
|
912
|
+
}
|
|
913
|
+
};
|
|
916
914
|
|
|
917
915
|
let file_hash = compute_hash(&file_content);
|
|
918
916
|
let node = MerkleNode {
|
package/src/merkle_tree/test.rs
CHANGED
|
@@ -43,8 +43,9 @@ mod tests {
|
|
|
43
43
|
// let path = Path::new(&temp_dir_path);
|
|
44
44
|
|
|
45
45
|
// Test construct_merkle_tree() function
|
|
46
|
+
let new_set = std::collections::HashSet::<String>::new();
|
|
46
47
|
let tree =
|
|
47
|
-
MerkleTree::construct_merkle_tree(temp_dir_path.clone()).await;
|
|
48
|
+
MerkleTree::construct_merkle_tree(temp_dir_path.clone(), new_set, false).await;
|
|
48
49
|
let mut tree = match tree {
|
|
49
50
|
Ok(tree) => {
|
|
50
51
|
assert_eq!(tree.files.len(), 2);
|