2b885b3c08b678a677716ed7ab97cd02c6415666
[redakcja.git] / lib / hg.py
1 # -*- coding: utf-8 -*-
2 import os
3 import codecs
4 from mercurial import localrepo, ui, error, match, node, encoding
5
6 encoding.encoding = 'utf-8'
7
8 class RepositoryDoesNotExist(Exception):
9     pass
10
11
12 class Repository(object):
13     """Abstrakcja repozytorium Mercurial. DziaƂa z Mercurial w wersji 1.3.1."""
14     
15     def __init__(self, path, create=False):
16         self.ui = ui.ui()
17         self.ui.config('ui', 'quiet', 'true')
18         self.ui.config('ui', 'interactive', 'false')
19         
20         self.real_path = os.path.realpath(path)
21         self.repo = self.open_repository(self.real_path, create)
22         self._pending_files = []
23     
24     def open_repository(self, path, create=False):
25         if os.path.isdir(path):
26             try:
27                 return localrepo.localrepository(self.ui, path)
28             except error.RepoError:
29                 # dir is not an hg repo, we must init it
30                 if create:
31                     return localrepo.localrepository(self.ui, path, create=1)
32         elif create:
33             os.makedirs(path)
34             return localrepo.localrepository(self.ui, path, create=1)
35         raise RepositoryDoesNotExist("Repository %s does not exist." % path)
36         
37     def all_files(self):
38         return list(self.repo['tip'])
39     
40     def get_file(self, path):
41         ctx = self.repo.changectx(None)
42         return ctx.filectx(path)
43     
44     def add_file(self, path, value):
45         f = codecs.open(os.path.join(self.real_path, path), 'w', encoding='utf-8')
46         f.write(value)
47         f.close()
48
49         if path not in self._pending_files:
50             self._pending_files.append(path)
51     
52     def commit(self, message=u'hgshelve auto commit', key=None, user=None):
53         """
54         Commit unsynchronized data to disk.
55         Arguments::
56
57          - message: mercurial's changeset message
58          - key: supply to sync only one key
59         """
60         if isinstance(message, unicode):
61             message = message.encode('utf-8')
62         if isinstance(user, unicode):
63             user = user.encode('utf-8')
64         
65         commited = False
66         rev = None
67         files_to_add = []
68         files_to_remove = []
69         files_to_commit = []
70
71         # first of all, add absent data and clean removed
72         if key is None:
73             # will commit all keys
74             pending_files = self._pending_files
75         else:
76             if keys not in self._pending_files:
77                 # key isn't changed
78                 return None
79             else:
80                 pending_files = [key]
81         for path in pending_files:
82             files_to_commit.append(path)
83             if path in self.all_files():
84                 if not os.path.exists(os.path.join(self.real_path, path)):
85                     # file removed
86                     files_to_remove.append(path)
87             else:
88                 # file added
89                 files_to_add.append(path)
90         # hg add
91         if files_to_add:
92             self.repo.add(files_to_add)
93         # hg forget
94         if files_to_remove:
95             self.repo.forget(files_to_remove)
96         # ---- hg commit
97         if files_to_commit:
98             for i, f in enumerate(files_to_commit):
99                 if isinstance(f, unicode):
100                     files_to_commit[i] = f.encode('utf-8')
101             matcher = match.match(self.repo.root, self.repo.root, files_to_commit, default='path')
102             rev = self.repo.commit(message, user=user, match=matcher)
103             commited = True
104         # clean pending keys
105         for key in pending_files:
106             self._pending_files.remove(key)
107         # if commited:
108             # reread keys
109             # self._keys = self.get_persisted_objects_keys()
110             # return node.hex(rev)
111
112     def in_branch(self, branch_name, action):
113         wlock = self.repo.wlock()
114         try:
115             current_branch = self.repo[None].branch()
116             self.repo.dirstate.setbranch(branch_name)
117             try:
118                 # do some stuff
119                 action()
120             finally:
121                 self.repo.dirstate.setbranch(current_branch)
122         finally:
123             wlock.release()
124
125     def write_lock(self):
126         """Returns w write lock to the repository."""
127         return self.repo.wlock()
128
129