mirror of
https://github.com/IEEE-SB-Passau/pelican-deployment-system.git
synced 2017-09-06 16:35:38 +02:00
110 lines
3.8 KiB
Python
110 lines
3.8 KiB
Python
from pathlib import Path
|
|
from collections import namedtuple
|
|
from git import Repo, InvalidGitRepositoryError, NoSuchPathError
|
|
from subprocess import Popen
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
from threading import RLock
|
|
import sys
|
|
import logging
|
|
import shlex
|
|
import os
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
BUILD_REPO_DIR = "build_repo"
|
|
OUTPUT_DIR = "output"
|
|
|
|
|
|
class DeploymentRunner:
|
|
def __init__(self, name, runner_config):
|
|
self.name = name
|
|
self.working_directory = Path(runner_config["working_directory"])
|
|
if not self.working_directory.exists():
|
|
log.info("creating working directory for %s: %s", name,
|
|
self.working_directory)
|
|
self.working_directory.mkdir(parents=True)
|
|
self.working_directory = self.working_directory.resolve()
|
|
|
|
self.clone_url = runner_config["clone_url"]
|
|
self.git_branch = runner_config["git_branch"]
|
|
self.target_directory = runner_config["target_directory"]
|
|
self.build_repo_path = self.working_directory / BUILD_REPO_DIR
|
|
self.pelican_command = runner_config["pelican_command"].format(
|
|
output=OUTPUT_DIR)
|
|
self.build_proc_env = dict(os.environ,
|
|
**runner_config.get("pelican_env", {}))
|
|
|
|
self.executor = ThreadPoolExecutor(max_workers=1)
|
|
self.futures = set()
|
|
self.build_proc = None
|
|
self.abort = False
|
|
self._build_lock = RLock()
|
|
|
|
def update_build_repository(self):
|
|
try:
|
|
build_repo = Repo(str(self.build_repo_path))
|
|
|
|
except (InvalidGitRepositoryError, NoSuchPathError) as e:
|
|
if not self.build_repo_path.is_dir() or \
|
|
next(self.build_repo_path.iterdir(), None) is not None:
|
|
log.error("non-empty %s exists but not a valid git repository!",
|
|
self.build_repo_path)
|
|
raise
|
|
else:
|
|
log.info("Build repository %s not there, cloneing", e)
|
|
build_repo = Repo.clone_from(self.clone_url,
|
|
str(self.build_repo_path),
|
|
branch=self.git_branch)
|
|
|
|
build_repo.head.reference = build_repo.create_head(self.git_branch)
|
|
assert not build_repo.head.is_detached
|
|
|
|
build_repo.remotes.origin.pull(
|
|
force=True,
|
|
no_edit=True,
|
|
refspec="+{b}:{b}".format(b=self.git_branch))
|
|
|
|
# forcefully reset the working tree
|
|
build_repo.head.reset(index=True, working_tree=True)
|
|
try:
|
|
build_repo.git.clean(force=True)
|
|
except:
|
|
log.warning("git clean failed!", exc_info=True)
|
|
|
|
def build(self, abort_running=False):
|
|
with self._build_lock:
|
|
if abort_running:
|
|
self.try_abort_build()
|
|
|
|
# cancel everything, so we are next
|
|
for fut in self.futures.copy():
|
|
fut.cancel()
|
|
if fut.done():
|
|
self.futures.remove(fut)
|
|
|
|
self.futures.add(self.executor.submit(self.build_blocking))
|
|
|
|
def try_abort_build(self):
|
|
proc = self.build_proc
|
|
self.abort = True
|
|
if proc:
|
|
proc.kill()
|
|
|
|
def build_blocking(self):
|
|
self.abort = False
|
|
|
|
# preparing build environment
|
|
self.update_build_repository()
|
|
# TODO: prepare_output()
|
|
|
|
# start the build if we should not abort
|
|
if not self.abort:
|
|
args = shlex.split(self.pelican_command)
|
|
self.build_proc = Popen(args,
|
|
cwd=str(self.build_repo_path),
|
|
env=self.build_proc_env)
|
|
status = self.build_proc.wait()
|
|
if status == 0:
|
|
# TODO: postproc...
|
|
pass
|