chiark / gitweb /
d5bd488701a3960a22aafd5b76969c36737be0a9
[stgit] / stgit / lib / stack.py
1 import os.path
2 from stgit import exception, utils
3 from stgit.lib import git
4
5 class Patch(object):
6     def __init__(self, stack, name):
7         self.__stack = stack
8         self.__name = name
9     name = property(lambda self: self.__name)
10     def __ref(self):
11         return 'refs/patches/%s/%s' % (self.__stack.name, self.__name)
12     @property
13     def commit(self):
14         return self.__stack.repository.refs.get(self.__ref())
15     def set_commit(self, commit, msg):
16         self.__stack.repository.refs.set(self.__ref(), commit, msg)
17     def delete(self):
18         self.__stack.repository.refs.delete(self.__ref())
19     def is_applied(self):
20         return self.name in self.__stack.patchorder.applied
21     def is_empty(self):
22         c = self.commit
23         return c.data.tree == c.data.parent.data.tree
24
25 class PatchOrder(object):
26     """Keeps track of patch order, and which patches are applied.
27     Works with patch names, not actual patches."""
28     __list_order = [ 'applied', 'unapplied' ]
29     def __init__(self, stack):
30         self.__stack = stack
31         self.__lists = {}
32     def __read_file(self, fn):
33         return tuple(utils.read_strings(
34             os.path.join(self.__stack.directory, fn)))
35     def __write_file(self, fn, val):
36         utils.write_strings(os.path.join(self.__stack.directory, fn), val)
37     def __get_list(self, name):
38         if not name in self.__lists:
39             self.__lists[name] = self.__read_file(name)
40         return self.__lists[name]
41     def __set_list(self, name, val):
42         val = tuple(val)
43         if val != self.__lists.get(name, None):
44             self.__lists[name] = val
45             self.__write_file(name, val)
46     applied = property(lambda self: self.__get_list('applied'),
47                        lambda self, val: self.__set_list('applied', val))
48     unapplied = property(lambda self: self.__get_list('unapplied'),
49                          lambda self, val: self.__set_list('unapplied', val))
50
51 class Patches(object):
52     """Creates Patch objects."""
53     def __init__(self, stack):
54         self.__stack = stack
55         def create_patch(name):
56             p = Patch(self.__stack, name)
57             p.commit # raise exception if the patch doesn't exist
58             return p
59         self.__patches = git.ObjectCache(create_patch) # name -> Patch
60     def exists(self, name):
61         try:
62             self.get(name)
63             return True
64         except KeyError:
65             return False
66     def get(self, name):
67         return self.__patches[name]
68     def new(self, name, commit, msg):
69         assert not name in self.__patches
70         p = Patch(self.__stack, name)
71         p.set_commit(commit, msg)
72         self.__patches[name] = p
73         return p
74
75 class Stack(object):
76     def __init__(self, repository, name):
77         self.__repository = repository
78         self.__name = name
79         try:
80             self.head
81         except KeyError:
82             raise exception.StgException('%s: no such branch' % name)
83         self.__patchorder = PatchOrder(self)
84         self.__patches = Patches(self)
85     name = property(lambda self: self.__name)
86     repository = property(lambda self: self.__repository)
87     patchorder = property(lambda self: self.__patchorder)
88     patches = property(lambda self: self.__patches)
89     @property
90     def directory(self):
91         return os.path.join(self.__repository.directory, 'patches', self.__name)
92     def __ref(self):
93         return 'refs/heads/%s' % self.__name
94     @property
95     def head(self):
96         return self.__repository.refs.get(self.__ref())
97     def set_head(self, commit, msg):
98         self.__repository.refs.set(self.__ref(), commit, msg)
99     @property
100     def base(self):
101         if self.patchorder.applied:
102             return self.patches.get(self.patchorder.applied[0]
103                                     ).commit.data.parent
104         else:
105             return self.head
106
107 class Repository(git.Repository):
108     def __init__(self, *args, **kwargs):
109         git.Repository.__init__(self, *args, **kwargs)
110         self.__stacks = {} # name -> Stack
111     @property
112     def current_branch(self):
113         return utils.strip_leading('refs/heads/', self.head)
114     @property
115     def current_stack(self):
116         return self.get_stack(self.current_branch)
117     def get_stack(self, name):
118         if not name in self.__stacks:
119             self.__stacks[name] = Stack(self, name)
120         return self.__stacks[name]