abra/bin/app-json.py

139 lines
4.1 KiB
Python
Executable File

#!/usr/bin/env python3
# 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:
# https://abra-apps.autonomic.zone
from json import dump
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 requests import get
HOME_PATH = expanduser("~/")
CLONES_PATH = Path(f"{HOME_PATH}/.abra/apps").absolute()
SCRIPT_PATH = Path(__file__).absolute().parent
def clone_apps():
if not exists(CLONES_PATH):
mkdir(CLONES_PATH)
response = get("https://git.autonomic.zone/api/v1/orgs/coop-cloud/repos")
repos = [[p["name"], p["ssh_url"]] for p in response.json()]
skips = ("organising", "cloud.autonomic.zone", "docs.cloud.autonomic.zone", "abra")
for name, url in repos:
if name in skips:
continue
try:
if not exists(f"{CLONES_PATH}/{name}"):
run(split(f"git clone {url} {CLONES_PATH}/{name}"))
chdir(f"{CLONES_PATH}/{name}")
if not int(check_output("git branch --list | wc -l", shell=True)):
run(split("git checkout main"))
except Exception:
pass
def gen_apps_json():
apps_json = {}
for app in listdir(CLONES_PATH):
app_path = f"{CLONES_PATH}/{app}"
chdir(app_path)
output = check_output("git tag --list", shell=True)
tags = output.decode("utf-8").strip().split()
if not tags:
continue
for tag in tags:
apps_json[app] = {
"category": "apps",
"repository": f"https://git.autonomic.zone/coop-cloud/{app}.git",
"features": get_app_features(app_path, tag),
"versions": get_app_versions(app_path, tag),
}
return apps_json
def get_app_features(app_path, tag):
print(f"Gathering features for {app_path}, tag: {tag}")
features = {}
chdir(app_path)
run(f"git checkout {tag}", shell=True)
with open(f"{app_path}/README.md", "r") as handle:
contents = handle.read()
for match in findall(r"\*\*.*\s\*", contents):
title = search(r"(?<=\*\*).*(?=\*\*)", match).group().lower()
if title == "image":
value = {
"image": search(r"(?<=`).*(?=`)", match).group(),
"url": search(r"(?<=\().*(?=\))", match).group(),
"rating": match.split(",")[1].strip(),
"source": match.split(",")[-1].replace("*", "").strip(),
}
else:
value = match.split(":")[-1].replace("*", "").strip()
features[title] = value
run(f"git checkout HEAD", shell=True)
return features
def get_app_versions(app_path, tag):
print(f"Gathering versions for {app_path}, tag: {tag}")
versions = []
chdir(app_path)
run(f"git checkout {tag}", shell=True)
services_command = "yq e '.services | keys | .[]' compose*.yml"
services = check_output(services_command, shell=True).decode("utf-8").split()
for service in services:
images_command = f"yq e '.services.{service}.image' compose*.yml"
images = check_output(images_command, shell=True).decode("utf-8").split()
for image in images:
if image in ("null", "---"):
continue
digest_command = f"skopeo inspect docker://{image} | jq '.Digest'"
output = check_output(digest_command, shell=True).decode("utf-8")
digest = output.strip().split(":")[-1][:8]
image_name = image.split(":")[0]
versions.append(
{service: {"image": image_name, "tag": tag, "digest": digest}}
)
run(f"git checkout HEAD", shell=True)
return versions
clone_apps()
target = f"{SCRIPT_PATH}/../deploy/abra-apps.cloud.autonomic.zone/abra-apps.json"
with open(target, "w", encoding="utf-8") as handle:
dump(gen_apps_json(), handle, ensure_ascii=False, indent=4)
print(f"Output saved to {target}")