#!/usr/bin/env python3
# coding: utf-8

'''
Check Hugo new releases from Hugo GitHub repo and update image automaticaly

Usage: update.py API_token project_uri
'''

import base64
import requests
import re
import sys
from urllib.parse import quote

GITLAB_URL = "https://gitlab.com/api/v4"
COMMIT_MESSAGE = "Update Hugo to version %s"

def compare_versions(version1, version2):
    def normalize(v):
        return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
    return normalize(version1) >= normalize(version2)

if len(sys.argv) != 3:
    print('Usage: update.py API_token project_uri')
    exit(1)

# Get vars from script arguments
GITLAB_TOKEN = sys.argv[1]
GITLAB_PROJECT = quote(sys.argv[2], safe='')

# Get latest release
rrelease = requests.get('https://api.github.com/repos/gohugoio/hugo/releases/latest')
if rrelease.status_code != 200:
    print('Failed to get Hugo latest release from GitHub')
    exit(1)

release = rrelease.json()
print('Last Hugo version is %s'%release['name'])

# Get repository tags
rtags = requests.get('%s/projects/%s/repository/tags'%(GITLAB_URL, GITLAB_PROJECT))
if rtags.status_code != 200:
    print('Failed to get tags from GitLab project')
    exit(1)

# If a higher version is present in the GitLab repository, do nothing
for tag in rtags.json():
    if tag['release'] is None:
        continue
    if compare_versions(tag['release']['tag_name'], release['name'][1:]):
        print('Already up to date, nothing to do')
        exit(0)
print('No tag is higher or equal to Hugo version.\nUpdating...')

# Find release archive checksum from GitHub
for asset in release['assets']:
    if re.search('checksums.txt', asset['name']):
        rchecksums = requests.get(asset['browser_download_url'])
        if rchecksums.status_code != 200:
            print('Failed to get checksums file from GitHub')
            exit(1)
        for line in rchecksums.text.split("\n"):
            if 'hugo_%s_Linux-64bit.tar.gz'%(release['name'][1:]) in line:
                checksum = line[:64]
                break

# Get Dockerfile from repository
rdockerfile = requests.get('%s/projects/%s/repository/files/Dockerfile/raw?ref=registry'%(GITLAB_URL, GITLAB_PROJECT))
if rdockerfile.status_code != 200:
    print('Failed to get Dockerfile from %s:'%sys.argv[1])
    print(rdockerfile.json())
    exit(1)
dockerfile = rdockerfile.text.split("\n")

# Replace env variables
for index, line in enumerate(dockerfile):
    if "ENV HUGO_VERSION" in line:
        dockerfile[index] = "ENV HUGO_VERSION %s"%release['name'][1:]
    if "ENV HUGO_SHA" in line:
        dockerfile[index] = "ENV HUGO_SHA %s"%checksum

# Update Dockerfile on repository
rupdate = requests.put('%s/projects/%s/repository/files/Dockerfile?branch=registry&content=%s&commit_message=%s&encoding=base64'%(
    GITLAB_URL,
    GITLAB_PROJECT,
    quote(base64.b64encode("\n".join(dockerfile).encode()), safe=''),
    quote(COMMIT_MESSAGE%(release['name'][1:]), safe='')
), headers={'Private-Token': GITLAB_TOKEN})
if rupdate.status_code != 200:
    print("Failed to update Dockerfile:")
    print(rupdate.json())
    exit(1)
print('Dockerfile was updated to version %s'%release['name'][1:])

# Create new tag
rtag = requests.post('%s/projects/%s/repository/tags?tag_name=%s&ref=registry&message=%s&release_description=%s'%(
    GITLAB_URL,
    GITLAB_PROJECT,
    release['name'][1:],
    quote(COMMIT_MESSAGE%(release['name'][1:]), safe=''),
    quote(release['body'], safe='')
), headers={'Private-Token': GITLAB_TOKEN})
if rtag.status_code != 201:
    print('Failed to create tag:')
    print(rtag.json())
    exit(0)
print('Tag %s created'%release['name'][1:])
print('Done !')
