abra/bin/app-json.py

182 lines
5.0 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
2021-04-02 14:05:31 +00:00
# Usage: ./app-json.py
#
# Gather metadata from Co-op Cloud apps in $ABRA_DIR/apps (default
# ~/.abra/apps), and format it as JSON so that it can be hosted here:
2021-04-02 15:03:58 +00:00
# https://abra-apps.cloud.autonomic.zone
2021-04-02 14:05:31 +00:00
from json import dump
from logging import DEBUG, basicConfig, getLogger
2021-04-02 14:05:31 +00:00
from os import chdir, listdir, mkdir
from os.path import exists, expanduser
from pathlib import Path
from re import findall, search
from shlex import split
from subprocess import check_output, run
from sys import exit
from requests import get
HOME_PATH = expanduser("~/")
CLONES_PATH = Path(f"{HOME_PATH}/.abra/apps").absolute()
SCRIPT_PATH = Path(__file__).absolute().parent
log = getLogger(__name__)
basicConfig()
log.setLevel(DEBUG)
def _run_cmd(cmd, shell=False):
"""Run a shell command."""
args = [split(cmd)]
kwargs = {}
if shell:
args = [cmd]
kwargs = {"shell": shell}
try:
return check_output(*args, **kwargs).decode("utf-8").strip()
except Exception as exception:
log.error(f"Failed to run {cmd}, saw {str(exception)}")
exit(1)
def clone_all_apps():
"""Clone all Co-op Cloud apps to ~/.abra/apps."""
if not exists(CLONES_PATH):
mkdir(CLONES_PATH)
skips = ("organising", "cloud.autonomic.zone", "docs.cloud.autonomic.zone", "abra")
url = "https://git.autonomic.zone/api/v1/orgs/coop-cloud/repos"
log.info(f"Retrieving {url}")
try:
response = get(url, timeout=30)
except Exception as exception:
log.error(f"Failed to retrieve {url}, saw {str(exception)}")
exit(1)
repos = [[p["name"], p["ssh_url"]] for p in response.json()]
for name, url in repos:
if name in skips:
continue
if not exists(f"{CLONES_PATH}/{name}"):
run(split(f"git clone {url} {CLONES_PATH}/{name}"))
chdir(f"{CLONES_PATH}/{name}")
if not int(_run_cmd("git branch --list | wc -l", shell=True)):
log.info(f"Guessing main branch is HEAD for {name}")
run(split("git checkout main"))
def generate_apps_json():
"""Generate the abra-apps.json application versions file."""
apps_json = {}
for app in listdir(CLONES_PATH):
app_path = f"{CLONES_PATH}/{app}"
chdir(app_path)
tags = _run_cmd("git tag --list").split()
if not tags:
log.info(f"No tags discovered for {app}, moving on")
continue
for tag in tags:
log.info(f"Processing {tag} for {app}")
apps_json[app] = {
"category": "apps",
"repository": f"https://git.autonomic.zone/coop-cloud/{app}.git",
2021-04-02 14:43:43 +00:00
"features": get_app_features(app_path, tag),
"versions": get_app_versions(app_path, tag),
}
return apps_json
2021-04-02 14:43:43 +00:00
def get_app_features(app_path, tag):
"""Parse features from app repo README files."""
features = {}
2021-04-02 14:43:43 +00:00
chdir(app_path)
_run_cmd(f"git checkout {tag}")
2021-04-02 14:43:43 +00:00
with open(f"{app_path}/README.md", "r") as handle:
log.info(f"{app_path}/README.md")
contents = handle.read()
for match in findall(r"\*\*.*\s\*", contents):
2021-04-01 19:40:38 +00:00
title = search(r"(?<=\*\*).*(?=\*\*)", match).group().lower()
if title == "image":
value = {
"image": search(r"(?<=`).*(?=`)", match).group(),
"url": search(r"(?<=\().*(?=\))", match).group(),
2021-04-01 19:40:38 +00:00
"rating": match.split(",")[1].strip(),
"source": match.split(",")[-1].replace("*", "").strip(),
}
else:
value = match.split(":")[-1].replace("*", "").strip()
features[title] = value
log.info(f"Parsed {features}")
_run_cmd("git checkout HEAD")
return features
2021-04-02 14:43:43 +00:00
def get_app_versions(app_path, tag):
versions = []
chdir(app_path)
_run_cmd(f"git checkout {tag}")
services_cmd = "yq e '.services | keys | .[]' compose*.yml"
services = _run_cmd(services_cmd, shell=True).split()
2021-04-02 14:43:43 +00:00
for service in services:
services_cmd = f"yq e '.services.{service}.image' compose*.yml"
images = _run_cmd(services_cmd, shell=True).split()
2021-04-02 14:43:43 +00:00
for image in images:
if image in ("null", "---"):
continue
images_cmd = f"skopeo inspect docker://{image} | jq '.Digest'"
output = _run_cmd(images_cmd, shell=True)
new_version_info = {
service: {
"image": image.split(":")[0],
"tag": tag,
"digest": output.split(":")[-1][:8],
}
}
versions.append(new_version_info)
log.info(f"Parsed {new_version_info}")
_run_cmd("git checkout HEAD")
return versions
def main():
"""Run the script."""
clone_all_apps()
target = f"{SCRIPT_PATH}/../deploy/abra-apps.cloud.autonomic.zone/abra-apps.json"
with open(target, "w", encoding="utf-8") as handle:
dump(generate_apps_json(), handle, ensure_ascii=False, indent=4)
log.info(f"Successfully generated {target}")
main()