fluidattacks_core_filesystem 13.0.0__tar.gz → 14.0.0__tar.gz

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.
Files changed (29) hide show
  1. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/PKG-INFO +1 -1
  2. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/defaults.py +3 -0
  3. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/partitioning.py +26 -4
  4. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/pyproject.toml +1 -1
  5. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_partitioning.py +35 -2
  6. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/uv.lock +1 -1
  7. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/.envrc +0 -0
  8. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/.gitignore +0 -0
  9. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/build/default.nix +0 -0
  10. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/build/filter.nix +0 -0
  11. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/flake.lock +0 -0
  12. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/flake.nix +0 -0
  13. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/__init__.py +0 -0
  14. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/detection.py +0 -0
  15. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/language.py +0 -0
  16. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/parts.py +0 -0
  17. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/projects.py +0 -0
  18. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/fluidattacks_core/filesystem/py.typed +0 -0
  19. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/import-linter.cfg +0 -0
  20. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/mypy.ini +0 -0
  21. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/ruff.toml +0 -0
  22. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/__init__.py +0 -0
  23. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/data/partitioning_snapshot.golden.json +0 -0
  24. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_defaults.py +0 -0
  25. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_extract_db.py +0 -0
  26. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_language_detection.py +0 -0
  27. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_partitioning_snapshot.py +0 -0
  28. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_parts.py +0 -0
  29. {fluidattacks_core_filesystem-13.0.0 → fluidattacks_core_filesystem-14.0.0}/tests/test_projects.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: fluidattacks_core_filesystem
3
- Version: 13.0.0
3
+ Version: 14.0.0
4
4
  Summary: Fluid Attacks Core Filesystem Library
5
5
  Author-email: Development <development@fluidattacks.com>
6
6
  License: MPL-2.0
@@ -28,6 +28,9 @@ class WorkspaceSpec(TypedDict):
28
28
  claims: frozenset[str]
29
29
 
30
30
 
31
+ BUNDLE_DIR_GLOBS = ["*.xcodeproj", "*.xcworkspace"]
32
+
33
+
31
34
  WORKSPACE_MARKERS: dict[str, WorkspaceSpec] = {
32
35
  "gradle": {
33
36
  "declares": frozenset({"settings.gradle", "settings.gradle.kts"}),
@@ -9,7 +9,7 @@ from fnmatch import fnmatch
9
9
  from pathlib import Path
10
10
  from typing import TYPE_CHECKING
11
11
 
12
- from .defaults import EXTENDED_EXCLUDE_DIRS
12
+ from .defaults import BUNDLE_DIR_GLOBS, EXTENDED_EXCLUDE_DIRS
13
13
  from .detection import (
14
14
  declared_workspaces,
15
15
  detect_anchor_language,
@@ -86,23 +86,45 @@ def _claiming_kinds(dir_path: Path, workspaces: Mapping[Path, frozenset[str]]) -
86
86
  return frozenset(kinds)
87
87
 
88
88
 
89
+ def _is_bundle_name(name: str) -> bool:
90
+ return any(fnmatch(name, pattern) for pattern in BUNDLE_DIR_GLOBS)
91
+
92
+
93
+ def _within_bundle(dir_path: Path, root_path: Path) -> bool:
94
+ current = dir_path
95
+ while current != root_path:
96
+ if _is_bundle_name(current.name):
97
+ return True
98
+ if current == current.parent:
99
+ return False
100
+ current = current.parent
101
+ return False
102
+
103
+
89
104
  def _anchor_names(
90
105
  dir_path: Path,
91
106
  filenames: Sequence[str],
92
107
  workspaces: Mapping[Path, frozenset[str]],
108
+ root_path: Path,
93
109
  ) -> tuple[str, ...]:
110
+ if _within_bundle(dir_path, root_path):
111
+ return ()
94
112
  kinds = _claiming_kinds(dir_path, workspaces)
95
113
  if not kinds:
96
114
  return tuple(filenames)
97
115
  return tuple(name for name in filenames if not is_claimed_manifest(name, kinds))
98
116
 
99
117
 
100
- def _discover_potential_parts(listing: DirListing) -> tuple[PotentialPart, ...]:
118
+ def _discover_potential_parts(listing: DirListing, root_path: Path) -> tuple[PotentialPart, ...]:
101
119
  workspaces = _workspace_kinds_by_dir(listing)
102
120
  return tuple(
103
121
  (dir_path, _find_config_files(dir_path, filenames), language.value)
104
122
  for dir_path, filenames in listing
105
- if (language := detect_anchor_language(_anchor_names(dir_path, filenames, workspaces)))
123
+ if (
124
+ language := detect_anchor_language(
125
+ _anchor_names(dir_path, filenames, workspaces, root_path)
126
+ )
127
+ )
106
128
  is not None
107
129
  )
108
130
 
@@ -223,7 +245,7 @@ def _build_single_root_tree(root_path: Path, listing: DirListing) -> PartTree:
223
245
 
224
246
 
225
247
  def decide_part_tree(root_path: Path, listing: DirListing) -> PartTree:
226
- potential_parts = _discover_potential_parts(listing)
248
+ potential_parts = _discover_potential_parts(listing, root_path)
227
249
  if not potential_parts:
228
250
  return _build_single_root_tree(root_path, listing)
229
251
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fluidattacks_core_filesystem"
3
- version = "13.0.0"
3
+ version = "14.0.0"
4
4
  description = "Fluid Attacks Core Filesystem Library"
5
5
  authors = [{ name = "Development", email = "development@fluidattacks.com" }]
6
6
  license = { text = "MPL-2.0" }
@@ -53,7 +53,7 @@ def test_config_files_are_found_by_name_and_glob() -> None:
53
53
 
54
54
 
55
55
  def test_only_directories_holding_a_manifest_become_parts() -> None:
56
- discovered = _discover_potential_parts(_LISTING)
56
+ discovered = _discover_potential_parts(_LISTING, _ROOT)
57
57
  assert [(path, language) for path, _, language in discovered] == [
58
58
  (_ROOT, "Python"),
59
59
  (_ROOT / "web", "JavaScript"),
@@ -61,7 +61,7 @@ def test_only_directories_holding_a_manifest_become_parts() -> None:
61
61
 
62
62
 
63
63
  def test_a_lone_hint_does_not_make_a_potential_part() -> None:
64
- assert _discover_potential_parts(((_ROOT / "tools", ("mypy.ini", "tox.ini")),)) == ()
64
+ assert _discover_potential_parts(((_ROOT / "tools", ("mypy.ini", "tox.ini")),), _ROOT) == ()
65
65
 
66
66
 
67
67
  def test_hierarchy_nests_parts_under_their_nearest_ancestor() -> None:
@@ -288,6 +288,39 @@ def test_a_gradle_module_without_a_settings_file_anchors_alone() -> None:
288
288
  assert sorted(tree.parts) == [".", "deployment/acceptance-test"]
289
289
 
290
290
 
291
+ def test_an_xcode_bundle_does_not_anchor_beside_its_project() -> None:
292
+ listing = (
293
+ (_ROOT, ("pubspec.yaml",)),
294
+ (_ROOT / "app" / "ios", ("Podfile",)),
295
+ (_ROOT / "app" / "ios" / "Runner.xcodeproj", ("project.pbxproj",)),
296
+ (_ROOT / "app" / "ios" / "Runner.xcworkspace", ("project.pbxproj",)),
297
+ )
298
+
299
+ assert sorted(decide_part_tree(_ROOT, listing).parts) == [".", "app/ios"]
300
+
301
+
302
+ def test_a_manifest_nested_inside_a_bundle_does_not_anchor() -> None:
303
+ listing = (
304
+ (_ROOT, ("Podfile",)),
305
+ (_ROOT / "Runner.xcodeproj", ("project.pbxproj",)),
306
+ (_ROOT / "Runner.xcodeproj" / "project.xcworkspace", ("Package.swift",)),
307
+ )
308
+
309
+ assert sorted(decide_part_tree(_ROOT, listing).parts) == ["."]
310
+
311
+
312
+ def test_a_root_named_like_a_bundle_still_anchors() -> None:
313
+ root = Path("/Thing.xcodeproj")
314
+
315
+ assert sorted(decide_part_tree(root, ((root, ("project.pbxproj",)),)).parts) == ["."]
316
+
317
+
318
+ def test_a_swift_package_outside_a_bundle_still_anchors() -> None:
319
+ listing = ((_ROOT, ("README",)), (_ROOT / "lib", ("Package.swift",)))
320
+
321
+ assert sorted(decide_part_tree(_ROOT, listing).parts) == [".", "lib"]
322
+
323
+
291
324
  def _write(root: Path, files: list[str]) -> None:
292
325
  for name in files:
293
326
  path = root / name
@@ -178,7 +178,7 @@ wheels = [
178
178
 
179
179
  [[package]]
180
180
  name = "fluidattacks-core-filesystem"
181
- version = "13.0.0"
181
+ version = "14.0.0"
182
182
  source = { editable = "." }
183
183
 
184
184
  [package.dev-dependencies]