Skip to content

Commit

Permalink
feat: add some argument generator scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
scop committed Nov 16, 2023
1 parent 1c8ef81 commit 4c7b998
Show file tree
Hide file tree
Showing 13 changed files with 1,002 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ If the `-use-pre-commit-cache` flag is given, a subdirectory in
[pre-commit.ci](https://pre-commit.ci) is not supported, because it
[disallows network access at runtime](https://github.com/pre-commit-ci/issues/issues/196#issuecomment-1810937079).

## Examples

The [generators](generators/) directory contains scripts that can be
used to generate command line arguments for various tools commonly
used tools.

## License

SPDX-License-Identifier: Apache-2.0
50 changes: 50 additions & 0 deletions generators/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# wrun command line argument generators

This directory contains scripts to generate wrun command line
arguments for various tools' releases. Generated arguments will
contain `-url`s, and `-archive-exe-path`s if applicable.

The scripts are not robust against all kinds of changes that might be
occurring in upstream release assets, and may need tweaking at times.

The intent is that they should work with the latest respective tool
release, and only that. Generators working with older versions might
be found in wrun Git history.

## Usage

The general usage is:

```shell
python3 wrun_TOOL_args.py VERSION
```

...where `TOOL` is the tool in question, and `VERSION` is the version
to generate for, typically the Git tag rather than the numeric
version if they differ.

The output is newline separated for readability.
Hint: if embedding to a YAML document as a string, e.g. a CI config,
using [line folding (`>-`)](https://yaml.org/spec/1.2.2/#65-line-folding)
the readability can likely be preserved there, too.

## TODO

Some tools for which generators would be nice to have, contributions welcome!

- trivy, https://trivy.dev, https://github.com/aquasecurity/trivy/releases
- typos, https://github.com/crate-ci/typos, https://github.com/crate-ci/typos

## Non-TODO

Some tools for which generators would be nice to have, but cannot be done,
at least yet at time of writing.

Unless mentioned otherwise, reasoning is that there is no `wrun`
runnable asset available for the tool.

- commitlint, https://commitlint.js.org
- gitlint, https://jorisroovers.com/gitlint/
- perlcritic, https://github.com/Perl-Critic/Perl-Critic
- perltidy, https://github.com/perltidy/perltidy
- prettier, https://prettier.io
53 changes: 53 additions & 0 deletions generators/wrun_black_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3

# Copyright 2023 Ville Skyttä
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

"""
wrun_black_args.py -- generate wrun command line args for black
* https://black.readthedocs.io
* https://github.com/psf/black/releases
"""

import hashlib
import sys
from urllib.parse import urljoin, quote as urlquote
from urllib.request import urlopen

file_os_archs = {
"black_linux": "linux/amd64",
"black_macos": "darwin/amd64",
"black_windows.exe": "windows/amd64",
}


def main(version: str) -> None:
base_url = f"https://github.com/psf/black/releases/download/{urlquote(version)}/"

for filename, os_arch in file_os_archs.items():
url = urljoin(base_url, filename)
with urlopen(url) as f:
hexdigest = hashlib.file_digest(f, "sha256").hexdigest()

print(f"-url {os_arch}={url}#sha256-{hexdigest}")


if __name__ == "__main__":
if len(sys.argv) != 2:
print(f"usage: {sys.argv[0]} VERSION")
sys.exit(2)
main(sys.argv[1])
100 changes: 100 additions & 0 deletions generators/wrun_committed_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python3

# Copyright 2023 Ville Skyttä
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

"""
wrun_committed_args.py -- generate wrun command line args for committed
* https://github.com/crate-ci/committed
* https://pypi.org/project/committed/#files
* https://warehouse.pypa.io/api-reference/json.html
"""

import hashlib
import json
import sys
from urllib.parse import quote as urlquote
from urllib.request import urlopen

file_os_archs = {
"committed-{version_number}-py3-none-macosx_10_7_x86_64.whl": "darwin/amd64",
"committed-{version_number}-py3-none-macosx_11_0_arm64.whl": "darwin/arm64",
"committed-{version_number}-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": None, # using musl one
"committed-{version_number}-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl": "linux/386",
"committed-{version_number}-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": None, # using musl one
"committed-{version_number}-py3-none-musllinux_1_2_aarch64.whl": "linux/arm64",
"committed-{version_number}-py3-none-musllinux_1_2_x86_64.whl": "linux/amd64",
"committed-{version_number}-py3-none-win32.whl": "windows/386",
"committed-{version_number}-py3-none-win_amd64.whl": "windows/amd64",
}


def check_hexdigest(url: str, algo: str, expected: str) -> None:
try:
assert len(expected) == len(hashlib.new(algo, b"canary").hexdigest())
_ = bytes.fromhex(expected)
except Exception as e:
raise ValueError(f'not a {algo} hex digest: "{expected}"') from e
with urlopen(url) as f:
got = hashlib.file_digest(f, algo).hexdigest()
if got != expected:
raise ValueError(f'{algo} mismatch for "{url}", expected {expected}, got {got}')


def main(version: str) -> None:
project = "committed"
version_number = version.lstrip("v")
archive_exe_paths = []

release_url = f"https://pypi.org/pypi/{urlquote(project)}/{urlquote(version_number)}/json"
with urlopen(release_url) as f:
release_data = json.load(f)

for url in release_data["urls"]:
if url["packagetype"] != "bdist_wheel":
continue

filename = url["filename"]

try:
hexdigest = url["digests"]["sha256"]
except KeyError as e:
raise KeyError(f"no sha256 digest available for {filename}") from e

lookup_filename = filename.replace(f"-{version_number}-", "-{version_number}-", 1)
if lookup_filename not in file_os_archs:
raise KeyError(f'unhandled file: "{filename}"')
os_arch = file_os_archs[lookup_filename]
if os_arch is None:
continue

check_hexdigest(url["url"], "sha256", hexdigest)

print(f"-url {os_arch}={url["url"]}#sha256-{hexdigest}")
suffix = ".exe" if os_arch.startswith("windows/") else ""
archive_exe_paths.append(
f"-archive-exe-path {os_arch}={project}-{version_number}.data/scripts/{project}{suffix}"
)
for p in archive_exe_paths:
print(p)


if __name__ == "__main__":
if len(sys.argv) != 2:
print(f"usage: {sys.argv[0]} VERSION")
sys.exit(2)
main(sys.argv[1])
87 changes: 87 additions & 0 deletions generators/wrun_dprint_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3

# Copyright 2023 Ville Skyttä
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

"""
wrun_dprint_args.py -- generate wrun command line args for dprint
* https://dprint.dev
* https://github.com/dprint/dprint/releases
"""

import hashlib
import sys
from urllib.parse import urljoin, quote as urlquote
from urllib.request import urlopen

file_os_archs = {
"dprint-aarch64-apple-darwin.zip": "darwin/arm64",
"dprint-aarch64-unknown-linux-gnu.zip": None, # using musl one
"dprint-aarch64-unknown-linux-musl.zip": "linux/arm64",
"dprint-x86_64-apple-darwin.zip": "darwin/amd64",
"dprint-x86_64-pc-windows-msvc-installer.exe": None,
"dprint-x86_64-pc-windows-msvc.zip": "windows/amd64",
"dprint-x86_64-unknown-linux-gnu.zip": None, # using musl one
"dprint-x86_64-unknown-linux-musl.zip": "linux/amd64",
}


def check_hexdigest(url: str, algo: str, expected: str) -> None:
try:
assert len(expected) == len(hashlib.new(algo, b"canary").hexdigest())
_ = bytes.fromhex(expected)
except Exception as e:
raise ValueError(f'not a {algo} hex digest: "{expected}"') from e
with urlopen(url) as f:
got = hashlib.file_digest(f, algo).hexdigest()
if got != expected:
raise ValueError(f'{algo} mismatch for "{url}", expected {expected}, got {got}')


def main(version: str) -> None:
base_url = (
f"https://github.com/dprint/dprint/releases/download/{urlquote(version)}/"
)

with urlopen(urljoin(base_url, "SHASUMS256.txt")) as f:
for line in f:
sline = line.decode()

hexdigest_filename = sline.split(maxsplit=3)
if len(hexdigest_filename) != 2:
raise ValueError(f'invalid checksums line: "{sline}"')
hexdigest, filename = hexdigest_filename

if filename not in file_os_archs:
raise KeyError(f'unhandled file: "{filename}"')
os_arch = file_os_archs[filename]
if os_arch is None:
continue

url = urljoin(base_url, filename)
check_hexdigest(url, "sha256", hexdigest)

print(f"-url {os_arch}={url}#sha256-{hexdigest}")
print("-archive-exe-path windows/*=dprint.exe")
print("-archive-exe-path dprint")


if __name__ == "__main__":
if len(sys.argv) != 2:
print(f"usage: {sys.argv[0]} VERSION")
sys.exit(2)
main(sys.argv[1])
Loading

0 comments on commit 4c7b998

Please sign in to comment.