00001
00002
00003
00004
00005
00006
00007
00008 import sys
00009 import os
00010 import re
00011 import filecmp
00012 import gobject
00013
00014 import filesystem
00015
00016 class Controller (filesystem.Controller):
00017 rules = ('_darcs',)
00018
00019 def __init__(self, path):
00020 filesystem.Controller.__init__(self, path)
00021
00022 def is_controlled(self, name):
00023 escaped = escape(os.path.join('.', name))
00024
00025 re_add = re.compile('^add(file|dir) %s$' % escaped)
00026 re_remove = re.compile('^rm(file|dir) %s$' % escaped)
00027 re_move_in = re.compile('^move .* %s$' % escaped)
00028 re_move_out = re.compile('^move %s ' % escaped)
00029
00030 current = self._get_current_path(name)
00031 control = os.path.exists(current)
00032
00033 pending = os.path.join(self.root, '_darcs', 'patches', 'pending')
00034 if os.path.exists(pending):
00035 file = open(pending)
00036
00037 for line in file:
00038 line = line.rstrip('\n')
00039
00040 if control:
00041 if re_remove.match(line) or re_move_out.match(line):
00042 control = False
00043 else:
00044 if re_add.match(line) or re_move_in.match(line):
00045 control = True
00046
00047 file.close()
00048
00049 return control
00050
00051 def is_modified(self, name):
00052 current = self._get_current_path(name)
00053 if os.path.exists(current):
00054 if os.path.isdir(current):
00055 return False
00056 else:
00057 work = self._get_path(name)
00058 return not filecmp.cmp(work, current)
00059 else:
00060 return True
00061
00062 def get_latest(self, name):
00063 current = self._get_current_path(name)
00064 if os.path.exists(current):
00065 file = open(current)
00066 data = file.read()
00067 file.close()
00068 return data
00069 else:
00070 return None
00071
00072 def control(self, name, recursive=False):
00073 if recursive:
00074 self._call(['add', '--recursive', name])
00075 else:
00076 self._call(['add', name])
00077
00078 def release(self, name):
00079 names = self._find_controlled(name)
00080 self._call(['remove'] + names)
00081
00082 def make_file(self, name, control=True):
00083 filesystem.Controller.make_file(self, name)
00084 if control:
00085 self._call(['add', name])
00086
00087 def make_directory(self, name, control=True):
00088 filesystem.Controller.make_directory(self, name)
00089 if control:
00090 self._call(['add', name])
00091
00092 def remove(self, name, control=True):
00093 filesystem.Controller.remove(self, name)
00094 if control:
00095 self._call(['remove', name])
00096
00097 def rename(self, old_name, new_name, control=True):
00098 if control:
00099 self._call(['mv', old_name, new_name])
00100 else:
00101 filesystem.Controller.rename(self, old_name, new_name)
00102
00103 def clone(self, old_name, new_name, control=True):
00104 filesystem.Controller.clone(self, old_name, new_name)
00105 if control:
00106 self._call(['add', '--recursive', new_name])
00107
00108 def _get_current_path(self, name):
00109 return os.path.join(self.root, '_darcs', 'current', name)
00110
00111 def _find_controlled(self, name):
00112 contents = [name]
00113
00114 path = self._get_path(name)
00115 if os.path.isdir(path):
00116 for filename in os.listdir(path):
00117 if filename == '.' or filename == '..':
00118 continue
00119
00120 child_name = os.path.join(name, filename)
00121 if self.is_controlled(child_name):
00122 child_contents = self._find_controlled(child_name)
00123 contents = child_contents + contents
00124
00125 return contents
00126
00127 def _call(self, params):
00128 args = ['darcs'] + params
00129 pid, fd = call(args, self.root)
00130
00131 errors = None
00132
00133 try:
00134 file = os.fdopen(fd, 'r')
00135
00136 while True:
00137 try:
00138 errors = file.read()
00139 except OSError:
00140 continue
00141 break
00142
00143 file.close()
00144 except:
00145 try:
00146 os.waitpid(pid, 0)
00147 except:
00148 pass
00149 raise
00150
00151 pid, status = os.waitpid(pid, 0)
00152
00153 code = status >> 8
00154 if code != 0:
00155 if not errors:
00156 errors = 'Return code: %d' % code
00157
00158 raise DarcsError(errors)
00159
00160 gobject.type_register(Controller)
00161
00162 class DarcsError (Exception):
00163 prefix = 'darcs failed:'
00164
00165 def __init__(self, message):
00166 if message.startswith(self.prefix):
00167 message = message[len(self.prefix):]
00168
00169 message = message.strip()
00170
00171 Exception.__init__(self, message)
00172
00173 def call(args, workdir):
00174 assert type(args) == list and len(args) > 0
00175
00176 pipe = os.pipe()
00177
00178 pid = os.fork()
00179 if pid == 0:
00180 try:
00181 os.dup2(pipe[1], 2)
00182 os.close(pipe[0])
00183 os.close(pipe[1])
00184
00185 os.close(0)
00186
00187 null = os.open(os.devnull, os.O_RDONLY)
00188 if null != 0:
00189 os.dup2(null, 0)
00190 os.close(null)
00191
00192 os.chdir(workdir)
00193 os.execvp(args[0], args)
00194
00195 except Exception, e:
00196 try:
00197 print >>sys.stderr, '%s:' % args[0],
00198 except:
00199 pass
00200
00201 try:
00202 print >>sys.stderr, e
00203 except:
00204 pass
00205
00206 os._exit(127)
00207
00208 try:
00209 os.close(pipe[1])
00210 except:
00211 try:
00212 os.waitpid(pid, 0)
00213 except:
00214 pass
00215 raise
00216
00217 return pid, pipe[0]
00218
00219 def escape(path):
00220 for c in '\\.':
00221 path = path.replace(c, '\\' + c)
00222 return path