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

refactor(store): use dataclasses for store models #1299

Merged
merged 1 commit into from
Sep 29, 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
6 changes: 4 additions & 2 deletions charmcraft/commands/store/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

"""Commands related to Charmhub."""
import collections
import dataclasses
import os
import pathlib
import shutil
Expand Down Expand Up @@ -1552,7 +1553,7 @@ def run(self, parsed_args):
if lib_data.lib_id is None:
for tip in libs_tips.values():
if lib_data.charm_name == tip.charm_name and lib_data.lib_name == tip.lib_name:
lib_data = lib_data._replace(lib_id=tip.lib_id)
lib_data = dataclasses.replace(lib_data, lib_id=tip.lib_id)
break

tip = libs_tips.get((lib_data.lib_id, lib_data.api))
Expand Down Expand Up @@ -1604,7 +1605,8 @@ def run(self, parsed_args):

# fix lib_data with new info so it's later available
# for the case of programmatic output
lib_data = lib_data._replace(
lib_data = dataclasses.replace(
lib_data,
patch=downloaded.patch,
content=downloaded.content,
content_hash=downloaded.content_hash,
Expand Down
23 changes: 16 additions & 7 deletions charmcraft/commands/store/charmlibs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import hashlib
import os
import pathlib
from collections import namedtuple
from dataclasses import dataclass
from typing import List, Optional, Set

Expand All @@ -29,10 +28,20 @@

from charmcraft.errors import BadLibraryNameError, BadLibraryPathError

LibData = namedtuple(
"LibData",
"lib_id api patch content content_hash full_name path lib_name charm_name",
)

@dataclass(frozen=True)
class LibData:
lengau marked this conversation as resolved.
Show resolved Hide resolved
"""All data fields for a library, including external ones."""

lib_id: Optional[str]
api: int
patch: int
content: Optional[str]
content_hash: Optional[str]
full_name: str
path: pathlib.Path
lib_name: str
charm_name: str


@dataclass
Expand All @@ -42,9 +51,9 @@ class LibInternals:
lib_id: str
api: int
patch: int
pydeps: list
pydeps: List[str]
content_hash: str
content: bytes
content: str
lengau marked this conversation as resolved.
Show resolved Hide resolved


def get_name_from_metadata() -> Optional[str]:
Expand Down
203 changes: 186 additions & 17 deletions charmcraft/commands/store/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
# For further info, check https://github.com/canonical/charmcraft

"""The Store API handling."""

import dataclasses
import datetime
import os
import platform
import time
from collections import namedtuple
from functools import wraps
from typing import Any, Dict, List, Tuple
from typing import Any, Dict, List, Literal, Optional, Tuple

import craft_store
from craft_cli import CraftError, emit
Expand All @@ -35,24 +35,193 @@
Client,
)


# helpers to build responses from this layer
Account = namedtuple("Account", "name username id")
Package = namedtuple("Package", "id name type")
MacaroonInfo = namedtuple("MacaroonInfo", "account channels packages permissions")
Entity = namedtuple("Charm", "entity_type name private status publisher_display_name")
Uploaded = namedtuple("Uploaded", "ok status revision errors")
@dataclasses.dataclass(frozen=True)
class Account:
"""Charmcraft-specific store account model.

Deprecated in favour of implementation in craft-store.
"""

name: str
username: str
id: str


@dataclasses.dataclass(frozen=True)
class Package:
"""Charmcraft-specific store package model.

Deprecated in favour of implementation in craft-store.
"""

id: Optional[str]
name: str
type: Literal["charm", "bundle"]


@dataclasses.dataclass(frozen=True)
class MacaroonInfo:
"""Charmcraft-specific macaroon information model.

Deprecated in favour of implementation in craft-store.
"""

account: Account
channels: Optional[List[str]]
packages: Optional[List[Package]]
permissions: List[str]


@dataclasses.dataclass(frozen=True)
class Entity:
"""Charmcraft-specific store entity model.

Deprecated in favour of implementation in craft-store.
"""

entity_type: Literal["charm", "bundle"]
name: str
private: bool
status: str
publisher_display_name: str


@dataclasses.dataclass(frozen=True)
class Error:
"""Charmcraft-specific store error model.

Deprecated in favour of implementation in craft-store.
"""

message: str
code: str


@dataclasses.dataclass(frozen=True)
class Uploaded:
"""Charmcraft-specific store upload result model.

Deprecated in favour of implementation in craft-store.
"""

ok: bool
status: int
revision: int
errors: List[Error]


# XXX Facundo 2020-07-23: Need to do a massive rename to call `revno` to the "revision as
# the number" inside the "revision as the structure", this gets super confusing in the code with
# time, and now it's the moment to do it (also in Release below!)
Revision = namedtuple("Revision", "revision version created_at status errors bases")
Error = namedtuple("Error", "message code")
Release = namedtuple("Release", "revision channel expires_at resources base")
Channel = namedtuple("Channel", "name fallback track risk branch")
Library = namedtuple("Library", "api content content_hash lib_id lib_name charm_name patch")
Resource = namedtuple("Resource", "name optional revision resource_type")
ResourceRevision = namedtuple("ResourceRevision", "revision created_at size")
RegistryCredentials = namedtuple("RegistryCredentials", "image_name username password")
Base = namedtuple("Base", "architecture channel name")
@dataclasses.dataclass(frozen=True)
class Base:
"""Charmcraft-specific store object base model.

Deprecated in favour of implementation in craft-store.
"""

architecture: str
channel: str
name: str


@dataclasses.dataclass(frozen=True)
class Revision:
"""Charmcraft-specific store name revision model.

Deprecated in favour of implementation in craft-store.
"""

revision: int
version: Optional
created_at: datetime.datetime
status: str
errors: List[Error]
bases: List[Base]


@dataclasses.dataclass(frozen=True)
class Resource:
"""Charmcraft-specific store name resource model.

Deprecated in favour of implementation in craft-store.
"""

name: str
optional: bool
revision: int
resource_type: str


@dataclasses.dataclass(frozen=True)
class ResourceRevision:
"""Charmcraft-specific store resource revision model.

Deprecated in favour of implementation in craft-store.
"""

revision: int
created_at: datetime.datetime
size: int


@dataclasses.dataclass(frozen=True)
class Release:
"""Charmcraft-specific store release model.

Deprecated in favour of implementation in craft-store.
"""

revision: int
channel: str
expires_at: datetime.datetime
resources: List[Resource]
base: Base


@dataclasses.dataclass(frozen=True)
class Channel:
"""Charmcraft-specific store channel model.

Deprecated in favour of implementation in craft-store.
"""

name: str
fallback: str
track: str
risk: str
branch: str


@dataclasses.dataclass(frozen=True)
class Library:
lengau marked this conversation as resolved.
Show resolved Hide resolved
"""Charmcraft-specific store library model.

Deprecated in favour of implementation in craft-store.
"""

lib_id: str
lib_name: str
charm_name: str
api: int
patch: int
content: Optional[str]
content_hash: str


@dataclasses.dataclass(frozen=True)
class RegistryCredentials:
"""Charmcraft-specific store registry credential model.

Deprecated in favour of implementation in craft-store.
"""

image_name: str
username: str
password: str


# those statuses after upload that flag that the review ended (and if it ended successfully or not)
UPLOAD_ENDING_STATUSES = {
Expand Down