Skip to content

Commit

Permalink
ref: also distribute sentry-cli as a pip package (getsentry#1494)
Browse files Browse the repository at this point in the history
  • Loading branch information
asottile-sentry authored Mar 1, 2023
1 parent 52f43ec commit 2885be5
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .craft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ targets:
checksums:
- algorithm: sha256
format: hex
- name: pypi
- name: sentry-pypi
internalPypiRepo: getsentry/pypi
requireNames:
- /^sentry-cli-Darwin-x86_64$/
- /^sentry-cli-Darwin-arm64$/
Expand All @@ -73,3 +76,5 @@ requireNames:
- /^sentry-cli-Linux-aarch64$/
- /^sentry-cli-Windows-i686.exe$/
- /^sentry-cli-Windows-x86_64.exe$/
- /^sentry_cli-.*.tar.gz$/
- /^sentry_cli-.*.whl$/
44 changes: 44 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,47 @@ jobs:
with:
name: ${{ github.sha }}
path: '*.tgz'

python-base:
name: python (base)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # pin@v1
with:
toolchain: stable
target: x86_64-unknown-linux-musl
profile: minimal
override: true
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: python3 -m pip install build && python3 -m build
- uses: actions/[email protected]
with:
name: ${{ github.sha }}-python-base
path: dist/*

python:
name: python
runs-on: ubuntu-latest
needs: [linux, macos, macos_universal, windows, python-base]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- uses: actions/download-artifact@v3
with:
name: ${{ github.sha }}
path: binaries
- uses: actions/download-artifact@v3
with:
name: ${{ github.sha }}-python-base
path: python-base
- run: scripts/wheels --binaries binaries --base python-base --dest dist
- uses: actions/[email protected]
with:
name: ${{ github.sha }}
path: dist/*

2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include build.rs Cargo.toml Cargo.lock
recursive-include src *
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build-system]
requires = ["setuptools", "wheel", "setuptools-rust"]
174 changes: 174 additions & 0 deletions scripts/wheels
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/usr/bin/env python3
import argparse
import base64
import hashlib
import os.path
import shutil
import tempfile
import zipfile
from typing import NamedTuple


class Wheel(NamedTuple):
src: str
plat: str
exe: str = 'sentry-cli'


WHEELS = (
Wheel(
src='sentry-cli-Darwin-arm64',
plat='macos_11_0_arm64',
),
Wheel(
src='sentry-cli-Darwin-universal',
plat='macos_11_0_universal2',
),
Wheel(
src='sentry-cli-Darwin-x86_64',
plat='macos_10_15_x86_64',
),
Wheel(
src='sentry-cli-Linux-aarch64',
plat='manylinux_2_17_aarch64.manylinux2014_aarch64',
),
Wheel(
src='sentry-cli-Linux-armv7',
plat='manylinux_2_17_armv7l.manylinux2014_armv7l',
),
Wheel(
src='sentry-cli-Linux-i686',
plat='manylinux_2_17_i686.manylinux2014_i686',
),
Wheel(
src='sentry-cli-Linux-x86_64',
plat='manylinux_2_17_x86_64.manylinux2014_x86_64',
),
Wheel(
src='sentry-cli-Windows-i686.exe',
plat='win32',
exe='sentry-cli.exe',
),
Wheel(
src='sentry-cli-Windows-x86_64.exe',
plat='win_amd64',
exe='sentry-cli.exe',
),
)


def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('--binaries', required=True)
parser.add_argument('--base', required=True)
parser.add_argument('--dest', required=True)
args = parser.parse_args()

expected = {wheel.src for wheel in WHEELS}
received = set(os.listdir(args.binaries))
if expected != received:
raise SystemExit(
f'Unexpected binaries:\n\n'
f'- extra: {", ".join(sorted(received - expected))}\n'
f'- missing: {", ".join(sorted(expected - received))}'
)

sdist_path = wheel_path = None
for fname in os.listdir(args.base):
if fname.endswith('.tar.gz'):
sdist_path = os.path.join(args.base, fname)
elif fname.endswith('.whl'):
wheel_path = os.path.join(args.base, fname)
else:
raise SystemExit(f'unexpected file in `--base`: {fname}')

if sdist_path is None or wheel_path is None:
raise SystemExit('expected wheel and sdist in `--base`')

os.makedirs(args.dest, exist_ok=True)
shutil.copy(sdist_path, args.dest)

for wheel in WHEELS:
binary_src = os.path.join(args.binaries, wheel.src)
binary_size = os.stat(binary_src).st_size
with open(binary_src, 'rb') as bf:
digest = hashlib.sha256(bf.read()).digest()
digest_b64 = base64.urlsafe_b64encode(digest).rstrip(b'=').decode()

basename = os.path.basename(wheel_path)
wheelname, _ = os.path.splitext(basename)
name, version, py, abi, plat = wheelname.split('-')

with tempfile.TemporaryDirectory() as tmp:
with zipfile.ZipFile(wheel_path) as zipf:
zipf.extractall(tmp)

distinfo = os.path.join(tmp, f'{name}-{version}.dist-info')
scripts = os.path.join(tmp, f'{name}-{version}.data', 'scripts')

# replace the script binary with our copy
os.remove(os.path.join(scripts, 'sentry-cli'))
shutil.copy(binary_src, os.path.join(scripts, wheel.exe))

# rewrite RECORD to include the new file
record_fname = os.path.join(distinfo, 'RECORD')
with open(record_fname) as f:
record_lines = list(f)

record = f'{name}-{version}.data/scripts/sentry-cli,'
for i, line in enumerate(record_lines):
if line.startswith(record):
record_lines[i] = (
f'{name}-{version}.data/scripts/{wheel.exe},'
f'sha256={digest_b64},'
f'{binary_size}\n'
)
break
else:
raise SystemExit(f'could not find {record!r} in RECORD')

with open(record_fname, 'w') as f:
f.writelines(record_lines)

# rewrite WHEEL to have the new tags
wheel_fname = os.path.join(distinfo, 'WHEEL')
with open(wheel_fname) as f:
wheel_lines = list(f)

for i, line in enumerate(wheel_lines):
if line.startswith('Tag: '):
wheel_lines[i:i + 1] = [
f'Tag: {py}-{abi}-{plat}\n'
for plat in wheel.plat.split('.')
]
break
else:
raise SystemExit("could not find 'Tag: ' in WHEEL")

with open(wheel_fname, 'w') as f:
f.writelines(wheel_lines)

# write out the final zip
new_basename = f'{name}-{version}-{py}-{abi}-{wheel.plat}.whl'
tmp_new_wheel = os.path.join(tmp, new_basename)
fnames = sorted(
os.path.join(root, fname)
for root, _, fnames in os.walk(tmp)
for fname in fnames
)
with zipfile.ZipFile(tmp_new_wheel, 'w') as zipf:
for fname in fnames:
zinfo = zipfile.ZipInfo(os.path.relpath(fname, tmp))
if '/scripts/' in zinfo.filename:
zinfo.external_attr = 0o100755 << 16
with open(fname, 'rb') as fb:
zipf.writestr(zinfo, fb.read())

# move into dest
shutil.move(tmp_new_wheel, args.dest)

return 0


if __name__ == '__main__':
raise SystemExit(main())
21 changes: 21 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[metadata]
name = sentry_cli
description = A command line utility to work with Sentry.
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/getsentry/sentry-cli
author = Sentry
author_email = [email protected]
license = BSD-3-Clause
license_file = LICENSE
classifiers =
License :: OSI Approved :: BSD License
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy

[options]
packages =
py_modules =
python_requires = >=3.7
26 changes: 26 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from setuptools import setup
from setuptools_rust import RustBin
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel

with open('Cargo.toml') as f:
for line in f:
if line.startswith('version = "'):
_, VERSION, _ = line.split('"')
break


class bdist_wheel(_bdist_wheel):
def finalize_options(self):
super().finalize_options()
self.root_is_pure = False

def get_tag(self):
_, _, plat = super().get_tag()
return 'py3', 'none', plat


setup(
version=VERSION,
rust_extensions=[RustBin("sentry-cli")],
cmdclass={'bdist_wheel': bdist_wheel},
)

0 comments on commit 2885be5

Please sign in to comment.