2022-06-11 01:19:22 +03:00
#!/usr/bin/python3
import argparse
2023-02-09 02:18:05 +03:00
import functools
2022-07-30 02:45:16 +03:00
import json
2022-06-11 01:19:22 +03:00
import re
import subprocess
2022-12-08 03:47:41 +03:00
import textwrap
2022-06-11 01:19:22 +03:00
from graphlib import TopologicalSorter
from pathlib import Path
2023-02-09 02:18:05 +03:00
import tomli
2022-06-11 01:19:22 +03:00
from jinja2 import Template
2022-12-06 04:00:08 +03:00
ORG_DIR = Path ( " org " )
2022-06-11 01:19:22 +03:00
2023-02-09 02:18:05 +03:00
class Image :
def __init__ ( self , canonical_name ) :
self . canonical_name = canonical_name
self . path = ORG_DIR / canonical_name
self . base_name = re . sub ( " ^[^/]+/ " , " " , canonical_name )
2023-07-18 13:35:09 +03:00
def __str__ ( self ) :
return ( f ' Image(canonical_name= " { self . canonical_name } " , '
f ' path= " { self . path } " , base_name= " { self . base_name } " ) ' )
2023-02-09 02:18:05 +03:00
2022-12-12 02:34:20 +03:00
class Tasks :
def __init__ ( self , tasks ) :
if tasks is None :
self . _tasks = None
else :
2023-03-27 18:18:25 +03:00
self . _tasks = tomli . loads ( Path ( tasks ) . read_text ( ) )
2022-12-12 02:34:20 +03:00
2023-07-18 13:35:09 +03:00
def __str__ ( self ) :
return f " { self . _tasks } "
2023-02-09 02:18:05 +03:00
def get ( self , branch , image : Image ) :
2022-12-12 02:34:20 +03:00
if self . _tasks is None :
return [ ]
else :
if branch_tasks := self . _tasks . get ( branch ) :
2023-02-09 02:18:05 +03:00
return [
n
for n , i in branch_tasks . items ( )
if image . canonical_name in i or len ( i ) == 0
]
2022-12-12 02:34:20 +03:00
2022-12-22 02:41:07 +03:00
class Tags :
def __init__ ( self , tags_file , latest ) :
if tags_file is None :
self . _tags = None
else :
tags_file = Path ( tags_file )
2023-03-27 18:18:25 +03:00
self . _tags = tomli . loads ( tags_file . read_text ( ) )
2022-12-22 02:41:07 +03:00
self . _latest = latest
2023-02-09 02:18:05 +03:00
def tags ( self , branch , image : Image ) :
2022-12-22 02:41:07 +03:00
if self . _tags is None :
tags = [ branch ]
else :
2023-07-18 13:24:02 +03:00
tags = self . _tags [ image . canonical_name ] [ branch ] . copy ( )
2022-12-22 02:41:07 +03:00
if branch == self . _latest :
tags . append ( " latest " )
return tags
2023-02-09 02:18:05 +03:00
class Distroless :
def __init__ ( self , distrolessfile , renderer ) :
dd = tomli . loads ( distrolessfile . read_text ( ) )
self . raw_from = dd [ " from " ]
2023-02-14 02:18:46 +03:00
self . renderer = renderer
2023-02-09 02:18:05 +03:00
self . from_ = renderer ( dd [ " from " ] )
self . file_lists = dd . get ( " file-lists " , [ ] )
self . files = dd . get ( " files " , [ ] )
2023-02-14 02:16:57 +03:00
self . library_files = dd . get ( " library-files " , [ ] )
2023-02-09 02:18:05 +03:00
self . packages = dd . get ( " packages " , [ ] )
2023-02-14 02:16:57 +03:00
self . library_packages = dd . get ( " library-packages " , [ ] )
2023-02-10 15:59:22 +03:00
self . exclude_regexes = dd . get ( " exclude-regexes " , [ ] )
2023-02-09 02:18:05 +03:00
2023-02-14 02:17:57 +03:00
self . builder_install_packages = dd . get ( " builder-install-packages " , [ ] )
for file in dd . get ( " full-files " , [ ] ) :
self . builder_install_packages . append ( file )
self . files . append ( file )
self . library_files . append ( file )
2023-02-09 02:18:05 +03:00
self . timezone = dd . get ( " timezone " )
2023-02-12 19:00:47 +03:00
if self . timezone :
self . files . append ( " /etc/localtime " )
2023-02-09 02:18:05 +03:00
self . copy = dd . get ( " copy " , { } )
self . config_options = [ ]
for option in [ " cmd " , " entrypoint " , " user " ] :
if value := dd . get ( option ) :
2023-02-14 02:18:46 +03:00
if isinstance ( value , list ) :
value = json . dumps ( value )
2023-02-09 02:18:05 +03:00
self . config_options . append ( f " -- { option } = { value } " )
2023-02-10 15:59:54 +03:00
if value := dd . get ( " workdir " ) :
self . config_options . append ( f " --workingdir= { value } " )
elif value := dd . get ( " workingdir " ) :
self . config_options . append ( f " --workingdir= { value } " )
2023-02-09 02:18:05 +03:00
2023-02-14 02:18:46 +03:00
def render_arch_branch ( self , arch , branch ) :
def if_arches ( arches , value , default = " " ) :
if arch in arches or not arches :
return value
else :
return default
def if_branches ( branches , value , default = " " ) :
if branch in branches or not branches :
return value
else :
return default
def if_arches_branches ( arches , branches , value , default = " " ) :
if arches and arch not in arches or branches and branch not in branches :
return default
else :
return value
renderer = functools . partial (
self . renderer ,
if_arches = if_arches ,
if_branches = if_branches ,
if_arches_branches = if_arches_branches ,
)
def filter_map ( values ) :
if isinstance ( values , dict ) :
return { k : r for k , v in values . items ( ) if ( r := renderer ( v ) ) != " " }
else :
return [ r for v in values if ( r := renderer ( v ) ) != " " ]
self . builder_install_packages = filter_map ( self . builder_install_packages )
self . config_options = filter_map ( self . config_options )
self . copy = filter_map ( self . copy )
self . file_lists = filter_map ( self . file_lists )
self . files = filter_map ( self . files )
self . library_files = filter_map ( self . library_files )
self . library_packages = filter_map ( self . library_packages )
self . packages = filter_map ( self . packages )
2023-02-09 02:18:05 +03:00
2022-06-11 01:19:22 +03:00
class DockerBuilder :
2023-02-09 02:18:05 +03:00
def make_image_re ( self ) :
2022-06-11 01:19:22 +03:00
registry = r " (?P<registry>[ \ w.:]+) "
organization = r " (?P<organization> \ w+) "
2023-02-09 02:18:05 +03:00
name = r " (?P<name>[-. \ w]+) "
2022-06-11 01:19:22 +03:00
tag = r " (?P<tag>[ \ w.]+) "
2023-02-09 02:18:05 +03:00
return rf " (:? { registry } /)?(:? { organization } /)? { name } (:?: { tag } )? "
def make_dockerfile_from_re ( self ) :
image_re = self . make_image_re ( )
return rf " ^ \ s*FROM \ s+ { image_re } $ "
2022-06-11 01:19:22 +03:00
2022-12-06 04:00:08 +03:00
def __init__ (
self ,
registry ,
2023-02-09 02:18:05 +03:00
branch ,
2022-12-06 04:00:08 +03:00
organization ,
overwrite_organization ,
latest ,
dry_run ,
images_info ,
2022-12-12 02:34:20 +03:00
tasks : Tasks ,
2022-12-22 02:41:07 +03:00
tags : Tags ,
2022-12-06 04:00:08 +03:00
) :
2023-02-09 02:18:05 +03:00
self . image_re = re . compile ( self . make_image_re ( ) )
self . dockerfile_from_re = re . compile ( self . make_dockerfile_from_re ( ) )
2022-12-06 04:00:08 +03:00
self . org_dir = ORG_DIR
self . images_dir = ORG_DIR / organization
2022-06-11 01:19:22 +03:00
self . registry = registry
2023-02-09 02:18:05 +03:00
self . branch = branch
2022-06-11 01:19:22 +03:00
self . organization = organization
2022-12-06 04:00:08 +03:00
if overwrite_organization :
self . overwrite_organization = overwrite_organization
else :
self . overwrite_organization = organization
2022-06-11 01:19:22 +03:00
self . latest = latest
self . dry_run = dry_run
2022-07-30 02:45:16 +03:00
self . images_info = images_info
2022-12-12 02:34:20 +03:00
self . tasks = tasks
2022-12-22 02:41:07 +03:00
self . tags = tags
2023-02-09 02:18:05 +03:00
self . distrolesses = { }
2022-12-06 04:00:08 +03:00
2022-06-11 01:19:22 +03:00
def forall_images ( consume_result ) :
def forall_images_decorator ( f ) :
def wrapped ( self , * args , * * kwargs ) :
2023-02-09 02:18:05 +03:00
for image_path in self . images_dir . iterdir ( ) :
image = Image ( " / " . join ( image_path . parts [ 1 : ] ) )
2022-06-11 01:19:22 +03:00
local_kwargs = {
" image " : image ,
2023-02-09 02:18:05 +03:00
" dockerfile " : image_path / " Dockerfile " ,
" dockerfile_template " : image_path / " Dockerfile.template " ,
" distrolessfile " : image_path / " distroless.toml " ,
2022-06-11 01:19:22 +03:00
}
new_kwargs = kwargs | local_kwargs
yield f ( self , * args , * * new_kwargs )
def consumer ( * args , * * kwargs ) :
for _ in wrapped ( * args , * * kwargs ) :
pass
if consume_result :
return consumer
else :
return wrapped
return forall_images_decorator
@forall_images ( consume_result = True )
def remove_dockerfiles ( self , * * kwargs ) :
if kwargs [ " dockerfile " ] . exists ( ) :
kwargs [ " dockerfile " ] . unlink ( )
2023-02-09 02:18:05 +03:00
def render_template (
2023-02-14 02:18:46 +03:00
self ,
template : str ,
organization : str ,
install_pakages = None ,
* * kwargs ,
2023-02-09 02:18:05 +03:00
) - > str :
2023-02-03 01:59:31 +03:00
if self . registry :
registry = self . registry . rstrip ( " / " ) + " / "
alt_image = " alt/alt "
else :
registry = " "
alt_image = " alt "
rendered = Template ( template ) . render (
alt_image = alt_image ,
2023-02-09 02:18:05 +03:00
branch = self . branch ,
2023-02-03 01:59:31 +03:00
install_pakages = install_pakages ,
2023-02-09 02:18:05 +03:00
organization = organization ,
2023-02-03 01:59:31 +03:00
registry = registry ,
2023-02-14 02:18:46 +03:00
* * kwargs ,
2023-02-03 01:59:31 +03:00
)
return rendered
2022-06-11 01:19:22 +03:00
@forall_images ( consume_result = True )
2023-02-09 02:18:05 +03:00
def render_dockerfiles ( self , * * kwargs ) :
2022-12-08 03:47:41 +03:00
def install_pakages ( * names ) :
2023-02-15 20:25:51 +03:00
tasks = self . tasks . get ( self . branch , kwargs [ " image " ] )
2022-12-14 15:55:14 +03:00
linux32 = ' $([ " $(rpm --eval % _host_cpu) " = i586 ] && echo linux32) '
2022-12-12 02:34:20 +03:00
if tasks :
apt_repo = " \\ \n apt-get install apt-repo -y && \\ "
for task in tasks :
apt_repo + = f " \n { linux32 } apt-repo add { task } && \\ "
2022-12-13 02:40:16 +03:00
apt_repo + = " \n apt-get update && \\ "
2022-12-12 02:34:20 +03:00
else :
apt_repo = " \\ "
update_command = f """ RUN apt-get update && { apt_repo } """
install_command = f """
2022-12-14 15:55:14 +03:00
{ linux32 } apt - get install - y { ' ' . join ( names ) } & & \\
2022-12-12 02:34:20 +03:00
rm - f / var / cache / apt / archives / * . rpm \\
/ var / cache / apt / * . bin \\
/ var / lib / apt / lists / * . *
"""
install_command = textwrap . dedent ( install_command ) . rstrip ( " \n " )
install_command = textwrap . indent ( install_command , " " * 4 )
return update_command + install_command
2022-12-08 03:47:41 +03:00
2023-02-03 01:59:31 +03:00
dockerfile_template = kwargs [ " dockerfile_template " ]
if dockerfile_template . exists ( ) :
rendered = self . render_template (
2023-02-09 02:18:05 +03:00
dockerfile_template . read_text ( ) ,
self . overwrite_organization ,
install_pakages ,
2022-06-11 01:19:22 +03:00
)
kwargs [ " dockerfile " ] . write_text ( rendered + " \n " )
2023-02-09 02:18:05 +03:00
@forall_images ( consume_result = True )
def load_distrolesses ( self , * * kwargs ) :
renderer = functools . partial (
self . render_template ,
organization = self . overwrite_organization ,
)
distrolessfile = kwargs [ " distrolessfile " ]
canonical_name = " / " . join ( distrolessfile . parts [ - 3 : - 1 ] )
if distrolessfile . exists ( ) :
self . distrolesses [ canonical_name ] = Distroless ( distrolessfile , renderer )
2022-06-11 01:19:22 +03:00
@forall_images ( consume_result = False )
def get_requires ( self , * * kwargs ) :
requires = set ( )
2023-02-09 02:18:05 +03:00
dockerfile_template = kwargs [ " dockerfile_template " ]
distrolessfile = kwargs [ " distrolessfile " ]
canonical_name = kwargs [ " image " ] . canonical_name
2022-06-11 01:19:22 +03:00
2023-02-09 02:18:05 +03:00
if dockerfile_template . exists ( ) :
for line in dockerfile_template . read_text ( ) . splitlines ( ) :
if not re . match ( r " \ s*FROM " , line ) :
continue
line = self . render_template ( line , self . organization )
if match := re . match ( self . dockerfile_from_re , line ) :
from_image = match . groupdict ( )
if from_image [ " name " ] != " scratch " :
requires . add (
f " { from_image [ ' organization ' ] } / { from_image [ ' name ' ] } "
)
elif distrolessfile . exists ( ) :
requires . add ( " alt/distroless-builder " )
raw_from = self . distrolesses [ canonical_name ] . raw_from
from_ = self . render_template ( raw_from , self . organization )
if match := re . match ( self . image_re , from_ ) :
2022-06-11 01:19:22 +03:00
from_image = match . groupdict ( )
2023-02-09 02:18:05 +03:00
if from_image [ " name " ] != " scratch " :
requires . add ( f " { from_image [ ' organization ' ] } / { from_image [ ' name ' ] } " )
2022-06-11 01:19:22 +03:00
2023-02-09 02:18:05 +03:00
return ( canonical_name , requires )
2022-06-11 01:19:22 +03:00
def get_build_order ( self ) :
requires = { }
2023-02-09 02:18:05 +03:00
for canonical_name , image_requires in self . get_requires ( ) :
requires [ canonical_name ] = image_requires
2022-06-11 01:19:22 +03:00
ts = TopologicalSorter ( requires )
2023-02-09 02:18:05 +03:00
return ( Image ( i ) for i in ts . static_order ( ) )
2022-06-11 01:19:22 +03:00
2023-02-09 02:18:05 +03:00
def render_full_tag ( self , image : Image , tag : str ) :
2022-06-11 01:19:22 +03:00
if self . registry :
registry = self . registry . rstrip ( " / " ) + " / "
else :
registry = " "
if tag :
tag = f " : { tag } "
2023-02-09 02:18:05 +03:00
return f " { registry } { self . overwrite_organization } / { image . base_name } { tag } "
2022-06-11 01:19:22 +03:00
def run ( self , cmd , * args , * * kwargs ) :
2022-12-14 15:56:13 +03:00
if " check " not in kwargs :
kwargs [ " check " ] = True
2022-06-11 01:19:22 +03:00
if self . dry_run :
pre_cmd = [ " echo " ]
else :
pre_cmd = [ ]
subprocess . run ( pre_cmd + cmd , * args , * * kwargs )
2023-02-09 02:18:05 +03:00
def distroless_build ( self , image : Image , arches ) :
def distroless_build_arch ( arch , manifest ) :
distroless_builder = self . render_full_tag (
Image ( " alt/distroless-builder " ) , self . branch
)
distroless = self . distrolesses [ image . canonical_name ]
2023-02-14 02:18:46 +03:00
distroless . render_arch_branch ( arch , self . branch )
2023-02-09 02:18:05 +03:00
builder = f " distroless-builder- { arch } "
new = f " distroless-new- { arch } "
run = functools . partial ( self . run , cwd = image . path )
run (
[ " buildah " , " rm " , builder , new ] ,
check = False ,
stderr = subprocess . DEVNULL ,
stdout = subprocess . DEVNULL ,
)
run (
[
" buildah " ,
" from " ,
" --arch " ,
arch ,
" --name " ,
builder ,
distroless_builder ,
]
)
run ( [ " buildah " , " from " , " --arch " , arch , " --name " , new , distroless . from_ ] )
if packages := distroless . builder_install_packages :
2023-02-15 20:26:28 +03:00
tasks = self . tasks . get ( self . branch , image )
if tasks :
if arch == " 386 " :
apt_repo_add = [ " linux32 " , " apt-repo " , " add " ]
else :
apt_repo_add = [ " apt-repo " , " add " ]
for task in tasks :
run ( [ " buildah " , " run " , builder ] + apt_repo_add + [ task ] )
2023-02-09 02:18:05 +03:00
run ( [ " buildah " , " run " , builder , " apt-get " , " update " ] )
run (
[ " buildah " , " run " , builder , " apt-get " , " reinstall " , " -y " ] + packages
)
if timezone := distroless . timezone :
run (
[
" buildah " ,
" run " ,
builder ,
" ln " ,
" -s " ,
f " /usr/share/zoneinfo/ { timezone } " ,
" /etc/localtime " ,
]
)
2023-02-14 02:16:57 +03:00
options = [ ]
2023-02-09 02:18:05 +03:00
if distroless . files :
2023-02-14 02:16:57 +03:00
options + = [ " -f " ] + distroless . files
if distroless . library_files :
options + = [ " --library-files " ] + distroless . library_files
2023-02-09 02:18:05 +03:00
if file_lists := distroless . file_lists :
2023-02-14 02:16:57 +03:00
options + = [ " -l " ]
options + = [ f " file-lists/ { f } " for f in file_lists ]
2023-02-09 02:18:05 +03:00
for file_list in file_lists :
run (
[
" buildah " ,
" copy " ,
builder ,
f " ./ { file_list } " ,
f " file-lists/ { file_list } " ,
]
)
if distroless . packages :
2023-02-14 02:16:57 +03:00
options + = [ " -p " ] + distroless . packages
if distroless . library_packages :
options + = [ " --library-packages " ] + distroless . library_packages
2023-02-09 02:18:05 +03:00
run (
[
" buildah " ,
" run " ,
builder ,
" ./distroless-builder.py " ,
" add " ,
" --clean " ,
]
2023-02-14 02:16:57 +03:00
+ options
2023-02-09 02:18:05 +03:00
)
2023-02-10 15:59:22 +03:00
exclude_regexes_options = [ ]
if distroless . exclude_regexes :
exclude_regexes_options = [ " -r " ] + distroless . exclude_regexes
run (
[
" buildah " ,
" run " ,
builder ,
" ./distroless-builder.py " ,
" tar " ,
]
+ exclude_regexes_options
)
2023-02-09 02:18:05 +03:00
run (
[
" buildah " ,
" add " ,
" --from " ,
builder ,
new ,
" /usr/src/distroless/distroless.tar " ,
" / " ,
]
)
for local_file , image_file in distroless . copy . items ( ) :
run (
[
" buildah " ,
" copy " ,
new ,
f " ./ { local_file } " ,
image_file ,
]
)
run ( [ " buildah " , " config " ] + distroless . config_options + [ new ] )
run ( [ " buildah " , " commit " , " --rm " , " --manifest " , manifest , new ] )
run (
[ " buildah " , " rm " , builder ] ,
check = False ,
stderr = subprocess . DEVNULL ,
stdout = subprocess . DEVNULL ,
)
if self . images_info . skip_branch ( image . canonical_name , self . branch ) :
2022-12-14 15:57:35 +03:00
return
2023-02-09 02:18:05 +03:00
build_arches = set ( arches ) - set (
self . images_info . skip_arches ( image . canonical_name )
)
2023-02-28 15:43:14 +03:00
tags = self . tags . tags ( self . branch , image )
2023-02-09 02:18:05 +03:00
manifest = self . render_full_tag ( image , tags [ 0 ] )
msg = " Building image {} for {} arches " . format (
manifest ,
2022-12-14 15:57:35 +03:00
arches ,
)
print ( msg )
2023-02-09 02:18:05 +03:00
rm_image_cmd = [
" podman " ,
" image " ,
" rm " ,
" --force " ,
manifest ,
]
self . run (
rm_image_cmd ,
check = False ,
stderr = subprocess . DEVNULL ,
stdout = subprocess . DEVNULL ,
)
rm_manifest_cmd = [
" podman " ,
" manifest " ,
" rm " ,
manifest ,
]
self . run (
rm_manifest_cmd ,
check = False ,
stderr = subprocess . DEVNULL ,
stdout = subprocess . DEVNULL ,
)
for arch in build_arches :
distroless_build_arch ( arch , manifest )
for tag in tags [ 1 : ] :
other_manifest = self . render_full_tag ( image , tag )
tag_cmd = [ " podman " , " tag " , manifest , other_manifest ]
self . run ( tag_cmd )
def podman_build ( self , image : Image , arches ) :
if self . images_info . skip_branch ( image . canonical_name , self . branch ) :
return
build_arches = set ( arches ) - set (
self . images_info . skip_arches ( image . canonical_name )
)
2022-12-14 15:57:35 +03:00
platforms = " , " . join ( [ f " linux/ { a } " for a in build_arches ] )
2023-02-28 15:43:14 +03:00
tags = self . tags . tags ( self . branch , image )
2023-02-09 02:18:05 +03:00
manifest = self . render_full_tag ( image , tags [ 0 ] )
msg = " Building image {} for {} arches " . format (
manifest ,
arches ,
)
print ( msg )
2022-12-14 15:57:35 +03:00
2023-02-09 02:18:05 +03:00
rm_image_cmd = [
" podman " ,
" image " ,
" rm " ,
" --force " ,
manifest ,
]
self . run (
rm_image_cmd ,
check = False ,
stderr = subprocess . DEVNULL ,
stdout = subprocess . DEVNULL ,
)
2022-12-20 00:55:15 +03:00
rm_manifest_cmd = [
" podman " ,
" manifest " ,
" rm " ,
2023-02-09 02:18:05 +03:00
manifest ,
2022-12-20 00:55:15 +03:00
]
2023-02-09 02:18:05 +03:00
self . run (
rm_manifest_cmd ,
check = False ,
stderr = subprocess . DEVNULL ,
stdout = subprocess . DEVNULL ,
)
2022-12-14 15:57:35 +03:00
build_cmd = [
" podman " ,
" build " ,
2023-02-09 02:18:05 +03:00
" --rm " ,
" --force-rm " ,
f " --manifest= { manifest } " ,
2022-12-14 15:57:35 +03:00
f " --platform= { platforms } " ,
" . " ,
]
2023-02-09 02:18:05 +03:00
self . run ( build_cmd , cwd = image . path )
2022-12-14 15:57:35 +03:00
2022-12-22 02:41:07 +03:00
for tag in tags [ 1 : ] :
2023-02-09 02:18:05 +03:00
other_manifest = self . render_full_tag ( image , tag )
tag_cmd = [ " podman " , " tag " , manifest , other_manifest ]
2022-12-14 15:57:35 +03:00
self . run ( tag_cmd )
2023-02-09 02:18:05 +03:00
def podman_push ( self , image : Image , sign = None ) :
if self . images_info . skip_branch ( image . canonical_name , self . branch ) :
2022-12-14 15:57:35 +03:00
return
2023-02-28 15:43:14 +03:00
tags = self . tags . tags ( self . branch , image )
2022-12-22 02:41:07 +03:00
manifests = [ self . render_full_tag ( image , t ) for t in tags ]
2022-12-14 15:57:35 +03:00
for manifest in manifests :
2022-12-22 02:41:07 +03:00
print ( f " Push manifest { manifest } " )
2022-12-14 15:57:35 +03:00
cmd = [
" podman " ,
" manifest " ,
" push " ,
manifest ,
f " docker:// { manifest } " ,
]
if sign is not None :
cmd . append ( f " --sign-by= { sign } " )
self . run ( cmd )
2022-06-11 01:19:22 +03:00
2022-12-14 16:46:32 +03:00
class ImagesInfo :
def __init__ ( self ) :
info = { }
2023-03-27 18:18:25 +03:00
images_info = Path ( " images-info.toml " )
2022-12-14 16:46:32 +03:00
if images_info . exists ( ) :
2023-03-27 18:18:25 +03:00
info = tomli . loads ( images_info . read_text ( ) )
2022-12-14 16:46:32 +03:00
self . _info = info
2023-02-09 02:18:05 +03:00
def skip_arch ( self , canonical_name , arch ) :
info = self . _info . get ( canonical_name , { } )
2022-12-14 16:46:32 +03:00
return arch in info . get ( " skip-arches " , [ ] )
2023-02-09 02:18:05 +03:00
def skip_arches ( self , canonical_name ) :
info = self . _info . get ( canonical_name , { } )
2022-12-14 16:46:32 +03:00
return info . get ( " skip-arches " , [ ] )
2023-02-09 02:18:05 +03:00
def skip_branch ( self , canonical_name , branch ) :
info = self . _info . get ( canonical_name , { } )
2022-12-14 16:46:32 +03:00
return branch in info . get ( " skip-branches " , [ ] )
2023-02-09 02:18:05 +03:00
def skip_branches ( self , canonical_name ) :
info = self . _info . get ( canonical_name , { } )
2022-12-14 16:46:32 +03:00
return info . get ( " skip-branches " , [ ] )
2022-06-11 01:19:22 +03:00
def parse_args ( ) :
2022-12-26 02:50:46 +03:00
stages = [ " build " , " remove_dockerfiles " , " render_dockerfiles " , " push " ]
2022-06-11 01:19:22 +03:00
arches = [ " amd64 " , " 386 " , " arm64 " , " arm " , " ppc64le " ]
branches = [ " p9 " , " p10 " , " sisyphus " ]
2022-12-06 04:00:08 +03:00
organizations = list ( ORG_DIR . iterdir ( ) )
images = [ f " { o . name } / { i . name } " for o in organizations for i in o . iterdir ( ) ]
organizations = [ o . name for o in organizations ]
2022-06-11 01:19:22 +03:00
parser = argparse . ArgumentParser (
formatter_class = argparse . ArgumentDefaultsHelpFormatter ,
)
2022-12-06 04:00:08 +03:00
images_group = parser . add_mutually_exclusive_group ( required = True )
images_group . add_argument (
" -i " ,
" --images " ,
nargs = " + " ,
default = images ,
choices = images ,
help = " list of branches " ,
)
images_group . add_argument (
" -o " ,
" --organizations " ,
nargs = " + " ,
default = organizations ,
choices = organizations ,
help = " build all images from these organizations " ,
)
2022-06-11 01:19:22 +03:00
parser . add_argument (
" -r " ,
" --registry " ,
default = " registry.altlinux.org " ,
)
parser . add_argument (
2022-12-06 04:00:08 +03:00
" --overwrite-organization " ,
2022-06-11 01:19:22 +03:00
)
parser . add_argument (
" -l " ,
" --latest " ,
default = " p10 " ,
2023-07-18 13:37:19 +03:00
help = " tag images in this branch as latest " ,
2022-06-11 01:19:22 +03:00
)
2022-12-12 02:34:20 +03:00
parser . add_argument (
" --tasks " ,
type = Tasks ,
default = Tasks ( None ) ,
2023-07-18 13:37:19 +03:00
help = " use tasks from TASKS file " ,
2022-12-12 02:34:20 +03:00
)
2022-12-22 02:41:07 +03:00
parser . add_argument (
" --tags " ,
help = " use tags from TAGS file " ,
)
2022-06-11 01:19:22 +03:00
parser . add_argument (
" --dry-run " ,
action = " store_true " ,
help = " print instead of running docker commands " ,
)
2022-12-14 15:57:35 +03:00
parser . add_argument (
" --sign " ,
)
2022-06-11 01:19:22 +03:00
parser . add_argument (
" --skip-images " ,
nargs = " + " ,
default = [ ] ,
choices = images ,
help = " list of skipping images " ,
)
parser . add_argument (
" -a " ,
" --arches " ,
nargs = " + " ,
default = arches ,
choices = arches ,
help = " list of arches " ,
)
parser . add_argument (
" --skip-arches " ,
nargs = " + " ,
default = [ ] ,
choices = arches ,
help = " list of skipping arches " ,
)
parser . add_argument (
" -b " ,
" --branches " ,
nargs = " + " ,
default = branches ,
choices = branches ,
help = " list of branches " ,
)
parser . add_argument (
" --skip-branches " ,
nargs = " + " ,
default = [ ] ,
choices = branches ,
help = " list of skipping branches " ,
)
parser . add_argument (
" --stages " ,
nargs = " + " ,
default = stages ,
choices = stages ,
help = " list of stages " ,
)
parser . add_argument (
" --skip-stages " ,
nargs = " + " ,
default = [ ] ,
choices = stages ,
help = " list of skipping stages " ,
)
args = parser . parse_args ( )
args . stages = set ( args . stages ) - set ( args . skip_stages )
2023-06-19 18:43:03 +03:00
args . arches = set ( args . arches ) - set ( args . skip_arches )
2022-06-11 01:19:22 +03:00
args . branches = set ( args . branches ) - set ( args . skip_branches )
args . images = set ( args . images ) - set ( args . skip_images )
return args
def main ( ) :
args = parse_args ( )
2023-02-09 02:18:05 +03:00
arches = args . arches
2022-12-14 16:46:32 +03:00
images_info = ImagesInfo ( )
2022-12-22 02:41:07 +03:00
tags = Tags ( args . tags , args . latest )
2022-12-06 04:00:08 +03:00
for organization in args . organizations :
for branch in args . branches :
db = DockerBuilder (
args . registry ,
2023-02-09 02:18:05 +03:00
branch ,
2022-12-06 04:00:08 +03:00
organization ,
args . overwrite_organization ,
args . latest ,
args . dry_run ,
images_info ,
2022-12-12 02:34:20 +03:00
args . tasks ,
2022-12-22 02:41:07 +03:00
tags ,
2022-12-06 04:00:08 +03:00
)
if " remove_dockerfiles " in args . stages :
db . remove_dockerfiles ( )
if " render_dockerfiles " in args . stages :
2023-02-09 02:18:05 +03:00
db . render_dockerfiles ( )
db . load_distrolesses ( )
2022-12-27 02:42:25 +03:00
for image in db . get_build_order ( ) :
2023-02-09 02:18:05 +03:00
if image . canonical_name not in args . images :
2022-12-27 02:42:25 +03:00
continue
2022-12-06 04:00:08 +03:00
2022-12-27 02:42:25 +03:00
if " build " in args . stages :
2023-02-09 02:18:05 +03:00
if image . canonical_name in db . distrolesses :
db . distroless_build ( image , arches )
else :
db . podman_build ( image , arches )
2022-12-26 02:50:46 +03:00
2022-12-27 02:42:25 +03:00
if " push " in args . stages :
2023-02-09 02:18:05 +03:00
db . podman_push ( image , args . sign )
2022-06-11 01:19:22 +03:00
if __name__ == " __main__ " :
main ( )
# vim: colorcolumn=89