Implement unedit
[yap.git] / yap / yap.py
blobc00b31a6f2e8f9eeeb3d68cd73e7ff634e9988e0
1 import sys
2 import os
3 import getopt
4 import pickle
6 def get_output(cmd):
7 fd = os.popen(cmd)
8 output = fd.readlines()
9 rc = fd.close()
10 return [x.strip() for x in output]
12 def run_command(cmd):
13 rc = os.system("%s > /dev/null 2>&1" % cmd)
14 rc >>= 8
15 return rc
17 class YapError(Exception):
18 def __init__(self, msg):
19 self.msg = msg
21 def __str__(self):
22 return self.msg
24 def takes_options(options):
25 def decorator(func):
26 func.options = options
27 return func
28 return decorator
30 class Yap(object):
31 def _add_new_file(self, file):
32 repo = get_output('git rev-parse --git-dir')[0]
33 dir = os.path.join(repo, 'yap')
34 try:
35 os.mkdir(dir)
36 except OSError:
37 pass
38 files = self._get_new_files()
39 files.append(file)
40 path = os.path.join(dir, 'new-files')
41 pickle.dump(files, open(path, 'w'))
43 def _get_new_files(self):
44 repo = get_output('git rev-parse --git-dir')[0]
45 path = os.path.join(repo, 'yap', 'new-files')
46 try:
47 files = pickle.load(file(path))
48 except IOError:
49 files = []
51 x = []
52 for f in files:
53 # if f in the index
54 if get_output("git ls-files --cached '%s'" % f) != []:
55 continue
56 x.append(f)
57 return x
59 def _remove_new_file(self, file):
60 files = self._get_new_files()
61 files = filter(lambda x: x != file, files)
63 repo = get_output('git rev-parse --git-dir')[0]
64 path = os.path.join(repo, 'yap', 'new-files')
65 pickle.dump(files, open(path, 'w'))
67 def _clear_new_files(self):
68 repo = get_output('git rev-parse --git-dir')[0]
69 path = os.path.join(repo, 'yap', 'new-files')
70 os.unlink(path)
72 def _assert_file_exists(self, file):
73 if not os.access(file, os.R_OK):
74 raise YapError("No such file: %s" % file)
76 def cmd_clone(self, url, directory=""):
77 # XXX: implement in terms of init + remote add + fetch
78 os.system("git clone '%s' %s" % (url, directory))
80 def cmd_init(self):
81 os.system("git init")
83 def cmd_add(self, file):
84 self._assert_file_exists(file)
85 x = get_output("git ls-files '%s'" % file)
86 if x != []:
87 raise YapError("File '%s' already in repository" % file)
88 self._add_new_file(file)
89 self.cmd_status()
91 def cmd_rm(self, file):
92 self._assert_file_exists(file)
93 if get_output("git ls-files '%s'" % file) != []:
94 os.system("git rm --cached '%s'" % file)
95 self._remove_new_file(file)
96 self.cmd_status()
98 def cmd_stage(self, file):
99 self._assert_file_exists(file)
100 os.system("git update-index --add '%s'" % file)
101 self.cmd_status()
103 def cmd_unstage(self, file):
104 self._assert_file_exists(file)
105 if run_command("git rev-parse HEAD"):
106 os.system("git update-index --force-remove '%s'" % file)
107 else:
108 os.system("git diff-index HEAD '%s' | git apply -R --cached" % file)
109 self.cmd_status()
111 def cmd_status(self):
112 branch = get_output("git symbolic-ref HEAD")[0]
113 branch = branch.replace('refs/heads/', '')
114 print "Current branch: %s" % branch
116 print "Files with staged changes:"
117 if run_command("git rev-parse HEAD"):
118 files = get_output("git ls-files --cached")
119 else:
120 files = get_output("git diff-index --name-only HEAD")
121 for f in files:
122 print "\t%s" % f
123 if not files:
124 print "\t(none)"
126 print "Files with unstages changes:"
127 files = self._get_new_files()
128 files += get_output("git ls-files -m")
129 for f in files:
130 print "\t%s" % f
131 if not files:
132 print "\t(none)"
134 def cmd_unedit(self, file):
135 self._assert_file_exists(file)
136 os.system("git checkout-index -f '%s'" % file)
137 self.cmd_status()
139 def cmd_version(self):
140 print "Yap version 0.1"
142 def cmd_usage(self):
143 print >> sys.stderr, "usage: %s <command>" % sys.argv[0]
144 print >> sys.stderr, " valid commands: version"
146 def main(self, args):
147 if len(args) < 1:
148 self.cmd_usage()
149 sys.exit(2)
151 command = args[0]
152 args = args[1:]
154 debug = os.getenv('YAP_DEBUG')
156 try:
157 meth = self.__getattribute__("cmd_"+command)
158 try:
159 if "option" in meth.__dict__:
160 flags, args = getopt.getopt(args, meth.options)
161 flags = dict(flags)
162 else:
163 flags = dict()
165 meth(*args, **flags)
166 except (TypeError, getopt.GetoptError):
167 if debug:
168 raise
169 print "%s %s %s" % (sys.argv[0], command, meth.__doc__)
170 except YapError, e:
171 print >> sys.stderr, e
172 sys.exit(1)
173 except AttributeError:
174 if debug:
175 raise
176 self.cmd_usage()
177 sys.exit(2)