Craft Parts
Craft Parts is a Python package that provides a reusable and extensible framework for defining, processing, and organizing software components into deployment-ready filesystems. It supports various source types and build plugins, enabling declarative management of complex build processes and dependencies. The library is actively developed by Canonical and is a core component for tools like Snapcraft and Charmcraft, with regular releases.
Common errors
-
InvalidPluginError: The part '<part_name>' didn't define a plugin and the part name is not a valid plugin name.
cause A part in your configuration (`parts.yaml` or `Part` object) either omits the `plugin` property or specifies a plugin name that doesn't exist or isn't recognized.fixEnsure every part has a `plugin` property set to a valid, installed plugin name (e.g., `python`, `nil`, `dump`, `autotools`). Check the documentation for available plugins. Example: `plugin: python` or `plugin: dump`. -
PluginBuildFailedError: Plugin build script for part '<part_name>' failed at runtime.
cause The build commands executed by the specified plugin for the part returned a non-zero exit code, indicating a build failure. This often points to issues in your project's `configure`, `make`, `install` steps or `override-build` script.fixExamine the detailed output/stderr from the build step for specific errors (e.g., missing dependencies, compilation errors). Debug your build script locally within a similar environment. Adjust your part's `build-packages` or `override-build` properties. -
OverlayPackageInstallationError: Failed to install an overlay package '<package_name>'.
cause A package listed in `build-packages` or `stage-packages` could not be installed in the isolated environment, often due to a typo in the package name, an unavailable package in the distribution, or network issues preventing package downloads.fixVerify the package name is correct and available for your target distribution. Check network connectivity. For `build-packages`, ensure your environment has access to the necessary repositories. -
FailedToCopyError: Failed to copy or link a file tree from '<source_path>' to '<destination_path>'.
cause An operation attempting to copy or link files (e.g., during `pull`, `stage`, or `prime` steps) failed because the source file/directory was not found, or there was a permissions issue at the destination.fixConfirm that the `source` specified for the part points to an existing file or directory. Check paths referenced in `organize` or `prime` properties. Ensure file system permissions allow `craft-parts` to write to the target directories.
Warnings
- gotcha Understanding the part lifecycle (pull, overlay, build, stage, prime) is crucial. Misconfiguring `source`, `build-packages`, `stage-packages`, or `prime` properties can lead to unexpected build outputs or missing files in the final artifact.
- gotcha When developing custom plugins or overriding build steps, ensure correct environment variable propagation and command execution within the isolated build environments. Pathing issues are common.
- gotcha The `dump` plugin simply copies source files. If your part requires compilation or complex build steps, you must specify an appropriate plugin (e.g., `autotools`, `cmake`, `poetry`, `go`) or provide `override-build` instructions.
Install
-
pip install craft-parts
Imports
- LifecycleManager
from craft_parts.lifecycle import LifecycleManager
- Part
from craft_parts.models import Part
- plugins
from craft_parts import plugins
- PartInfo
from craft_parts.models import PartInfo
Quickstart
import os
import pathlib
from craft_parts.models import PartSpec, Part
from craft_parts.lifecycle import LifecycleManager, Step
# Create a dummy project directory
project_dir = pathlib.Path('./my-craft-project')
project_dir.mkdir(exist_ok=True)
# Create a simple parts.yaml content
parts_yaml_content = '''
parts:
hello:
plugin: dump
source: hello.txt
'''
(project_dir / 'parts.yaml').write_text(parts_yaml_content)
(project_dir / 'hello.txt').write_text('Hello from Craft Parts!')
# Define the part specification programmatically
part_spec = PartSpec(
name="hello",
part=Part(
plugin="dump",
source="hello.txt"
)
)
# Initialize LifecycleManager
lcm = LifecycleManager(
parts={part_spec.name: part_spec.part},
application_name="my-craft-app",
project_dir=project_dir,
build_dir=project_dir / 'build',
stage_dir=project_dir / 'stage',
prime_dir=project_dir / 'prime',
cache_dir=project_dir / '.cache'
)
# Plan and execute the full lifecycle
actions = lcm.plan(Step.PRIME)
with lcm.action_executor() as aex:
aex.execute(actions)
print(f"Project built to: {project_dir / 'prime'}")
print(f"Content of staged file: {(project_dir / 'prime' / 'hello.txt').read_text()}")