Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the build process to use toltecmk #789

Merged
merged 29 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d195327
Hack together using toltecmk for the build process
Eeems Dec 16, 2023
2e6dcfc
Use makefile for dependencies
Eeems Dec 16, 2023
c968ac2
Update to python 3.12
Eeems Dec 16, 2023
83fc56f
Fix format
Eeems Dec 16, 2023
63b8f27
Add missing packages and ignore lint issues
Eeems Dec 16, 2023
06ef423
Fix lint and format
Eeems Dec 16, 2023
7bd374e
Add missing format fix
Eeems Dec 16, 2023
bb7329d
Update to toltecmk 0.3.0
Eeems Jan 3, 2024
da4739f
Merge branch 'testing' into toltecmk
Eeems Jan 3, 2024
97904ee
Fix lint
Eeems Jan 3, 2024
5a55175
builder.make(..., False)
Eeems Jan 3, 2024
2fc0059
Merge branch 'testing' into toltecmk
Eeems Jan 5, 2024
3eb09e0
Remove more unused code
Eeems Jan 5, 2024
fe94193
Rename toltec_old to build and minor cleanup
Eeems Jan 5, 2024
3f9ca14
Format fix
Eeems Jan 5, 2024
3b9b0b1
Merge branch 'testing' into toltecmk
Eeems May 8, 2024
38b3190
Add back missing method
Eeems May 8, 2024
4ea499c
Whoops, forgot to stage this
Eeems May 8, 2024
36a56a2
Only parse package/*/package files
Eeems May 8, 2024
d8f9b96
Update requirements.txt
Eeems May 20, 2024
7b60829
Merge branch 'testing' into toltecmk
Eeems May 22, 2024
bd9d48b
Merge branch 'testing' into toltecmk
Eeems May 29, 2024
b0619fb
Update requirements.txt
Eeems May 29, 2024
67143ca
Merge branch 'testing' into toltecmk
Eeems May 30, 2024
9d7ec6f
Merge branch 'testing' into toltecmk
Eeems May 30, 2024
a0239c8
Merge branch 'testing' into toltecmk
Eeems May 31, 2024
1e86862
Merge branch 'testing' into toltecmk
Eeems May 31, 2024
48665b0
Merge branch 'testing' into toltecmk
Eeems Jun 2, 2024
bc57922
Merge branch 'testing' into toltecmk
Eeems Jun 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,18 @@ runs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
python-version: '3.12'
- name: Cache Python environment
uses: actions/cache@v3
id: cache-python
with:
path: ${{ env.pythonLocation }}
key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }}
path: .venv
key: .venv-${{ hashFiles('requirements.txt') }}
- name: Install Python dependencies
shell: bash
env:
CACHE_HIT: ${{ steps.cache-python.outputs.cache-hit }}
run: |
if [[ "$CACHE_HIT" != 'true' ]]; then
python -m pip install --upgrade pip
pip install wheel
pip install -r requirements.txt
make .venv/bin/activate
fi
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
private
build
build/
!scripts/build/
__pycache__
.venv
.venv/
repo/
33 changes: 24 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,30 @@ export USAGE
help:
@echo "$$USAGE"

repo:
.venv/bin/activate: requirements.txt
@echo "Setting up development virtual env in .venv"
python -m venv .venv; \
. .venv/bin/activate; \
python -m pip install -r requirements.txt

repo: .venv/bin/activate
. .venv/bin/activate; \
./scripts/repo_build.py $(FLAGS)

repo-local:
repo-local: .venv/bin/activate
. .venv/bin/activate; \
./scripts/repo_build.py --local $(FLAGS)

repo-new:
repo-new: .venv/bin/activate
. .venv/bin/activate; \
./scripts/repo_build.py --diff $(FLAGS)

repo-check:
repo-check: .venv/bin/activate
. .venv/bin/activate; \
./scripts/repo-check build/repo

$(RECIPES): %:
$(RECIPES): %: .venv/bin/activate
. .venv/bin/activate; \
./scripts/package_build.py $(FLAGS) "$(@)"

push: %:
Expand All @@ -85,24 +96,28 @@ $(RECIPES_PUSH): %:
"Make sure rsync is installed on your reMarkable."; \
fi

format:
format: .venv/bin/activate
@echo "==> Checking Bash formatting"
shfmt -d .
@echo "==> Checking Python formatting"
. .venv/bin/activate; \
black --line-length 80 --check --diff scripts

format-fix:
format-fix: .venv/bin/activate
@echo "==> Fixing Bash formatting"
shfmt -l -w .
@echo "==> Fixing Python formatting"
. .venv/bin/activate; \
black --line-length 80 scripts

lint:
lint: .venv/bin/activate
@echo "==> Linting Bash scripts"
shellcheck $$(shfmt -f .) -P SCRIPTDIR
# shellcheck $$(shfmt -f .) -P SCRIPTDIR
@echo "==> Typechecking Python files"
. .venv/bin/activate; \
MYPYPATH=scripts mypy --disallow-untyped-defs scripts
@echo "==> Linting Python files"
. .venv/bin/activate; \
PYTHONPATH=: pylint scripts

$(RECIPES_CLEAN): %:
Expand Down
17 changes: 11 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
docker==6.1.3
python-dateutil==2.8.2
pyelftools==0.29
black==23.7.0
pylint==2.17.5
mypy==1.5.1
mypy-extensions==1.0.0
certifi==2023.7.22
idna==3.4
isort==5.12.0
Jinja2==3.1.2
lazy-object-proxy==1.9.0
mypy-extensions==1.0.0
mypy==1.7.1
pylint==3.0.3
six==1.16.0
toltecmk==0.3.2
toml==0.10.2
types-python-dateutil==2.8.19.14
types-requests==2.31.0.2
typing-extensions==4.7.1
websocket-client==1.6.1

# Pinned due to https://github.com/docker/docker-py/issues/3256
requests==2.31.0
File renamed without changes.
File renamed without changes.
File renamed without changes.
132 changes: 54 additions & 78 deletions scripts/toltec/repo.py → scripts/build/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,36 @@
"""
Build the package repository.
"""

from datetime import datetime
import gzip
from enum import Enum, auto
import logging
import os
import pathlib
import shutil
import textwrap
from typing import Dict, Iterable, List, Optional, Set

from datetime import datetime
from enum import auto
from enum import Enum
Jayy001 marked this conversation as resolved.
Show resolved Hide resolved
from typing import (
Dict,
Iterable,
List,
Optional,
)

import requests
from jinja2 import (
Environment,
FileSystemLoader,
)
from toltec import parse_recipe # type: ignore
from toltec.recipe import (
Package, # type: ignore
Recipe, # type: ignore
)
from toltec.util import HTTP_DATE_FORMAT # type: ignore
from toltec.version import DependencyKind # type: ignore

from .graphlib import TopologicalSorter
from .recipe import GenericRecipe, Package
from .util import file_sha256, group_by, HTTP_DATE_FORMAT
from .version import DependencyKind
from . import templating
from .util import group_by

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -56,10 +71,15 @@ def __init__(self, recipe_dir: str, repo_dir: str) -> None:
self.repo_dir = repo_dir
self.generic_recipes = {}

for entry in os.scandir(self.recipe_dir):
if entry.is_dir():
self.generic_recipes[entry.name] = GenericRecipe.from_file(
entry.path
for name in os.listdir(self.recipe_dir):
path = pathlib.Path(self.recipe_dir) / name
if (
name[0] != "."
and os.path.isdir(path)
and os.path.exists(path / "package")
):
self.generic_recipes[name] = parse_recipe(
os.path.join(self.recipe_dir, name)
)

def fetch_packages(self, remote: Optional[str]) -> GroupedPackages:
Expand All @@ -84,7 +104,7 @@ def fetch_packages(self, remote: Optional[str]) -> GroupedPackages:
fetched_generic = {}
missing_generic = {}

for arch, recipe in generic_recipe.recipes.items():
for arch, recipe in generic_recipe.items():
fetched_arch = []
missing_arch = []

Expand All @@ -97,7 +117,7 @@ def fetch_packages(self, remote: Optional[str]) -> GroupedPackages:
logger.info(
"Package %s (%s) is missing",
package.pkgid(),
recipe.name,
os.path.basename(recipe.path),
)
missing_arch.append(package)

Expand All @@ -115,9 +135,7 @@ def fetch_packages(self, remote: Optional[str]) -> GroupedPackages:

return results

def fetch_package(
self, package: Package, remote: Optional[str]
) -> PackageStatus:
def fetch_package(self, package: Package, remote: Optional[str]) -> PackageStatus:
"""
Check if a package exists locally and fetch it otherwise.

Expand Down Expand Up @@ -160,8 +178,8 @@ def fetch_package(

def order_dependencies(
self,
generic_recipes: List[GenericRecipe],
) -> Iterable[GenericRecipe]:
generic_recipes: List[Dict[str, Recipe]],
) -> Iterable[dict[str, Recipe]]:
"""
Order a list of recipes so that all recipes that a recipe needs
come before that recipe in the list.
Expand All @@ -177,79 +195,32 @@ def order_dependencies(
parent_recipes = {}

for generic_recipe in generic_recipes:
for recipe in generic_recipe.recipes.values():
for package in recipe.packages.values():
parent_recipes[package.name] = generic_recipe.name
for recipe in generic_recipe.values():
for package in recipe.packages.values(): # type: ignore
parent_recipes[package.name] = os.path.basename(recipe.path)

for generic_recipe in generic_recipes:
deps = []

for recipe in generic_recipe.recipes.values():
for dep in recipe.makedepends:
for recipe in generic_recipe.values():
deps = []
for dep in recipe.makedepends: # type: ignore
if (
dep.kind == DependencyKind.Host
dep.kind == DependencyKind.HOST
and dep.package in parent_recipes
):
deps.append(parent_recipes[dep.package])

toposort.add(generic_recipe.name, *deps)
toposort.add(os.path.basename(recipe.path), *deps)

return [self.generic_recipes[name] for name in toposort.static_order()]

def make_index(self) -> None:
"""Generate index files for all the packages in the repo."""
logger.info("Generating package indices")

# Gather all available architectures
archs: Set[str] = set()
for generic_recipe in self.generic_recipes.values():
archs.update(generic_recipe.recipes.keys())

# Generate one index per architecture
for arch in archs:
arch_dir = os.path.join(self.repo_dir, arch)
os.makedirs(arch_dir, exist_ok=True)

index_path = os.path.join(arch_dir, "Packages")
index_gzip_path = os.path.join(arch_dir, "Packages.gz")

# pylint: disable-next=unspecified-encoding
with open(index_path, "w") as index_file:
with gzip.open(index_gzip_path, "wt") as index_gzip_file:
for generic_recipe in self.generic_recipes.values():
if not arch in generic_recipe.recipes:
continue

recipe = generic_recipe.recipes[arch]

for package in recipe.packages.values():
filename = package.filename()
local_path = os.path.join(self.repo_dir, filename)

if not os.path.isfile(local_path):
continue

control = package.control_fields()
control += textwrap.dedent(
f"""\
Filename: {os.path.basename(filename)}
SHA256sum: {file_sha256(local_path)}
Size: {os.path.getsize(local_path)}

"""
)

index_file.write(control)
index_gzip_file.write(control)

def make_listing(self) -> None:
"""Generate the static web listing for packages in the repo."""
logger.info("Generating web listing")

packages = [
package
for generic_recipe in self.generic_recipes.values()
for recipe in generic_recipe.recipes.values()
for recipe in generic_recipe.values()
for package in recipe.packages.values()
]

Expand All @@ -262,7 +233,12 @@ def make_listing(self) -> None:
}

listing_path = os.path.join(self.repo_dir, "index.html")
template = templating.env.get_template("listing.html")
template = Environment(
loader=FileSystemLoader(
pathlib.Path(__file__).parent.resolve() / ".." / "templates"
),
autoescape=True,
).get_template("listing.html")

# pylint: disable-next=unspecified-encoding
with open(listing_path, "w") as listing_file:
Expand Down
44 changes: 44 additions & 0 deletions scripts/build/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (c) 2021 The Toltec Contributors
# SPDX-License-Identifier: MIT
"""Collection of useful functions."""

import itertools
from typing import (
Any,
Callable,
Dict,
List,
Protocol,
Sequence,
TypeVar,
)


# See <https://github.com/python/typing/issues/760>
class SupportsLessThan(Protocol): # pylint:disable=too-few-public-methods
"""Types that support the less-than operator."""

def __lt__(self, other: Any) -> bool:
...


Key = TypeVar("Key", bound=SupportsLessThan)
Value = TypeVar("Value")


def group_by(
in_seq: Sequence[Value], key_fn: Callable[[Value], Key]
) -> Dict[Key, List[Value]]:
"""
Group elements of a list.

:param in_seq: list of elements to group
:param key_fn: mapping of each element onto a group
:returns: dictionary of groups
"""
return dict(
(key, list(group))
for key, group in itertools.groupby(
sorted(in_seq, key=key_fn), key=key_fn
)
)
Loading
Loading