envrcctl 0.2.5__tar.gz → 0.2.7__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 (52) hide show
  1. {envrcctl-0.2.5 → envrcctl-0.2.7}/PKG-INFO +1 -1
  2. {envrcctl-0.2.5 → envrcctl-0.2.7}/pyproject.toml +1 -1
  3. {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/release_artifacts.py +133 -5
  4. {envrcctl-0.2.5 → envrcctl-0.2.7}/.gitignore +0 -0
  5. {envrcctl-0.2.5 → envrcctl-0.2.7}/LICENSE +0 -0
  6. {envrcctl-0.2.5 → envrcctl-0.2.7}/README.md +0 -0
  7. {envrcctl-0.2.5 → envrcctl-0.2.7}/completions/envrcctl.bash +0 -0
  8. {envrcctl-0.2.5 → envrcctl-0.2.7}/completions/envrcctl.fish +0 -0
  9. {envrcctl-0.2.5 → envrcctl-0.2.7}/completions/envrcctl.zsh +0 -0
  10. {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/build_macos_auth_helper.sh +0 -0
  11. {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/generate_completions.py +0 -0
  12. {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/macos/envrcctl-macos-auth.swift +0 -0
  13. {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/package_for_ship.sh +0 -0
  14. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/__init__.py +0 -0
  15. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/audit.py +0 -0
  16. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/auth.py +0 -0
  17. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/cli.py +0 -0
  18. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/command_runner.py +0 -0
  19. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/envrc.py +0 -0
  20. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/envrcctl-macos-auth.bak +0 -0
  21. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/errors.py +0 -0
  22. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/keychain.py +0 -0
  23. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/main.py +0 -0
  24. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/managed_block.py +0 -0
  25. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/secrets.py +0 -0
  26. {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/secretservice.py +0 -0
  27. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/__init__.py +0 -0
  28. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/conftest.py +0 -0
  29. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/helpers/__init__.py +0 -0
  30. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/helpers/cli_support.py +0 -0
  31. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_audit.py +0 -0
  32. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_audit_cli.py +0 -0
  33. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_auth.py +0 -0
  34. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli.py +0 -0
  35. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_doctor.py +0 -0
  36. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_errors.py +0 -0
  37. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_eval.py +0 -0
  38. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_exec.py +0 -0
  39. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_helpers.py +0 -0
  40. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_inject.py +0 -0
  41. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_migrate.py +0 -0
  42. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_secret_get.py +0 -0
  43. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_secret_list.py +0 -0
  44. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_secret_set_unset.py +0 -0
  45. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_command_runner.py +0 -0
  46. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_envrc.py +0 -0
  47. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_keychain.py +0 -0
  48. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_main.py +0 -0
  49. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_managed_block.py +0 -0
  50. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_secrets.py +0 -0
  51. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_secretservice.py +0 -0
  52. {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_smoke.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: envrcctl
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: Manage .envrc with managed blocks and OS-backed secrets.
5
5
  Project-URL: Homepage, https://github.com/rioriost/envrcctl
6
6
  Project-URL: Issues, https://github.com/rioriost/envrcctl/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "envrcctl"
3
- version = "0.2.5"
3
+ version = "0.2.7"
4
4
  description = "Manage .envrc with managed blocks and OS-backed secrets."
5
5
  readme = { file = "README.md", content-type = "text/markdown" }
6
6
  license = "MIT"
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  import argparse
5
5
  import hashlib
6
+ import re
6
7
  import shutil
7
8
  import subprocess
8
9
  import sys
@@ -40,6 +41,119 @@ def project_version(pyproject_path: Path) -> str:
40
41
  raise RuntimeError(f"Could not find project version in {pyproject_path}")
41
42
 
42
43
 
44
+ def project_dependencies(pyproject_path: Path) -> list[str]:
45
+ text = pyproject_path.read_text(encoding="utf-8")
46
+ match = re.search(r"(?ms)^\[project\]\n.*?^dependencies\s*=\s*\[(.*?)\]", text)
47
+ if not match:
48
+ return []
49
+
50
+ dependencies: list[str] = []
51
+ for raw_line in match.group(1).splitlines():
52
+ stripped = raw_line.strip().rstrip(",")
53
+ if not stripped:
54
+ continue
55
+ if stripped.startswith('"') and stripped.endswith('"'):
56
+ dependencies.append(stripped[1:-1])
57
+ elif stripped.startswith("'") and stripped.endswith("'"):
58
+ dependencies.append(stripped[1:-1])
59
+ return dependencies
60
+
61
+
62
+ def normalize_package_name(name: str) -> str:
63
+ return re.sub(r"[-_.]+", "-", name).lower()
64
+
65
+
66
+ def dependency_name(requirement: str) -> str:
67
+ base = re.split(r"[<>=!~;\[\]\s]", requirement, maxsplit=1)[0]
68
+ if not base:
69
+ raise RuntimeError(f"Could not parse dependency requirement: {requirement}")
70
+ return normalize_package_name(base)
71
+
72
+
73
+ def package_dependencies(block: str) -> list[str]:
74
+ deps_match = re.search(r"dependencies = \[(.*?)\]\n", block, re.DOTALL)
75
+ if not deps_match:
76
+ return []
77
+
78
+ dependencies: list[str] = []
79
+ for match in re.finditer(r'\{ name = "([^"]+)"(?:, marker = "([^"]+)")?', deps_match.group(1)):
80
+ name = normalize_package_name(match.group(1))
81
+ marker = match.group(2)
82
+ if marker and "win32" in marker.lower():
83
+ continue
84
+ if marker and "windows" in marker.lower():
85
+ continue
86
+ dependencies.append(name)
87
+
88
+ return dependencies
89
+
90
+
91
+ def uv_lock_package_block(lock_text: str, package_name: str) -> str:
92
+ normalized = normalize_package_name(package_name)
93
+ current: list[str] = []
94
+ in_package = False
95
+
96
+ for line in lock_text.splitlines():
97
+ if line == "[[package]]":
98
+ if in_package:
99
+ block = "\n".join(current)
100
+ name_match = re.search(r'^name = "([^"]+)"$', block, re.MULTILINE)
101
+ if name_match and normalize_package_name(name_match.group(1)) == normalized:
102
+ return block
103
+ current = [line]
104
+ in_package = True
105
+ continue
106
+
107
+ if in_package:
108
+ current.append(line)
109
+
110
+ if in_package:
111
+ block = "\n".join(current)
112
+ name_match = re.search(r'^name = "([^"]+)"$', block, re.MULTILINE)
113
+ if name_match and normalize_package_name(name_match.group(1)) == normalized:
114
+ return block
115
+
116
+ raise RuntimeError(f"Package {package_name!r} not found in uv.lock")
117
+
118
+
119
+ def extract_sdist_url_and_sha(block: str, package_name: str) -> tuple[str, str]:
120
+ sdist_match = re.search(
121
+ r'sdist = \{ url = "([^"]+\.tar\.gz)", hash = "sha256:([0-9a-f]+)"',
122
+ block,
123
+ )
124
+ if sdist_match:
125
+ return sdist_match.group(1), sdist_match.group(2)
126
+
127
+ raise RuntimeError(f"Could not find sdist URL and sha256 for {package_name!r} in uv.lock")
128
+
129
+
130
+ def dependency_resource_specs(repo_root: Path) -> list[tuple[str, str, str]]:
131
+ lock_text = (repo_root / "uv.lock").read_text(encoding="utf-8")
132
+ ordered_names: list[str] = []
133
+ seen: set[str] = set()
134
+ queue = [dependency_name(req) for req in project_dependencies(repo_root / "pyproject.toml")]
135
+
136
+ while queue:
137
+ package_name = normalize_package_name(queue.pop(0))
138
+ if package_name in seen:
139
+ continue
140
+ seen.add(package_name)
141
+ ordered_names.append(package_name)
142
+
143
+ block = uv_lock_package_block(lock_text, package_name)
144
+ for dependency in package_dependencies(block):
145
+ if dependency not in seen and dependency not in queue:
146
+ queue.append(dependency)
147
+
148
+ specs: list[tuple[str, str, str]] = []
149
+ for package_name in ordered_names:
150
+ block = uv_lock_package_block(lock_text, package_name)
151
+ url, sha256 = extract_sdist_url_and_sha(block, package_name)
152
+ specs.append((package_name, url, sha256))
153
+
154
+ return specs
155
+
156
+
43
157
  def require_command(name: str) -> None:
44
158
  if shutil.which(name) is None:
45
159
  raise RuntimeError(f"Required command not found in PATH: {name}")
@@ -141,11 +255,26 @@ def formula_content(
141
255
  helper_sha256: str,
142
256
  homepage: str,
143
257
  license_name: str,
258
+ dependency_resources: list[tuple[str, str, str]],
144
259
  ) -> str:
145
260
  release_base = f"{homepage}/releases/download/{version}"
146
261
  source_url = f"{release_base}/envrcctl-{version}.tar.gz"
147
262
  helper_url = f"{release_base}/envrcctl-macos-auth-{version}-arm64.tar.gz"
148
263
 
264
+ resource_blocks = []
265
+ install_lines = []
266
+ for package_name, package_url, package_sha256 in dependency_resources:
267
+ resource_blocks.append(
268
+ f""" resource "{package_name}" do
269
+ url "{package_url}"
270
+ sha256 "{package_sha256}"
271
+ end"""
272
+ )
273
+ install_lines.append(f' venv.pip_install resource("{package_name}")')
274
+
275
+ resources_section = "\n\n".join(resource_blocks)
276
+ install_resources = "\n".join(install_lines)
277
+
149
278
  return f"""class Envrcctl < Formula
150
279
  include Language::Python::Virtualenv
151
280
 
@@ -157,10 +286,7 @@ def formula_content(
157
286
 
158
287
  depends_on "python@3.12"
159
288
 
160
- resource "typer" do
161
- url "https://files.pythonhosted.org/packages/source/t/typer/typer-0.24.1.tar.gz"
162
- sha256 "8bf4e81499611d3161106e998fe4d624a83abf8bfda3b99898b4498d0c2f0976"
163
- end
289
+ {resources_section}
164
290
 
165
291
  on_macos do
166
292
  on_arm do
@@ -173,7 +299,7 @@ def formula_content(
173
299
 
174
300
  def install
175
301
  venv = virtualenv_create(libexec, "python3.12")
176
- venv.pip_install resource("typer")
302
+ {install_resources}
177
303
  venv.pip_install buildpath
178
304
 
179
305
  bin.install_symlink libexec/"bin/envrcctl"
@@ -261,6 +387,7 @@ def main() -> int:
261
387
 
262
388
  source_sha256 = sha256_file(sdist_path)
263
389
  helper_sha256 = sha256_file(helper_archive)
390
+ dependency_resources = dependency_resource_specs(repo_root)
264
391
 
265
392
  formula_path = write_formula(
266
393
  repo_root,
@@ -270,6 +397,7 @@ def main() -> int:
270
397
  helper_sha256=helper_sha256,
271
398
  homepage=args.homepage,
272
399
  license_name=args.license_name,
400
+ dependency_resources=dependency_resources,
273
401
  ),
274
402
  args.formula_dir,
275
403
  )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes