Skip to content

Commit 28b7515

Browse files
Dockerhub tags (#167)
* added new flag to build to retrieve image tags * improved print system for container tags option * added fix for components without container directives
1 parent 95b4525 commit 28b7515

File tree

4 files changed

+105
-6
lines changed

4 files changed

+105
-6
lines changed

changelog.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
- Added new `recipe` system to flowcraft along with 6 starting recipes.
88
Recipes are pre-made and curated pipelines that address specific questions.
99
To create a recipe, the `-r <recipe_name>` can be used. To list available
10-
recipes, the `--recipe-list` and `--recipe-list-short` options were added.
10+
recipes, the `--recipe-list` and `--recipe-list-short` options were added.
11+
- Added `-ft` or `--fetch-tags` which allows to retrieve all DockerHub
12+
container tags.
1113

1214
### Components changes
1315

flowcraft/flowcraft.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ def get_args(args=None):
113113
"components (via -t option) in JSON format to stdout. "
114114
"No pipeline will be generated with this option."
115115
)
116+
build_parser.add_argument(
117+
"-ft", "--fetch-tags", dest="fetch_docker_tags",
118+
action="store_const", const=True, help="Allows to fetch all docker tags"
119+
" for the components listed with"
120+
" the -t flag."
121+
)
116122

117123
# GENERAL OPTIONS
118124
parser.add_argument(
@@ -191,9 +197,9 @@ def validate_build_arguments(args):
191197
if args.detailed_list or args.short_list:
192198
return
193199

194-
# Skill all checks when exporting parameters AND providing at least one
200+
# Skip all checks when exporting parameters AND providing at least one
195201
# component
196-
if args.export_params or args.export_directives:
202+
if args.export_params or args.export_directives or args.fetch_docker_tags:
197203
# Check if components provided
198204
if not args.tasks:
199205
logger.error(colored_print(
@@ -284,7 +290,7 @@ def build(args):
284290

285291
# Disable standard logging for stdout when the following modes are
286292
# executed:
287-
if args.export_params or args.export_directives:
293+
if args.export_params or args.export_directives or args.fetch_docker_tags:
288294
logger.setLevel(logging.ERROR)
289295

290296
if args.recipe_list_short:
@@ -357,6 +363,9 @@ def build(args):
357363
elif args.export_directives:
358364
nfg.export_directives()
359365
sys.exit(0)
366+
elif args.fetch_docker_tags:
367+
nfg.fetch_docker_tags()
368+
sys.exit(0)
360369
else:
361370
# building the actual pipeline nf file
362371
nfg.build()

flowcraft/generator/engine.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
import sys
33
import json
44
import jinja2
5+
import shutil
56
import logging
7+
import requests
68

79
from collections import defaultdict
810
from os.path import dirname, join, abspath, split, splitext, exists, basename
@@ -1525,6 +1527,87 @@ def export_directives(self):
15251527
# Flush params json to stdout
15261528
sys.stdout.write(json.dumps(directives_json))
15271529

1530+
def fetch_docker_tags(self):
1531+
"""
1532+
Export all dockerhub tags associated with each component given by
1533+
the -t flag.
1534+
"""
1535+
1536+
# fetches terminal width and subtracts 1 because we always add a
1537+
# new line character
1538+
terminal_width = shutil.get_terminal_size().columns - 1
1539+
1540+
# first header
1541+
center_string = " Selected container tags "
1542+
1543+
# starts a list with the headers
1544+
tags_list = [
1545+
[
1546+
"=" * int(terminal_width / 4),
1547+
"{0}{1}{0}".format(
1548+
"=" * int(((terminal_width/2 - len(center_string)) / 2)),
1549+
center_string)
1550+
,
1551+
"{}\n".format("=" * int(terminal_width / 4))
1552+
],
1553+
["component", "container", "tags"],
1554+
[
1555+
"=" * int(terminal_width / 4),
1556+
"=" * int(terminal_width / 2),
1557+
"=" * int(terminal_width / 4)
1558+
]
1559+
]
1560+
1561+
# Skip first init process and iterate through the others
1562+
for p in self.processes[1:]:
1563+
template = p.template
1564+
# fetch repo name from directives of the template. Since some
1565+
# components like integrity_coverage doesn't have a directives with
1566+
# container, thus if no directive there the script will skip this
1567+
# template
1568+
try:
1569+
repo = p.directives[template]["container"]
1570+
except KeyError:
1571+
continue
1572+
# make the request to docker hub
1573+
r = requests.get(
1574+
"https://hub.docker.com/v2/repositories/{}/tags/".format(
1575+
repo
1576+
))
1577+
# checks the status code of the request, if it is 200 then parses
1578+
# docker hub entry, otherwise retrieve no tags but alerts the user
1579+
if r.status_code != 404:
1580+
# parse response content to dict and fetch results key
1581+
r_content = json.loads(r.content)["results"]
1582+
for version in r_content:
1583+
tags_list.append([template, repo, version["name"]])
1584+
else:
1585+
tags_list.append([template, repo, "No DockerHub tags"])
1586+
1587+
# iterate through each entry in tags_list and print the list of tags
1588+
# for each component. Each entry (excluding the headers) contains
1589+
# 3 elements (component name, container and tag version)
1590+
for x, entry in enumerate(tags_list):
1591+
# adds different color to the header in the first list and
1592+
# if row is pair add one color and if is even add another (different
1593+
# background)
1594+
color = "blue_bold" if x < 3 else \
1595+
("white" if x % 2 != 0 else "0;37;40m")
1596+
# generates a small list with the terminal width for each column,
1597+
# this will be given to string formatting as the 3, 4 and 5 element
1598+
final_width = [
1599+
int(terminal_width/4),
1600+
int(terminal_width/2),
1601+
int(terminal_width/4)
1602+
]
1603+
# writes the string to the stdout
1604+
sys.stdout.write(
1605+
colored_print("\n{0: <{3}} {1: ^{4}} {2: >{5}}".format(
1606+
*entry, *final_width), color)
1607+
)
1608+
# assures that the entire line gets the same color
1609+
sys.stdout.write("\n")
1610+
15281611
def build(self):
15291612
"""Main pipeline builder
15301613

flowcraft/generator/process_details.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
COLORS = {
77
"green_bold": "1;32m",
88
"red_bold": "1;31m",
9-
"white": "2;38m",
9+
"white": "0;38m",
1010
"white_bold": "1;38m",
1111
"white_underline": "4;38m",
1212
"blue_bold": "1;36m",
@@ -37,7 +37,12 @@ def colored_print(msg, color_label="white_bold"):
3737
if sys.stdout.encoding != "UTF-8":
3838
msg = "".join([i if ord(i) < 128 else "" for i in msg])
3939

40-
col = COLORS[color_label]
40+
# try except first looks for the color in COLORS dictionary, otherwise use
41+
# color_label as the color.
42+
try:
43+
col = COLORS[color_label]
44+
except KeyError:
45+
col = color_label
4146

4247
return "\x1b[{}{}\x1b[0m".format(col, msg)
4348

0 commit comments

Comments
 (0)