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.
- {envrcctl-0.2.5 → envrcctl-0.2.7}/PKG-INFO +1 -1
- {envrcctl-0.2.5 → envrcctl-0.2.7}/pyproject.toml +1 -1
- {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/release_artifacts.py +133 -5
- {envrcctl-0.2.5 → envrcctl-0.2.7}/.gitignore +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/LICENSE +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/README.md +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/completions/envrcctl.bash +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/completions/envrcctl.fish +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/completions/envrcctl.zsh +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/build_macos_auth_helper.sh +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/generate_completions.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/macos/envrcctl-macos-auth.swift +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/scripts/package_for_ship.sh +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/__init__.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/audit.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/auth.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/cli.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/command_runner.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/envrc.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/envrcctl-macos-auth.bak +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/errors.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/keychain.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/main.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/managed_block.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/secrets.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/src/envrcctl/secretservice.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/__init__.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/conftest.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/helpers/__init__.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/helpers/cli_support.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_audit.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_audit_cli.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_auth.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_doctor.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_errors.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_eval.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_exec.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_helpers.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_inject.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_migrate.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_secret_get.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_secret_list.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_cli_secret_set_unset.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_command_runner.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_envrc.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_keychain.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_main.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_managed_block.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_secrets.py +0 -0
- {envrcctl-0.2.5 → envrcctl-0.2.7}/tests/test_secretservice.py +0 -0
- {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.
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|