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

Allow use actions/config/metadata in charmcraft.yaml #1126

Merged
merged 7 commits into from
Jul 7, 2023
Merged
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
21 changes: 12 additions & 9 deletions charmcraft/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import charmcraft.parts
import charmcraft.providers
import charmcraft.instrum
from charmcraft.metafiles.metadata import parse_metadata_yaml
from charmcraft.metafiles.actions import create_actions
from charmcraft.metafiles.config import create_config_yaml
from charmcraft.metafiles.actions import create_actions_yaml
from charmcraft.metafiles.manifest import create_manifest
from charmcraft.const import (
BUILD_DIRNAME,
Expand All @@ -42,6 +42,7 @@
VENV_DIRNAME,
UBUNTU_LTS_STABLE,
)
from charmcraft.metafiles.metadata import create_metadata_yaml
from charmcraft.commands.store.charmlibs import collect_charmlib_pydeps
from charmcraft.models.charmcraft import Base, BasesConfiguration
from charmcraft.parts import Step
Expand Down Expand Up @@ -93,7 +94,6 @@ def __init__(self, *, config, force, debug, shell, shell_after, measure):
self.charmdir = config.project.dirpath
self.buildpath = self.charmdir / BUILD_DIRNAME
self.config = config
self.metadata = parse_metadata_yaml(self.charmdir)
self._parts = self.config.parts.copy()

# a part named "charm" using plugin "charm" is special and has
Expand Down Expand Up @@ -170,17 +170,20 @@ def build_charm(self, bases_config: BasesConfiguration) -> str:
self._parts,
work_dir=work_dir,
project_dir=self.charmdir,
project_name=self.metadata.name,
project_name=self.config.name,
ignore_local_sources=["*.charm"],
)
with charmcraft.instrum.Timer("Lifecycle run"):
lifecycle.run(Step.PRIME)

create_actions_yaml(lifecycle.prime_dir, self.config)
create_config_yaml(lifecycle.prime_dir, self.config)
create_metadata_yaml(lifecycle.prime_dir, self.config)

# run linters and show the results
linting_results = charmcraft.linters.analyze(self.config, lifecycle.prime_dir)
self.show_linting_results(linting_results)

create_actions(lifecycle.prime_dir, self.config.actions)
create_manifest(
lifecycle.prime_dir,
self.config.project.started_at,
Expand Down Expand Up @@ -295,7 +298,7 @@ def pack_charm_in_instance(
self, *, bases_index: int, build_on: Base, build_on_index: int
) -> str:
"""Pack instance in Charm."""
charm_name = format_charm_file_name(self.metadata.name, self.config.bases[bases_index])
charm_name = format_charm_file_name(self.config.name, self.config.bases[bases_index])

# If building in project directory, use the project path as the working
# directory. The output charms will be placed in the correct directory
Expand Down Expand Up @@ -338,7 +341,7 @@ def pack_charm_in_instance(
instance_name = charmcraft.providers.get_instance_name(
bases_index=bases_index,
build_on_index=build_on_index,
project_name=self.metadata.name,
project_name=self.config.name,
project_path=self.charmdir,
target_arch=get_host_architecture(),
)
Expand All @@ -363,7 +366,7 @@ def pack_charm_in_instance(
)

with self.provider.launched_environment(
project_name=self.metadata.name,
project_name=self.config.name,
project_path=self.charmdir,
base_configuration=base_configuration,
instance_name=instance_name,
Expand Down Expand Up @@ -407,7 +410,7 @@ def pack_charm_in_instance(
def handle_package(self, prime_dir, bases_config: BasesConfiguration):
"""Handle the final package creation."""
emit.progress("Creating the package itself")
zipname = format_charm_file_name(self.metadata.name, bases_config)
zipname = format_charm_file_name(self.config.name, bases_config)
zipfh = zipfile.ZipFile(zipname, "w", zipfile.ZIP_DEFLATED)
for dirpath, dirnames, filenames in os.walk(prime_dir, followlinks=True):
dirpath = pathlib.Path(dirpath)
Expand Down
8 changes: 3 additions & 5 deletions charmcraft/commands/clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

from charmcraft import providers
from charmcraft.cmdbase import BaseCommand
from charmcraft.metafiles.metadata import parse_metadata_yaml
from charmcraft.utils import get_host_architecture

_overview = """
Expand All @@ -47,8 +46,7 @@ def run(self, parsed_args):
"""
self._check_config(config_file=True, bases=True)
project_path = self.config.project.dirpath
metadata = parse_metadata_yaml(project_path)
emit.message(f"Cleaning project {metadata.name!r}.")
emit.message(f"Cleaning project {self.config.name!r}.")
provider = providers.get_provider()
build_plan = providers.create_build_plan(
bases=self.config.bases,
Expand All @@ -60,7 +58,7 @@ def run(self, parsed_args):

for plan in build_plan:
instance_name = providers.get_instance_name(
project_name=metadata.name,
project_name=self.config.name,
project_path=project_path,
bases_index=plan.bases_index,
build_on_index=plan.build_on_index,
Expand All @@ -70,4 +68,4 @@ def run(self, parsed_args):
emit.debug(f"Cleaning environment {instance_name!r}")
provider.clean_project_environments(instance_name=instance_name)

emit.message(f"Cleaned project {metadata.name!r}.")
emit.message(f"Cleaned project {self.config.name!r}.")
2 changes: 0 additions & 2 deletions charmcraft/commands/pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
from charmcraft.cmdbase import BaseCommand
from charmcraft.commands import build
from charmcraft.errors import DuplicateCharmsError
from charmcraft.metafiles.actions import create_actions
from charmcraft.metafiles.manifest import create_manifest
from charmcraft.parts import Step
from charmcraft.utils import (
Expand Down Expand Up @@ -310,7 +309,6 @@ def _pack_bundle(
raise

# pack everything
create_actions(lifecycle.prime_dir, self.config.actions)
create_manifest(lifecycle.prime_dir, project.started_at, None, [])
zipname = project.dirpath / (bundle_name + ".zip")
if overwrite_bundle:
Expand Down
4 changes: 2 additions & 2 deletions charmcraft/commands/store/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -999,10 +999,10 @@ def run(self, parsed_args: "Namespace") -> None:
emit.debug(f"Error when running PRIME step: {error}")
raise

from charmcraft.metafiles.actions import create_actions
from charmcraft.metafiles.metadata import create_metadata_yaml
lengau marked this conversation as resolved.
Show resolved Hide resolved
from charmcraft.metafiles.manifest import create_manifest

create_actions(lifecycle.prime_dir, self.config.actions)
create_metadata_yaml(lifecycle.prime_dir, self.config)
create_manifest(lifecycle.prime_dir, self.config.project.started_at, None, [])
zipname = bundle_dir_path / (bundle_name + ".zip")
build_zip(zipname, lifecycle.prime_dir)
Expand Down
3 changes: 3 additions & 0 deletions charmcraft/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ def load(dirpath: Optional[str]) -> CharmcraftConfig:
config_provided=False,
started_at=now,
),
name="missing-charm-name",
summary="missing-charm-summary",
description="missing-charm-description",
)

return CharmcraftConfig.unmarshal(
Expand Down
119 changes: 93 additions & 26 deletions charmcraft/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"""Constants used in charmcraft."""

METADATA_FILENAME = "metadata.yaml"
JUJU_ACTIONS_FILENAME = "actions.yaml"
JUJU_CONFIG_FILENAME = "config.yaml"

IMAGE_INFO_ENV_VAR = "CHARMCRAFT_IMAGE_INFO"

WORK_DIRNAME = "work_dir"
Expand All @@ -40,34 +43,98 @@
"""

# The minimum set of hooks to be provided for compatibility with old Juju
MANDATORY_HOOK_NAMES = {"install", "start", "upgrade-charm"}
MANDATORY_HOOK_NAMES = frozenset(("install", "start", "upgrade-charm"))
HOOKS_DIRNAME = "hooks"

# The minimum set of files for a charm to be considered valid
CHARM_FILES = [
METADATA_FILENAME,
DISPATCH_FILENAME,
HOOKS_DIRNAME,
]
CHARM_FILES = frozenset(
Copy link
Collaborator

Choose a reason for hiding this comment

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

❤️

Copy link
Contributor Author

@syu-w syu-w Jul 7, 2023

Choose a reason for hiding this comment

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

The only downside is some tests are order sensitive when this changed to unordered, had to add a workaround.

(
DISPATCH_FILENAME,
HOOKS_DIRNAME,
)
)

# Optional files that can be present in a charm
CHARM_OPTIONAL = [
"config.yaml",
"metrics.yaml",
"actions.yaml",
"lxd-profile.yaml",
"templates",
"version",
"lib",
"mod",
"LICENSE",
"icon.svg",
"README.md",
"actions",
]

UBUNTU_LTS_STABLE = {
"18.04",
"20.04",
"22.04",
}
CHARM_OPTIONAL = frozenset(
(
METADATA_FILENAME,
JUJU_ACTIONS_FILENAME,
JUJU_CONFIG_FILENAME,
"metrics.yaml",
"lxd-profile.yaml",
"templates",
"version",
"lib",
"mod",
"LICENSE",
"icon.svg",
"README.md",
"actions",
)
)

UBUNTU_LTS_STABLE = frozenset(
(
"18.04",
"20.04",
"22.04",
)
)

# Metadata keys that are defined in the metadata.yaml file, for backwards compatible
CHARM_METADATA_LEGACY_KEYS = frozenset(
(
"assumes",
"containers",
"description",
"devices",
"display-name",
"docs",
"extra-bindings",
"issues",
"maintainers",
"name",
"peers",
"provides",
"requires",
"resources",
"series",
"storage",
"subordinate",
"summary",
"terms",
"website",
)
)

CHARM_METADATA_LEGARY_KEYS_ALIAS = frozenset(
(
"display_name",
"extra_bindings",
)
)

# Metadata keys that are allowed in the charmcraft.yaml file
CHARM_METADATA_KEYS = frozenset(
(
"assumes",
"containers",
"description",
"devices",
"title",
"documentation",
"extra-bindings",
"links",
"name",
"peers",
"provides",
"requires",
"resources",
"storage",
"subordinate",
"summary",
"terms",
)
)

CHARM_METADATA_KEYS_ALIAS = frozenset(("extra_bindings",))
4 changes: 2 additions & 2 deletions charmcraft/linters.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import yaml

from charmcraft import config, utils
from charmcraft.metafiles.metadata import parse_metadata_yaml, read_metadata_yaml
from charmcraft.metafiles.metadata import parse_charm_metadata_yaml, read_metadata_yaml

CheckType = namedtuple("CheckType", "attribute lint")(attribute="attribute", lint="lint")

Expand Down Expand Up @@ -184,7 +184,7 @@ def _check_operator(self, basedir: pathlib.Path) -> bool:
def _check_reactive(self, basedir: pathlib.Path) -> bool:
"""Detect if the Reactive Framework is used."""
try:
metadata = parse_metadata_yaml(basedir)
metadata = parse_charm_metadata_yaml(basedir)
except Exception:
# file not found, corrupted, or mandatory "name" not present
return False
Expand Down
19 changes: 18 additions & 1 deletion charmcraft/metafiles/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,21 @@

"""Submodule for handling the all extra yaml files."""

__all__ = ["actions", "manifest", "metadata"]
import pathlib
from typing import Any, Dict

import yaml

from craft_cli import emit

__all__ = ["actions", "manifest", "metadata", "config", "read_yaml"]


def read_yaml(yaml_file_path: pathlib.Path) -> Dict[str, Any]:
"""Parse yaml file.

:returns: the YAML decoded yaml content
"""
emit.debug(f"Reading {str(yaml_file_path)!r}")
with yaml_file_path.open("rt", encoding="utf8") as fh:
return yaml.safe_load(fh)
Loading
Loading