Anurag commited on
Commit
ff724b2
·
1 Parent(s): af84aa7

Prune DevData traversal excludes

Browse files
Files changed (1) hide show
  1. jupyter-devdata-sync.py +46 -5
jupyter-devdata-sync.py CHANGED
@@ -167,6 +167,10 @@ def _matches_prefix(parts: tuple[str, ...], prefix: tuple[str, ...]) -> bool:
167
  return len(parts) >= len(prefix) and parts[:len(prefix)] == prefix
168
 
169
 
 
 
 
 
170
  def should_skip(p: Path):
171
  # Reserved sync helper files are not user data. Old datasets may still have
172
  # these markers, but fresh snapshots no longer create them.
@@ -188,15 +192,52 @@ def should_skip(p: Path):
188
  # Skip any component whose name looks like a secret file/dir.
189
  return any(_name_is_secret(part) for part in parts)
190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  def snapshot(src: Path, dst: Path) -> tuple[bool, set[str]]:
192
  had_copy_failures = False
193
  protected_large_files: set[str] = set()
194
- for p in src.rglob("*"):
195
  rel = p.relative_to(src)
196
- if should_skip(rel):
197
- continue
198
- if p.is_symlink():
199
- continue
200
  target = dst / rel
201
  if p.is_dir():
202
  # Keep parent directories for files copied later in this snapshot.
 
167
  return len(parts) >= len(prefix) and parts[:len(prefix)] == prefix
168
 
169
 
170
+ def _is_prefix_of(parts: tuple[str, ...], full_path: tuple[str, ...]) -> bool:
171
+ return len(parts) <= len(full_path) and full_path[:len(parts)] == parts
172
+
173
+
174
  def should_skip(p: Path):
175
  # Reserved sync helper files are not user data. Old datasets may still have
176
  # these markers, but fresh snapshots no longer create them.
 
192
  # Skip any component whose name looks like a secret file/dir.
193
  return any(_name_is_secret(part) for part in parts)
194
 
195
+
196
+ def iter_sync_tree(root: Path):
197
+ """Yield syncable DevData paths without descending into excluded trees."""
198
+ if not root.exists():
199
+ return
200
+
201
+ for dirpath, dirnames, filenames in os.walk(root):
202
+ dir_path = Path(dirpath)
203
+ try:
204
+ dir_rel = dir_path.relative_to(root)
205
+ except ValueError:
206
+ dir_rel = Path()
207
+
208
+ kept_dirnames: list[str] = []
209
+ for dirname in sorted(dirnames):
210
+ rel = dir_rel / dirname
211
+ child = dir_path / dirname
212
+ rel_parts = rel.parts
213
+ # Do not prune ancestors of explicitly allowed Jupyter settings
214
+ # paths. should_skip(.local/share/jupyter) is true by design for
215
+ # files under that tree, but we must still descend through the
216
+ # parent dirs to reach lab/user-settings and lab/workspaces.
217
+ allowed_ancestor = any(
218
+ _is_prefix_of(rel_parts, prefix) for prefix in JUPYTER_DATA_ALLOW_PREFIXES
219
+ )
220
+ if child.is_symlink() or (should_skip(rel) and not allowed_ancestor):
221
+ continue
222
+ kept_dirnames.append(dirname)
223
+ dirnames[:] = kept_dirnames
224
+
225
+ for dirname in kept_dirnames:
226
+ yield dir_path / dirname
227
+
228
+ for filename in sorted(filenames):
229
+ rel = dir_rel / filename
230
+ child = dir_path / filename
231
+ if child.is_symlink() or should_skip(rel):
232
+ continue
233
+ yield child
234
+
235
+
236
  def snapshot(src: Path, dst: Path) -> tuple[bool, set[str]]:
237
  had_copy_failures = False
238
  protected_large_files: set[str] = set()
239
+ for p in iter_sync_tree(src):
240
  rel = p.relative_to(src)
 
 
 
 
241
  target = dst / rel
242
  if p.is_dir():
243
  # Keep parent directories for files copied later in this snapshot.