root / trunk / twisted / scripts / tkunzip.py

Revision 15413, 9.1 kB (checked in by foom, 4 years ago)

Remove python-2.2 specific code.
Also update suppressWarning->.suppress in some places.

Line 
1 """Post-install GUI to compile to pyc and unpack twisted doco"""
2
3 from __future__ import generators
4
5 import sys
6 import zipfile
7 import py_compile
8
9 # we're going to ignore failures to import tkinter and fall back
10 # to using the console if the required dll is not found
11
12 # Scary kludge to work around tk84.dll bug:
13 # https://sourceforge.net/tracker/index.php?func=detail&aid=814654&group_id=5470&atid=105470
14 # Without which(): you get a windows missing-dll popup message
15 from twisted.python.procutils import which
16 tkdll='tk84.dll'
17 if which(tkdll) or which('DLLs/%s' % tkdll):
18     try:
19         import Tkinter
20         from Tkinter import *
21         from twisted.internet import tksupport
22     except ImportError:
23         pass
24
25 # twisted
26 from twisted.internet import reactor, defer
27 from twisted.python import failure, log, zipstream, util, usage, log
28 # local
29 import os.path
30
31 class ProgressBar:
32     def __init__(self, master=None, orientation="horizontal",
33                  min=0, max=100, width=100, height=18,
34                  doLabel=1, appearance="sunken",
35                  fillColor="blue", background="gray",
36                  labelColor="yellow", labelFont="Arial",
37                  labelText="", labelFormat="%d%%",
38                  value=0, bd=2):
39         # preserve various values
40         self.master=master
41         self.orientation=orientation
42         self.min=min
43         self.max=max
44         self.width=width
45         self.height=height
46         self.doLabel=doLabel
47         self.fillColor=fillColor
48         self.labelFont= labelFont
49         self.labelColor=labelColor
50         self.background=background
51         self.labelText=labelText
52         self.labelFormat=labelFormat
53         self.value=value
54         self.frame=Frame(master, relief=appearance, bd=bd)
55         self.canvas=Canvas(self.frame, height=height, width=width, bd=0,
56                            highlightthickness=0, background=background)
57         self.scale=self.canvas.create_rectangle(0, 0, width, height,
58                                                 fill=fillColor)
59         self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2,
60                                            height / 2, text=labelText,
61                                            anchor="c", fill=labelColor,
62                                            font=self.labelFont)
63         self.update()
64         self.canvas.pack(side='top', fill='x', expand='no')
65
66     def pack(self, *args, **kwargs):
67         self.frame.pack(*args, **kwargs)
68    
69     def updateProgress(self, newValue, newMax=None):
70         if newMax:
71             self.max = newMax
72         self.value = newValue
73         self.update()
74
75     def update(self):
76         # Trim the values to be between min and max
77         value=self.value
78         if value > self.max:
79             value = self.max
80         if value < self.min:
81             value = self.min
82         # Adjust the rectangle
83         if self.orientation == "horizontal":
84             self.canvas.coords(self.scale, 0, 0,
85               float(value) / self.max * self.width, self.height)
86         else:
87             self.canvas.coords(self.scale, 0,
88                                self.height - (float(value) /
89                                               self.max*self.height),
90                                self.width, self.height)
91         # Now update the colors
92         self.canvas.itemconfig(self.scale, fill=self.fillColor)
93         self.canvas.itemconfig(self.label, fill=self.labelColor)
94         # And update the label
95         if self.doLabel:
96             if value:
97                 if value >= 0:
98                     pvalue = int((float(value) / float(self.max)) *
99                                    100.0)
100                 else:
101                     pvalue = 0
102                 self.canvas.itemconfig(self.label, text=self.labelFormat
103                                          % pvalue)
104             else:
105                 self.canvas.itemconfig(self.label, text='')
106         else:
107             self.canvas.itemconfig(self.label, text=self.labelFormat %
108                                    self.labelText)
109         self.canvas.update_idletasks()
110
111
112 class Progressor:
113     """A base class to make it simple to hook a progress bar up to a process.
114     """
115     def __init__(self, title, *args, **kwargs):
116         self.title=title
117         self.stopping=0
118         self.bar=None
119         self.iterator=None
120         self.remaining=1000
121
122     def setBar(self, bar, max):
123         self.bar=bar
124         bar.updateProgress(0, max)
125         return self
126
127     def setIterator(self, iterator):
128         self.iterator=iterator
129         return self
130    
131     def updateBar(self, deferred):
132         b=self.bar
133         try:
134             b.updateProgress(b.max - self.remaining)
135         except TclError:
136             self.stopping=1
137         except:
138             deferred.errback(failure.Failure())
139
140     def processAll(self, root):
141         assert self.bar and self.iterator, "must setBar and setIterator"
142         self.root=root
143         root.title(self.title)
144         d=defer.Deferred()
145         d.addErrback(log.err)
146         reactor.callLater(0.1, self.processOne, d)
147         return d
148
149     def processOne(self, deferred):
150         if self.stopping:
151             deferred.callback(self.root)
152             return
153        
154         try:
155             self.remaining=self.iterator.next()
156         except StopIteration:
157             self.stopping=1           
158         except:
159             deferred.errback(failure.Failure())
160        
161         if self.remaining%10==0:
162             reactor.callLater(0, self.updateBar, deferred)
163         if self.remaining%100==0:
164             log.msg(self.remaining)
165         reactor.callLater(0, self.processOne, deferred)
166
167 def compiler(path):
168     """A generator for compiling files to .pyc"""
169     def justlist(arg, directory, names):
170         pynames=[os.path.join(directory, n) for n in names
171                  if n.endswith('.py')]
172         arg.extend(pynames)
173     all=[]
174     os.path.walk(path, justlist, all)
175
176     remaining=len(all)
177     i=zip(all, range(remaining-1, -1, -1))
178     for f, remaining in i:
179         py_compile.compile(f)
180         yield remaining
181
182 class TkunzipOptions(usage.Options):
183     optParameters=[["zipfile", "z", "", "a zipfile"],
184                    ["ziptargetdir", "t", ".", "where to extract zipfile"],
185                    ["compiledir", "c", "", "a directory to compile"],
186                    ]
187     optFlags=[["use-console", "C", "show in the console, not graphically"],
188               ["shell-exec", "x", """\
189 spawn a new console to show output (implies -C)"""],
190               ]
191
192 def countPys(countl, directory, names):
193     sofar=countl[0]
194     sofar=sofar+len([f for f in names if f.endswith('.py')])
195     countl[0]=sofar
196     return sofar
197
198 def countPysRecursive(path):
199     countl=[0]
200     os.path.walk(path, countPys, countl)
201     return countl[0]
202
203 def run(argv=sys.argv):
204     log.startLogging(file('tkunzip.log', 'w'))
205     opt=TkunzipOptions()
206     try:
207         opt.parseOptions(argv[1:])
208     except usage.UsageError, e:
209         print str(opt)
210         print str(e)
211         sys.exit(1)
212
213     if opt['use-console']:
214         # this should come before shell-exec to prevent infinite loop
215         return doItConsolicious(opt)             
216     if opt['shell-exec'] or not 'Tkinter' in sys.modules:
217         from distutils import sysconfig
218         from twisted.scripts import tkunzip
219         myfile=tkunzip.__file__
220         exe=os.path.join(sysconfig.get_config_var('prefix'), 'python.exe')
221         return os.system('%s %s --use-console %s' % (exe, myfile,
222                                                      ' '.join(argv[1:])))
223     return doItTkinterly(opt)
224
225 def doItConsolicious(opt):
226     # reclaim stdout/stderr from log
227     sys.stdout = sys.__stdout__
228     sys.stderr = sys.__stderr__
229     if opt['zipfile']:
230         print 'Unpacking documentation...'
231         for n in zipstream.unzipIter(opt['zipfile'], opt['ziptargetdir']):
232             if n % 100 == 0:
233                 print n,
234             if n % 1000 == 0:
235                 print
236         print 'Done unpacking.'
237        
238     if opt['compiledir']:
239         print 'Compiling to pyc...'
240         import compileall
241         compileall.compile_dir(opt["compiledir"])
242         print 'Done compiling.'
243
244 def doItTkinterly(opt):
245     root=Tkinter.Tk()
246     root.withdraw()
247     root.title('One Moment.')
248     root.protocol('WM_DELETE_WINDOW', reactor.stop)
249     tksupport.install(root)
250    
251     prog=ProgressBar(root, value=0, labelColor="black", width=200)
252     prog.pack()
253
254     # callback immediately
255     d=defer.succeed(root).addErrback(log.err)
256
257     def deiconify(root):
258         root.deiconify()
259         return root
260
261     d.addCallback(deiconify)
262    
263     if opt['zipfile']:
264         uz=Progressor('Unpacking documentation...')
265         max=zipstream.countZipFileChunks(opt['zipfile'], 4096)
266         uz.setBar(prog, max)
267         uz.setIterator(zipstream.unzipIterChunky(opt['zipfile'],
268                                                  opt['ziptargetdir']))
269         d.addCallback(uz.processAll)
270
271     if opt['compiledir']:
272         comp=Progressor('Compiling to pyc...')
273         comp.setBar(prog, countPysRecursive(opt['compiledir']))
274         comp.setIterator(compiler(opt['compiledir']))
275         d.addCallback(comp.processAll)
276
277     def stop(ignore):
278         reactor.stop()
279         root.destroy()
280     d.addCallback(stop)
281
282     reactor.run()
283
284
285 if __name__=='__main__':
286     run()
Note: See TracBrowser for help on using the browser.