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