Better tagging directory structure (#2228)

This commit is contained in:
Ayaz Salikhov
2025-02-21 12:48:18 +00:00
committed by GitHub
parent 355813e360
commit e815fde31b
45 changed files with 374 additions and 330 deletions

View File

@@ -78,7 +78,7 @@ jobs:
- name: Write tags file 🏷 - name: Write tags file 🏷
run: > run: >
python3 -m tagging.write_tags_file python3 -m tagging.apps.write_tags_file
--registry ${{ env.REGISTRY }} --registry ${{ env.REGISTRY }}
--owner ${{ env.OWNER }} --owner ${{ env.OWNER }}
--short-image-name ${{ inputs.image }} --short-image-name ${{ inputs.image }}
@@ -94,7 +94,7 @@ jobs:
- name: Write manifest and build history file 🏷 - name: Write manifest and build history file 🏷
run: > run: >
python3 -m tagging.write_manifest python3 -m tagging.apps.write_manifest
--registry ${{ env.REGISTRY }} --registry ${{ env.REGISTRY }}
--owner ${{ env.OWNER }} --owner ${{ env.OWNER }}
--short-image-name ${{ inputs.image }} --short-image-name ${{ inputs.image }}

View File

@@ -68,7 +68,7 @@ jobs:
- name: Merge tags for the images 🔀 - name: Merge tags for the images 🔀
if: env.PUSH_TO_REGISTRY == 'true' if: env.PUSH_TO_REGISTRY == 'true'
run: > run: >
python3 -m tagging.merge_tags python3 -m tagging.apps.merge_tags
--short-image-name ${{ inputs.image }} --short-image-name ${{ inputs.image }}
--variant ${{ inputs.variant }} --variant ${{ inputs.variant }}
--tags-dir /tmp/jupyter/tags/ --tags-dir /tmp/jupyter/tags/

View File

@@ -62,7 +62,7 @@ jobs:
path: /tmp/jupyter/tags/ path: /tmp/jupyter/tags/
- name: Apply tags to the loaded image 🏷 - name: Apply tags to the loaded image 🏷
run: > run: >
python3 -m tagging.apply_tags python3 -m tagging.apps.apply_tags
--registry ${{ env.REGISTRY }} --registry ${{ env.REGISTRY }}
--owner ${{ env.OWNER }} --owner ${{ env.OWNER }}
--short-image-name ${{ inputs.image }} --short-image-name ${{ inputs.image }}

View File

@@ -37,12 +37,12 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
repository: ${{ github.repository }}.wiki repository: ${{ github.repository }}.wiki
path: wiki/ path: wiki_src/
- name: Update wiki 🏷 - name: Update wiki 🏷
run: > run: >
python3 -m tagging.update_wiki python3 -m wiki.update_wiki
--wiki-dir wiki/ --wiki-dir wiki_src/
--hist-lines-dir /tmp/jupyter/hist_lines/ --hist-lines-dir /tmp/jupyter/hist_lines/
--manifests-dir /tmp/jupyter/manifests/ --manifests-dir /tmp/jupyter/manifests/
--repository ${{ github.repository }} --repository ${{ github.repository }}

View File

@@ -30,6 +30,7 @@ on:
- "!tagging/README.md" - "!tagging/README.md"
- "tests/**" - "tests/**"
- "!tests/README.md" - "!tests/README.md"
- "wiki/**"
- "requirements-dev.txt" - "requirements-dev.txt"
push: push:
branches: branches:
@@ -50,6 +51,7 @@ on:
- "!tagging/README.md" - "!tagging/README.md"
- "tests/**" - "tests/**"
- "!tests/README.md" - "!tests/README.md"
- "wiki/**"
- "requirements-dev.txt" - "requirements-dev.txt"
workflow_dispatch: workflow_dispatch:

View File

@@ -3,6 +3,12 @@
This changelog only contains breaking and/or significant changes manually introduced to this repository (using Pull Requests). This changelog only contains breaking and/or significant changes manually introduced to this repository (using Pull Requests).
All image manifests can be found in [the wiki](https://github.com/jupyter/docker-stacks/wiki). All image manifests can be found in [the wiki](https://github.com/jupyter/docker-stacks/wiki).
## 2025-02-21
Affected: all images.
- **Non-breaking:**: Better tagging directory structure ([#2228](https://github.com/jupyter/docker-stacks/pull/2228)).
## 2025-02-18 ## 2025-02-18
Affected: all images. Affected: all images.

View File

@@ -78,20 +78,20 @@ linkcheck-docs: ## check broken links
hook/%: VARIANT?=default hook/%: VARIANT?=default
hook/%: ## run post-build hooks for an image hook/%: ## run post-build hooks for an image
python3 -m tagging.write_tags_file \ python3 -m tagging.apps.write_tags_file \
--registry "$(REGISTRY)" \ --registry "$(REGISTRY)" \
--owner "$(OWNER)" \ --owner "$(OWNER)" \
--short-image-name "$(notdir $@)" \ --short-image-name "$(notdir $@)" \
--variant "$(VARIANT)" \ --variant "$(VARIANT)" \
--tags-dir /tmp/jupyter/tags/ --tags-dir /tmp/jupyter/tags/
python3 -m tagging.write_manifest \ python3 -m tagging.apps.write_manifest \
--registry "$(REGISTRY)" \ --registry "$(REGISTRY)" \
--owner "$(OWNER)" \ --owner "$(OWNER)" \
--short-image-name "$(notdir $@)" \ --short-image-name "$(notdir $@)" \
--variant "$(VARIANT)" \ --variant "$(VARIANT)" \
--hist-lines-dir /tmp/jupyter/hist_lines/ \ --hist-lines-dir /tmp/jupyter/hist_lines/ \
--manifests-dir /tmp/jupyter/manifests/ --manifests-dir /tmp/jupyter/manifests/
python3 -m tagging.apply_tags \ python3 -m tagging.apps.apply_tags \
--registry "$(REGISTRY)" \ --registry "$(REGISTRY)" \
--owner "$(OWNER)" \ --owner "$(OWNER)" \
--short-image-name "$(notdir $@)" \ --short-image-name "$(notdir $@)" \

View File

@@ -35,6 +35,7 @@ Table of Contents
:caption: Maintainer Guide :caption: Maintainer Guide
maintaining/new-images-and-packages-policy maintaining/new-images-and-packages-policy
maintaining/tagging
maintaining/tasks maintaining/tasks
.. toctree:: .. toctree::

View File

@@ -0,0 +1,94 @@
# Tagging and manifest creation
The main purpose of the source code in [the `tagging` folder](https://github.com/jupyter/docker-stacks/tree/main/tagging) is to properly write tag files and manifests for single-platform images,
apply these tags, and merge single-platform images into one multi-arch image.
## What is a tag and a manifest
A tag is a label attached to a Docker image identifying specific attributes or versions.
For example, an image `jupyter/base-notebook` with Python 3.10.5 will have a full image name `quay.io/jupyter/base-notebook:python-3.10.5`.
These tags are pushed to our [Quay.io registry](https://quay.io/organization/jupyter).
A manifest is a description of important image attributes written in Markdown format.
For example, we dump all `conda` packages with their versions into the manifest.
## Main principles
- All images are organized in a hierarchical tree.
More info on [image relationships](../using/selecting.md#image-relationships).
- Classes inherit from `TaggerInterface` and `ManifestInterface` to generate tags and manifest pieces by running commands in Docker containers.
- Tags and manifests are reevaluated for each image in the hierarchy since values may change between parent and child images.
- To tag an image and create its manifest, run `make hook/<somestack>` (e.g., `make hook/base-notebook`).
## Utils
### DockerRunner
`DockerRunner` is a helper class to easily run a docker container and execute commands inside this container:
```{literalinclude} tagging_examples/docker_runner.py
:language: py
```
### GitHelper
`GitHelper` methods are run in the current `git` repo and give the information about the last commit hash and commit message:
```{literalinclude} tagging_examples/git_helper.py
:language: py
```
The prefix of commit hash (namely, 12 letters) is used as an image tag to make it easy to inherit from a fixed version of a docker image.
## Taggers and Manifests
### Tagger
`Tagger` is a class that can be run inside a docker container to calculate some tag for an image.
All the taggers are inherited from `TaggerInterface`:
```{literalinclude} ../../tagging/taggers/tagger_interface.py
:language: py
```
So, the `tag_value(container)` method gets a docker container as an input and returns a tag.
`SHATagger` example:
```{literalinclude} ../../tagging/taggers/sha.py
:language: py
```
- `taggers/` subdirectory contains all the taggers.
- `apps/write_tags_file.py`, `apps/apply_tags.py`, and `apps/merge_tags.py` are Python executable used to write tags for an image, apply tags from a file, and create multi-arch images.
### Manifest
`ManifestHeader` is a build manifest header.
It contains the following sections: `Build timestamp`, `Docker image size`, and `Git commit` info.
All the other manifest classes are inherited from `ManifestInterface`:
```{literalinclude} ../../tagging/manifests/manifest_interface.py
:language: py
```
- The `markdown_piece(container)` method returns a piece of markdown file to be used as a part of the build manifest.
`AptPackagesManifest` example:
```{literalinclude} ../../tagging/manifests/apt_packages.py
:language: py
```
- `quoted_output(container, cmd)` simply runs the command inside a container using `DockerRunner.run_simple_command` and wraps it to triple quotes to create a valid markdown piece.
It also adds the command which was run to the markdown piece.
- `manifests/` subdirectory contains all the manifests.
- `apps/write_manifest.py` is a Python executable to create the build manifest and history line for an image.
### Images Hierarchy
All images' dependencies on each other and what taggers and manifest are applicable to them are defined in `hierarchy/images_hierarchy.py`.
`hierarchy/get_taggers_and_manifests.py` defines a function to get the taggers and manifests for a specific image.

View File

@@ -0,0 +1,4 @@
from tagging.utils.docker_runner import DockerRunner
with DockerRunner("ubuntu") as container:
DockerRunner.run_simple_command(container, cmd="env", print_result=True)

View File

@@ -0,0 +1,4 @@
from tagging.utils.git_helper import GitHelper
print("Git hash:", GitHelper.commit_hash())
print("Git message:", GitHelper.commit_message())

View File

@@ -1,126 +1,3 @@
# Docker stacks tagging and manifest creation # Docker stacks tagging and manifest creation
The main purpose of the source code in this folder is to properly tag all the images and to update [build manifests](https://github.com/jupyter/docker-stacks/wiki). Please, refer to the [tagging section of documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/maintaing/tagging.html) to see how tags and manifests are created.
These two processes are closely related, so the source code is widely reused.
A basic example of a tag is a `Python` version tag.
For example, an image `jupyter/base-notebook` with `python 3.10.5` will have a full image name `quay.io/jupyter/base-notebook:python-3.10.5`.
This tag (and all the other tags) are pushed to Quay.io.
Manifest is a description of some important part of the image in a `markdown`.
For example, we dump all the `conda` packages, including their versions.
## Main principles
- All the images are located in a hierarchical tree.
More info on [image relationships](../docs/using/selecting.md#image-relationships).
- We have `tagger` and `manifest` classes, which can be run inside docker containers to obtain tags and build manifest pieces.
- These classes are inherited from the parent image to all the child images.
- Because manifests and tags might change from parent to child, `taggers` and `manifests` are reevaluated on each image.
So, the values are not inherited.
- To tag an image and create a manifest, run `make hook/base-notebook` (or another image of your choice).
## Source code description
In this section, we will briefly describe the source code in this folder and give examples of how to use it.
### DockerRunner
`DockerRunner` is a helper class to easily run a docker container and execute commands inside this container:
```python
from tagging.docker_runner import DockerRunner
with DockerRunner("ubuntu:22.04") as container:
DockerRunner.run_simple_command(container, cmd="env", print_result=True)
```
### GitHelper
`GitHelper` methods are run in the current `git` repo and give the information about the last commit hash and commit message:
```python
from tagging.git_helper import GitHelper
print("Git hash:", GitHelper.commit_hash())
print("Git message:", GitHelper.commit_message())
```
The prefix of commit hash (namely, 12 letters) is used as an image tag to make it easy to inherit from a fixed version of a docker image.
### Tagger
`Tagger` is a class that can be run inside a docker container to calculate some tag for an image.
All the taggers are inherited from `TaggerInterface`:
```python
class TaggerInterface:
"""Common interface for all taggers"""
@staticmethod
def tag_value(container) -> str:
raise NotImplementedError
```
So, the `tag_value(container)` method gets a docker container as an input and returns a tag.
`SHATagger` example:
```python
from tagging.git_helper import GitHelper
from tagging.taggers import TaggerInterface
class SHATagger(TaggerInterface):
@staticmethod
def tag_value(container):
return GitHelper.commit_hash_tag()
```
- `taggers.py` contains all the taggers.
- `tag_image.py` is a Python executable that is used to tag the image.
### Manifest
`ManifestHeader` is a build manifest header.
It contains the following sections: `Build timestamp`, `Docker image size`, and `Git commit` info.
All the other manifest classes are inherited from `ManifestInterface`:
```python
class ManifestInterface:
"""Common interface for all manifests"""
@staticmethod
def markdown_piece(container) -> str:
raise NotImplementedError
```
- The `markdown_piece(container)` method returns a piece of markdown file to be used as a part of the build manifest.
`AptPackagesManifest` example:
```python
from tagging.manifests import ManifestInterface, quoted_output
class AptPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container) -> str:
return f"""\
## Apt Packages
{quoted_output(container, "apt list --installed")}"""
```
- `quoted_output` simply runs the command inside a container using `DockerRunner.run_simple_command` and wraps it to triple quotes to create a valid markdown piece.
It also adds the command which was run to the markdown piece.
- `manifests.py` contains all the manifests.
- `write_manifest.py` is a Python executable that is used to create the build manifest and history line for an image.
### Images Hierarchy
All images' dependencies on each other and what taggers and manifest they make use of are defined in `images_hierarchy.py`.
`get_taggers_and_manifests.py` defines a helper function to get the taggers and manifests for a specific image.

0
tagging/apps/__init__.py Normal file
View File

View File

@@ -6,9 +6,9 @@ from pathlib import Path
import plumbum import plumbum
from tagging.common_arguments import common_arguments_parser from tagging.apps.common_cli_arguments import common_arguments_parser
from tagging.get_platform import unify_aarch64 from tagging.utils.get_platform import unify_aarch64
from tagging.get_prefix import get_file_prefix_for_platform from tagging.utils.get_prefix import get_file_prefix_for_platform
docker = plumbum.local["docker"] docker = plumbum.local["docker"]

View File

@@ -6,9 +6,9 @@ from pathlib import Path
import plumbum import plumbum
from tagging.common_arguments import common_arguments_parser from tagging.apps.common_cli_arguments import common_arguments_parser
from tagging.get_platform import ALL_PLATFORMS from tagging.utils.get_platform import ALL_PLATFORMS
from tagging.get_prefix import get_file_prefix_for_platform from tagging.utils.get_prefix import get_file_prefix_for_platform
docker = plumbum.local["docker"] docker = plumbum.local["docker"]

View File

@@ -7,12 +7,15 @@ from pathlib import Path
from docker.models.containers import Container from docker.models.containers import Container
from tagging.common_arguments import common_arguments_parser from tagging.apps.common_cli_arguments import common_arguments_parser
from tagging.docker_runner import DockerRunner from tagging.hierarchy.get_taggers_and_manifests import (
from tagging.get_prefix import get_file_prefix, get_tag_prefix get_taggers_and_manifests,
from tagging.get_taggers_and_manifests import get_taggers_and_manifests )
from tagging.git_helper import GitHelper from tagging.manifests.header import ManifestHeader
from tagging.manifests import ManifestHeader, ManifestInterface from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.docker_runner import DockerRunner
from tagging.utils.get_prefix import get_file_prefix, get_tag_prefix
from tagging.utils.git_helper import GitHelper
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)

View File

@@ -4,10 +4,12 @@
import logging import logging
from pathlib import Path from pathlib import Path
from tagging.common_arguments import common_arguments_parser from tagging.apps.common_cli_arguments import common_arguments_parser
from tagging.docker_runner import DockerRunner from tagging.hierarchy.get_taggers_and_manifests import (
from tagging.get_prefix import get_file_prefix, get_tag_prefix get_taggers_and_manifests,
from tagging.get_taggers_and_manifests import get_taggers_and_manifests )
from tagging.utils.docker_runner import DockerRunner
from tagging.utils.get_prefix import get_file_prefix, get_tag_prefix
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)

View File

View File

@@ -1,9 +1,9 @@
# Copyright (c) Jupyter Development Team. # Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License. # Distributed under the terms of the Modified BSD License.
from tagging.images_hierarchy import ALL_IMAGES from tagging.hierarchy.images_hierarchy import ALL_IMAGES
from tagging.manifests import ManifestInterface from tagging.manifests.manifest_interface import ManifestInterface
from tagging.taggers import TaggerInterface from tagging.taggers.tagger_interface import TaggerInterface
def get_taggers_and_manifests( def get_taggers_and_manifests(

View File

@@ -2,16 +2,17 @@
# Distributed under the terms of the Modified BSD License. # Distributed under the terms of the Modified BSD License.
from dataclasses import dataclass, field from dataclasses import dataclass, field
from tagging.manifests import ( from tagging.manifests.apt_packages import AptPackagesManifest
AptPackagesManifest, from tagging.manifests.conda_environment import CondaEnvironmentManifest
CondaEnvironmentManifest, from tagging.manifests.julia_packages import JuliaPackagesManifest
JuliaPackagesManifest, from tagging.manifests.manifest_interface import ManifestInterface
ManifestInterface, from tagging.manifests.r_packages import RPackagesManifest
RPackagesManifest, from tagging.manifests.spark_info import SparkInfoManifest
SparkInfoManifest, from tagging.taggers.date import DateTagger
) from tagging.taggers.sha import SHATagger
from tagging.taggers import ( from tagging.taggers.tagger_interface import TaggerInterface
DateTagger, from tagging.taggers.ubuntu_version import UbuntuVersionTagger
from tagging.taggers.versions import (
JavaVersionTagger, JavaVersionTagger,
JuliaVersionTagger, JuliaVersionTagger,
JupyterHubVersionTagger, JupyterHubVersionTagger,
@@ -21,11 +22,8 @@ from tagging.taggers import (
PythonVersionTagger, PythonVersionTagger,
PytorchVersionTagger, PytorchVersionTagger,
RVersionTagger, RVersionTagger,
SHATagger,
SparkVersionTagger, SparkVersionTagger,
TaggerInterface,
TensorflowVersionTagger, TensorflowVersionTagger,
UbuntuVersionTagger,
) )

View File

@@ -1,126 +0,0 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import plumbum
from docker.models.containers import Container
from tagging.docker_runner import DockerRunner
from tagging.git_helper import GitHelper
docker = plumbum.local["docker"]
def quoted_output(container: Container, cmd: str) -> str:
cmd_output = DockerRunner.run_simple_command(container, cmd, print_result=False)
# For example, `mamba info` adds redundant empty lines
cmd_output = cmd_output.strip("\n")
# For example, R packages list contains trailing backspaces
cmd_output = "\n".join(line.rstrip() for line in cmd_output.split("\n"))
assert cmd_output, f"Command `{cmd}` returned empty output"
return f"""\
`{cmd}`:
```text
{cmd_output}
```"""
class ManifestHeader:
"""ManifestHeader doesn't fall under common interface, and we run it separately"""
@staticmethod
def create_header(
short_image_name: str, registry: str, owner: str, build_timestamp: str
) -> str:
commit_hash = GitHelper.commit_hash()
commit_hash_tag = GitHelper.commit_hash_tag()
commit_message = GitHelper.commit_message()
# Unfortunately, `docker images` doesn't work when specifying `docker.io` as registry
fixed_registry = registry + "/" if registry != "docker.io" else ""
image_size = docker[
"images",
f"{fixed_registry}{owner}/{short_image_name}:latest",
"--format",
"{{.Size}}",
]().rstrip()
return f"""\
# Build manifest for image: {short_image_name}:{commit_hash_tag}
## Build Info
- Build timestamp: {build_timestamp}
- Docker image: `{registry}/{owner}/{short_image_name}:{commit_hash_tag}`
- Docker image size: {image_size}
- Git commit SHA: [{commit_hash}](https://github.com/jupyter/docker-stacks/commit/{commit_hash})
- Git commit message:
```text
{commit_message}
```"""
class ManifestInterface:
"""Common interface for all manifests"""
@staticmethod
def markdown_piece(container: Container) -> str:
raise NotImplementedError
class CondaEnvironmentManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Python Packages
{DockerRunner.run_simple_command(container, "python --version")}
{quoted_output(container, "conda info")}
{quoted_output(container, "mamba info")}
{quoted_output(container, "mamba list")}"""
class AptPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Apt Packages
{quoted_output(container, "apt list --installed")}"""
class RPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## R Packages
{quoted_output(container, "R --version")}
{quoted_output(container, "R --silent -e 'installed.packages(.Library)[, c(1,3)]'")}"""
class JuliaPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Julia Packages
{quoted_output(container, "julia -E 'using InteractiveUtils; versioninfo()'")}
{quoted_output(container, "julia -E 'import Pkg; Pkg.status()'")}"""
class SparkInfoManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Apache Spark
{quoted_output(container, "/usr/local/spark/bin/spark-submit --version")}"""

View File

View File

@@ -0,0 +1,15 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.quoted_output import quoted_output
class AptPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Apt Packages
{quoted_output(container, "apt list --installed")}"""

View File

@@ -0,0 +1,22 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.docker_runner import DockerRunner
from tagging.utils.quoted_output import quoted_output
class CondaEnvironmentManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Python Packages
{DockerRunner.run_simple_command(container, "python --version")}
{quoted_output(container, "conda info")}
{quoted_output(container, "mamba info")}
{quoted_output(container, "mamba list")}"""

View File

@@ -0,0 +1,44 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import plumbum
from tagging.utils.git_helper import GitHelper
docker = plumbum.local["docker"]
class ManifestHeader:
"""ManifestHeader doesn't fall under common interface, and we run it separately"""
@staticmethod
def create_header(
short_image_name: str, registry: str, owner: str, build_timestamp: str
) -> str:
commit_hash = GitHelper.commit_hash()
commit_hash_tag = GitHelper.commit_hash_tag()
commit_message = GitHelper.commit_message()
# Unfortunately, `docker images` doesn't work when specifying `docker.io` as registry
fixed_registry = registry + "/" if registry != "docker.io" else ""
image_size = docker[
"images",
f"{fixed_registry}{owner}/{short_image_name}:latest",
"--format",
"{{.Size}}",
]().rstrip()
return f"""\
# Build manifest for image: {short_image_name}:{commit_hash_tag}
## Build Info
- Build timestamp: {build_timestamp}
- Docker image: `{registry}/{owner}/{short_image_name}:{commit_hash_tag}`
- Docker image size: {image_size}
- Git commit SHA: [{commit_hash}](https://github.com/jupyter/docker-stacks/commit/{commit_hash})
- Git commit message:
```text
{commit_message}
```"""

View File

@@ -0,0 +1,17 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.quoted_output import quoted_output
class JuliaPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Julia Packages
{quoted_output(container, "julia -E 'using InteractiveUtils; versioninfo()'")}
{quoted_output(container, "julia -E 'import Pkg; Pkg.status()'")}"""

View File

@@ -0,0 +1,9 @@
from docker.models.containers import Container
class ManifestInterface:
"""Common interface for all manifests"""
@staticmethod
def markdown_piece(container: Container) -> str:
raise NotImplementedError

View File

@@ -0,0 +1,17 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.quoted_output import quoted_output
class RPackagesManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## R Packages
{quoted_output(container, "R --version")}
{quoted_output(container, "R --silent -e 'installed.packages(.Library)[, c(1,3)]'")}"""

View File

@@ -0,0 +1,15 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.manifests.manifest_interface import ManifestInterface
from tagging.utils.quoted_output import quoted_output
class SparkInfoManifest(ManifestInterface):
@staticmethod
def markdown_piece(container: Container) -> str:
return f"""\
## Apache Spark
{quoted_output(container, "/usr/local/spark/bin/spark-submit --version")}"""

View File

13
tagging/taggers/date.py Normal file
View File

@@ -0,0 +1,13 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import datetime
from docker.models.containers import Container
from tagging.taggers.tagger_interface import TaggerInterface
class DateTagger(TaggerInterface):
@staticmethod
def tag_value(container: Container) -> str:
return datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d")

12
tagging/taggers/sha.py Normal file
View File

@@ -0,0 +1,12 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.taggers.tagger_interface import TaggerInterface
from tagging.utils.git_helper import GitHelper
class SHATagger(TaggerInterface):
@staticmethod
def tag_value(container: Container) -> str:
return GitHelper.commit_hash_tag()

View File

@@ -0,0 +1,9 @@
from docker.models.containers import Container
class TaggerInterface:
"""Common interface for all taggers"""
@staticmethod
def tag_value(container: Container) -> str:
raise NotImplementedError

View File

@@ -0,0 +1,19 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.taggers.tagger_interface import TaggerInterface
from tagging.utils.docker_runner import DockerRunner
class UbuntuVersionTagger(TaggerInterface):
@staticmethod
def tag_value(container: Container) -> str:
os_release = DockerRunner.run_simple_command(
container,
"cat /etc/os-release",
).split("\n")
for line in os_release:
if line.startswith("VERSION_ID"):
return "ubuntu-" + line.split("=")[1].strip('"')
raise RuntimeError(f"did not find ubuntu version in: {os_release}")

View File

@@ -1,11 +1,9 @@
# Copyright (c) Jupyter Development Team. # Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License. # Distributed under the terms of the Modified BSD License.
import datetime
from docker.models.containers import Container from docker.models.containers import Container
from tagging.docker_runner import DockerRunner from tagging.taggers.tagger_interface import TaggerInterface
from tagging.git_helper import GitHelper from tagging.utils.docker_runner import DockerRunner
def _get_program_version(container: Container, program: str) -> str: def _get_program_version(container: Container, program: str) -> str:
@@ -25,39 +23,6 @@ def _get_pip_package_version(container: Container, package: str) -> str:
return version_line[len(PIP_VERSION_PREFIX) :] return version_line[len(PIP_VERSION_PREFIX) :]
class TaggerInterface:
"""Common interface for all taggers"""
@staticmethod
def tag_value(container: Container) -> str:
raise NotImplementedError
class SHATagger(TaggerInterface):
@staticmethod
def tag_value(container: Container) -> str:
return GitHelper.commit_hash_tag()
class DateTagger(TaggerInterface):
@staticmethod
def tag_value(container: Container) -> str:
return datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d")
class UbuntuVersionTagger(TaggerInterface):
@staticmethod
def tag_value(container: Container) -> str:
os_release = DockerRunner.run_simple_command(
container,
"cat /etc/os-release",
).split("\n")
for line in os_release:
if line.startswith("VERSION_ID"):
return "ubuntu-" + line.split("=")[1].strip('"')
raise RuntimeError(f"did not find ubuntu version in: {os_release}")
class PythonVersionTagger(TaggerInterface): class PythonVersionTagger(TaggerInterface):
@staticmethod @staticmethod
def tag_value(container: Container) -> str: def tag_value(container: Container) -> str:

View File

View File

@@ -1,6 +1,6 @@
# Copyright (c) Jupyter Development Team. # Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License. # Distributed under the terms of the Modified BSD License.
from tagging.get_platform import get_platform from tagging.utils.get_platform import get_platform
DEFAULT_VARIANT = "default" DEFAULT_VARIANT = "default"

View File

@@ -0,0 +1,22 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from docker.models.containers import Container
from tagging.utils.docker_runner import DockerRunner
def quoted_output(container: Container, cmd: str) -> str:
cmd_output = DockerRunner.run_simple_command(container, cmd, print_result=False)
# For example, `mamba info` adds redundant empty lines
cmd_output = cmd_output.strip("\n")
# For example, R packages list contains trailing backspaces
cmd_output = "\n".join(line.rstrip() for line in cmd_output.split("\n"))
assert cmd_output, f"Command `{cmd}` returned empty output"
return f"""\
`{cmd}`:
```text
{cmd_output}
```"""

0
wiki/__init__.py Normal file
View File