Skip to content

Commit

Permalink
Cross compile and publish to pypi (#1)
Browse files Browse the repository at this point in the history
* Cross compile wheels

* skip macos-latest wheel
  • Loading branch information
UnknownPlatypus authored Sep 22, 2024
1 parent e5196b4 commit df67172
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 148 deletions.
13 changes: 9 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,29 @@ name: main
on:
push:
branches: [main, test-me-*]
tags:
tags: '*'
pull_request:

jobs:
main-windows:
uses: asottile/workflows/.github/workflows/tox.yml@v1.4.1
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.1
with:
env: '["py38"]'
os: windows-latest
wheel-tags: true
main-macos:
uses: asottile/workflows/.github/workflows/tox.yml@v1.4.1
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.1
with:
env: '["py38"]'
os: macos-latest
main-macos-intel:
uses: asottile/workflows/.github/workflows/[email protected]
with:
env: '["py38"]'
os: macos-13
wheel-tags: true
main-linux:
uses: asottile/workflows/.github/workflows/tox.yml@v1.4.1
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.1
with:
env: '["py38"]'
os: ubuntu-latest
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Sample `.pre-commit-config.yaml`:

```yaml
- repo: https://github.com/UnknownPlatypus/jpegoptim-py
rev: v1.5.5.1
rev: v1.5.5.2
hooks:
- id: jpegoptim
```
Expand All @@ -39,7 +39,7 @@ Sample `.pre-commit-config.yaml` with lossy compression enabled:

```yaml
- repo: https://github.com/UnknownPlatypus/jpegoptim-py
rev: v1.5.5.1
rev: v1.5.5.2
hooks:
- id: jpegoptim
args: [--strip-all, --all-progressive, --max=85, --threshold=3]
Expand Down
32 changes: 31 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[metadata]
name = jpegoptim_py
version = 1.5.5.2
description = Python wrapper around invoking jpegoptim (https://github.com/tjko/jpegoptim)
long_description = file: README.md
long_description_content_type = text/markdown
Expand All @@ -16,4 +17,33 @@ classifiers =
Programming Language :: Python :: Implementation :: PyPy

[options]
python_requires = >=3.7
python_requires = >=3.8
setup_requires =
setuptools-download

[setuptools_download]
download_scripts =
[jpegoptim]
group = jpegoptim-binary
marker = sys_platform == "linux" and platform_machine == "x86_64"
url = https://github.com/tjko/jpegoptim/releases/download/v1.5.5/jpegoptim-1.5.5-x64-linux.zip
sha256 = 1b3f9f3e92771f49796b3060c7f338e0bb12c71c668d821446772bd92092d865
extract = zip
extract_path = jpegoptim
[jpegoptim]
group = jpegoptim-binary
marker = sys_platform == "darwin" and platform_machine == "x86_64"
marker = sys_platform == "darwin" and platform_machine == "arm64"
url = https://github.com/tjko/jpegoptim/releases/download/v1.5.5/jpegoptim-1.5.5-x64-osx.zip
sha256 = 7ab86a5a0e13b3df7ec496c61978e7a71c275cf1a0d2cc35de07ba8ae0c10b95
extract = zip
extract_path = jpegoptim
[jpegoptim.exe]
group = jpegoptim-binary
marker = sys_platform == "win32" and platform_machine == "AMD64"
marker = sys_platform == "win32" and platform_machine == "ARM64"
marker = sys_platform == "cygwin" and platform_machine == "x86_64"
url = https://github.com/tjko/jpegoptim/releases/download/v1.5.5/jpegoptim-1.5.5-x64-windows.zip
sha256 = ffa037ecc12e002c1c87c334d8ebaed988ec738c3ad606d054272950519b09a8
extract = zip
extract_path = jpegoptim.exe
143 changes: 3 additions & 140 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,149 +1,12 @@
#!/usr/bin/env python3
from __future__ import annotations

import hashlib
import http
import io
import os.path
import platform
import stat
import sys
import urllib.request
import zipfile

from distutils.command.build import build as orig_build
from distutils.core import Command
from setuptools import setup
from setuptools.command.install import install as orig_install

JPEGOPTIM_VERSION = "1.5.5"
PY_VERSION = "1" # Python wrapper version

POSTFIX_SHA256 = {
("linux", "x86_64"): (
"x64-linux.zip",
"1b3f9f3e92771f49796b3060c7f338e0bb12c71c668d821446772bd92092d865",
),
("darwin", "x86_64"): (
"x64-osx.zip",
"7ab86a5a0e13b3df7ec496c61978e7a71c275cf1a0d2cc35de07ba8ae0c10b95",
),
("win32", "AMD64"): (
"x64-windows.zip",
"ffa037ecc12e002c1c87c334d8ebaed988ec738c3ad606d054272950519b09a8",
),
}
POSTFIX_SHA256[("darwin", "arm64")] = POSTFIX_SHA256[("darwin", "x86_64")]


def get_download_url() -> tuple[str, str]:
postfix, sha256 = POSTFIX_SHA256[(sys.platform, platform.machine())]
url = (
f"https://github.com/tjko/jpegoptim/releases/download/"
f"v{JPEGOPTIM_VERSION}/jpegoptim-{JPEGOPTIM_VERSION}-{postfix}"
)
return url, sha256


def download(url: str, sha256: str) -> bytes:
with urllib.request.urlopen(url) as resp:
code = resp.getcode()
if code != http.HTTPStatus.OK:
raise ValueError(f"HTTP failure. Code: {code}")
data = resp.read()

checksum = hashlib.sha256(data).hexdigest()
if checksum != sha256:
raise ValueError(f"sha256 mismatch, expected {sha256}, got {checksum}")

return data


def extract(url: str, data: bytes) -> bytes:
with io.BytesIO(data) as bio:
with zipfile.ZipFile(bio) as zipf:
for info in zipf.infolist():
if info.filename.startswith("jpegoptim"):
return zipf.read(info.filename)

raise AssertionError(f"unreachable {url}")


def save_executable(data: bytes, base_dir: str):
exe = "jpegoptim" if sys.platform != "win32" else "jpegoptim.exe"
output_path = os.path.join(base_dir, exe)
os.makedirs(base_dir)

with open(output_path, "wb") as fp:
fp.write(data)

# Mark as executable.
# https://stackoverflow.com/a/14105527
mode = os.stat(output_path).st_mode
mode |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
os.chmod(output_path, mode)


class build(orig_build):
sub_commands = orig_build.sub_commands + [("fetch_binaries", None)]


class install(orig_install):
sub_commands = orig_install.sub_commands + [("install_jpegoptim", None)]


class fetch_binaries(Command):
build_temp = None

def initialize_options(self):
pass

def finalize_options(self):
self.set_undefined_options("build", ("build_temp", "build_temp"))

def run(self):
# save binary to self.build_temp
url, sha256 = get_download_url()
archive = download(url, sha256)
data = extract(url, archive)
save_executable(data, self.build_temp)


class install_jpegoptim(Command):
description = "install the jpegoptim executable"
outfiles = ()
build_dir = install_dir = None

def initialize_options(self):
pass

def finalize_options(self):
# this initializes attributes based on other commands' attributes
self.set_undefined_options("build", ("build_temp", "build_dir"))
self.set_undefined_options(
"install",
("install_scripts", "install_dir"),
)

def run(self):
self.outfiles = self.copy_tree(self.build_dir, self.install_dir)

def get_outputs(self):
return self.outfiles


command_overrides = {
"install": install,
"install_jpegoptim": install_jpegoptim,
"build": build,
"fetch_binaries": fetch_binaries,
}


try:
from wheel.bdist_wheel import bdist_wheel as orig_bdist_wheel
except ImportError:
pass
cmdclass = {}
else:

class bdist_wheel(orig_bdist_wheel):
Expand All @@ -157,6 +20,6 @@ def get_tag(self):
# We don't contain any python source, nor any python extensions
return "py2.py3", "none", plat

command_overrides["bdist_wheel"] = bdist_wheel
cmdclass = {"bdist_wheel": bdist_wheel}

setup(version=f"{JPEGOPTIM_VERSION}.{PY_VERSION}", cmdclass=command_overrides)
setup(cmdclass=cmdclass)
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py38,pre-commit
envlist = py,pre-commit

[testenv]
commands =
Expand Down

0 comments on commit df67172

Please sign in to comment.