Refactor openstack_git_repo & add openstack_commit
It will become more and more important to have more information about individual commits to an openstack repo. Therefore, add the OpenstackCommit class. Refactor OpenstackGitRepo to accomodate this.
This commit is contained in:
parent
a0c7bde589
commit
ffdccc26e9
|
@ -0,0 +1,140 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2014, Craig Tracey <craigtracey@gmail.com>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
|
||||
from giftwrap.gerrit import GerritReview
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenstackCommit(object):
|
||||
|
||||
def __init__(self, commit, project, branch, meta_cache_dir=None):
|
||||
self.commit = commit
|
||||
self.project = project
|
||||
self.branch = branch
|
||||
self._change_id = None
|
||||
self._editable_dependencies = None
|
||||
self._pip_dependencies = None
|
||||
self._is_merge = None
|
||||
self._parent = None
|
||||
self._gerrit_review = None
|
||||
self._meta_cache_dir = meta_cache_dir
|
||||
|
||||
@property
|
||||
def hexsha(self):
|
||||
return self.commit.hexsha
|
||||
|
||||
@property
|
||||
def change_id(self):
|
||||
if not self._change_id:
|
||||
self._change_id = str(self._get_change_id())
|
||||
return self._change_id
|
||||
|
||||
@property
|
||||
def is_merge(self):
|
||||
if self._is_merge is None:
|
||||
self._is_merge = (len(self.commit.parents) == 2)
|
||||
return self._is_merge
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
if self.is_merge:
|
||||
self._parent = OpenstackCommit(self.commit.parents[1],
|
||||
self.project, self.branch)
|
||||
return self._parent
|
||||
|
||||
@property
|
||||
def gerrit_review(self):
|
||||
if not self._gerrit_review:
|
||||
self._gerrit_review = GerritReview(self.change_id,
|
||||
self.project, self.branch)
|
||||
return self._gerrit_review
|
||||
|
||||
def _gather_dependencies(self):
|
||||
try:
|
||||
deps = self.gerrit_review.build_pip_dependencies()
|
||||
self._editable_dependencies = []
|
||||
self._pip_dependencies = {}
|
||||
for dep in deps:
|
||||
if '-e' in dep:
|
||||
self._editable_dependencies.append(dep)
|
||||
else:
|
||||
parts = dep.split('==')
|
||||
self._pip_dependencies[parts[0]] = parts[1]
|
||||
except Exception as e:
|
||||
LOG.debug("Couldn't find dependencies for %s: %s", self.hexsha, e)
|
||||
|
||||
@property
|
||||
def pip_dependencies(self):
|
||||
if not self._pip_dependencies:
|
||||
self._gather_dependencies()
|
||||
return self._pip_dependencies
|
||||
|
||||
@property
|
||||
def editable_dependencies(self):
|
||||
if not self._editable_dependencies:
|
||||
self._gather_dependencies()
|
||||
return self._editable_dependencies
|
||||
|
||||
def _get_change_id(self):
|
||||
commit = self.commit
|
||||
if self.is_merge:
|
||||
commit = self.parent.commit
|
||||
match = re.search('Change-Id:\s*(I\w+)', commit.message)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
def is_cached(self):
|
||||
return os.path.isfile(self.cache_file)
|
||||
|
||||
@property
|
||||
def cache_file(self):
|
||||
return os.path.join(self._meta_cache_dir, self.hexsha)
|
||||
|
||||
def _get_from_cache(self, key):
|
||||
if self.is_cached():
|
||||
with open(self.cache_file, 'r') as fh:
|
||||
cached_data = yaml.load(fh)
|
||||
if key in cached_data:
|
||||
return cached_data[key]
|
||||
return None
|
||||
|
||||
def is_cacheable(self):
|
||||
if self.pip_dependencies or self.editable_dependencies:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __dict__(self):
|
||||
data = {}
|
||||
data['pip_dependencies'] = self.pip_dependencies
|
||||
data['editable_dependencies'] = self.editable_dependencies
|
||||
data['change_id'] = self.change_id
|
||||
return data
|
||||
|
||||
def persist_to_cache(self):
|
||||
if not self.is_cacheable():
|
||||
LOG.debug("Not caching %s as there is no point", self.hexsha)
|
||||
return
|
||||
dirname = os.path.dirname(self.cache_file)
|
||||
if not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
with open(self.cache_file, 'w') as fh:
|
||||
fh.write(yaml.dump(self.__dict__()))
|
|
@ -16,22 +16,27 @@
|
|||
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
from giftwrap.openstack_commit import OpenstackCommit
|
||||
from git import Repo
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenstackGitRepo(object):
|
||||
def __init__(self, url, ref='master'):
|
||||
|
||||
def __init__(self, url, project=None, branch='master',
|
||||
metadata_cache_dir=None):
|
||||
self.url = url
|
||||
self.ref = ref
|
||||
self._project = project
|
||||
self.branch = branch
|
||||
self._repo = None
|
||||
self._head = None
|
||||
self._change_id = None
|
||||
self._committed_date = None
|
||||
self._metadata_cache_dir = metadata_cache_dir
|
||||
self._head_commit = None
|
||||
|
||||
@property
|
||||
def cloned(self):
|
||||
|
@ -39,50 +44,79 @@ class OpenstackGitRepo(object):
|
|||
|
||||
@property
|
||||
def head(self):
|
||||
if not self._head and self._repo:
|
||||
self._head = self._repo.head.commit.hexsha
|
||||
return self._head
|
||||
if not self._head_commit and self._repo:
|
||||
self._head_commit = OpenstackCommit(self._repo.head.commit,
|
||||
self.project, self.branch,
|
||||
self._cache_dir())
|
||||
return self._head_commit
|
||||
|
||||
@property
|
||||
def change_id(self):
|
||||
if not self._change_id and self._repo:
|
||||
for commit in self._repo.iter_commits():
|
||||
match = re.search('Change-Id:\s*(I\w+)', commit.message)
|
||||
if match:
|
||||
self._change_id = match.group(1)
|
||||
break
|
||||
return self._change_id
|
||||
|
||||
@property
|
||||
def committed_date(self):
|
||||
if not self._committed_date and self._repo:
|
||||
self._committed_date = self._repo.head.commit.committed_date
|
||||
return self._committed_date
|
||||
|
||||
def _invalidate_attrs(self):
|
||||
self._head = None
|
||||
self._change_id = None
|
||||
self._committed_date = None
|
||||
def project(self):
|
||||
if not self._project:
|
||||
parsed_url = urlparse.urlparse(self.url)
|
||||
project = os.path.splitext(parsed_url.path)[0]
|
||||
self._project = re.sub(r'^/', '', project)
|
||||
return self._project
|
||||
|
||||
def clone(self, outdir):
|
||||
LOG.info("Cloning '%s' to '%s'", self.url, outdir)
|
||||
self._repo = Repo.clone_from(self.url, outdir)
|
||||
LOG.debug("Cloning '%s' to '%s'", self.url, outdir)
|
||||
self._repo = Repo.clone_from(self.url, outdir, recursive=True)
|
||||
git = self._repo.git
|
||||
git.checkout(self.ref)
|
||||
git.checkout(self.branch)
|
||||
self._invalidate_attrs()
|
||||
|
||||
def checkout_branch(self, branch, update=True):
|
||||
if not self._repo:
|
||||
raise Exception("Cannot checkout on non-existent repo")
|
||||
LOG.debug("Checking out branch: %s (update: %s)", branch, update)
|
||||
self._repo.git.checkout(branch)
|
||||
self._invalidate_attrs()
|
||||
self.branch = branch
|
||||
if update:
|
||||
self._repo.git.pull('origin', branch)
|
||||
|
||||
@property
|
||||
def branches(self):
|
||||
branches = []
|
||||
for ref in self._repo.remotes.origin.refs:
|
||||
branches.append(re.sub('^\w*/', '', ref.name))
|
||||
return branches
|
||||
|
||||
def __iter__(self):
|
||||
if not self._repo:
|
||||
raise Exception("iterator called before clone")
|
||||
self._commit_iterator = self._repo.iter_commits()
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
print self._cache_dir()
|
||||
return OpenstackCommit(next(self._commit_iterator),
|
||||
self.project, self.branch,
|
||||
self._cache_dir())
|
||||
|
||||
def _cache_dir(self):
|
||||
if self._metadata_cache_dir:
|
||||
return os.path.join(self._metadata_cache_dir,
|
||||
self.project, self.branch)
|
||||
return None
|
||||
|
||||
def _invalidate_attrs(self):
|
||||
self._head_commit = None
|
||||
self._commit_iterator = None
|
||||
|
||||
def reset_to_date(self, date):
|
||||
if self._repo:
|
||||
commit_date_sha = None
|
||||
for commit in self._repo.iter_commits():
|
||||
if commit.committed_date >= date:
|
||||
commit_date_sha = commit.hexsha
|
||||
continue
|
||||
elif commit.committed_date < date:
|
||||
commit_date_sha = commit.hexsha
|
||||
break
|
||||
if not commit_date_sha:
|
||||
raise Exception("Unable to find commit for date %s",
|
||||
datetime.datetime.fromtimestamp(date))
|
||||
git = self._repo.git
|
||||
LOG.info("Reset repo '%s' to commit at '%s'", self.url,
|
||||
time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(date)))
|
||||
LOG.debug("Reset repo '%s' to commit at '%s'", self.url,
|
||||
time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(date)))
|
||||
git.checkout(commit_date_sha)
|
||||
|
|
Loading…
Reference in New Issue