Skip to content

Commit e4326bb

Browse files
authored
Add a cli command to pin a recipe (#122)
Also restore the recipe at the same time for good measure.
1 parent 1c018de commit e4326bb

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

pyodide_build/cli/skeleton.py

+26
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,32 @@ def disable(
8383
sys.exit(status)
8484

8585

86+
@app.command("pin")
87+
def pin(
88+
names: list[str],
89+
message: str = typer.Option(
90+
"", "--message", "-m", help="Comment to explain why it was pinned"
91+
),
92+
recipe_dir: str | None = typer.Option(
93+
None,
94+
help="The directory containing the recipe of packages. "
95+
"If not specified, the default is ``<cwd>/packages``.",
96+
),
97+
) -> int:
98+
recipe_dir_ = get_recipe_dir(recipe_dir)
99+
status = 0
100+
for name in names:
101+
try:
102+
skeleton.pin_package(recipe_dir_, name, message)
103+
except skeleton.MkpkgFailedException as e:
104+
status = -1
105+
logger.error("%s update failed: %s", name, e)
106+
except Exception:
107+
print(name)
108+
raise
109+
sys.exit(status)
110+
111+
86112
@app.command("pypi")
87113
def new_recipe_pypi(
88114
name: str,

pyodide_build/recipe/skeleton.py

+18
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,21 @@ def enable_package(recipe_dir: Path, package: str) -> None:
474474
del pkg["_disabled"]
475475

476476
store_meta_yaml(yaml, meta_path, yaml_content)
477+
478+
479+
def pin_package(recipe_dir: Path, package: str, message: str) -> None:
480+
yaml = YAML()
481+
meta_path = recipe_dir / package / "meta.yaml"
482+
# Try to restore the file to its original state. If git isn't installed or
483+
# the file isn't tracked, just ignore the error.
484+
subprocess.run(["git", "restore", meta_path], check=False, capture_output=True)
485+
yaml_content = load_meta_yaml(yaml, meta_path)
486+
pkg = yaml_content["package"]
487+
pkg_keys = list(pkg)
488+
# Insert after the version key
489+
version_idx = pkg_keys.index("version") + 1
490+
pkg.insert(version_idx, "pinned", True)
491+
# Add message above it
492+
if message:
493+
pkg.yaml_set_comment_before_after_key("pinned", before=message)
494+
store_meta_yaml(yaml, meta_path, yaml_content)

pyodide_build/tests/recipe/test_skeleton.py

+37
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,43 @@ def test_enable_disable(tmpdir):
121121
assert meta_path.read_text().strip() == disabled
122122

123123

124+
def test_pin(tmpdir):
125+
base_dir = Path(str(tmpdir))
126+
127+
pinned = dedent(
128+
"""\
129+
package:
130+
name: jedi
131+
version: 0.19.1
132+
# Here is some information
133+
pinned: true
134+
top-level:
135+
- jedi
136+
source:
137+
sha256: shasum
138+
url: aurlhere
139+
requirements:
140+
run:
141+
- parso
142+
about:
143+
home: https://github.com/davidhalter/jedi
144+
PyPI: https://pypi.org/project/jedi
145+
summary: An autocompletion tool for Python that can be used for text editors.
146+
license: MIT
147+
"""
148+
).strip()
149+
unpinned_lines = pinned.splitlines()
150+
del unpinned_lines[3:5]
151+
unpinned = "\n".join(unpinned_lines)
152+
153+
package_dir = base_dir / "jedi"
154+
package_dir.mkdir(parents=True)
155+
meta_path = package_dir / "meta.yaml"
156+
meta_path.write_text(unpinned)
157+
skeleton.pin_package(base_dir, "jedi", "Here is some information")
158+
assert meta_path.read_text().strip() == pinned
159+
160+
124161
def test_mkpkg_update_pinned(tmpdir):
125162
base_dir = Path(str(tmpdir))
126163

0 commit comments

Comments
 (0)