Skip to content

Commit 316ed31

Browse files
authored
Merge pull request #654 from sdispater/refactor/build-and-wheel
Improve how the project is built
2 parents 7f6d069 + d39ab42 commit 316ed31

File tree

6 files changed

+139
-175
lines changed

6 files changed

+139
-175
lines changed

.github/workflows/release.yml

Lines changed: 47 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -7,123 +7,73 @@ on:
77

88
jobs:
99

10-
Linux:
11-
runs-on: ubuntu-latest
12-
13-
steps:
14-
- uses: actions/checkout@v3
15-
- name: Get tag
16-
id: tag
17-
run: |
18-
echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
19-
- name: Building release
20-
run: |
21-
make linux_release
22-
- name: Upload distributions artifacts
23-
uses: actions/upload-artifact@v2
24-
with:
25-
name: pendulum-dist
26-
path: dist/wheelhouse
27-
28-
MacOS:
29-
runs-on: macos-latest
10+
build:
11+
name: Build wheels on ${{ matrix.os }}
12+
runs-on: ${{ matrix.os }}-latest
3013
strategy:
3114
matrix:
32-
python-version: [3.7, 3.8, 3.9, "3.10"]
15+
os: [ ubuntu, windows, macos ]
3316

3417
steps:
35-
- uses: actions/checkout@v2
36-
- name: Get tag
37-
id: tag
38-
run: |
39-
echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
40-
- name: Set up Python ${{ matrix.python-version }}
41-
uses: actions/setup-python@v2
42-
with:
43-
python-version: ${{ matrix.python-version }}
44-
- name: Install and set up Poetry
45-
run: |
46-
curl -fsS https://install.python-poetry.org | python - --preview -y
47-
- name: Build distributions
48-
run: |
49-
source $HOME/.poetry/env
50-
poetry build -vvv
51-
- name: Upload distribution artifacts
52-
uses: actions/upload-artifact@v2
53-
with:
54-
name: pendulum-dist
55-
path: dist
56-
57-
Windows:
58-
runs-on: windows-latest
59-
strategy:
60-
matrix:
61-
python-version: [3.7, 3.8, 3.9, "3.10"]
18+
- uses: actions/checkout@v3
6219

63-
steps:
64-
- uses: actions/checkout@v2
65-
- name: Get tag
66-
id: tag
67-
shell: bash
68-
run: |
69-
echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
70-
- name: Set up Python ${{ matrix.python-version }}
71-
uses: actions/setup-python@v2
72-
with:
73-
python-version: ${{ matrix.python-version }}
74-
- name: Install and setup Poetry
75-
run: |
76-
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python - --preview -y
77-
- name: Build distributions
78-
run: |
79-
$env:Path += ";$env:Userprofile\.poetry\bin"
80-
poetry build -vvv
81-
- name: Upload distribution artifact
82-
uses: actions/upload-artifact@v2
83-
with:
84-
name: pendulum-dist
85-
path: dist
20+
- name: Build wheels
21+
uses: pypa/cibuildwheel@v2.10.1
22+
env:
23+
CIBW_PROJECT_REQUIRES_PYTHON: ">=3.7"
24+
with:
25+
package-dir: .
26+
output-dir: dist
27+
28+
- uses: actions/upload-artifact@v3
29+
with:
30+
name: dist
31+
path: ./dist/*
8632

8733
Release:
88-
needs: [Linux, MacOS, Windows]
34+
needs: [ build-wheel ]
8935
runs-on: ubuntu-latest
9036

9137
steps:
9238
- name: Checkout code
9339
uses: actions/checkout@v2
94-
- name: Get tag
95-
id: tag
96-
run: |
97-
echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
98-
- name: Download distribution artifact
99-
uses: actions/download-artifact@master
40+
41+
- name: Download artifacts
42+
uses: actions/download-artifact@v3
10043
with:
101-
name: pendulum-dist
44+
name: dist
10245
path: dist
103-
- name: Install and set up Poetry
46+
47+
- name: Install Poetry
10448
run: |
105-
curl -fsS https://install.python-poetry.org | python - --preview -y
106-
- name: Set up cache
107-
uses: actions/cache@v2
108-
with:
109-
path: .venv
110-
key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }}
49+
curl -fsS https://install.python-poetry.org | python - -y
50+
51+
- name: Update PATH
52+
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
53+
54+
- name: Build sdist
55+
run: poetry build --format sdist
56+
11157
- name: Check distributions
11258
run: |
11359
ls -la dist
60+
61+
- name: Check Version
62+
id: check-version
63+
run: |
64+
[[ "${GITHUB_REF#refs/tags/}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] \
65+
|| echo ::set-output name=prerelease::true
66+
67+
- name: Create Release
68+
uses: ncipollo/release-action@v1
69+
with:
70+
artifacts: "dist/*"
71+
token: ${{ secrets.GITHUB_TOKEN }}
72+
draft: false
73+
prerelease: steps.check-version.outputs.prerelease == 'true'
74+
11475
- name: Publish to PyPI
11576
env:
11677
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
11778
run: |
118-
source $HOME/.poetry/env
11979
poetry publish
120-
- name: Create Release
121-
id: create_release
122-
uses: actions/create-release@v1
123-
env:
124-
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
125-
with:
126-
tag_name: ${{ steps.tag.outputs.tag }}
127-
release_name: ${{ steps.tag.outputs.tag }}
128-
draft: false
129-
prerelease: false

build.py

Lines changed: 17 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,32 @@
1-
import os
2-
import shutil
3-
import sys
1+
import subprocess
42

5-
from distutils.command.build_ext import build_ext
6-
from distutils.core import Distribution
7-
from distutils.core import Extension
8-
from distutils.errors import CCompilerError
9-
from distutils.errors import DistutilsExecError
10-
from distutils.errors import DistutilsPlatformError
3+
from pathlib import Path
114

125

13-
# C Extensions
14-
with_extensions = os.getenv("PENDULUM_EXTENSIONS", None)
6+
def meson(*args):
7+
subprocess.call(["meson"] + list(args))
158

16-
if with_extensions == "1" or with_extensions is None:
17-
with_extensions = True
189

19-
if with_extensions == "0" or hasattr(sys, "pypy_version_info"):
20-
with_extensions = False
10+
def _build():
11+
build_dir = Path(__file__).parent.joinpath("build")
12+
build_dir.mkdir(parents=True, exist_ok=True)
2113

22-
extensions = []
23-
if with_extensions:
24-
extensions = [
25-
Extension("pendulum._extensions._helpers", ["pendulum/_extensions/_helpers.c"]),
26-
Extension("pendulum.parsing._iso8601", ["pendulum/parsing/_iso8601.c"]),
27-
]
28-
29-
30-
class BuildFailed(Exception):
31-
32-
pass
33-
34-
35-
class ExtBuilder(build_ext):
36-
# This class allows C extension building to fail.
37-
38-
built_extensions = []
39-
40-
def run(self):
41-
try:
42-
build_ext.run(self)
43-
except (DistutilsPlatformError, FileNotFoundError):
44-
print(
45-
" Unable to build the C extensions, "
46-
"Pendulum will use the pure python code instead."
47-
)
48-
49-
def build_extension(self, ext):
50-
try:
51-
build_ext.build_extension(self, ext)
52-
except (CCompilerError, DistutilsExecError, DistutilsPlatformError, ValueError):
53-
print(
54-
f' Unable to build the "{ext.name}" C extension, '
55-
"Pendulum will use the pure python version of the extension."
56-
)
14+
meson("setup", build_dir.as_posix())
15+
meson("compile", "-C", build_dir.as_posix())
16+
meson("install", "-C", build_dir.as_posix())
5717

5818

5919
def build(setup_kwargs):
6020
"""
6121
This function is mandatory in order to build the extensions.
6222
"""
63-
distribution = Distribution({"name": "pendulum", "ext_modules": extensions})
64-
distribution.package_dir = "pendulum"
65-
66-
cmd = ExtBuilder(distribution)
67-
cmd.ensure_finalized()
68-
cmd.run()
69-
70-
# Copy built extensions back to the project
71-
for output in cmd.get_outputs():
72-
relative_extension = os.path.relpath(output, cmd.build_lib)
73-
if not os.path.exists(output):
74-
continue
75-
76-
shutil.copyfile(output, relative_extension)
77-
mode = os.stat(relative_extension).st_mode
78-
mode |= (mode & 0o444) >> 2
79-
os.chmod(relative_extension, mode)
80-
81-
return setup_kwargs
23+
try:
24+
_build()
25+
except Exception:
26+
print(
27+
" Unable to build C extensions, "
28+
"Pendulum will use the pure python version of the extensions."
29+
)
8230

8331

8432
if __name__ == "__main__":

meson.build

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
project('pendulum C extensions', 'c')
2+
3+
py_mod = import('python')
4+
py = py_mod.find_installation()
5+
py_dep = py.dependency()
6+
7+
extensions = [
8+
['_helpers', 'pendulum/_extensions/_helpers.c', meson.source_root() / 'pendulum/_extensions/'],
9+
['_iso8601', 'pendulum/parsing/_iso8601.c', meson.source_root() / 'pendulum/parsing/'],
10+
]
11+
12+
foreach extension : extensions
13+
py.extension_module(
14+
extension[0],
15+
extension[1],
16+
dependencies : py_dep,
17+
install : true,
18+
install_dir: extension[2]
19+
)
20+
endforeach

pendulum/parsing/_iso8601.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
522522
int leap = 0;
523523
int separators = 0;
524524
int time = 0;
525-
int has_hour = 0;
526525
int i;
527526
int j;
528527

@@ -773,7 +772,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
773772
}
774773

775774
parsed->hour = time;
776-
has_hour = 1;
777775
break;
778776
case 4:
779777
// Hours and minutes
@@ -786,7 +784,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
786784

787785
parsed->hour = time / 100;
788786
parsed->minute = time % 100;
789-
has_hour = 1;
790787
break;
791788
case 6:
792789
// Hours, minutes and seconds
@@ -800,7 +797,6 @@ Parsed* _parse_iso8601_datetime(char *str, Parsed *parsed) {
800797
parsed->hour = time / 10000;
801798
parsed->minute = time / 100 % 100;
802799
parsed->second = time % 100;
803-
has_hour = 1;
804800
break;
805801
default:
806802
// Any other case is wrong
@@ -942,7 +938,6 @@ Parsed* _parse_iso8601_duration(char *str, Parsed *parsed) {
942938
int fraction = 0;
943939
int has_ymd = 0;
944940
int has_week = 0;
945-
int has_year = 0;
946941
int has_month = 0;
947942
int has_day = 0;
948943
int has_hour = 0;
@@ -979,7 +974,6 @@ Parsed* _parse_iso8601_duration(char *str, Parsed *parsed) {
979974
fraction = 0;
980975
in_fraction = 0;
981976
has_ymd = 1;
982-
has_year = 1;
983977

984978
break;
985979
case 'M':

0 commit comments

Comments
 (0)