Skip to content

Commit

Permalink
🌠 Packaging revamp, introduce cleaner installation, add cross-compila…
Browse files Browse the repository at this point in the history
…tion (#12)

Closes #7 and sets up baseline work for #2, which can be continued with setting up `cibuildwheel`.
  • Loading branch information
agriyakhetarpal committed Jan 4, 2024
2 parents f22f696 + e1dc1ca commit f3b572e
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 101 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
run: choco install mingw

- name: Restore Hugo builder cache
uses: actions/cache@v3.3.2
uses: actions/cache/restore@v3
with:
path: ./hugo_cache/
key: ${{ runner.os }}-${{ matrix.go-version }}-hugo-build-cache-${{ hashFiles('**/setup.py', '**/pyproject.toml') }}
Expand All @@ -63,5 +63,11 @@ jobs:
run: |
python -m build --wheel . --outdir dist/
- name: Save Hugo builder cache
uses: actions/cache/save@v3
with:
path: ./hugo_cache/
key: ${{ runner.os }}-${{ matrix.go-version }}-hugo-build-cache-${{ hashFiles('**/setup.py', '**/pyproject.toml') }}

- name: Test entry points for package
run: nox -s venv
34 changes: 28 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ pip install hugo-python

This places a `hugo` executable in a `binaries` directory in your virtual environment and adds an entry point to it.

> [!IMPORTANT]
> It is currently necessary to use a virtual environment to install and use isolated version of Hugo. Please refer to https://github.com/agriyakhetarpal/hugo-python-distributions/issues/7
Alternatively, you can install the package globally on your system:

```bash
pip3 install hugo-python
```

> [!TIP]
> You can, however, use [`pipx`](https://github.com/pypa/pipx) to install Hugo in an isolated environment without having to create a virtual environment manually, allowing you to use Hugo as a command-line tool without having to install it globally on your system. Please refer to the [`pipx` documentation](https://pipx.pypa.io/stable/) for more information.
> It is a great idea to use [`pipx`](https://github.com/pypa/pipx) to install Hugo in an isolated location without having to create a virtual environment, which will allow you to use Hugo as a command-line tool without having to install it globally on your system. Please refer to the [`pipx` documentation](https://pipx.pypa.io/stable/) for more information.
Then, you can use the `hugo` commands as you would normally:

Expand All @@ -52,15 +55,13 @@ For more information on using Hugo and its command-line interface, please refer

## Supported platforms

<!-- Add a table -->
| Platform | Architecture | Supported |
| -------- | ------------ | ---------------- |
| macOS | x86_64 | ✅ |
| macOS | arm64 | Coming soon |
| macOS | arm64 | ✅ |
| Linux | amd64 | ✅ |
| Linux | arm64 | Coming soon |
| Windows | x86_64 | ✅ |
| Windows | arm64 | Coming soon |

## Building from source

Expand All @@ -87,6 +88,27 @@ pip install -e . # editable installation
pip install . # regular installation
```

### Cross-compiling for different architectures

> [!NOTE]
> This functionality is implemented just for macOS at the moment, but it can be extended to other platforms as well in the near future.
This package is capable of cross-compiling Hugo binaries for the same platform but different architectures and it can be used as follows.

Say, on an Intel-based (x86_64) macOS machine:

```bash
export GOARCH="arm64"
pip install . # or pip install -e .
```

This will build a macOS arm64 binary distribution of Hugo that can be used on Apple Silicon-based (arm64) macOS machines. To build a binary distribution for the _target_ Intel-based (x86_64) macOS platform on the _host_ Apple Silicon-based (arm64) macOS machine, you can use the following command:

```bash
export GOARCH="amd64"
pip install . # or pip install -e .
```

## Background

Binaries for the Hugo static site generator are available for download from the [Hugo releases page](https://github.com/gohugoio/hugo/releases). These binaries have to be downloaded and placed in an appropriate location on the system manually and the PATH environment variable has to be updated to include said location.
Expand Down
2 changes: 1 addition & 1 deletion licenses/LICENSE-hugo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,4 @@
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.
limitations under the License.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools>=61", "pooch", "tqdm", "wheel"]
requires = ["setuptools>=64", "pooch", "tqdm", "wheel==0.42.0"]
build-backend = "setuptools.build_meta"

[project]
Expand Down
65 changes: 4 additions & 61 deletions python_hugo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,8 @@

from __future__ import annotations

import os
import sys
from python_hugo.cli import __call

import importlib.metadata

HUGO_VERSION = importlib.metadata.version("python-hugo")
FILE_EXT = ".exe" if sys.platform == "win32" else ""

# On editable and source installs, we keep binaries in the package directory
# for ease of use. On wheel installs, we keep them in the venv/binaries directory.
# On installing from a wheel, the binary is in the venv/binaries, but the package
# is in venv/lib/python3.X/site-packages, so we need to go up two directories and
# then down into binaries
# Note: on Windows, this is venv\Lib\site-packages (instead of venv/lib/python3.X/site-packages)
# therefore we need to go up to the venv directory and then down into the data files
try:
hugo_executable = os.path.join(
os.path.dirname(__file__),
"binaries",
f"hugo-{HUGO_VERSION}" + FILE_EXT,
)
if not os.path.exists(hugo_executable):
raise FileNotFoundError
except FileNotFoundError:
if sys.platform == "win32":
PATH_TO_SEARCH = os.path.join(
os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(__file__)
)
)
),
"binaries"
) # four times instead of five
else:
# five times instead of four
PATH_TO_SEARCH = os.path.join(
os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(__file__)
)
)
)
),
"binaries"
)

# Go up into the venv directory and down into the data files
hugo_executable = os.path.join(PATH_TO_SEARCH, f"hugo-{HUGO_VERSION}" + FILE_EXT)
if not os.path.exists(hugo_executable):
raise FileNotFoundError from None
except Exception as e:
sys.exit(f"Error: {e}")

def __call():
"""
Hugo binary entry point. Passes all command-line arguments to Hugo.
"""
os.execvp(hugo_executable, ["hugo", *sys.argv[1:]])
# Hugo binary entry point caller
if __name__ == "__main__":
__call()
1 change: 1 addition & 0 deletions python_hugo/binaries/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!.gitignore
46 changes: 46 additions & 0 deletions python_hugo/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
Copyright (c) 2023 Agriya Khetarpal. All rights reserved.
python-hugo: Binaries for the Hugo static site generator, installable with pip
"""

from __future__ import annotations

import importlib.metadata
import os
import platform
import sys
from functools import lru_cache

HUGO_VERSION = importlib.metadata.version("python-hugo")
FILE_EXT = ".exe" if sys.platform == "win32" else ""
HUGO_PLATFORM = {
"darwin": "darwin",
"linux": "linux",
"win32": "windows",
}[sys.platform]
HUGO_ARCH = {
"x86_64": "amd64",
"arm64": "arm64",
"AMD64": "amd64",
"aarch64": "arm64",
}[platform.machine()]


@lru_cache(maxsize=1)
def hugo_executable():
"""
Returns the path to the Hugo executable.
"""
return os.path.join(
os.path.dirname(__file__),
"binaries",
f"hugo-{HUGO_VERSION}-{HUGO_PLATFORM}-{HUGO_ARCH}" + FILE_EXT,
)


def __call():
"""
Hugo binary entry point. Passes all command-line arguments to Hugo.
"""
os.execvp(hugo_executable(), ["hugo", *sys.argv[1:]])
Loading

0 comments on commit f3b572e

Please sign in to comment.