From 3d5d70cfd00f2eb08ef445ed97f0081d1a7155d0 Mon Sep 17 00:00:00 2001 From: Peter Dahlberg Date: Fri, 10 Jun 2016 21:59:52 +0200 Subject: [PATCH] add early code --- deploy_config.py | 13 +++++ pelican_deploy/__init__.py | 3 + pelican_deploy/deploy.py | 109 +++++++++++++++++++++++++++++++++++++ requirements.txt | 3 + 4 files changed, 128 insertions(+) create mode 100644 deploy_config.py create mode 100644 pelican_deploy/__init__.py create mode 100644 pelican_deploy/deploy.py create mode 100644 requirements.txt diff --git a/deploy_config.py b/deploy_config.py new file mode 100644 index 0000000..98156a5 --- /dev/null +++ b/deploy_config.py @@ -0,0 +1,13 @@ +if __name__ == "__main__": + raise SystemExit("Not meant to be run directly!") + +RUNNERS = { + "website_master": { + "working_directory": "/tmp/test", + "clone_url": "https://github.com/catdog2/sandbox.git", + "git_branch": "master", + "target_directory": "/tmp/wwwout", + "pelican_command": 'echo $PELICAN_SITEURL', + "pelican_env": {"PELICAN_SITEURL": "//apu:800"} + } +} diff --git a/pelican_deploy/__init__.py b/pelican_deploy/__init__.py new file mode 100644 index 0000000..56fb5cc --- /dev/null +++ b/pelican_deploy/__init__.py @@ -0,0 +1,3 @@ +from pelican_deploy.deploy import DeploymentRunner + +__all__ = [DeploymentRunner] diff --git a/pelican_deploy/deploy.py b/pelican_deploy/deploy.py new file mode 100644 index 0000000..4eff38b --- /dev/null +++ b/pelican_deploy/deploy.py @@ -0,0 +1,109 @@ +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 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7eb1096 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +bottle +GitPython +apscheduler