Skip to content

Commit 856fc23

Browse files
mballanceCopilot
andcommitted
Fix packages.envrc location and sub-package src_type in lock file
- Move packages.envrc inside deps_dir (was placed parallel to it); update source_env paths to be relative within deps_dir - Set src_type='dir' in PackageDir.process_options and src_type='git' in PackageGit.process_options so that package-lock.json always records the full source URL/path for every package, including those resolved by sub-packages - Update test_direnv.py to expect packages.envrc at the new location - Add test_package_lock tests verifying src_type is set at create time - Add test_smoke assertion that sub-package lock entries have src+path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ea91ea3 commit 856fc23

File tree

6 files changed

+66
-15
lines changed

6 files changed

+66
-15
lines changed

src/ivpm/handlers/package_handler_direnv.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,15 @@ def update(self, update_info: ProjectUpdateInfo):
7474
ordered.append(pkg_name)
7575

7676
deps_dir = update_info.deps_dir
77-
root_dir = os.path.dirname(deps_dir)
78-
deps_dir_name = os.path.basename(deps_dir)
79-
output_path = os.path.join(root_dir, "packages.envrc")
77+
output_path = os.path.join(deps_dir, "packages.envrc")
8078

8179
_logger.debug("Writing packages.envrc to %s", output_path)
8280

8381
with open(output_path, "w") as fp:
8482
fp.write("# Generated by IVPM — do not edit manually\n")
8583
for pkg_name in ordered:
8684
_, envrc_file = self.envrc_pkgs[pkg_name]
87-
fp.write("source_env ./%s/%s/%s\n" % (deps_dir_name, pkg_name, envrc_file))
85+
fp.write("source_env ./%s/%s\n" % (pkg_name, envrc_file))
8886

8987
from ..utils import note
9088
note("Generated packages.envrc with %d entries" % len(ordered))

src/ivpm/pkg_types/package_dir.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def update(self, update_info : ProjectUpdateInfo):
6262

6363
def process_options(self, opts, si):
6464
super().process_options(opts, si)
65+
self.src_type = "dir"
6566

6667
if "link" in opts.keys():
6768
self.link = bool(opts["link"])

src/ivpm/pkg_types/package_git.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ def sync(self, sync_info : ProjectSyncInfo):
370370

371371
def process_options(self, opts, si):
372372
super().process_options(opts, si)
373+
self.src_type = "git"
373374

374375
if "anonymous" in opts.keys():
375376
self.anonymous = opts["anonymous"]

test/unit/test_direnv.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ def test_leaf_export_envrc(self):
1919

2020
self.ivpm_update(skip_venv=True)
2121

22-
envrc_path = os.path.join(self.testdir, "packages.envrc")
22+
envrc_path = os.path.join(self.testdir, "packages", "packages.envrc")
2323
self.assertTrue(os.path.isfile(envrc_path),
2424
"packages.envrc should be generated")
2525

2626
with open(envrc_path) as f:
2727
content = f.read()
28-
self.assertIn("source_env ./packages/envrc_leaf1/export.envrc", content)
28+
self.assertIn("source_env ./envrc_leaf1/export.envrc", content)
2929

3030
def test_no_envrc_no_file(self):
3131
"""Packages without envrc files produce no packages.envrc."""
@@ -42,7 +42,7 @@ def test_no_envrc_no_file(self):
4242

4343
self.ivpm_update(skip_venv=True)
4444

45-
envrc_path = os.path.join(self.testdir, "packages.envrc")
45+
envrc_path = os.path.join(self.testdir, "packages", "packages.envrc")
4646
self.assertFalse(os.path.isfile(envrc_path),
4747
"packages.envrc should NOT be generated when no envrc files exist")
4848

@@ -61,11 +61,11 @@ def test_dotenvrc_used_when_no_export(self):
6161

6262
self.ivpm_update(skip_venv=True)
6363

64-
envrc_path = os.path.join(self.testdir, "packages.envrc")
64+
envrc_path = os.path.join(self.testdir, "packages", "packages.envrc")
6565
self.assertTrue(os.path.isfile(envrc_path))
6666
with open(envrc_path) as f:
6767
content = f.read()
68-
self.assertIn("source_env ./packages/envrc_leaf2/.envrc", content)
68+
self.assertIn("source_env ./envrc_leaf2/.envrc", content)
6969

7070
def test_dependency_order(self):
7171
"""Leaf packages appear before dependents in packages.envrc."""
@@ -82,15 +82,15 @@ def test_dependency_order(self):
8282

8383
self.ivpm_update(skip_venv=True)
8484

85-
envrc_path = os.path.join(self.testdir, "packages.envrc")
85+
envrc_path = os.path.join(self.testdir, "packages", "packages.envrc")
8686
self.assertTrue(os.path.isfile(envrc_path))
8787
with open(envrc_path) as f:
8888
content = f.read()
8989

9090
# All three packages should appear
91-
self.assertIn("packages/envrc_leaf1/export.envrc", content)
92-
self.assertIn("packages/envrc_leaf2/.envrc", content)
93-
self.assertIn("packages/envrc_nonleaf/export.envrc", content)
91+
self.assertIn("envrc_leaf1/export.envrc", content)
92+
self.assertIn("envrc_leaf2/.envrc", content)
93+
self.assertIn("envrc_nonleaf/export.envrc", content)
9494

9595
# Leaves must appear before the non-leaf that depends on them
9696
idx_leaf1 = content.index("envrc_leaf1")
@@ -117,7 +117,7 @@ def test_export_envrc_preferred_over_dotenvrc(self):
117117
# envrc_leaf1 already has export.envrc; verify it's used not .envrc
118118
self.ivpm_update(skip_venv=True)
119119

120-
with open(os.path.join(self.testdir, "packages.envrc")) as f:
120+
with open(os.path.join(self.testdir, "packages", "packages.envrc")) as f:
121121
content = f.read()
122122
self.assertIn("export.envrc", content)
123123
self.assertNotIn("envrc_leaf1/.envrc", content)

test/unit/test_package_lock.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,44 @@ def test_reject_unknown_lock_version(self):
243243
with self.assertRaises(ValueError):
244244
read_lock(lock_path)
245245

246+
# ------------------------------------------------------------------
247+
# src_type set at create time (regression test for sub-package URLs)
248+
# ------------------------------------------------------------------
249+
250+
def test_dir_pkg_src_type_set_by_create(self):
251+
"""PackageDir.create must set src_type='dir' so the lock file records the path."""
252+
from ivpm.pkg_types.pkg_type_rgy import PkgTypeRgy
253+
class _Si:
254+
pass
255+
pkg = PkgTypeRgy.inst().mkPackage("dir", "mypkg", {"url": "file:///some/path"}, _Si())
256+
self.assertEqual(pkg.src_type, "dir")
257+
pkgs = self._make_pkgs(pkg)
258+
write_lock(self.tmpdir, pkgs)
259+
data = read_lock(os.path.join(self.tmpdir, "package-lock.json"))
260+
entry = data["packages"]["mypkg"]
261+
self.assertEqual(entry["src"], "dir")
262+
self.assertIn("path", entry)
263+
self.assertEqual(entry["path"], "/some/path")
264+
265+
def test_git_pkg_src_type_set_by_create(self):
266+
"""PackageGit.create must set src_type='git' so the lock file records the URL."""
267+
from ivpm.pkg_types.pkg_type_rgy import PkgTypeRgy
268+
class _Si:
269+
pass
270+
pkg = PkgTypeRgy.inst().mkPackage(
271+
"git", "myrepo",
272+
{"url": "https://github.com/org/myrepo.git", "branch": "main"},
273+
_Si()
274+
)
275+
self.assertEqual(pkg.src_type, "git")
276+
pkgs = self._make_pkgs(pkg)
277+
write_lock(self.tmpdir, pkgs)
278+
data = read_lock(os.path.join(self.tmpdir, "package-lock.json"))
279+
entry = data["packages"]["myrepo"]
280+
self.assertEqual(entry["src"], "git")
281+
self.assertEqual(entry["url"], "https://github.com/org/myrepo.git")
282+
self.assertEqual(entry["branch"], "main")
283+
246284

247285
if __name__ == "__main__":
248286
unittest.main()

test/unit/test_smoke.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,20 @@ def test_nested_2(self):
3838
self.assertTrue(os.path.isdir(os.path.join(self.testdir, "packages/nonleaf_refleaf_proj1")))
3939
self.assertTrue(os.path.isdir(os.path.join(self.testdir, "packages/leaf_proj1")))
4040
self.assertTrue(os.path.isdir(os.path.join(self.testdir, "packages/leaf_proj2")))
41-
# self.assertTrue(os.path.isfile(os.path.join(self.testdir, "packages/leaf_proj1/leaf_proj1.txt")))
41+
42+
# Sub-packages resolved by nonleaf_refleaf_proj1 must have their
43+
# source URL recorded in the lock file so the workspace can be reproduced.
44+
import json
45+
with open(os.path.join(self.testdir, "packages/package-lock.json")) as f:
46+
lock = json.load(f)
47+
for pkg_name in ("leaf_proj1", "leaf_proj2"):
48+
entry = lock["packages"][pkg_name]
49+
self.assertEqual(entry["src"], "dir",
50+
"%s must have src='dir' in lock file" % pkg_name)
51+
self.assertIn("path", entry,
52+
"%s must have a path recorded in lock file" % pkg_name)
53+
self.assertTrue(entry["path"],
54+
"%s path must not be empty" % pkg_name)
4255

4356
def test_git_fetch_leaf1(self):
4457
self.mkFile("ivpm.yaml", """

0 commit comments

Comments
 (0)