~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/scripts/tkunzip.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
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()