|
1 # Copyright (C) 2003-2007 John Goerzen |
|
2 # <jgoerzen@complete.org> |
|
3 # |
|
4 # This program is free software; you can redistribute it and/or modify |
|
5 # it under the terms of the GNU General Public License as published by |
|
6 # the Free Software Foundation; either version 2 of the License, or |
|
7 # (at your option) any later version. |
|
8 # |
|
9 # This program is distributed in the hope that it will be useful, |
|
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 # GNU General Public License for more details. |
|
13 # |
|
14 # You should have received a copy of the GNU General Public License |
|
15 # along with this program; if not, write to the Free Software |
|
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
|
18 import sys, os |
|
19 import util |
|
20 from commandver import isdarcs |
|
21 from tempfile import mkdtemp |
|
22 |
|
23 class interaction: |
|
24 def __init__(self, wcobj, importdir, docommit, log = '', verbose = 0, |
|
25 summary = None): |
|
26 self.wcobj = wcobj |
|
27 self.log = log |
|
28 self.docommit = docommit |
|
29 self.verb = verbose |
|
30 self.summary = summary |
|
31 |
|
32 if os.path.isdir(importdir): |
|
33 self.importdir = os.path.abspath(importdir) |
|
34 self.importfile = None |
|
35 self.tmpdir = None |
|
36 |
|
37 else: # Not a dir, try to unpack an archive. |
|
38 self.importfile = os.path.abspath(importdir) |
|
39 # mkdtemp returns an absolute path |
|
40 self.importdir = mkdtemp("-vcs-load-dirs", ",,unpack-", "..") |
|
41 self.tmpdir = self.importdir |
|
42 |
|
43 try: |
|
44 if self.verb: |
|
45 print "Unpacking archive..." |
|
46 |
|
47 if self.importfile.endswith(".tar.gz"): |
|
48 util.chdircmd(self.importdir, util.safeexec, "tar", |
|
49 ["-zxf", self.importfile]) |
|
50 |
|
51 elif self.importfile.endswith(".tar.bz2"): |
|
52 util.chdircmd(self.importdir, util.safeexec, "tar", |
|
53 ["-jxf", self.importfile]) |
|
54 elif self.importfile.endswith(".zip"): |
|
55 util.chdircmd(self.importdir, util.safeexec, "unzip", |
|
56 [self.importfile]) |
|
57 else: |
|
58 raise IOError, "Unknown archive file type" |
|
59 |
|
60 # Many tarballs expand into just one single directory. |
|
61 # Check to see if that's the case. |
|
62 |
|
63 dents = os.listdir(self.importdir) |
|
64 if len(dents) == 1 and os.path.isdir(self.importdir + "/" + |
|
65 dents[0]): |
|
66 self.importdir = self.importdir + "/" + dents[0] |
|
67 except: |
|
68 self.cleanup() |
|
69 raise |
|
70 |
|
71 def cleanup(self): |
|
72 if not (self.tmpdir is None): |
|
73 util.safeexec("rm", ["-rf", self.tmpdir]) |
|
74 self.tmpdir = None |
|
75 |
|
76 def updateimportfiles(self): |
|
77 if self.verb: |
|
78 print "Scanning upstream tree..." |
|
79 self.importfiles = util.maketree(self.importdir) |
|
80 |
|
81 def updatewcfiles(self): |
|
82 if self.verb: |
|
83 print "Scanning working copy tree..." |
|
84 self.wcfiles = self.wcobj.gettree() |
|
85 |
|
86 def update(self): |
|
87 self.updatewcfiles() |
|
88 self.updatechangedfiles() |
|
89 |
|
90 def updatechangedfiles(self): |
|
91 if self.verb: |
|
92 print "Calculating changes..." |
|
93 wcfilehash = {} |
|
94 for x in self.wcfiles: |
|
95 wcfilehash[x] = 1 |
|
96 importfilehash = {} |
|
97 for x in self.importfiles: |
|
98 importfilehash[x] = 1 |
|
99 |
|
100 self.addedfiles = [x for x in self.importfiles if not wcfilehash.has_key(x)] |
|
101 self.deletedfiles = [x for x in self.wcfiles if not importfilehash.has_key(x)] |
|
102 |
|
103 |
|
104 def main(self): |
|
105 def readloop(): |
|
106 for command in sys.stdin.readline().strip().split(','): |
|
107 command = command.strip() |
|
108 if command == 'q': |
|
109 return 0 |
|
110 if command == 'r': |
|
111 return 1 |
|
112 src, dest = command.split(' ') |
|
113 src = int(src, 16) |
|
114 dest = int(dest, 16) |
|
115 self.mv(self.deletedfiles[src], self.addedfiles[dest]) |
|
116 return 1 |
|
117 |
|
118 self.updateimportfiles() |
|
119 needsupdate = 1 |
|
120 |
|
121 while 1: |
|
122 self.update() |
|
123 if self.wcobj.fsonly: |
|
124 # Don't show this interface if we're not talking to the VCS |
|
125 break |
|
126 if not (len(self.addedfiles) and len(self.deletedfiles)): |
|
127 # Just ran update; don't do it again. |
|
128 needsupdate = 0 |
|
129 break |
|
130 |
|
131 counter = 0 |
|
132 print "%3s %-35s %3s %-35s" % ('Num', 'Source Files', 'Num', |
|
133 'Destination Files',) |
|
134 print "%s %s %s %s" % ("-" * 3, "-" * 35, "-" * 3, "-" * 35) |
|
135 while counter < max(len(self.addedfiles), len(self.deletedfiles)): |
|
136 addfile = '' |
|
137 delfile = '' |
|
138 if counter < len(self.addedfiles): |
|
139 addfile = self.addedfiles[counter] |
|
140 if counter < len(self.deletedfiles): |
|
141 delfile = self.deletedfiles[counter] |
|
142 print "%3x %-35s %3x %-35s" % (counter, delfile, counter, addfile) |
|
143 counter += 1 |
|
144 print "Syntax: src dest [,src dest [,...]] to move, q to accept, r to redraw:" |
|
145 sys.stdout.write("Command: ") |
|
146 sys.stdout.flush() |
|
147 try: |
|
148 if not readloop(): |
|
149 break |
|
150 except ValueError: |
|
151 print "Error handling input; please try again." |
|
152 except IndexError: |
|
153 print "Error handling input; please try again." |
|
154 |
|
155 self.catchup(needsupdate) |
|
156 |
|
157 def catchup(self, needsupdate = 1): |
|
158 if self.verb: |
|
159 print " *** Processing changes." |
|
160 if needsupdate: |
|
161 self.update() |
|
162 if self.verb: |
|
163 print "Deleting %d files" % len(self.deletedfiles) |
|
164 if isdarcs(): |
|
165 for file in util.sorttree(self.deletedfiles, filesfirst = True): |
|
166 self.delfile(file) |
|
167 else: |
|
168 for file in self.deletedfiles: |
|
169 self.delfile(file) |
|
170 |
|
171 if self.verb: |
|
172 print "Copying upstream directory to working copy..." |
|
173 util.copyfrom(self.importdir, self.wcobj.wcpath) |
|
174 |
|
175 if self.verb: |
|
176 print "Adding %d files" % len(self.addedfiles) |
|
177 self.addedfiles.sort() # Make sure top-level dirs added before files |
|
178 for file in self.addedfiles: |
|
179 self.addfile(file) |
|
180 self.writelog() |
|
181 if self.docommit: |
|
182 self.wcobj.commit() |
|
183 |
|
184 def writelog(self): |
|
185 logtext = "" |
|
186 if not (self.importfile is None): |
|
187 importname = self.importfile |
|
188 else: |
|
189 importname = self.importdir |
|
190 |
|
191 if self.summary: |
|
192 summary = self.summary |
|
193 else: |
|
194 summary = "Imported %s" % os.path.basename(importname) |
|
195 logtext += "Imported %s\ninto %s\n\n" % \ |
|
196 (os.path.basename(importname), |
|
197 self.wcobj.gettreeversion()) |
|
198 logtext += self.log |
|
199 self.wcobj.makelog(summary, logtext) |
|
200 |
|
201 |
|
202 def addfile(self, file): |
|
203 self.wcobj.addtag(file) |
|
204 |
|
205 def delfile(self, file): |
|
206 self.wcobj.deltag(file) |
|
207 self.wcobj.delfile(file) |
|
208 |
|
209 |
|
210 def mv(self, src, dest): |
|
211 print "%s -> %s" % (src, dest) |
|
212 self.wcobj.movefile(src, dest) |
|
213 self.wcobj.movetag(src, dest) |
|
214 |