@anysphere/file-service 0.0.0-b4c871b2 → 0.0.0-b6f39ec9
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 +5 -0
- package/index.d.ts +7 -2
- package/package.json +10 -8
- package/src/file_utils.rs +12 -14
- package/src/git_utils.rs +166 -20
- package/src/lib.rs +215 -61
- package/src/merkle_tree/local_construction.rs +54 -21
- package/src/merkle_tree/mod.rs +465 -150
- package/src/test.rs +5 -0
- package/src/proto/aiserver.v1.rs +0 -12041
package/Cargo.toml
CHANGED
|
@@ -17,6 +17,11 @@ tempfile = "3.8.0"
|
|
|
17
17
|
anyhow = "1.0.75"
|
|
18
18
|
tonic = "0.9.2"
|
|
19
19
|
prost = "0.11.9"
|
|
20
|
+
tracing = "0.1.37"
|
|
21
|
+
tracing-subscriber = "0.3.17"
|
|
22
|
+
tracing-appender = "0.2.2"
|
|
23
|
+
binaryornot = "1.0.0"
|
|
24
|
+
dunce = "1.0.1"
|
|
20
25
|
|
|
21
26
|
[build-dependencies]
|
|
22
27
|
napi-build = "2.0.1"
|
package/index.d.ts
CHANGED
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
/* auto-generated by NAPI-RS */
|
|
5
5
|
|
|
6
6
|
export class MerkleClient {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(absoluteRootDirectory: string)
|
|
8
8
|
init(): Promise<void>
|
|
9
|
+
computeMerkleTree(): Promise<void>
|
|
9
10
|
updateFile(filePath: string): Promise<void>
|
|
10
11
|
deleteFile(filePath: string): Promise<void>
|
|
11
|
-
getSubtreeHash(
|
|
12
|
+
getSubtreeHash(relativePath: string): Promise<string>
|
|
12
13
|
getNumEmbeddableFiles(): Promise<number>
|
|
13
14
|
getAllFiles(): Promise<Array<string>>
|
|
15
|
+
getAllDirFilesToEmbed(absoluteFilePath: string): Promise<Array<string>>
|
|
16
|
+
getNextFileToEmbed(): Promise<Array<string>>
|
|
17
|
+
getSpline(absoluteFilePath: string): Promise<Array<string>>
|
|
14
18
|
getHashesForFiles(files: Array<string>): Promise<Array<string>>
|
|
19
|
+
updateRootDirectory(rootDirectory: string): void
|
|
15
20
|
}
|
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-b6f39ec9",
|
|
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-b6f39ec9",
|
|
40
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-b6f39ec9",
|
|
41
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-b6f39ec9",
|
|
42
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-b6f39ec9",
|
|
43
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-b6f39ec9",
|
|
44
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-b6f39ec9",
|
|
45
|
+
"@anysphere/file-service-linux-arm64-gnu": "0.0.0-b6f39ec9"
|
|
44
46
|
}
|
|
45
47
|
}
|
package/src/file_utils.rs
CHANGED
|
@@ -12,9 +12,8 @@ pub fn is_in_bad_dir(file_path: &Path) -> Result<bool, Error> {
|
|
|
12
12
|
let item_path = file_path
|
|
13
13
|
.to_str()
|
|
14
14
|
.ok_or(anyhow::anyhow!("Failed to convert path to string"))?;
|
|
15
|
-
let is_bad_dir =
|
|
16
|
-
|| item_path.contains(".git")
|
|
17
|
-
&& !(item_path.ends_with(".git") || item_path.ends_with("node_modules"));
|
|
15
|
+
let is_bad_dir =
|
|
16
|
+
item_path.contains("node_modules") || item_path.contains(".git");
|
|
18
17
|
Ok(is_bad_dir)
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -38,14 +37,14 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
38
37
|
|
|
39
38
|
match file_name {
|
|
40
39
|
"package-lock.json" | "pnpm-lock.yaml" | "yarn.lock" | "composer.lock"
|
|
41
|
-
| "Gemfile.lock" => {
|
|
40
|
+
| "Gemfile.lock" | "bun.lockb" => {
|
|
42
41
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
43
42
|
}
|
|
44
43
|
_ => {}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
match extension {
|
|
48
|
-
"lock" | "bak" | "tmp" | "bin" | "exe" | "dll" | "so" => {
|
|
47
|
+
"lock" | "bak" | "tmp" | "bin" | "exe" | "dll" | "so" | "lockb" => {
|
|
49
48
|
return Err(anyhow::anyhow!("File is just a lock file"));
|
|
50
49
|
}
|
|
51
50
|
_ => {}
|
|
@@ -63,7 +62,7 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
63
62
|
Some(extension) => match extension.to_str() {
|
|
64
63
|
Some(ext_str) => {
|
|
65
64
|
if bad_extensions.contains(&ext_str) {
|
|
66
|
-
return Err(anyhow::anyhow!("
|
|
65
|
+
return Err(anyhow::anyhow!("Binary file excluded from indexing."));
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
None => {
|
|
@@ -89,10 +88,12 @@ pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
|
|
|
89
88
|
Ok(())
|
|
90
89
|
}
|
|
91
90
|
|
|
91
|
+
// use binaryornot::is_binary;
|
|
92
|
+
// use anyhow::Context;
|
|
92
93
|
// implement the buffer above:
|
|
93
94
|
pub async fn is_good_file_runtime_check(
|
|
94
95
|
file_path: &Path,
|
|
95
|
-
|
|
96
|
+
_buffer: &[u8],
|
|
96
97
|
) -> Result<(), Error> {
|
|
97
98
|
match get_file_size(file_path).await {
|
|
98
99
|
Ok(size) if size > 2 * 1024 * 1024 => {
|
|
@@ -102,13 +103,10 @@ pub async fn is_good_file_runtime_check(
|
|
|
102
103
|
_ => {}
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return Err(anyhow::anyhow!("File is not a valid UTF-8 string"));
|
|
110
|
-
}
|
|
111
|
-
}
|
|
106
|
+
// if is_binary(file_path).context("Failed to check if file is binary")? {
|
|
107
|
+
// return Err(anyhow::anyhow!("File is binary"));
|
|
108
|
+
// }
|
|
109
|
+
|
|
112
110
|
Ok(())
|
|
113
111
|
}
|
|
114
112
|
|
package/src/git_utils.rs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
use std::collections::HashSet;
|
|
2
|
-
use std::path::PathBuf;
|
|
3
2
|
use std::process::Command;
|
|
4
3
|
|
|
5
|
-
pub fn
|
|
4
|
+
pub fn list_ignored_files_and_directories(
|
|
6
5
|
workspace_root_path: &str,
|
|
7
|
-
|
|
6
|
+
should_return_absolute_paths: bool,
|
|
7
|
+
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
|
8
8
|
let mut gitignored_files = HashSet::new();
|
|
9
9
|
|
|
10
10
|
let commands = vec![
|
|
@@ -14,13 +14,69 @@ pub fn list_ignored_files(
|
|
|
14
14
|
"--others",
|
|
15
15
|
"--ignored",
|
|
16
16
|
"--exclude-standard",
|
|
17
|
+
"--directory",
|
|
18
|
+
"--no-empty-directory"
|
|
17
19
|
],
|
|
20
|
+
// FIXME(sualeh): this is super sketchy and might totally break in like a bazillion ways. i dont like it.
|
|
21
|
+
vec![
|
|
22
|
+
"sh",
|
|
23
|
+
"-c",
|
|
24
|
+
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard --directory --no-empty-directory | sed \"s|^|$path/|\"'",
|
|
25
|
+
],
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
for command in commands {
|
|
29
|
+
let output = Command::new(&command[0])
|
|
30
|
+
.args(&command[1..])
|
|
31
|
+
.current_dir(workspace_root_path)
|
|
32
|
+
.output()?;
|
|
33
|
+
|
|
34
|
+
if output.status.success() {
|
|
35
|
+
let files = String::from_utf8(output.stdout)?
|
|
36
|
+
.lines()
|
|
37
|
+
.filter(|line| !line.is_empty())
|
|
38
|
+
.map(|line| {
|
|
39
|
+
if should_return_absolute_paths {
|
|
40
|
+
let mut path = std::path::PathBuf::from(workspace_root_path);
|
|
41
|
+
path.push(line);
|
|
42
|
+
|
|
43
|
+
match path.canonicalize() {
|
|
44
|
+
Ok(canonical_path) => {
|
|
45
|
+
canonical_path.to_string_lossy().into_owned()
|
|
46
|
+
}
|
|
47
|
+
Err(_) => String::from(line),
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
String::from(line)
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
.collect::<HashSet<_>>();
|
|
54
|
+
|
|
55
|
+
gitignored_files.extend(files);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
Ok(gitignored_files)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn list_ignored_files_with_absolute_paths(
|
|
63
|
+
workspace_root_path: &str,
|
|
64
|
+
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
|
65
|
+
let mut gitignored_files = HashSet::new();
|
|
66
|
+
|
|
67
|
+
let commands = vec![
|
|
18
68
|
vec![
|
|
19
69
|
"git",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"--
|
|
23
|
-
"
|
|
70
|
+
"ls-files",
|
|
71
|
+
"--others",
|
|
72
|
+
"--ignored",
|
|
73
|
+
"--exclude-standard",
|
|
74
|
+
],
|
|
75
|
+
// FIXME(sualeh): this is super sketchy and might totally break in like a bazillion ways. i dont like it.
|
|
76
|
+
vec![
|
|
77
|
+
"sh",
|
|
78
|
+
"-c",
|
|
79
|
+
"git submodule foreach --quiet 'git ls-files --others --ignored --exclude-standard | sed \"s|^|$path/|\"'",
|
|
24
80
|
],
|
|
25
81
|
];
|
|
26
82
|
|
|
@@ -34,7 +90,7 @@ pub fn list_ignored_files(
|
|
|
34
90
|
let files = String::from_utf8(output.stdout)?
|
|
35
91
|
.lines()
|
|
36
92
|
.filter(|line| !line.is_empty())
|
|
37
|
-
.map(|line|
|
|
93
|
+
.map(|line| String::from(line))
|
|
38
94
|
.collect::<HashSet<_>>();
|
|
39
95
|
|
|
40
96
|
gitignored_files.extend(files);
|
|
@@ -57,6 +113,18 @@ pub async fn is_git_ignored(
|
|
|
57
113
|
Ok(output.status.success())
|
|
58
114
|
}
|
|
59
115
|
|
|
116
|
+
pub async fn is_git_directory(
|
|
117
|
+
workspace_root_path: &str,
|
|
118
|
+
) -> Result<bool, anyhow::Error> {
|
|
119
|
+
let output = tokio::process::Command::new("git")
|
|
120
|
+
.args(&["rev-parse", "--is-inside-work-tree"])
|
|
121
|
+
.current_dir(workspace_root_path)
|
|
122
|
+
.output()
|
|
123
|
+
.await?;
|
|
124
|
+
|
|
125
|
+
Ok(output.status.success())
|
|
126
|
+
}
|
|
127
|
+
|
|
60
128
|
#[cfg(test)]
|
|
61
129
|
mod tests {
|
|
62
130
|
use super::*;
|
|
@@ -66,7 +134,9 @@ mod tests {
|
|
|
66
134
|
#[test]
|
|
67
135
|
fn test_no_ignored_files() {
|
|
68
136
|
let dir = tempfile::tempdir().unwrap();
|
|
69
|
-
let gitignored_files =
|
|
137
|
+
let gitignored_files =
|
|
138
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
139
|
+
.unwrap();
|
|
70
140
|
Command::new("git")
|
|
71
141
|
.args(&["init"])
|
|
72
142
|
.current_dir(dir.path())
|
|
@@ -92,13 +162,15 @@ mod tests {
|
|
|
92
162
|
.current_dir(dir.path())
|
|
93
163
|
.output()
|
|
94
164
|
.unwrap();
|
|
95
|
-
let gitignored_files =
|
|
165
|
+
let gitignored_files =
|
|
166
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
167
|
+
.unwrap();
|
|
96
168
|
println!(
|
|
97
169
|
"ignored files for test_one_ignored_file: {:?}",
|
|
98
170
|
gitignored_files
|
|
99
171
|
);
|
|
100
172
|
// assert_eq!(gitignored_files.len(), 1);
|
|
101
|
-
assert!(gitignored_files.contains(&
|
|
173
|
+
assert!(gitignored_files.contains(&String::from("ignored.txt")));
|
|
102
174
|
}
|
|
103
175
|
|
|
104
176
|
#[test]
|
|
@@ -121,19 +193,86 @@ mod tests {
|
|
|
121
193
|
.current_dir(dir.path())
|
|
122
194
|
.output()
|
|
123
195
|
.unwrap();
|
|
124
|
-
let gitignored_files =
|
|
196
|
+
let gitignored_files =
|
|
197
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
198
|
+
.unwrap();
|
|
125
199
|
println!(
|
|
126
200
|
"ignored files for test_multiple_ignored_files: {:?}",
|
|
127
201
|
gitignored_files
|
|
128
202
|
);
|
|
129
203
|
// assert_eq!(gitignored_files.len(), 2);
|
|
130
|
-
assert!(gitignored_files.contains(&
|
|
131
|
-
assert!(gitignored_files.contains(&
|
|
204
|
+
assert!(gitignored_files.contains(&String::from("ignored1.txt")));
|
|
205
|
+
assert!(gitignored_files.contains(&String::from("ignored2.txt")));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#[test]
|
|
209
|
+
fn test_git_submodule_ignored_files() {
|
|
210
|
+
let dir = tempfile::tempdir().unwrap();
|
|
211
|
+
let submodule_path = dir.path().join("submodule");
|
|
212
|
+
std::fs::create_dir(&submodule_path).unwrap();
|
|
213
|
+
|
|
214
|
+
let o = Command::new("git")
|
|
215
|
+
.args(&["init"])
|
|
216
|
+
.current_dir(&submodule_path)
|
|
217
|
+
.output()
|
|
218
|
+
.unwrap();
|
|
219
|
+
println!("git init output: {:?}", o);
|
|
220
|
+
|
|
221
|
+
let file_path = submodule_path.join("ignored.txt");
|
|
222
|
+
let mut file = File::create(&file_path).unwrap();
|
|
223
|
+
writeln!(file, "This is an ignored file.").unwrap();
|
|
224
|
+
|
|
225
|
+
let file2 = submodule_path.join("ignored2.txt");
|
|
226
|
+
let mut file = File::create(&file2).unwrap();
|
|
227
|
+
writeln!(file, "This is another ignored file.").unwrap();
|
|
228
|
+
|
|
229
|
+
let gitignore_path = submodule_path.join(".gitignore");
|
|
230
|
+
let mut gitignore = File::create(&gitignore_path).unwrap();
|
|
231
|
+
writeln!(gitignore, "*.txt").unwrap();
|
|
232
|
+
|
|
233
|
+
let o = Command::new("git")
|
|
234
|
+
.args(&["init"])
|
|
235
|
+
.current_dir(dir.path())
|
|
236
|
+
.output()
|
|
237
|
+
.unwrap();
|
|
238
|
+
println!("git init output: {:?}", o);
|
|
239
|
+
|
|
240
|
+
// make a commit in the submodule
|
|
241
|
+
let o = Command::new("git")
|
|
242
|
+
.args(&["add", "."])
|
|
243
|
+
.current_dir(&submodule_path)
|
|
244
|
+
.output()
|
|
245
|
+
.unwrap();
|
|
246
|
+
println!("git add output: {:?}", o);
|
|
247
|
+
let o = Command::new("git")
|
|
248
|
+
.args(&["commit", "-m", "initial commit"])
|
|
249
|
+
.current_dir(&submodule_path)
|
|
250
|
+
.output()
|
|
251
|
+
.unwrap();
|
|
252
|
+
println!("git commit output: {:?}", o);
|
|
253
|
+
|
|
254
|
+
let o = Command::new("git")
|
|
255
|
+
.args(&["submodule", "add", "./submodule"])
|
|
256
|
+
.current_dir(dir.path())
|
|
257
|
+
.output()
|
|
258
|
+
.unwrap();
|
|
259
|
+
println!("git submodule add output: {:?}", o);
|
|
260
|
+
|
|
261
|
+
let gitignored_files =
|
|
262
|
+
list_ignored_files_and_directories(dir.path().to_str().unwrap(), false)
|
|
263
|
+
.unwrap();
|
|
264
|
+
println!(
|
|
265
|
+
"ignored files for test_git_submodule_ignored_files: {:?}",
|
|
266
|
+
gitignored_files
|
|
267
|
+
);
|
|
268
|
+
assert!(gitignored_files.contains(&String::from("submodule/ignored.txt")));
|
|
269
|
+
assert!(gitignored_files.contains(&String::from("submodule/ignored2.txt")));
|
|
132
270
|
}
|
|
133
271
|
|
|
134
272
|
#[test]
|
|
135
273
|
fn test_multiple_ignored_files_in_current_dir() {
|
|
136
|
-
let gitignored_files =
|
|
274
|
+
let gitignored_files =
|
|
275
|
+
list_ignored_files_and_directories(".", false).unwrap();
|
|
137
276
|
assert!(gitignored_files.len() > 1);
|
|
138
277
|
|
|
139
278
|
// print a sample of the ignored files
|
|
@@ -147,7 +286,6 @@ mod tests {
|
|
|
147
286
|
}
|
|
148
287
|
}
|
|
149
288
|
|
|
150
|
-
|
|
151
289
|
#[tokio::test]
|
|
152
290
|
async fn test_file_not_ignored() {
|
|
153
291
|
let dir = tempfile::tempdir().unwrap();
|
|
@@ -160,7 +298,10 @@ mod tests {
|
|
|
160
298
|
.current_dir(dir.path())
|
|
161
299
|
.output()
|
|
162
300
|
.unwrap();
|
|
163
|
-
let is_ignored =
|
|
301
|
+
let is_ignored =
|
|
302
|
+
is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt")
|
|
303
|
+
.await
|
|
304
|
+
.unwrap();
|
|
164
305
|
assert_eq!(is_ignored, false);
|
|
165
306
|
}
|
|
166
307
|
|
|
@@ -180,7 +321,10 @@ mod tests {
|
|
|
180
321
|
.current_dir(dir.path())
|
|
181
322
|
.output()
|
|
182
323
|
.unwrap();
|
|
183
|
-
let is_ignored =
|
|
324
|
+
let is_ignored =
|
|
325
|
+
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
326
|
+
.await
|
|
327
|
+
.unwrap();
|
|
184
328
|
assert_eq!(is_ignored, true);
|
|
185
329
|
}
|
|
186
330
|
|
|
@@ -200,8 +344,10 @@ mod tests {
|
|
|
200
344
|
.current_dir(dir.path())
|
|
201
345
|
.output()
|
|
202
346
|
.unwrap();
|
|
203
|
-
let is_ignored =
|
|
347
|
+
let is_ignored =
|
|
348
|
+
is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
|
|
349
|
+
.await
|
|
350
|
+
.unwrap();
|
|
204
351
|
assert_eq!(is_ignored, true);
|
|
205
352
|
}
|
|
206
|
-
|
|
207
353
|
}
|