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

Add support for using artifacts from another Job #185

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,8 @@ Options available in `builder.yml`:
- `packages: bool` --- Component that generate packages (default: True). If set to False (e.g. `builder-rpm`), no `.qubesbuilder` file is allowed.
- `verification-mode: str` --- component source code verification mode, supported values are: `signed-tag` (this is default), `less-secure-signed-commits-sufficient`, `insecure-skip-checking`. This option takes precedence over top level `less-secure-signed-commits-sufficient`.
- `stages: List[Dict]` --- Allow to override stages options.
- `distribution_name: List[Dict]` -- Allow to override per distribution, stages options.
- `package_set: List[Dict]` -- Allow to override per distribution package set, stages options.
- `distribution_name: List[Dict]` -- Allow to override per distribution, stages options or to provides dependencies.
- `package_set: List[Dict]` -- Allow to override per distribution package set, stages options.

- `templates: List[Dict]` -- List of templates you want to build. See example configs for sensible lists.
- `<template_name>`: --- Template name.
Expand Down Expand Up @@ -859,3 +859,34 @@ For the `fetch` stage, the Qubes executor with disposable template `qubes-builde
For the `build` stage of `vm-fc42`, the Podman executor with container image `fedoraimg` will be used.
For the `sign` stage, the Qubes executor with disposable template `signing-access-dvm` will be used for both `vm-fc42` and `vm-jammy`
For the `prep` stage of `vm-jammy`, the Local executor with base directory `/some/path` will be used.

### Cross-compile Build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, cross-compile is something else, like building ARM binaries on X86. Better use different term, like cross-distribution dependencies


To perform cross-compilation between distributions, you must declare dependencies using the `needs: List[Dict]` structure within the appropriate distribution stage.
Each dependency is represented as a dictionary with the following keys:

- `component: str` --- The name of the component. This value is not limited to the top-level component reference; it can reference any available component.
- `distribution: str` --- The name of the target distribution.
- `stage: str` --- The stage name for which the dependency is required.
- `build: str` --- The build reference as provided in a `.qubesbuilder` file.

For example:

```yaml
components:
- installer-qubes-os:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

installer-qubes-os-windows-tools? (and below too)

host-fc41:
stages:
- build:
needs:
- component: installer-qubes-os
distribution: vm-win10
stage: build
build: vs2022/installer.sln
- component: installer-qubes-os
distribution: vm-win10
stage: sign
build: vs2022/installer.sln
```

This example shows how to specify multiple dependencies for different stages (build and sign) under a given distribution.
57 changes: 57 additions & 0 deletions qubesbuilder/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
DistributionComponentPlugin,
ComponentPlugin,
TemplatePlugin,
JobReference,
JobDependency,
)
from qubesbuilder.template import QubesTemplate

Expand Down Expand Up @@ -611,6 +613,56 @@
def get_plugin_manager(self):
return PluginManager(self.get_plugins_dirs())

def get_needs(
self,
component: QubesComponent,
dist: QubesDistribution,
stage_name: str,
):
needs = []
stages = component.kwargs.get(dist.distribution, {}).get("stages", [])
for stage in stages:
if (

Check warning on line 625 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L625

Added line #L625 was not covered by tests
isinstance(stage, dict)
and next(iter(stage)) == stage_name
and isinstance(stage[stage_name], dict)
Comment on lines +625 to +628
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least some of this not matching should show a warning or even error. Otherwise it will be hard to find why it doesn't work if you make a typo (like extra - making it a list instead of dict).

):
for need in stage[stage_name].get("needs", []):
if all(

Check warning on line 631 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L630-L631

Added lines #L630 - L631 were not covered by tests
[
need.get("component", None),
need.get("distribution", None),
need.get("stage", None),
need.get("build", None),
]
Comment on lines +631 to +637
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and same here - if some part is missing, at least log a warning why it's ignored

):
filtered_components = self.get_components(

Check warning on line 639 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L639

Added line #L639 was not covered by tests
[need["component"]]
)
if not filtered_components:
raise ConfigError(

Check warning on line 643 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L642-L643

Added lines #L642 - L643 were not covered by tests
f"Cannot find dependency component name '{need["component"]}'."
)
filtered_distributions = self.get_distributions(

Check warning on line 646 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L646

Added line #L646 was not covered by tests
[need["distribution"]]
)
if not filtered_distributions:
raise ConfigError(

Check warning on line 650 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L649-L650

Added lines #L649 - L650 were not covered by tests
f"Cannot find dependency distribution name '{need["distribution"]}'."
)
needs.append(

Check warning on line 653 in qubesbuilder/config.py

View check run for this annotation

Codecov / codecov/patch

qubesbuilder/config.py#L653

Added line #L653 was not covered by tests
JobDependency(
JobReference(
component=filtered_components[0],
dist=filtered_distributions[0],
stage=need["stage"],
template=None,
build=need["build"],
)
)
)
return needs

def get_jobs(
self,
components: List[QubesComponent],
Expand Down Expand Up @@ -638,6 +690,11 @@
)
if not job:
continue
job.dependencies += self.get_needs(
component=component,
dist=distribution,
stage_name=stage,
)
jobs.append(job)

# ComponentPlugin
Expand Down
4 changes: 4 additions & 0 deletions qubesbuilder/executors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ def get_repository_dir(self):
def get_cache_dir(self):
return self.get_builder_dir() / "cache"

def get_dependencies_dir(self):
return self.get_builder_dir() / "dependencies"

@abstractmethod
def copy_in(self, *args, **kwargs):
pass
Expand All @@ -102,6 +105,7 @@ def get_placeholders(self):
"@BUILD_DIR@": self.get_build_dir(),
"@PLUGINS_DIR@": self.get_plugins_dir(),
"@DISTFILES_DIR@": self.get_distfiles_dir(),
"@DEPENDENCIES_DIR@": self.get_dependencies_dir(),
}

def replace_placeholders(self, s: str):
Expand Down
10 changes: 10 additions & 0 deletions qubesbuilder/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,16 @@ def default_copy_in(self, plugins_dir: Path, sources_dir: Path):
sources_dir,
)
)
if dependency.builder_object == "job":
artifact_path = get_artifact_path(
self.config, dependency.reference
)
for artifact in artifact_path.parent.iterdir():
if artifact == artifact_path:
continue
copy_in.append(
(artifact, self.executor.get_dependencies_dir())
)
Comment on lines +334 to +336
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should they all be copied together, or maybe better in separate subdirs? what if file names conflict (for example you declare QWT use vm-win10 and vm-win11 if that would exist)?

return copy_in


Expand Down