Updated package list to match new versions / new packages.
[beastbuild.git] / utils.py
1 ###########################################################
2 # taken from kde windows port emerge
3 ###########################################################
4
5 # this file contains some helper functions for emerge
6
7 # copyright:
8 # Holger Schroeder <holger [AT] holgis [DOT] net>
9 # Patrick Spendrin <ps_ml [AT] gmx [DOT] de>
10
11
12 import httplib
13 import ftplib
14 import os
15 import sys
16 import re
17 import urlparse
18 import shutil
19 import zipfile
20 import tarfile
21 import hashlib
22 import subprocess
23 import __builtin__
24 import imp
25 from Path import Path
26 from config import config
27 from buildutils import platform_is_win32, platform_is_unix
28
29 ### fetch functions
30
31 #FIXME: get this from somewhere else:
32 if platform_is_win32():
33   WGetExecutable = os.path.join( config.PREFIX.native(), "bin", "wget.exe" )
34 else:
35   WGetExecutable = os.path.join( config.PREFIX.native(), "bin", "wget" )
36
37
38 def getFiles( urls, destdir ):
39     debug( "getfiles called. urls: %s" % urls, 1 )
40     # make sure distfiles dir exists
41     if ( not os.path.exists( destdir ) ):
42         os.makedirs( destdir )
43
44     for url in urls.split():
45         #print "getfiles url:", url
46         if ( not getFile( url, destdir ) ):
47             return False
48
49     return True
50
51 def getFile( url, destdir ):
52     debug( "getFile called. url: %s" % url, 1 )
53     if url == "":
54         error( "fetch: no url given" )
55         return False
56
57
58     wgetpath = WGetExecutable             ### FIXME
59     if ( os.path.exists( wgetpath ) ):
60         return wgetFile( url, destdir )
61
62     scheme, host, path, params, qu, fr = urlparse.urlparse( url )
63
64
65     filename = os.path.basename( path )
66     debug( "%s\n%s\n%s\n%s" % ( scheme, host, path, filename ) )
67
68     if ( scheme == "http" ):
69         return getHttpFile( host, path, destdir, filename )
70     elif ( scheme == "ftp" ):
71         return getFtpFile( host, path, destdir, filename )
72     else:
73         error( "getFile: protocol not understood" )
74         return False
75
76 def wgetFile( url, destdir ):
77     compath = WGetExecutable
78     command = "%s -c -t 1 -P %s %s" % ( compath, destdir, url )
79     debug( "wgetfile called", 1 )
80     attempts = 1
81     if url.lower().startswith( "http://downloads.sourceforge.net" ):
82         debug( "Detected downloads.sourceforge.net... Trying three times." )
83         attempts=3
84
85     while( attempts > 0 ):
86         attempts -= 1
87         ret = os.system( command )
88         debug( "wget ret: %s" % ret )
89         if ret == True:
90             # success stop early.
91             break;
92
93     return ret
94
95 def getFtpFile( host, path, destdir, filename ):
96     # FIXME check return values here (implement useful error handling)...
97     debug( "FIXME getFtpFile called. %s %s" % ( host, path ), 1 )
98
99     outfile = open( os.path.join( destdir, filename ), "wb" )
100     ftp = ftplib.FTP( host )
101     ftp.login( "anonymous", "johndoe@nowhere.org" )
102     ftp.retrbinary( "RETR " + path, outfile.write )
103
104     outfile.close()
105     return True
106
107 def getHttpFile( host, path, destdir, filename ):
108     # FIXME check return values here (implement useful error handling)...
109     debug( "getHttpFile called. %s %s" % ( host, path ) , 1 )
110
111     conn = httplib.HTTPConnection( host )
112     conn.request( "GET", path )
113     r1 = conn.getresponse()
114     debug( "status: %s; reason: %s" % ( str( r1.status ), str( r1.reason ) ) )
115         
116     count = 0
117     while r1.status == 302:
118         if count > 10:
119             print "Redirect loop"
120             return False
121         count += 1
122         scheme, host, path, params, qu, fr = urlparse.urlparse( r1.getheader( "Location" ) )
123         debug( "Redirection: %s %s" % ( host, path ), 1 )
124         conn = httplib.HTTPConnection( host )
125         conn.request( "GET", path )
126         r1 = conn.getresponse()
127         debug( "status: %s; reason: %s" % ( str( r1.status ), str( r1.reason ) ) )
128     
129         
130     data = r1.read()
131
132     f = open( os.path.join( destdir, filename ), "wb" )
133     f.write( data )
134     f.close()
135     return True
136
137
138 ### unpack functions
139
140 def unpackFiles( downloaddir, filenames, workdir ):
141     cleanDirectory( workdir )
142
143     for filename in filenames:
144         debug( "unpacking this file: %s" % filename, 1 )
145         if ( not unpackFile( downloaddir, filename, workdir ) ):
146             return False
147
148     return True
149
150 def unpackFile( downloaddir, filename, workdir ):
151     ( shortname, ext ) = os.path.splitext( filename )
152     if ( ext == ".zip" ):
153         return unZip (os.path.join (downloaddir.native(), filename), workdir)
154     elif ( ext == ".tgz" ):
155         return unTar (downloaddir.join (Path (filename)), workdir)
156     elif ( ext == ".gz" or ext == ".bz2" ):
157         ( myshortname, myext ) = os.path.splitext( shortname )
158         if ( myext == ".tar" ):
159             return unTar (downloaddir.join (Path (filename)), workdir)
160         else:
161             error( "unpacking %s" % myext )
162             return False
163     elif ( ext == ".exe" ):
164         warning( "unpack ignoring exe file" )
165         return True
166     error( "dont know how to unpack this file: %s" % filename )
167     return False
168
169 def unTar( file, destdir ):
170     debug( "unTar called. file: %s, destdir: %s" % ( file, destdir ), 1 )
171     ( shortname, ext ) = os.path.splitext( file.unix() )
172
173     mode = "r"
174     if (ext == ".gz" or ext == ".tgz"):
175         mode = "r:gz"
176     elif (ext == ".bz2"):
177         mode = "r:bz2"
178
179     tar = tarfile.open (file.native(), mode)
180
181     # FIXME how to handle errors here ?
182     for foo in tar:
183         tar.extract (foo, destdir.native())
184
185     return True
186
187 def unZip (file, destdir):
188     debug ("unZip called: file %s to destination %s" % (file, destdir.native()), 1)
189
190     if not os.path.exists (destdir.native()):
191         os.makedirs (destdir.native())
192
193     zip = zipfile.ZipFile (file)
194
195     for i, name in enumerate( zip.namelist() ):
196         if not name.endswith( '/' ):
197             dirname = os.path.join (destdir.native(), os.path.dirname (name))
198
199             if not os.path.exists (dirname):
200                 os.makedirs (dirname)
201
202             outfile = open (os.path.join (destdir.native(), name), 'wb')
203             outfile.write (zip.read (name))
204             outfile.flush()
205             outfile.close()
206
207     return True
208
209 ### debug functions
210 def info( message ):
211     if verbose() > 0:
212         print "beastbuild info: %s" % message
213     return True
214
215 def debug( message, level=0 ):
216     if verbose() > level:
217         print "beastbuild debug:", message
218     return True
219
220 def warning( message ):
221     if verbose() > 0:
222         print "beastbuild warning: %s" % message
223     return True
224
225 def debug_line( level=0 ):
226     if verbose() > level:
227         print "_" * 80
228
229 def error( message ):
230     if verbose() > 0:
231         print >> sys.stderr, "beastbuild error: %s" % message
232     return False
233
234 def die( message ):
235     print >> sys.stderr, "beastbuild fatal error: %s" % message
236     exit( 1 )
237
238 def verbose():
239     verb = os.getenv( "BEASTBUILD_VERBOSE" )
240     if ( not verb == None and verb.isdigit() and int(verb) > 0 ):
241         return int( verb )
242     else:
243         return 0
244
245 ### create directory
246 def makeDirs (path):
247     if os.path.exists (path.native()):
248         if os.path.isdir (path.native()):
249             return
250     else:
251         try:
252             os.makedirs (path.native())
253             if os.path.exists (path.native()) and os.path.isdir (path.native()):
254                 return
255         except:
256             pass
257     die ("Can't create directory '" + path.native() + "'")