@anysphere/file-service 0.0.0-5d343fb9 → 0.0.0-63cdba18

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 CHANGED
@@ -17,6 +17,9 @@ 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"
20
23
 
21
24
  [build-dependencies]
22
25
  napi-build = "2.0.1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anysphere/file-service",
3
- "version": "0.0.0-5d343fb9",
3
+ "version": "0.0.0-63cdba18",
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-5d343fb9",
39
- "@anysphere/file-service-darwin-x64": "0.0.0-5d343fb9",
40
- "@anysphere/file-service-linux-x64-gnu": "0.0.0-5d343fb9",
41
- "@anysphere/file-service-darwin-arm64": "0.0.0-5d343fb9",
42
- "@anysphere/file-service-win32-arm64-msvc": "0.0.0-5d343fb9",
43
- "@anysphere/file-service-darwin-universal": "0.0.0-5d343fb9"
38
+ "@anysphere/file-service-win32-x64-msvc": "0.0.0-63cdba18",
39
+ "@anysphere/file-service-darwin-x64": "0.0.0-63cdba18",
40
+ "@anysphere/file-service-linux-x64-gnu": "0.0.0-63cdba18",
41
+ "@anysphere/file-service-darwin-arm64": "0.0.0-63cdba18",
42
+ "@anysphere/file-service-win32-arm64-msvc": "0.0.0-63cdba18",
43
+ "@anysphere/file-service-darwin-universal": "0.0.0-63cdba18"
44
44
  }
45
45
  }
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 = (item_path.contains("node_modules")
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
  _ => {}
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
4
  pub fn list_ignored_files(
6
5
  workspace_root_path: &str,
7
- ) -> Result<HashSet<PathBuf>, Box<dyn std::error::Error>> {
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![
@@ -15,12 +15,66 @@ 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![
18
66
  vec![
19
67
  "git",
20
- "submodule",
21
- "foreach",
22
- "--quiet",
23
- "git ls-files --others --ignored --exclude-standard | sed 's|^|$path/|'",
68
+ "ls-files",
69
+ "--others",
70
+ "--ignored",
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/|\"'",
24
78
  ],
25
79
  ];
26
80
 
@@ -34,7 +88,7 @@ pub fn list_ignored_files(
34
88
  let files = String::from_utf8(output.stdout)?
35
89
  .lines()
36
90
  .filter(|line| !line.is_empty())
37
- .map(|line| PathBuf::from(line))
91
+ .map(|line| String::from(line))
38
92
  .collect::<HashSet<_>>();
39
93
 
40
94
  gitignored_files.extend(files);
@@ -66,7 +120,8 @@ mod tests {
66
120
  #[test]
67
121
  fn test_no_ignored_files() {
68
122
  let dir = tempfile::tempdir().unwrap();
69
- let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
123
+ let gitignored_files =
124
+ list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
70
125
  Command::new("git")
71
126
  .args(&["init"])
72
127
  .current_dir(dir.path())
@@ -92,13 +147,14 @@ mod tests {
92
147
  .current_dir(dir.path())
93
148
  .output()
94
149
  .unwrap();
95
- let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
150
+ let gitignored_files =
151
+ list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
96
152
  println!(
97
153
  "ignored files for test_one_ignored_file: {:?}",
98
154
  gitignored_files
99
155
  );
100
156
  // assert_eq!(gitignored_files.len(), 1);
101
- assert!(gitignored_files.contains(&PathBuf::from("ignored.txt")));
157
+ assert!(gitignored_files.contains(&String::from("ignored.txt")));
102
158
  }
103
159
 
104
160
  #[test]
@@ -121,19 +177,83 @@ mod tests {
121
177
  .current_dir(dir.path())
122
178
  .output()
123
179
  .unwrap();
124
- let gitignored_files = list_ignored_files(dir.path().to_str().unwrap()).unwrap();
180
+ let gitignored_files =
181
+ list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
125
182
  println!(
126
183
  "ignored files for test_multiple_ignored_files: {:?}",
127
184
  gitignored_files
128
185
  );
129
186
  // assert_eq!(gitignored_files.len(), 2);
130
- assert!(gitignored_files.contains(&PathBuf::from("ignored1.txt")));
131
- assert!(gitignored_files.contains(&PathBuf::from("ignored2.txt")));
187
+ assert!(gitignored_files.contains(&String::from("ignored1.txt")));
188
+ assert!(gitignored_files.contains(&String::from("ignored2.txt")));
189
+ }
190
+
191
+ #[test]
192
+ fn test_git_submodule_ignored_files() {
193
+ let dir = tempfile::tempdir().unwrap();
194
+ let submodule_path = dir.path().join("submodule");
195
+ std::fs::create_dir(&submodule_path).unwrap();
196
+
197
+ let o = Command::new("git")
198
+ .args(&["init"])
199
+ .current_dir(&submodule_path)
200
+ .output()
201
+ .unwrap();
202
+ println!("git init output: {:?}", o);
203
+
204
+ let file_path = submodule_path.join("ignored.txt");
205
+ let mut file = File::create(&file_path).unwrap();
206
+ writeln!(file, "This is an ignored file.").unwrap();
207
+
208
+ let file2 = submodule_path.join("ignored2.txt");
209
+ let mut file = File::create(&file2).unwrap();
210
+ writeln!(file, "This is another ignored file.").unwrap();
211
+
212
+ let gitignore_path = submodule_path.join(".gitignore");
213
+ let mut gitignore = File::create(&gitignore_path).unwrap();
214
+ writeln!(gitignore, "*.txt").unwrap();
215
+
216
+ let o = Command::new("git")
217
+ .args(&["init"])
218
+ .current_dir(dir.path())
219
+ .output()
220
+ .unwrap();
221
+ println!("git init output: {:?}", o);
222
+
223
+ // make a commit in the submodule
224
+ let o = Command::new("git")
225
+ .args(&["add", "."])
226
+ .current_dir(&submodule_path)
227
+ .output()
228
+ .unwrap();
229
+ println!("git add output: {:?}", o);
230
+ let o = Command::new("git")
231
+ .args(&["commit", "-m", "initial commit"])
232
+ .current_dir(&submodule_path)
233
+ .output()
234
+ .unwrap();
235
+ println!("git commit output: {:?}", o);
236
+
237
+ let o = Command::new("git")
238
+ .args(&["submodule", "add", "./submodule"])
239
+ .current_dir(dir.path())
240
+ .output()
241
+ .unwrap();
242
+ println!("git submodule add output: {:?}", o);
243
+
244
+ let gitignored_files =
245
+ list_ignored_files(dir.path().to_str().unwrap(), false).unwrap();
246
+ println!(
247
+ "ignored files for test_git_submodule_ignored_files: {:?}",
248
+ gitignored_files
249
+ );
250
+ assert!(gitignored_files.contains(&String::from("submodule/ignored.txt")));
251
+ assert!(gitignored_files.contains(&String::from("submodule/ignored2.txt")));
132
252
  }
133
253
 
134
254
  #[test]
135
255
  fn test_multiple_ignored_files_in_current_dir() {
136
- let gitignored_files = list_ignored_files(".").unwrap();
256
+ let gitignored_files = list_ignored_files(".", false).unwrap();
137
257
  assert!(gitignored_files.len() > 1);
138
258
 
139
259
  // print a sample of the ignored files
@@ -147,7 +267,6 @@ mod tests {
147
267
  }
148
268
  }
149
269
 
150
-
151
270
  #[tokio::test]
152
271
  async fn test_file_not_ignored() {
153
272
  let dir = tempfile::tempdir().unwrap();
@@ -160,7 +279,10 @@ mod tests {
160
279
  .current_dir(dir.path())
161
280
  .output()
162
281
  .unwrap();
163
- let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt").await.unwrap();
282
+ let is_ignored =
283
+ is_git_ignored(dir.path().to_str().unwrap(), "not_ignored.txt")
284
+ .await
285
+ .unwrap();
164
286
  assert_eq!(is_ignored, false);
165
287
  }
166
288
 
@@ -180,7 +302,10 @@ mod tests {
180
302
  .current_dir(dir.path())
181
303
  .output()
182
304
  .unwrap();
183
- let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt").await.unwrap();
305
+ let is_ignored =
306
+ is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
307
+ .await
308
+ .unwrap();
184
309
  assert_eq!(is_ignored, true);
185
310
  }
186
311
 
@@ -200,8 +325,10 @@ mod tests {
200
325
  .current_dir(dir.path())
201
326
  .output()
202
327
  .unwrap();
203
- let is_ignored = is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt").await.unwrap();
328
+ let is_ignored =
329
+ is_git_ignored(dir.path().to_str().unwrap(), "ignored.txt")
330
+ .await
331
+ .unwrap();
204
332
  assert_eq!(is_ignored, true);
205
333
  }
206
-
207
334
  }
package/src/lib.rs CHANGED
@@ -1,4 +1,5 @@
1
1
  #![deny(clippy::all)]
2
+ #![deny(unsafe_op_in_unsafe_fn)]
2
3
  pub mod file_utils;
3
4
  pub mod git_utils;
4
5
  pub mod merkle_tree;
@@ -6,6 +7,9 @@ pub mod merkle_tree;
6
7
  use std::vec;
7
8
 
8
9
  use merkle_tree::{LocalConstruction, MerkleTree};
10
+ use tracing::{info, Level};
11
+ use tracing_appender::rolling::{RollingFileAppender, Rotation};
12
+ use tracing_subscriber::fmt;
9
13
 
10
14
  #[macro_use]
11
15
  extern crate napi_derive;
@@ -14,15 +18,35 @@ extern crate napi_derive;
14
18
  pub struct MerkleClient {
15
19
  tree: MerkleTree,
16
20
  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
17
38
  }
18
39
 
19
40
  #[napi]
20
41
  impl MerkleClient {
21
42
  #[napi(constructor)]
22
43
  pub fn new(root_directory: String) -> MerkleClient {
44
+ let _guard = init_logger();
45
+
23
46
  MerkleClient {
24
47
  tree: MerkleTree::empty_tree(),
25
48
  root_directory,
49
+ _guard,
26
50
  }
27
51
  }
28
52
 
@@ -31,7 +55,9 @@ impl MerkleClient {
31
55
  // 1. compute the merkle tree
32
56
  // 2. update the backend
33
57
  // 3. sync with the remote
34
- self.compute_merkle_tree().await?;
58
+ unsafe {
59
+ self.compute_merkle_tree().await?;
60
+ }
35
61
 
36
62
  Ok(())
37
63
  }
@@ -47,6 +73,17 @@ impl MerkleClient {
47
73
  let t =
48
74
  MerkleTree::construct_merkle_tree(self.root_directory.clone()).await;
49
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
+
50
87
  match t {
51
88
  Ok(tree) => {
52
89
  self.tree = tree;
@@ -74,9 +111,13 @@ impl MerkleClient {
74
111
  &self,
75
112
  relative_path: String,
76
113
  ) -> Result<String, napi::Error> {
114
+ info!("relative_path: {:?}", relative_path);
77
115
  let absolute_path =
78
116
  std::path::Path::new(&self.root_directory).join(relative_path);
79
- let hash = self.tree.get_subtree_hash(absolute_path).await;
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;
80
121
 
81
122
  match hash {
82
123
  Ok(hash) => Ok(hash),
@@ -104,8 +145,10 @@ impl MerkleClient {
104
145
  &self,
105
146
  relative_path: String,
106
147
  ) -> Result<i32, napi::Error> {
107
- let absolute_path =
108
- std::path::Path::new(&self.root_directory).join(relative_path);
148
+ let absolute_path = std::path::Path::new(&self.root_directory)
149
+ .join(relative_path)
150
+ .canonicalize()?;
151
+
109
152
  let num = self
110
153
  .tree
111
154
  .get_num_embeddable_files_in_subtree(absolute_path)
@@ -166,7 +209,10 @@ impl MerkleClient {
166
209
  // TODO(sualeh): we should assert that the path is ascending up to the path.
167
210
 
168
211
  let ret = vec![file];
212
+ info!("file: {:?}", ret);
213
+
169
214
  let ret = ret.into_iter().chain(path.into_iter()).collect::<Vec<_>>();
215
+ info!("ret to js: {:?}", ret);
170
216
 
171
217
  Ok(ret)
172
218
  }
@@ -1,11 +1,11 @@
1
+ use crate::git_utils;
1
2
  use crate::merkle_tree::{
2
3
  File, MerkleNode, MerkleNodePtr, NodeType, PinnedFuture,
3
4
  };
4
5
 
5
6
  use super::{LocalConstruction, MerkleTree};
6
- use std::collections::BTreeMap;
7
- use std::path::PathBuf;
8
- use std::{collections::HashMap, path::Path, sync::Arc};
7
+ use std::collections::{BTreeMap, HashSet};
8
+ use std::path::{Path, PathBuf};
9
9
  use tonic::async_trait;
10
10
 
11
11
  #[async_trait]
@@ -29,20 +29,30 @@ impl LocalConstruction for MerkleTree {
29
29
  /// 3. construct merkle tree
30
30
  /// 4. return merkle tree
31
31
  async fn construct_merkle_tree(
32
- root_directory: String,
32
+ absolute_path_to_root_directory: String,
33
33
  ) -> Result<MerkleTree, anyhow::Error> {
34
- let path = PathBuf::from(root_directory.clone());
34
+ let path = PathBuf::from(absolute_path_to_root_directory.clone());
35
35
  if !path.exists() {
36
36
  // FIXME: we should report this via a good logger.
37
37
  panic!("Root directory does not exist!");
38
38
  }
39
39
 
40
- let root_node = MerkleNode::new(path, None).await;
40
+ // 1. get all the gitignored files
41
+ let git_ignored_files = match git_utils::list_ignored_files(
42
+ absolute_path_to_root_directory.as_str(),
43
+ true,
44
+ ) {
45
+ Ok(git_ignored) => git_ignored,
46
+ Err(_e) => HashSet::new(),
47
+ };
48
+
49
+ let root_node = MerkleNode::new(path, None, &git_ignored_files).await;
41
50
  let mut mt = MerkleTree {
42
51
  root: root_node,
43
52
  files: BTreeMap::new(),
44
- root_path: root_directory,
53
+ root_path: absolute_path_to_root_directory,
45
54
  cursor: None,
55
+ git_ignored_files,
46
56
  };
47
57
 
48
58
  // we now iterate over all the nodes and add them to the hashmap
@@ -1,10 +1,11 @@
1
1
  use super::file_utils;
2
2
  use sha2::Digest;
3
- use std::collections::BTreeMap;
3
+ use std::collections::{BTreeMap, HashSet};
4
4
  use std::path::PathBuf;
5
5
  use std::{fs, path::Path, sync::Arc};
6
6
  use tokio::sync::RwLock;
7
7
  use tonic::async_trait;
8
+ use tracing::info;
8
9
  pub mod local_construction;
9
10
  pub mod test;
10
11
 
@@ -15,6 +16,7 @@ pub struct MerkleTree {
15
16
  root: MerkleNodePtr,
16
17
  files: BTreeMap<String, File>,
17
18
  cursor: Option<usize>,
19
+ git_ignored_files: HashSet<String>,
18
20
  }
19
21
 
20
22
  #[derive(Debug)]
@@ -91,6 +93,7 @@ impl MerkleTree {
91
93
  files: BTreeMap::new(),
92
94
  root_path: "".to_string(),
93
95
  cursor: None,
96
+ git_ignored_files: HashSet::new(),
94
97
  }
95
98
  }
96
99
 
@@ -301,26 +304,51 @@ impl MerkleTree {
301
304
  Ok(files)
302
305
  }
303
306
 
307
+ // TODO(sualeh): i need tests for this!!
304
308
  pub async fn get_spline(
305
309
  &self,
306
310
  absolute_path: &str,
307
311
  ) -> Result<Vec<String>, anyhow::Error> {
312
+ info!("get_spline called with absolute_path: {}", absolute_path);
308
313
  let mut files = Vec::new();
309
314
 
310
315
  let current_node = match self.files.get(absolute_path) {
311
- Some(node) => node.node.clone(),
312
- None => return Err(anyhow::anyhow!("File not found: {}", absolute_path)),
316
+ Some(node) => {
317
+ info!("Found node for absolute_path: {}", absolute_path);
318
+ node.node.clone()
319
+ }
320
+ None => {
321
+ info!("File not found for absolute_path: {}", absolute_path);
322
+ return Err(anyhow::anyhow!("File not found: {}", absolute_path));
323
+ }
313
324
  };
325
+
314
326
  let mut stack = Vec::new();
315
327
  stack.push(current_node);
316
328
 
317
329
  while let Some(node) = stack.pop() {
318
330
  let parent = node.read().await.parent.clone();
319
331
  if let Some(parent) = parent {
320
- files.push(parent.read().await.hash.clone());
332
+ info!("Adding parent hash to files vector");
333
+ {
334
+ let parent_node = parent.read().await;
335
+ match &parent_node.node_type {
336
+ NodeType::File(file_name) => {
337
+ files.push(file_name.clone());
338
+ }
339
+ NodeType::Branch((branch_name, _)) => {
340
+ files.push(branch_name.clone());
341
+ }
342
+ _ => {
343
+ continue;
344
+ }
345
+ }
346
+ }
347
+
321
348
  stack.push(parent);
322
349
  }
323
350
  }
351
+ info!("Returning files vector with {} elements", files.len());
324
352
  Ok(files)
325
353
  }
326
354
 
@@ -363,8 +391,12 @@ impl MerkleTree {
363
391
  0 => {
364
392
  // this means that the ancestor is the root.
365
393
  // we need to create a new node and attach it to the ancestor.
366
- let new_node =
367
- MerkleNode::new(file_path.clone(), Some(ancestor.clone())).await;
394
+ let new_node = MerkleNode::new(
395
+ file_path.clone(),
396
+ Some(ancestor.clone()),
397
+ &self.git_ignored_files,
398
+ )
399
+ .await;
368
400
  ancestor.write().await.attach_child(new_node.clone()).await;
369
401
  new_node
370
402
  }
@@ -375,9 +407,12 @@ impl MerkleTree {
375
407
  // UNSURE: not sure this is the correct thing to do but it is the fastest.
376
408
  // get the last thing that is not in the tree.
377
409
  let first_child_path = path.last().unwrap();
378
- let first_child =
379
- MerkleNode::new(first_child_path.clone(), Some(ancestor.clone()))
380
- .await;
410
+ let first_child = MerkleNode::new(
411
+ first_child_path.clone(),
412
+ Some(ancestor.clone()),
413
+ &self.git_ignored_files,
414
+ )
415
+ .await;
381
416
 
382
417
  // TODO(sualeh): we should do an assertion check that the entire vec is contained here.
383
418
 
@@ -654,18 +689,34 @@ use std::future::Future;
654
689
  use std::pin::Pin;
655
690
 
656
691
  type PinnedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
692
+ type IgnoredFiles = HashSet<String>;
657
693
 
658
694
  impl MerkleNode {
659
695
  /// please be careful using this.
660
696
  async fn __new_unchecked(
661
697
  file_or_directory: String,
662
698
  parent: ParentPtr,
699
+ ignored_files: &IgnoredFiles,
663
700
  ) -> MerkleNodePtr {
664
- MerkleNode::construct_node(Path::new(&file_or_directory), parent).await
701
+ MerkleNode::construct_node(
702
+ Path::new(&file_or_directory),
703
+ parent,
704
+ ignored_files,
705
+ )
706
+ .await
665
707
  }
666
708
 
667
- async fn new(file_or_directory: PathBuf, parent: ParentPtr) -> MerkleNodePtr {
668
- MerkleNode::construct_node(Path::new(&file_or_directory), parent).await
709
+ async fn new(
710
+ absolute_file_or_directory: PathBuf,
711
+ parent: ParentPtr,
712
+ ignored_files: &IgnoredFiles,
713
+ ) -> MerkleNodePtr {
714
+ MerkleNode::construct_node(
715
+ Path::new(&absolute_file_or_directory),
716
+ parent,
717
+ ignored_files,
718
+ )
719
+ .await
669
720
  }
670
721
 
671
722
  /// NOT added to the tree by default.
@@ -676,38 +727,40 @@ impl MerkleNode {
676
727
  // let file_hash = self.files.get_mut(&file_path).unwrap();
677
728
 
678
729
  fn construct_node<'a>(
679
- file_or_directory: &'a Path,
730
+ absolute_file_or_directory: &'a Path,
680
731
  parent: ParentPtr,
732
+ ignored_files: &'a IgnoredFiles,
681
733
  ) -> PinnedFuture<'a, MerkleNodePtr> {
682
734
  Box::pin(async move {
683
735
  // check if it is a file
684
- let path_str = file_or_directory.to_str().unwrap().to_string();
685
- if file_or_directory.is_file() {
736
+ let path_str = absolute_file_or_directory.to_str().unwrap().to_string();
737
+ if absolute_file_or_directory.is_file() {
686
738
  return Arc::new(RwLock::new(
687
739
  MerkleNode::construct_file_node_or_error_node(
688
- file_or_directory,
740
+ absolute_file_or_directory,
689
741
  parent,
742
+ ignored_files,
690
743
  )
691
744
  .await,
692
745
  ));
693
746
  }
694
747
 
695
748
  // check if the directory fails the bad dir test.
696
- let is_bad_dir = file_utils::is_in_bad_dir(file_or_directory);
749
+ let is_bad_dir = file_utils::is_in_bad_dir(absolute_file_or_directory);
697
750
  if is_bad_dir.is_err() || is_bad_dir.unwrap_or(false) {
698
751
  // println!("skipping directory: {}", path_str);
699
752
  return Arc::new(RwLock::new(MerkleNode::empty_node(
700
- Some(file_or_directory),
753
+ Some(absolute_file_or_directory),
701
754
  Some("Directory is in bad dir!".to_string()),
702
755
  )));
703
756
  }
704
757
 
705
- let entries = fs::read_dir(file_or_directory);
758
+ let entries = fs::read_dir(absolute_file_or_directory);
706
759
  match entries {
707
760
  Ok(_) => (),
708
761
  Err(e) => {
709
762
  return Arc::new(RwLock::new(MerkleNode::empty_node(
710
- Some(file_or_directory),
763
+ Some(absolute_file_or_directory),
711
764
  Some(e.to_string()),
712
765
  )));
713
766
  }
@@ -727,13 +780,17 @@ impl MerkleNode {
727
780
  match entry {
728
781
  Ok(entry) => {
729
782
  children.push(
730
- MerkleNode::construct_node(&entry.path(), Some(node.clone()))
731
- .await,
783
+ MerkleNode::construct_node(
784
+ &entry.path(),
785
+ Some(node.clone()),
786
+ ignored_files,
787
+ )
788
+ .await,
732
789
  );
733
790
  }
734
791
  Err(e) => {
735
792
  children.push(Arc::new(RwLock::new(MerkleNode::empty_node(
736
- Some(file_or_directory),
793
+ Some(absolute_file_or_directory),
737
794
  Some(e.to_string()),
738
795
  ))));
739
796
  }
@@ -753,23 +810,33 @@ impl MerkleNode {
753
810
  }
754
811
 
755
812
  async fn construct_file_node(
756
- file_path: &Path,
813
+ absolute_file_path: &Path,
757
814
  parent: ParentPtr,
815
+ ignored_files: &IgnoredFiles,
758
816
  ) -> Result<MerkleNode, String> {
759
- let file_str = file_path
817
+ let file_str = absolute_file_path
760
818
  .to_str()
761
819
  .ok_or("Could not convert file path to string!")?
762
820
  .to_string();
763
821
  // first see if it passes the
764
- match file_utils::is_good_file(file_path) {
822
+ match file_utils::is_good_file(absolute_file_path) {
765
823
  Ok(_) => {}
766
824
  Err(e) => {
767
825
  return Err(format!("File failed runtime checks! {}", e.to_string()));
768
826
  }
769
827
  }
770
828
 
829
+ // check if the file is in the git ignore buffer.
830
+ // this is a bug right because we are not checking absoluteness here.
831
+ match ignored_files.contains(&file_str) {
832
+ true => {
833
+ return Err(format!("File is in git ignore buffer!"));
834
+ }
835
+ false => {}
836
+ }
837
+
771
838
  // read the file_content to a buffer
772
- let file_content = match tokio::fs::read(file_path).await {
839
+ let file_content = match tokio::fs::read(absolute_file_path).await {
773
840
  Ok(content) => content,
774
841
  Err(e) => {
775
842
  return Err(format!("Could not read file! {}", e.to_string()));
@@ -777,7 +844,11 @@ impl MerkleNode {
777
844
  };
778
845
 
779
846
  // check if the file passes runtime checks.
780
- match file_utils::is_good_file_runtime_check(file_path, &file_content).await
847
+ match file_utils::is_good_file_runtime_check(
848
+ absolute_file_path,
849
+ &file_content,
850
+ )
851
+ .await
781
852
  {
782
853
  Ok(_) => {}
783
854
  Err(e) => {
@@ -808,15 +879,22 @@ impl MerkleNode {
808
879
  }
809
880
 
810
881
  async fn construct_file_node_or_error_node(
811
- file_path: &Path,
882
+ absolute_file_path: &Path,
812
883
  parent: ParentPtr,
884
+ ignored_files: &IgnoredFiles,
813
885
  ) -> MerkleNode {
814
- let node = match MerkleNode::construct_file_node(file_path, parent).await {
886
+ let node = match MerkleNode::construct_file_node(
887
+ absolute_file_path,
888
+ parent,
889
+ ignored_files,
890
+ )
891
+ .await
892
+ {
815
893
  Ok(node) => node,
816
894
  Err(e) => {
817
895
  // println!("constructing error node. error: {}", e);
818
896
  // println!("file_path: {:?}", file_path);
819
- MerkleNode::empty_node(Some(file_path), Some(e))
897
+ MerkleNode::empty_node(Some(absolute_file_path), Some(e))
820
898
  }
821
899
  };
822
900
 
package/src/test.rs ADDED
@@ -0,0 +1,5 @@
1
+ #[cfg(test)]
2
+ mod tests {
3
+ use super::super::*;
4
+ use std::path::PathBuf;
5
+ }