Skip to content

Commit

Permalink
add dockhub
Browse files Browse the repository at this point in the history
  • Loading branch information
zoumingzhe committed Sep 4, 2024
1 parent 7897fa9 commit ac9ac74
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,7 @@ jobs:
- name: List all images
run: docker image ls

- name: List docker hub image all tags
run: |
dockhub tags list --stdout --debug library/nginx
2 changes: 1 addition & 1 deletion dockloader/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from urllib.parse import urljoin

__project__ = "dockloader"
__version__ = "0.2.alpha.1"
__version__ = "0.2.alpha.2"
__description__ = "Docker Image Downloader."
__url_home__ = "https://github.com/podboy/dockloader/"
__url_code__ = __url_home__
Expand Down
33 changes: 33 additions & 0 deletions dockloader/dockhub/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# coding:utf-8

from typing import Optional
from typing import Sequence

from xarg import add_command
from xarg import argp
from xarg import commands
from xarg import run_command

from ..attribute import __url_home__
from ..attribute import __version__
from .tags import add_cmd_tags


@add_command("dockhub")
def add_cmd(_arg: argp):
pass


@run_command(add_cmd, add_cmd_tags)
def run_cmd(cmds: commands) -> int:
return 0


def main(argv: Optional[Sequence[str]] = None) -> int:
cmds = commands()
cmds.version = __version__
return cmds.run(
root=add_cmd,
argv=argv,
description="docker hub toolkit",
epilog=f"For more, please visit {__url_home__}.")
36 changes: 36 additions & 0 deletions dockloader/dockhub/tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# coding:utf-8

from xarg import add_command
from xarg import argp
from xarg import commands
from xarg import run_command

from ..utils import DockerHubTags


def add_pos_images(_arg: argp, help: str):
_arg.add_argument(type=str, dest="images", help=help,
nargs="*", default=[], metavar="IMAGE")


@add_command("list", help="list docker hub image all tags")
def add_cmd_list(_arg: argp):
add_pos_images(_arg, "image name")


@run_command(add_cmd_list)
def run_cmd_list(cmds: commands) -> int:
for image in cmds.args.images:
for tag in DockerHubTags.fetch(image).values():
cmds.stdout(tag.name)
return 0


@add_command("tags", help="docker hub image additional name")
def add_cmd_tags(_arg: argp):
pass


@run_command(add_cmd_tags, add_cmd_list)
def run_cmd_tags(cmds: commands) -> int:
return 0
2 changes: 2 additions & 0 deletions dockloader/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# coding:utf-8

from .docker import DockerClient
from .docker_hub import DockerHubTag
from .docker_hub import DockerHubTags
from .tags import Tag
from .tags import TagConfigFile
from .tags import Tags
Expand Down
100 changes: 100 additions & 0 deletions dockloader/utils/docker_hub.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# coding:utf-8

from typing import Any
from typing import Dict
from typing import Tuple

import requests


class DockerHubTag:
class ImageTag:
def __init__(self, data: Dict[str, Any]):
self.__data: Dict[str, Any] = data
self.__architecture: str = data["architecture"]
self.__os: str = data["os"]
self.__digest: str = data["digest"]
self.__size: int = data["size"]

@property
def architecture(self) -> str:
return self.__architecture

@property
def os(self) -> str:
return self.__os

@property
def digest(self) -> str:
return self.__digest

@property
def size(self) -> int:
return self.__size

def __init__(self, data: Dict[str, Any]):
self.__data: Dict[str, Any] = data
self.__name: str = data["name"]
self.__digest: str = data["digest"]
self.__full_size: int = data["full_size"]
self.__image_tags: Tuple[DockerHubTag.ImageTag, ...] = tuple(
DockerHubTag.ImageTag(image) for image in data["images"])

@property
def name(self) -> str:
return self.__name

@property
def digest(self) -> str:
return self.__digest

@property
def full_size(self) -> int:
return self.__full_size

@property
def images(self) -> Tuple["DockerHubTag.ImageTag", ...]:
return self.__image_tags


class DockerHubTags(Dict[str, DockerHubTag]):

def __init__(self, image: str):
self.__image: str = image
super().__init__()

@property
def image(self) -> str:
return self.__image

@classmethod
def fetch(cls, image: str) -> "DockerHubTags":
"""fetch all tags of an image
"""
count: int = 0
tags: DockerHubTags = DockerHubTags(image)
headers: Dict[str, str] = {"Accept": "application/json"}
url: str = f"https://hub.docker.com/v2/repositories/{tags.image}/tags/"

while url:
response = requests.get(url, headers=headers)
if response.status_code != 200:
raise IOError(f"{url} {response.status_code} {response.reason}") # noqa: E501

data = response.json()
for tag_data in data["results"]:
tag = DockerHubTag(tag_data)
tags[tag.name] = tag

_count: int = data["count"]
if count == 0:
count = _count
elif count != _count:
raise ValueError(f"count {_count} != {count}")

url = data["next"]

if count != len(tags):
raise ValueError(f"actual count {len(tags)} != {count}")

return tags
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ python_requires = >=3.10
[options.entry_points]
console_scripts =
dockloader = dockloader.cmds:main
dockhub = dockloader.dockhub:main

0 comments on commit ac9ac74

Please sign in to comment.