summaryrefslogtreecommitdiff
path: root/ick
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2015-05-10 10:25:11 +0300
committerLars Wirzenius <liw@liw.fi>2015-05-10 11:32:56 +0300
commit813e198fcd83aa2ae4fea5a66ef592f42aa6c293 (patch)
tree0c4bd1412d7b8044c0ddfbc3450ba0ff133346f9 /ick
parent3fdbb1e7351839a3e08d9783620fba6d4ad8e9a6 (diff)
downloadick-813e198fcd83aa2ae4fea5a66ef592f42aa6c293.tar.gz
Add state and don't build unless git's changed
Diffstat (limited to 'ick')
-rwxr-xr-xick103
1 files changed, 86 insertions, 17 deletions
diff --git a/ick b/ick
index 50cbe06..e8b9017 100755
--- a/ick
+++ b/ick
@@ -18,9 +18,8 @@
import logging
-import shutil
+import os
import subprocess
-import tempfile
import cliapp
import yaml
@@ -53,10 +52,11 @@ class Ick(cliapp.Application):
return yaml.safe_load(f)
def build_projects(self, ick):
+ statedir = ick['state']
targets = self.get_targets(ick)
projects = self.get_projects(ick)
for project_name, project in projects.items():
- self.build_project(project_name, project, targets)
+ self.build_project(statedir, project_name, project, targets)
def get_targets(self, ick):
return self.pick_from_dict(
@@ -74,24 +74,76 @@ class Ick(cliapp.Application):
ick.get('projects', {}),
self.settings['project'])
- def build_project(self, project_name, project, targets):
+ def build_project(self, statedir, project_name, project, targets):
with self.logger:
self.logger.log(
'Building project {project_name}', project_name=project_name)
- git_dir = self.clone_git_repository_locally(
- project['git'], project['branch'])
- try:
- for target_name, target in targets.items():
- self.build_on_target(
- project_name, project, target_name, target, git_dir)
- except Exception:
- shutil.rmtree(git_dir)
- raise
- def clone_git_repository_locally(self, url, branch):
- git_dir = tempfile.mkdtemp()
- cliapp.runcmd(['git', 'clone', '--verbose', '--branch', branch, url, git_dir])
- return git_dir
+ git_dir = self.get_git_dir(statedir, project_name)
+ self.clone_or_update_git_repository_locally(
+ git_dir, project['git'], project['branch'])
+ meta = BuildMetadata()
+ meta.commit = self.get_head_commit(git_dir)
+
+ if not self.needs_to_be_built(statedir, project_name, meta.commit):
+ with self.logger:
+ self.logger.log(
+ 'No need to build {project_name}',
+ project_name=project_name)
+ return
+
+ build_dir = self.get_next_build_dir(statedir, project_name)
+ for target_name, target in targets.items():
+ self.build_on_target(
+ project_name, project, target_name, target, git_dir)
+ self.save_build_metadata(build_dir, meta)
+
+ def needs_to_be_built(self, statedir, project_name, current_commit):
+ builds_dir = os.path.join(statedir, project_name, 'builds')
+ if os.path.exists(builds_dir):
+ basenames = os.listdir(builds_dir)
+ if basenames:
+ numbers = [int(x) for x in basenames]
+ latest = sorted(numbers)[-1]
+ latest_dir = os.path.join(builds_dir, str(latest))
+ latest_meta = self.load_build_metadata(latest_dir)
+ return latest_meta.commit != current_commit
+ return True
+
+ def load_build_metadata(self, build_dir):
+ filename = os.path.join(build_dir, 'meta.yaml')
+ with open(filename) as f:
+ obj = yaml.safe_load(f)
+ meta = BuildMetadata()
+ meta.commit = obj['commit']
+ return meta
+
+ def get_next_build_dir(self, statedir, project_name):
+ builds_dir = os.path.join(statedir, project_name, 'builds')
+ if os.path.exists(builds_dir):
+ basenames = os.listdir(builds_dir)
+ else:
+ basenames = []
+ if basenames:
+ numbers = [int(x) for x in basenames]
+ next = sorted(numbers)[-1] + 1
+ else:
+ next = 1
+ build_dir = os.path.join(builds_dir, str(next))
+ os.makedirs(build_dir)
+ return build_dir
+
+ def get_git_dir(self, statedir, project_name):
+ return os.path.join(statedir, project_name, 'git')
+
+ def clone_or_update_git_repository_locally(self, git_dir, url, branch):
+ cliapp.runcmd(['rm', '-rf', git_dir])
+ cliapp.runcmd(
+ ['git', 'clone', '--verbose', '--branch', branch, url, git_dir])
+
+ def get_head_commit(self, git_dir):
+ output = cliapp.runcmd(['git', 'rev-parse', 'HEAD'], cwd=git_dir)
+ return output.strip()
def build_on_target(self, project_name, project, target_name, target,
git_dir):
@@ -136,6 +188,10 @@ class Ick(cliapp.Application):
lineno=lineno+1,
line=line)
+ def save_build_metadata(self, build_dir, meta):
+ filename = os.path.join(build_dir, 'meta.yaml')
+ meta.save(filename)
+
class Logger(object):
@@ -157,5 +213,18 @@ class Logger(object):
self._output.write(formatted + '\n')
+class BuildMetadata(object):
+
+ def __init__(self):
+ self.commit = None
+
+ def save(self, filename):
+ obj = {
+ "commit": self.commit,
+ }
+ with open(filename, 'w') as f:
+ yaml.safe_dump(obj, stream=f, default_flow_style=False, indent=4)
+
+
if __name__ == '__main__':
Ick().run()