its faster, and has some nicer features
This commit is contained in:
1
.dockerignore
Symbolic link
1
.dockerignore
Symbolic link
@@ -0,0 +1 @@
|
||||
.gitignore
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,9 +5,10 @@ global/data/topbanner/.topbanner.??.xml
|
||||
.*.xmllist
|
||||
# Local build stuff
|
||||
output
|
||||
# Python venv
|
||||
# Python stuff
|
||||
.venv
|
||||
__pycache__
|
||||
uv.lock
|
||||
#Nltk
|
||||
.nltk_data
|
||||
|
||||
|
||||
27
Dockerfile
27
Dockerfile
@@ -1,33 +1,30 @@
|
||||
FROM debian:latest
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
|
||||
# Install deps
|
||||
RUN apt update
|
||||
RUN apt install --yes --no-install-recommends \
|
||||
RUN apt-get update && apt-get install --yes --no-install-recommends \
|
||||
rsync \
|
||||
libxslt1.1 \
|
||||
libxml2 \
|
||||
golang \
|
||||
python3 \
|
||||
python3-venv \
|
||||
python3-pip \
|
||||
git \
|
||||
node-less \
|
||||
openssh-client \
|
||||
ca-certificates \
|
||||
expect
|
||||
|
||||
# Set uv project env, to persist stuff moving dirs
|
||||
ENV UV_PROJECT_ENVIRONMENT=/root/.cache/uv/venv
|
||||
# Set the workdir
|
||||
WORKDIR /website-source
|
||||
|
||||
# Setup venv
|
||||
ENV VIRTUAL_ENV=/opt/venv
|
||||
RUN python3 -m venv $VIRTUAL_ENV
|
||||
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
# Copy the requirements
|
||||
# Copy the pyproject and build deps
|
||||
# Done in a seperate step for optimal docker caching
|
||||
COPY ./requirements.txt /website-source/requirements.txt
|
||||
RUN pip install -r /website-source/requirements.txt
|
||||
COPY ./pyproject.toml .
|
||||
RUN uv sync --no-install-package build
|
||||
|
||||
# Copy everything else
|
||||
COPY . /website-source/
|
||||
WORKDIR /website-source
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT [ "bash", "./entrypoint.sh" ]
|
||||
|
||||
|
||||
18
README.md
18
README.md
@@ -82,12 +82,12 @@ Alterations to build scripts or the files used site-wide will result in near ful
|
||||
|
||||
### Native
|
||||
|
||||
We can either install the required dependencies manually using our preferred package manager. If you are a nix use one can run `nix-shell` to enter a shell with the required build dependencies, with the python `virtualenv` already installed and activated.
|
||||
We can either install the required dependencies manually using our preferred package manager. If you are a nix use one can run `nix-shell` to enter a shell with the required build dependencies.
|
||||
|
||||
If installing manually, the required binary names are
|
||||
|
||||
```
|
||||
python3 pip
|
||||
uv
|
||||
```
|
||||
|
||||
Also needed are the libraries
|
||||
@@ -96,17 +96,9 @@ Also needed are the libraries
|
||||
libxml2 libxslt
|
||||
```
|
||||
|
||||
Then, we must activate a Python virtual env and install the python dependencies.
|
||||
As we are using [UV](https://docs.astral.sh/uv/) we can just run the build process directly, and let it handle deps.
|
||||
|
||||
```
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
After getting the dependencies one way or another we can actually build and serve the pages.
|
||||
|
||||
The pages can be built and served by running `./build.py`. Try `--help` for more information. The simple web server used lacks the features of `apache` which used on the FSFE web servers. This is why no index is automatically selected for each directory and other behaviours.
|
||||
The pages can be built and served by running `uv run build`. Try `--help` for more information. The simple web server used lacks the features of `apache` which used on the FSFE web servers. This is why no index is automatically selected for each directory and other behaviours.
|
||||
|
||||
### Docker
|
||||
|
||||
@@ -129,7 +121,7 @@ KEY_PRIVATE=none KEY_PASSWORD=none GIT_TOKEN=none docker compose
|
||||
Once your preferred method has been chosen, simply running `docker compose run --service-ports build --serve` should build the webpages and make them available over localhost.
|
||||
|
||||
|
||||
Some more explanation: we are essentially just using docker as a way to provide dependencies and then running the build script. All flags after `build` are passed to `build.py`. The `service-ports` flag is required to open ports from the container for serving the output, not needed if not using the `--serve` flag of the build script.
|
||||
Some more explanation: we are essentially just using docker as a way to provide dependencies and then running the build script. All flags after `build` are passed to the `build` cli. The `service-ports` flag is required to open ports from the container for serving the output, not needed if not using the `--serve` flag of the build script.
|
||||
|
||||
## Githooks
|
||||
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# __init__.py is a special Python file that allows a directory to become
|
||||
# a Python package so it can be accessed using the 'import' statement.
|
||||
from .build import main
|
||||
|
||||
__all__ = ["main"]
|
||||
|
||||
@@ -7,21 +7,20 @@
|
||||
import argparse
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from build.lib.misc import lang_from_filename
|
||||
from .lib.misc import lang_from_filename
|
||||
|
||||
from build.phase0.full import full
|
||||
from build.phase0.global_symlinks import global_symlinks
|
||||
from build.phase0.prepare_early_subdirectories import prepare_early_subdirectories
|
||||
from .phase0.full import full
|
||||
from .phase0.global_symlinks import global_symlinks
|
||||
from .phase0.prepare_early_subdirectories import prepare_early_subdirectories
|
||||
|
||||
from build.phase1.run import phase1_run
|
||||
from build.phase2.run import phase2_run
|
||||
from .phase1.run import phase1_run
|
||||
from .phase2.run import phase2_run
|
||||
|
||||
from build.phase3.serve_websites import serve_websites
|
||||
from build.phase3.stage_to_target import stage_to_target
|
||||
from .phase3.serve_websites import serve_websites
|
||||
from .phase3.stage_to_target import stage_to_target
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -84,7 +83,11 @@ def parse_arguments() -> argparse.Namespace:
|
||||
return args
|
||||
|
||||
|
||||
def main(args: argparse.Namespace):
|
||||
def main():
|
||||
"""
|
||||
Main process of the website builder
|
||||
"""
|
||||
args = parse_arguments()
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
@@ -158,13 +161,3 @@ def main(args: argparse.Namespace):
|
||||
|
||||
if args.serve:
|
||||
serve_websites(working_target, 2000, 100)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
Main process of the website builder
|
||||
"""
|
||||
# Change to the dir the script is in.
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
args = parse_arguments()
|
||||
main(args)
|
||||
@@ -1,21 +1,35 @@
|
||||
# Contributing
|
||||
|
||||
## Build Process Code
|
||||
|
||||
### Tooling
|
||||
|
||||
We use [UV](https://docs.astral.sh/uv/) for managing python versions, and project dependencies.
|
||||
Please install it in your prefered package manager, and then use
|
||||
|
||||
```
|
||||
uv run build
|
||||
```
|
||||
|
||||
To run the build process.
|
||||
|
||||
We check the validity of python code in the repo using [ruff](https://astral.sh/ruff). We use it for both checking and formatting, with `ruff check` enabled in CI.
|
||||
|
||||
To run it in the project using the project config, please use `uv run ruff`.
|
||||
|
||||
### Overview Stuff
|
||||
|
||||
We try to keep to some design patterns to keep things manageable.
|
||||
|
||||
Firstly, each phase as described in [the overview](./overview.md) should handle a meaningfully different kind of interaction. Each phase should be structured, to the greatest degree possible, as a sequence of steps. We consider that each phase should have a `run.py` file that exposes a `ipahse_*run` function that takes the arguments needed for its phase.
|
||||
|
||||
Each run function then calls a sequence of functions that are defined in the other files in the `phase*` folder. Each other file in the folder should expose one function, with the same name as the file, minus file extension. For example, `create_files.py` should expose the function `create_files`. It is a common pattern for the first expose function to generate a list of files or things to act on, and then multithread this using another function.
|
||||
Each run function then calls a sequence of functions that are defined in the other files in the `phase*` folder. Each other file in the folder should expose one function, with the same name as the file, minus file extension. For example, `create_files.py` should expose the function `create_files`. It is a common pattern for the first expose function to generate a list of files or things to act on, and then multithread this using another function.
|
||||
|
||||
Each step function should use `logger.info` at the top of its function to declare what it is doing.
|
||||
|
||||
### Best Practices
|
||||
This is a little bit of a mesys list of things we have found that are not perhaps entirely obvious.
|
||||
|
||||
This is a little bit of a messy list of things we have found that are not perhaps entirely obvious.
|
||||
|
||||
- When doing manipulation of stuff, have a look in the lib functions to see if it is already present. If you find a common pattern, perhaps functionise it.
|
||||
- In phase 1, only update files using the `update_if_changed` function. This function will, as expected, take a file path and a string, and only update the file with the string if there is a difference. Not doing this means a file will always be updated, and hence anything depending on it will always be rebuild, even if the file has not actually changed.
|
||||
@@ -23,7 +37,5 @@ This is a little bit of a mesys list of things we have found that are not perhap
|
||||
- All steps are largely considered to be synchronous, and must be finished before the next step can start. Therefore, async must unfortunately be avoided. There are some steps where performance benefits could be achieved by allowing the next step to run concurrently, but the design complications make this unattractive.
|
||||
- We use a single process pool to multithread with. This gives a small performance benefit over making and deleting pools continuously.
|
||||
- All paths are to be handled with `pathlib`, not as strings.
|
||||
- XML code should be generated with LXML instead of string templating. This is to ensure that we generate valid XML every time, and prevents issues with escaping, etc.
|
||||
- Where possibly, type hint stuff. We try and keep the codebase reasonably typed to make it comprehensible
|
||||
|
||||
|
||||
- XML code should be generated with LXML instead of string templating. This is to ensure that we generate valid XML every time, and prevents issues with escaping, etc.
|
||||
- Where possibly, type hint stuff. We try and keep the codebase reasonably typed to make it comprehensible
|
||||
|
||||
@@ -44,4 +44,4 @@ rsync -rlpgoDz --delete --checksum --filter=':- .gitignore' ./ /website-cached/s
|
||||
cd /website-cached/source
|
||||
|
||||
# run build script expaning all args passed to this script
|
||||
python3 ./build.py "$@"
|
||||
uv run --reinstall-package build build "$@"
|
||||
|
||||
35
pyproject.toml
Normal file
35
pyproject.toml
Normal file
@@ -0,0 +1,35 @@
|
||||
[project]
|
||||
name = "build"
|
||||
version = "0.0.0"
|
||||
description = "Python tooling to build the fsfe websites"
|
||||
readme = "README.md"
|
||||
# Pinned to 3.12 as a known working version, that also has a prebuild wheel for tdewolff-minify
|
||||
requires-python = "==3.12.*"
|
||||
dependencies = [
|
||||
# XML parser
|
||||
"lxml==5.3.2",
|
||||
# For getting english language names of languages from two letter codes.
|
||||
"python-iso639==2025.2.18",
|
||||
# For stopwords for the search index
|
||||
"nltk==3.9.1",
|
||||
# For minification html css and js
|
||||
"tdewolff-minify==2.20.37",
|
||||
# For HTTP requests
|
||||
"requests==2.32.3",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
build = "build:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"ruff"
|
||||
]
|
||||
[build-system]
|
||||
requires = ["uv_build"]
|
||||
build-backend = "uv_build"
|
||||
|
||||
[tool.uv.build-backend]
|
||||
module-name = "build"
|
||||
module-root = ""
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# XML parser
|
||||
lxml==5.3.2
|
||||
# For getting english language names of languages from two letter codes.
|
||||
python-iso639==2025.2.18
|
||||
# For stopwords for the search index
|
||||
nltk==3.9.1
|
||||
# For minification html css and js
|
||||
tdewolff-minify==2.20.37
|
||||
# For HTTP requests
|
||||
requests==2.32.3
|
||||
94
shell.nix
94
shell.nix
@@ -8,49 +8,53 @@ let
|
||||
treefmt-nixSrc = builtins.fetchTarball "https://github.com/numtide/treefmt-nix/archive/refs/heads/master.tar.gz";
|
||||
treefmt-nix = import treefmt-nixSrc;
|
||||
in
|
||||
pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
# The main required tool python
|
||||
python3
|
||||
# needed by lxml
|
||||
libxslt
|
||||
libxml2
|
||||
# For less compilation
|
||||
lessc
|
||||
# Needed for git clean in full rebuilds
|
||||
git
|
||||
# Needed for compiling minifiers
|
||||
libffi
|
||||
go
|
||||
# Formatter
|
||||
(treefmt-nix.mkWrapper pkgs {
|
||||
# Used to find the project root
|
||||
projectRootFile = "shell.nix";
|
||||
enableDefaultExcludes = true;
|
||||
programs = {
|
||||
ruff-check.enable = true;
|
||||
ruff-format.enable = true;
|
||||
nixfmt.enable = true;
|
||||
};
|
||||
settings = {
|
||||
global = {
|
||||
on-unmatched = "debug";
|
||||
excludes = [
|
||||
".nltk_data"
|
||||
".venv"
|
||||
];
|
||||
(pkgs.buildFHSEnv {
|
||||
name = "simple-env";
|
||||
# Installed for host pc only
|
||||
targetPkgs =
|
||||
pkgs:
|
||||
(with pkgs; [
|
||||
# For getting python deps
|
||||
uv
|
||||
# needed by lxml
|
||||
libxslt
|
||||
libxml2
|
||||
# For less compilation
|
||||
lessc
|
||||
# Needed for git clean in full rebuilds
|
||||
git
|
||||
# Needed for compiling minifiers
|
||||
libffi
|
||||
go
|
||||
# Formatter
|
||||
(treefmt-nix.mkWrapper pkgs {
|
||||
# Used to find the project root
|
||||
projectRootFile = "shell.nix";
|
||||
enableDefaultExcludes = true;
|
||||
programs = {
|
||||
ruff-check.enable = true;
|
||||
ruff-format.enable = true;
|
||||
nixfmt.enable = true;
|
||||
};
|
||||
};
|
||||
})
|
||||
# Packages for git hooks
|
||||
mediainfo
|
||||
perl
|
||||
file
|
||||
];
|
||||
shellHook = ''
|
||||
export PIP_DISABLE_PIP_VERSION_CHECK=1;
|
||||
python -m venv .venv;
|
||||
source .venv/bin/activate;
|
||||
pip install -r requirements.txt;
|
||||
'';
|
||||
}
|
||||
settings = {
|
||||
global = {
|
||||
on-unmatched = "debug";
|
||||
excludes = [
|
||||
".nltk_data"
|
||||
".venv"
|
||||
];
|
||||
};
|
||||
};
|
||||
})
|
||||
# Packages for git hooks
|
||||
mediainfo
|
||||
perl
|
||||
file
|
||||
]);
|
||||
# Installed for every architecture: only install the lib outputs
|
||||
multiPkgs =
|
||||
pkgs:
|
||||
(with pkgs; [
|
||||
]);
|
||||
# runScript = '''';
|
||||
}).env
|
||||
|
||||
Reference in New Issue
Block a user