1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
# Copyright 2015 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
import os.path
import subprocess
from fixtures import (
EnvironmentVariable,
TempDir,
)
from testtools import TestCase
class GitRepository:
def __init__(self, path, allow_create=True):
self.path = path
if not os.path.exists(path):
os.makedirs(path)
if allow_create and not os.path.exists(os.path.join(path, ".git")):
self._git_call("init", "-q")
def _git_call(self, *args, **kwargs):
subprocess.check_call(["git", "-C", self.path] + list(args), **kwargs)
def _git_output(self, *args, **kwargs):
return subprocess.check_output(
["git", "-C", self.path] + list(args),
universal_newlines=True, **kwargs)
def rev_parse(self, rev):
return self._git_output("rev-parse", rev).rstrip("\n")
def last_revision(self):
return self.rev_parse("HEAD")
def status(self):
return self._git_output("status", "--porcelain").splitlines()
def add(self, files):
self._git_call("add", *files)
def commit(self, message, date=None):
env = os.environ.copy()
if date is not None:
env["GIT_COMMITTER_DATE"] = date
self._git_call("commit", "-q", "--allow-empty", "-m", message, env=env)
return self.last_revision()
def branch(self, branch_name, commit):
self._git_call("branch", branch_name, commit)
def tag(self, tag_name, commit, force=False):
args = ["tag"]
if force:
args.append("--force")
args.extend([tag_name, commit])
self._git_call(*args, stdout=subprocess.DEVNULL)
def set_head(self, ref_path):
self._git_call("symbolic-ref", "HEAD", ref_path)
def get_parents(self, commit):
return self._git_output(
"log", "-1", "--format=%P", commit).rstrip("\n").split()
def clone_to(self, new_path):
subprocess.check_call(["git", "clone", "-q", self.path, new_path])
return GitRepository(new_path, allow_create=False)
def build_tree(self, shape):
"""Build a test tree according to a pattern.
shape is a sequence of file specifications. If the final character
is '/', a directory is created.
This assumes that all the elements in the tree being built are new.
This doesn't add anything to the index or make any commits.
:type shape: list or tuple
:return: None
"""
if not isinstance(shape, (list, tuple)):
raise AssertionError(
"Parameter 'shape' should be a list or a tuple. Got %r "
"instead" % (shape,))
for name in shape:
assert isinstance(name, str)
if name.endswith("/"):
os.mkdir(os.path.join(self.path, name))
else:
dirname = os.path.dirname(os.path.join(self.path, name))
if not os.path.isdir(dirname):
os.makedirs(dirname)
with open(os.path.join(self.path, name), "w") as f:
f.write("contents of %s\n" % name)
def build_tree_contents(self, template):
"""Reconstitute some files from a text description.
Each element of template is a tuple. The first element is a
filename, with an optional ending character indicating the type.
The template is built relative to the repository's current working
directory.
('foo/',) will build a directory.
('foo', 'bar') will write 'bar' to 'foo'.
('foo@', 'linktarget') will raise an error.
"""
for tt in template:
name = tt[0]
output_path = os.path.join(self.path, name)
if name.endswith("/"):
os.mkdir(output_path)
elif name.endswith("@"):
os.symlink(tt[1], output_path[:-1])
else:
with open(output_path, "w") as f:
f.write(tt[1])
class GitTestCase(TestCase):
def setUp(self):
super().setUp()
# git complains if the user name and email aren't configured at all.
home = self.make_temporary_directory()
self.useFixture(EnvironmentVariable("HOME", home))
with open(os.path.join(home, ".gitconfig"), "w") as gitconfig:
print("[user]", file=gitconfig)
print('\tname = "Committer"', file=gitconfig)
print('\temail = "committer@example.org"', file=gitconfig)
def make_temporary_directory(self):
"""Create a temporary directory, and return its path."""
return self.useFixture(TempDir()).path
def use_temp_dir(self):
"""Use a temporary directory for this test."""
tempdir = self.make_temporary_directory()
cwd = os.getcwd()
os.chdir(tempdir)
self.addCleanup(os.chdir, cwd)
return tempdir
|