From d95f1aacb8f5576b3cf59f5669c2b323c262e2d7 Mon Sep 17 00:00:00 2001 From: Christoph Miksche Date: Mon, 26 Aug 2019 21:26:19 +0200 Subject: [PATCH] feat: New structure, added CLI, logging and setup * Changed structure to a Object orientated approach. * Add CLI with input for the settings file. * Added logging via file. * Added setup for publishing in pip. --- .gitignore | 3 +- .travis.yml | 3 +- Pipfile | 14 ++++++++ README.md | 28 ++++++++++----- functions.py | 71 -------------------------------------- settings.ini | 9 +++++ settings.py | 23 ------------- setup.py | 24 +++++++++++++ tests.py | 18 +++++----- update/__init__.py | 33 ++++++++++++++++++ update/build.py | 24 +++++++++++++ update/download.py | 79 ++++++++++++++++++++++++++++++++++++++++++ update/update.py | 56 ++++++++++++++++++++++++++++++ update/version.py | 48 ++++++++++++++++++++++++++ updater.py | 86 ---------------------------------------------- 15 files changed, 320 insertions(+), 199 deletions(-) create mode 100644 Pipfile delete mode 100644 functions.py create mode 100644 settings.ini delete mode 100644 settings.py create mode 100644 setup.py create mode 100644 update/__init__.py create mode 100644 update/build.py create mode 100644 update/download.py create mode 100644 update/update.py create mode 100644 update/version.py delete mode 100644 updater.py diff --git a/.gitignore b/.gitignore index a4499c6..f482011 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ __pycache__ .pyc -.idea \ No newline at end of file +.idea +Pipfile.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 8559eed..a979c14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - "3.7" cache: pip install: - - pip install requests packaging + - pip install pipenv + - pipenv install script: - python tests.py diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..b04ba3d --- /dev/null +++ b/Pipfile @@ -0,0 +1,14 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +requests = "*" +packaging = "*" +fire = "*" + +[requires] +python_version = "3.7" diff --git a/README.md b/README.md index c3764df..5ab3116 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Gitea Auto Updater +# Gitea Auto Update [![Build Status](https://travis-ci.org/CMiksche/gitea-auto-update.svg?branch=master)](https://travis-ci.org/CMiksche/gitea-auto-update) @@ -28,19 +28,29 @@ Uses python version 3 ## Installation -1. Use the following command to install all dependencies. +Create a settings.ini file on your system. Example: + + ```` +[Gitea] +site=https://your-gitea-instance.com/api/v1/version +apiUrl=https://api.github.com/repos/go-gitea/gitea/releases/latest +system=linux-amd64 +file=/usr/local/bin/gitea +tmpDir=/tmp/ +buildFromSource=None +sourceDir=/home/git/go/src/code.gitea.io/gitea +logFile=update.log + ```` + +Use the following command to install all gitea-auto-update. ``` - sudo pip install requests packaging + sudo pip install gitea-auto-update ``` -2. Then clone the git repository. +Enter the command `gite-auto-update --settings=/path/to/settings.ini` in your commandline. -3. After that, please change the variables in the settings.py file. - -4. Enter the command `python updater.py` in your commandline. - -5. If you want to schedule your updates, edit your /etc/crontab file. +If you want to schedule your updates, edit your /etc/crontab file. ## Tutorials diff --git a/functions.py b/functions.py deleted file mode 100644 index ee68d05..0000000 --- a/functions.py +++ /dev/null @@ -1,71 +0,0 @@ -''' -Gitea Auto Updater - -Copyright 2018, 2019 The Gitea-Auto-Update Authors -All rights reserved. - -License: GNU General Public License -''' -import settings -import requests -import os - -# Function to download a file -def download(url, file_name): - # open in binary mode - with open(file_name, "wb") as file: - # get request - response = requests.get(url) - # write to file - file.write(response.content) - -# Function to build the new version from source -def buildFromSource(tag): - # Change to source dir - os.chdir(settings.source_dir) - # Checkout master - os.system("git checkout master") - # Update - os.system("git pull") - # Checkout relase branch - os.system("git checkout "+tag) - # Build from source - os.system('TAGS="bindata sqlite sqlite_unlock_notify" make generate build') - # Move binary - os.system("mv gitea "+settings.gtfile) - -# Function to check if there is a new version -def checkVersion(new_version, old_version): - - from packaging import version - - return version.parse(new_version) > version.parse(old_version) - -# Function to check if tool is available -def is_tool(name): - ##Check whether `name` is on PATH and marked as executable. - - # from whichcraft import which - from shutil import which - - return which(name) is not None - -def parseFileVersion(string): - return string.split(" ")[2] - -def getVersionFromFile(): - version_string = os.popen(settings.gtfile+" -v").read() - return parseFileVersion(version_string) - -# Function to get the current version -def getCurrentVersion(): - try: - # Try to get the version from the file - current_version = getVersionFromFile() - except: - # Get the version via the web api if the file does fail - current_version = requests.get(settings.gtsite).json()['version'] - if current_version.status_code != 200: - current_version = getVersionFromFile() - finally: - return current_version \ No newline at end of file diff --git a/settings.ini b/settings.ini new file mode 100644 index 0000000..6ac5c43 --- /dev/null +++ b/settings.ini @@ -0,0 +1,9 @@ +[Gitea] +site=https://your-gitea-instance.com/api/v1/version +apiUrl=https://api.github.com/repos/go-gitea/gitea/releases/latest +system=linux-amd64 +file=/usr/local/bin/gitea +tmpDir=/tmp/ +buildFromSource=None +sourceDir=/home/git/go/src/code.gitea.io/gitea +logFile=update.log \ No newline at end of file diff --git a/settings.py b/settings.py deleted file mode 100644 index 03d1913..0000000 --- a/settings.py +++ /dev/null @@ -1,23 +0,0 @@ -''' -Gitea Auto Updater - -Copyright 2018, 2019 The Gitea-Auto-Update Authors -All rights reserved. - -License: GNU General Public License -''' -# Gitea Site -# Optional - the script will get the version from the gitea file if you change the url to a empty string -gtsite = 'https://your-gitea-instance.com/api/v1/version' -# Gitea GitHub API URL for latest Relase -gtgithubapiurl = 'https://api.github.com/repos/go-gitea/gitea/releases/latest' -# Gitea System -gtsystem = 'linux-amd64' -# Name and Path of gitea file -gtfile = '/usr/local/bin/gitea' -# tmp Name and Path of gitea file -tmpdir = '/tmp/' -# Build new version from source? -build_from_source = None -# Source directroy -source_dir = '/home/git/go/src/code.gitea.io/gitea' diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..eb18bc7 --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +from setuptools import setup + +setup(name='gitea_auto_update', + version='2.0.0', + description='A script which can update gitea to a new version.', + url='https://github.com/CMiksche/gitea-auto-update', + author='Christoph Miksche', + author_email='christoph@miksche.org', + license='GPLv3', + classifiers=[ + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: Unix", + ], + keywords=['gitea', 'update', 'debian', 'linux'], + install_requires=[ + 'requests', + 'packaging', + 'fire' + ], + packages=['update'], + entry_points={ + 'console_scripts': ['gitea-auto-update=update.__init__:main'], + } + ) \ No newline at end of file diff --git a/tests.py b/tests.py index 7548757..1957465 100644 --- a/tests.py +++ b/tests.py @@ -6,31 +6,33 @@ All rights reserved. License: GNU General Public License ''' -import functions +import update.version import unittest +version = update.version.Version('', '') + class Tests(unittest.TestCase): def testSimpleVersion(self): - self.assertTrue(functions.checkVersion('1.9.1', '1.9.0')) + self.assertTrue(version.checkVersion('1.9.1', '1.9.0')) def testTwoIntVersion(self): - self.assertTrue(functions.checkVersion('1.10.0', '1.9.0')) + self.assertTrue(version.checkVersion('1.10.0', '1.9.0')) def testFalseVersion(self): - self.assertFalse(functions.checkVersion('1.8.0', '1.9.0')) + self.assertFalse(version.checkVersion('1.8.0', '1.9.0')) def testSameVersion(self): - self.assertFalse(functions.checkVersion('1.9.7', '1.9.7')) + self.assertFalse(version.checkVersion('1.9.7', '1.9.7')) def testInt(self): - self.assertTrue(functions.checkVersion('9', '8')) + self.assertTrue(version.checkVersion('9', '8')) def testSuffix(self): - self.assertTrue(functions.checkVersion('1.9.0+dev-264-g8de76b6e6', '1.8.0')) + self.assertTrue(version.checkVersion('1.9.0+dev-264-g8de76b6e6', '1.8.0')) def testParseFileVersion(self): - self.assertEqual(functions.parseFileVersion('Gitea version 1.8.1 built with go1.12.2 : bindata, sqlite, sqlite_unlock_notify'), '1.8.1') + self.assertEqual(version.parseFileVersion('Gitea version 1.8.1 built with go1.12.2 : bindata, sqlite, sqlite_unlock_notify'), '1.8.1') if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/update/__init__.py b/update/__init__.py new file mode 100644 index 0000000..0992dc6 --- /dev/null +++ b/update/__init__.py @@ -0,0 +1,33 @@ +''' +Gitea Auto Updater + +Copyright 2018, 2019 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' +import logging +import configparser +import fire +from update import update + +def updater(settings='settings.ini'): + # Config + config = configparser.ConfigParser() + config.read(settings) + # Create a log file + logging.basicConfig(filename=config.get('Gitea', 'logFile'), level=logging.DEBUG) + # Start update + update.Update(config.get('Gitea', 'site'), + config.get('Gitea', 'file'), + config.get('Gitea', 'sourceDir'), + config.get('Gitea', 'apiUrl'), + config.get('Gitea', 'buildFromSource'), + config.get('Gitea', 'tmpDir'), + config.get('Gitea', 'system')) + +def main(): + fire.Fire(updater) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/update/build.py b/update/build.py new file mode 100644 index 0000000..06ead68 --- /dev/null +++ b/update/build.py @@ -0,0 +1,24 @@ +''' +Gitea Auto Updater + +Copyright 2018, 2019 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' +import os + +class Build: + + def __init__(self, gtFile, sourceDir): + self.gtFile = gtFile + self.sourceDir = sourceDir + + def fromSource(self, tag): + # Function to build the new version from source + os.chdir(self.sourceDir) + os.system("git checkout master") + os.system("git pull") + os.system("git checkout " + tag) + os.system('TAGS="bindata sqlite sqlite_unlock_notify" make generate build') + os.system("mv gitea " + self.gtFile) \ No newline at end of file diff --git a/update/download.py b/update/download.py new file mode 100644 index 0000000..1baeddf --- /dev/null +++ b/update/download.py @@ -0,0 +1,79 @@ +''' +Gitea Auto Updater + +Copyright 2018, 2019 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' +import requests +import os +import logging +from shutil import which # from whichcraft import which + + +class Download: + + def __init__(self, tmpDir, githubVersion, githubVersionTag, gtSystem, gtFile): + if not self.isTool("xz"): + logging.error("missing dependency: xz") + quit() + + self.tmpDir = tmpDir + self.githubVersion = githubVersion + self.githubVersionTag = githubVersionTag + self.gtSystem = gtSystem + self.gtFile = gtFile + + self.downloadGiteaFiles() + self.checkAndExtract() + + def isTool(name): + # Function to check if tool is available + ##Check whether `name` is on PATH and marked as executable. + return which(name) is not None + + def download(self, url, fileName): + # Function to download a file + # open in binary mode + with open(fileName, "wb") as file: + # get request + response = requests.get(url) + # write to file + file.write(response.content) + + def downloadGiteaFiles(self): + # Set download url + gtDownload = 'https://github.com/go-gitea/gitea/releases/download/' + self.githubVersionTag + '/gitea-' + self.githubVersion + '-' + self.gtSystem + '.xz' + logging.info('Gitea file: %s', gtDownload) + shaDownload = gtDownload + '.sha256' + logging.info('SHA file: %s', shaDownload) + + # Download file + logging.info("downloading sha256 hashsum") + self.download(shaDownload, self.tmpDir + 'gitea.xz.sha256') + logging.info("downloading %s", self.githubVersionTag + 'gitea.xz') + self.tmpXz = self.tmpDir +'gitea-' + self.githubVersion + '-' + self.gtSystem + '.xz' + self.download(gtDownload, self.tmpXz) + + def shaCheck(self): + return os.system("sha256sum -c gitea.xz.sha256 > /dev/null") == 0 + + def extractFile(self): + logging.info("sha ok, extracting file to location") + # extracting download file + cmd = "xz -d " + self.tmpXz + logging.info(cmd) + os.system(cmd) + # moving temp file to gtfile location + cmd = 'mv ' + self.tmpDir + 'gitea-' + self.githubVersion + '-' + self.gtSystem + ' ' + self.gtFile + logging.info(cmd) + os.system(cmd) + + def checkAndExtract(self): + os.chdir(self.tmpDir) + if self.shaCheck(): + self.extractFile() + else: + logging.error("error: sha256sum failed") + quit() \ No newline at end of file diff --git a/update/update.py b/update/update.py new file mode 100644 index 0000000..4b7b7f4 --- /dev/null +++ b/update/update.py @@ -0,0 +1,56 @@ +''' +Gitea Auto Updater + +Copyright 2018, 2019 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' +import os +import logging +from update import version, download, build + + +class Update: + + def __init__(self, gtSite, gtFile, sourceDir, apiUrl, buildFromSource, tmpDir, gtSystem): + self.gtSite = gtSite + self.gtFile = gtFile + self.sourceDir = sourceDir + self.apiUrl = apiUrl + self.buildFromSource = buildFromSource + self.tmpDir = tmpDir + self.gtSystem = gtSystem + + self.initVersionAndBuild() + self.getVersionAndTag() + + def initVersionAndBuild(self): + self.version = version.Version(self.gtSite, self.gtFile) + self.build = build.Build(self.gtFile, self.sourceDir) + + def getVersionAndTag(self): + self.currentVersion = self.version.getCurrentVersion() # Version from gitea site + self.githubVersionTag = self.version.getGithubVersionTag(self.apiUrl) # Get version tag from github and remove first char (v) + self.githubVersion = self.githubVersionTag[1:] # Get version from version tag + + def doUpdate(self): + if self.buildFromSource: # Should the new version be build from source? + build.fromSource(self.githubVersionTag) + else: + self.download = download.Download(self.tmpDir, + self.githubVersion, + self.githubVersionTag, + self.gtSystem, + self.gtFile) + + def checkAndUpdate(self): + if version.checkVersion(self.githubVersion, self.currentVersion): # Check if there is a new version + logging.info("new version available, stopping service") + os.system("systemctl stop gitea.service") + self.doUpdate() + logging.info("starting gitea.service") + os.system("systemctl start gitea.service") + print("update successfully") + else: + print("current version is uptodate") diff --git a/update/version.py b/update/version.py new file mode 100644 index 0000000..fde25f3 --- /dev/null +++ b/update/version.py @@ -0,0 +1,48 @@ +''' +Gitea Auto Updater + +Copyright 2018, 2019 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' +from packaging import version +import os +import requests +import logging + +class Version: + + def __init__(self, gtSite, gtFile): + self.gtSite = gtSite + self.gtFile = gtFile + + def checkVersion(self, newVersion, oldVersion): + # Function to check if there is a new version + return version.parse(newVersion) > version.parse(oldVersion) + + def parseFileVersion(self, string): + return string.split(" ")[2] + + def getVersionFromFile(self): + versionString = os.popen(self.gtFile + " -v").read() + return self.parseFileVersion(versionString) + + def getCurrentVersion(self): + # Function to get the current version + try: + # Try to get the version from the file + currentVersion = self.getVersionFromFile() + except: + # Get the version via the web api if the file does fail + currentVersion = requests.get(self.gtSite).json()['version'] + if currentVersion.status_code != 200: + currentVersion = self.getVersionFromFile() + finally: + logging.info("current_version =", currentVersion) + return currentVersion + + def getGithubVersionTag(self, apiUrl): + versionTag = requests.get(apiUrl).json()['tag_name'] + logging.info("github_version_tag =", versionTag) + return versionTag \ No newline at end of file diff --git a/updater.py b/updater.py deleted file mode 100644 index 0df9c1d..0000000 --- a/updater.py +++ /dev/null @@ -1,86 +0,0 @@ -''' -Gitea Auto Updater - -Copyright 2018, 2019 The Gitea-Auto-Update Authors -All rights reserved. - -License: GNU General Public License -''' -import settings -import requests -import os -import functions - -if not functions.is_tool("xz"): - print ("missing dependency: xz") - quit() - -# Version from gitea site -current_version = functions.getCurrentVersion() -print ("current_version =", current_version) -# Get version tag from github and remove first char (v) -github_version_tag = requests.get(settings.gtgithubapiurl).json()['tag_name'] -print ("github_version_tag =", github_version_tag) -# Get version from version tag -github_version = github_version_tag[1:] -# Check if there is a new version -if functions.checkVersion(github_version, current_version): - - - # Stop systemd service - print ("new version available, stopping service") - os.system("systemctl stop gitea.service") - - # Should the new version be build from source? - if settings.build_from_source: - - functions.buildFromSource(github_version_tag) - - else: - # Set download url - ## main file - gtdownload = 'https://github.com/go-gitea/gitea/releases/download/'+github_version_tag+'/gitea-'+github_version+'-'+settings.gtsystem+'.xz' - print (gtdownload) - ## sha256 file - shadownload = 'https://github.com/go-gitea/gitea/releases/download/'+github_version_tag+'/gitea-'+github_version+'-'+settings.gtsystem+'.xz.sha256' - print (shadownload) - - # Download file - - ## downloading sha - print ("downloading sha256 hashsum") - functions.download(shadownload, settings.tmpdir+'gitea.xz.sha256') - ## downloading xz - print ("downloading", github_version_tag+'gitea.xz') - tmpxz = settings.tmpdir+'gitea-'+github_version+'-'+settings.gtsystem+'.xz' - functions.download(gtdownload, tmpxz) - - # doing sha256 sum - os.chdir(settings.tmpdir) - #sha_value = os.system("sha256sum -c gitea.xz.sha256 > /dev/null") - - if os.system("sha256sum -c gitea.xz.sha256 > /dev/null") == 0: - print ("sha ok, extracting file to location") - # extracting download file - cmd = "xz -d "+tmpxz - print (cmd) - os.system(cmd) - # moving temp file to gtfile location - cmd = 'mv '+settings.tmpdir+'gitea-'+github_version+'-'+settings.gtsystem+' '+settings.gtfile - print (cmd) - os.system(cmd) - else: - print ("error") - quit() - - # Start systemd service - print ("starting gitea.service") - os.system("systemctl start gitea.service") - - print ("update successfully") - - -else: - - #Print current version is uptodate - print ("current version is uptodate")