1#
2#    make_pkg.py
3#
4import os
5
6print( 'Info: setup vesion info' )
7import sys
8sys.path.insert( 0, os.path.abspath( '../../Source' ) )
9import pysvn
10import time
11import glob
12
13package_maker = '/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker'
14package_maker_kit = os.path.exists( package_maker )
15
16os.system( 'lipo -info %s >lipo-info.tmp' % (sys.executable,) )
17lipo_info = open( 'lipo-info.tmp' ).read()
18os.remove( 'lipo-info.tmp' )
19
20is_x86_64 = 'x86_64' in lipo_info
21is_i386 = 'i386' in lipo_info
22
23if is_x86_64 and is_i386:
24    processor = 'intel'
25
26elif is_x86_64:
27    processor = 'x86_64'
28
29elif is_i386:
30    processor = 'i386'
31
32else:
33    assert False, 'Unknown processor type'
34
35python_vendor = os.environ.get( 'BUILDER_VENDOR', 'unknown' )
36
37if processor == 'i386':
38    if hasattr( sys, 'maxsize' ):
39        maxsize = sys.maxsize
40    else:
41        maxsize = sys.maxint
42
43    if maxsize == (2**31-1):
44        processor = 'i386'
45    else:
46        processor = 'x86_64'
47
48print( 'Info: Process is %s' % (processor,) )
49
50pymaj, pymin, pypat, _, _ = sys.version_info
51python_version_string = '%d.%d.%d' % (pymaj, pymin, pypat)
52pysvnmaj, pysvnmin, pysvnpat, _ = pysvn.version
53pysvn_version_string = '%d.%d.%d-%d' % (pysvn.version[0], pysvn.version[1], pysvn.version[2], pysvn.version[3])
54pysvn_short_version_string = '%d.%d.%d' % (pysvn.version[0], pysvn.version[1], pysvn.version[2])
55svn_version_package_string = '%d%d%d' % (pysvn.svn_version[0], pysvn.svn_version[1], pysvn.svn_version[2])
56svn_version_string = '%d.%d.%d' % (pysvn.svn_version[0], pysvn.svn_version[1], pysvn.svn_version[2])
57pysvn_so_string = '_pysvn_%d_%d.so' % (pymaj, pymin)
58pkg_filename = 'py%s%s-%s-pysvn-svn%s-%s-%s' % (pymaj, pymin, python_vendor, svn_version_package_string, pysvn_version_string, processor)
59
60print( 'Info: Packageing %s' % (pkg_filename,) )
61build_time  = time.time()
62build_time_str = time.strftime( '%d-%b-%Y %H:%M', time.localtime( build_time ) )
63year = time.strftime( '%Y', time.localtime( build_time ) )
64tmpdir = os.path.join( os.getcwd(), 'tmp' )
65
66if pymaj == 2 and pymin == 7:
67    if python_vendor == 'apple_com':
68        install_dir = '/Library/Python/2.7/site-packages'
69    else:
70        install_dir = '/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages'
71
72elif pymaj == 3:
73    install_dir = '/Library/Frameworks/Python.framework/Versions/3.%d/lib/python3.%d/site-packages' % (pymin, pymin)
74
75else:
76    raise RuntimeError( 'Unsupported version of python' )
77
78if os.path.exists( tmpdir ):
79    print( 'Info: Clean up tmp directory' )
80    os.system( 'rm -rf tmp' )
81
82print( 'Info: Create directories' )
83
84for kit_dir in [
85    tmpdir,
86    os.path.join( tmpdir, 'Resources' ),
87    os.path.join( tmpdir, 'Contents' ),
88    os.path.join( tmpdir, 'Contents/pysvn' ),
89    os.path.join( tmpdir, pkg_filename),
90    os.path.join( tmpdir, '%s/Examples' % pkg_filename ),
91    os.path.join( tmpdir, '%s/Examples/Client' % pkg_filename ),
92    os.path.join( tmpdir, '%s/Documentation' % pkg_filename),
93    ]:
94    if not os.path.exists( kit_dir ):
95        os.makedirs( kit_dir )
96
97
98print( 'Info: Finding dylibs used by pysvn' )
99
100def findDylibs( image, dylib_list, depth=0 ):
101    cmd = 'otool -L "%s" >/tmp/pysvn_otool.tmp' % image
102    #print( 'Debug: cmd %r' % cmd )
103    os.system( cmd )
104    # always skip the first line that lists the image being dumped
105    for line in open( '/tmp/pysvn_otool.tmp' ).readlines()[1:]:
106        line = line.strip()
107        libpath = line.split()[0]
108        #print( 'Debug: line %r' % line )
109        if( libpath.startswith( '/' )               # lines with libs on them
110        and not libpath.startswith( '/usr/lib' )    # ignore libs shipped by Apple
111        and not libpath.startswith( '/System' )     # ignore libs shipped by Apple
112        and not libpath.endswith( '/Python' ) ):    # do not need to ignore python
113            if libpath not in dylib_list:
114                #print( 'Info: ',depth,' Need lib',libpath,'for',image )
115                dylib_list.append( libpath )
116                findDylibs( libpath, dylib_list, depth+1 )
117
118dylib_list = []
119findDylibs( '../../Source/pysvn/%s' % pysvn_so_string, dylib_list )
120
121print( 'Info: Copy files' )
122
123cp_list = [
124    ('../../Source/pysvn/__init__.py',
125        'Contents/pysvn'),
126    ('../../Source/pysvn/%s' % pysvn_so_string,
127        'Contents/pysvn'),
128    ('../../LICENSE.txt',
129        'Resources/License.txt'),
130    ('../../LICENSE.txt',
131        '%s/License.txt' % pkg_filename ),
132    ('../../Docs/pysvn.html',
133        '%s/Documentation' % pkg_filename ),
134    ('../../Docs/pysvn_prog_ref.html',
135        '%s/Documentation' % pkg_filename ),
136    ('../../Docs/pysvn_prog_ref.js',
137        '%s/Documentation' % pkg_filename ),
138    ('../../Docs/pysvn_prog_guide.html',
139        '%s/Documentation' % pkg_filename ),
140    ('../../Examples/Client/svn_cmd.py',
141        '%s/Examples/Client' % pkg_filename ),
142    ('../../Examples/Client/parse_datetime.py',
143        '%s/Examples/Client' % pkg_filename ),
144    ]
145
146for libpath in dylib_list:
147    cp_list.append( (libpath, 'Contents/pysvn') )
148
149for cp_src, cp_dst_dir_fmt in cp_list:
150    cmd = 'cp -f "%s" "tmp/%s"' % (cp_src, cp_dst_dir_fmt % locals())
151    print( 'Info: CMD %r' % cmd )
152    os.system( cmd )
153
154for dylib in glob.glob( 'tmp/Contents/pysvn/*.dylib' ):
155    # all the dylib need to be writable
156    cmd = 'chmod +w "%s"' % (dylib,)
157    print( 'Info: CMD %r' % cmd )
158    os.system( cmd )
159
160print( 'Info: Fix the install paths for the dylib files' )
161
162fixup_path_list = ['tmp/Contents/pysvn/%s' % pysvn_so_string]
163for libpath in dylib_list:
164    fixup_path_list.append( 'tmp/Contents/pysvn/' + os.path.basename( libpath ) )
165
166for fixup_path in fixup_path_list:
167    for libpath in dylib_list:
168        if libpath != fixup_path:
169            os.system( cmd )
170            cmd = ('install_name_tool'
171                ' -change'
172                ' %s'
173                ' %s/pysvn/%s'
174                ' %s' %
175                    (libpath, install_dir, os.path.basename( libpath ), fixup_path))
176            print( 'Info: CMD %s' % (cmd,) )
177            os.system( cmd )
178
179for dylib in glob.glob( 'tmp/Contents/pysvn/*.dylib' ):
180    # can now remove the +w
181    cmd = 'chmod -w "%s"' % (dylib,)
182    print( 'Info: CMD %r' % cmd )
183    os.system( cmd )
184
185if python_vendor == 'apple_com':
186    readme_vendor_name = "Apple's"
187
188elif python_vendor == 'python_org':
189    readme_vendor_name = "Python.org's"
190
191else:
192    readme_vendor_name = python_vendor
193
194print( 'Info: Create tmp/Resources/ReadMe.txt' )
195if package_maker_kit:
196    f = open( 'tmp/Resources/ReadMe.txt', 'w' )
197
198else:
199    f = open( 'tmp/%s/ReadMe.txt' % (pkg_filename,), 'w' )
200
201f.write('''<html>
202<body>
203<h1>PySVN %(pysvn_version_string)s for Mac OS X, %(readme_vendor_name)s Python %(pymaj)s.%(pymin)s and Subversion %(svn_version_string)s</h1>
204
205<h2>Copyright Barry A. Scott (c) 2003-%(year)s</h2>
206
207<h2>Mail <a href="mailto:barry@barrys-emacs.org">barry@barrys-emacs.org</a></h2>
208
209<h2>Pysvn home <a href="https://pysvn.sourceforge.io">https://pysvn.sourceforge.io</a></h2>
210
211<h2>&#160;&#160;&#160;&#160;&#160;Barry Scott</h2>
212</body>
213</html>
214''' % locals() )
215f.close()
216
217if package_maker_kit:
218    print( 'Info: Create tmp/Info.plist' )
219    f = open( 'tmp/Info.plist', 'w' )
220    f.write('''<?xml version="1.0" encoding="UTF-8"?>
221<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
222<plist version="1.0">
223<dict>
224    <key>CFBundleGetInfoString</key>
225    <string>pysvn Extension %(pysvn_version_string)s for Python %(pymaj)s.%(pymin)s</string>
226    <key>CFBundleIdentifier</key>
227    <string>org.tigris.pysvn.extension.py%(pymaj)s.%(pymin)s.%(python_vendor)s</string>
228    <key>CFBundleName</key>
229    <string>pysvn Extension</string>
230    <key>CFBundleShortVersionString</key>
231    <string>%(pysvn_short_version_string)s</string>
232    <key>IFMajorVersion</key>
233    <integer>%(pysvnmaj)s</integer>
234    <key>IFMinorVersion</key>
235    <integer>%(pysvnmin)s</integer>
236    <key>IFPkgFlagAllowBackRev</key>
237    <false/>
238    <key>IFPkgFlagAuthorizationAction</key>
239    <string>AdminAuthorization</string>
240    <key>IFPkgFlagDefaultLocation</key>
241    <string>%(install_dir)s</string>
242    <key>IFPkgFlagInstallFat</key>
243    <false/>
244    <key>IFPkgFlagIsRequired</key>
245    <false/>
246    <key>IFPkgFlagRelocatable</key>
247    <false/>
248    <key>IFPkgFlagRestartAction</key>
249    <string>NoRestart</string>
250    <key>IFPkgFlagRootVolumeOnly</key>
251    <true/>
252    <key>IFPkgFlagUpdateInstalledLanguages</key>
253    <false/>
254    <key>IFPkgFormatVersion</key>
255    <real>0.10000000149011612</real>
256</dict>
257</plist>
258''' % locals() )
259    f.close()
260
261    print( 'Info: Create tmp/Description.plist' )
262    f = open( 'tmp/Description.plist', 'w' )
263    f.write('''<?xml version="1.0" encoding="UTF-8"?>
264<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
265<plist version="1.0">
266<dict>
267	<key>IFPkgDescriptionDescription</key>
268	<string>PySVN Extension
269</string>
270	<key>IFPkgDescriptionTitle</key>
271	<string>PySVN Extension</string>
272</dict>
273</plist>
274''' )
275    f.close()
276
277    print( 'Info: PackageMaker' )
278    cmd = [ package_maker,
279            '-build',
280            '-p %s' % os.path.abspath( 'tmp/%s/%s.pkg' % (pkg_filename, pkg_filename) ),
281            '-f %s' % os.path.abspath( 'tmp/Contents' ),
282            '-r %s' % os.path.abspath( 'tmp/Resources' ),
283            '-i %s' % os.path.abspath( 'tmp/Info.plist' ),
284            '-d %s' % os.path.abspath( 'tmp/Description.plist' ),
285            ]
286    os.system( ' '.join( cmd ) )
287
288    print( 'Info: Make Disk Image' )
289    os.system( 'hdiutil create -srcfolder tmp/%s tmp/tmp.dmg' % pkg_filename )
290    os.system( 'hdiutil convert tmp/tmp.dmg -format UDZO -imagekey zlib-level=9 '
291            '-o tmp/%s.dmg' % pkg_filename )
292
293else:
294    print( 'Info: Create installation script' )
295    f = open( 'tmp/%s/Install PySVN' % (pkg_filename,), 'w' )
296    f.write( '''#!/bin/bash
297    if [ "$( id -u )" != "0" ]
298    then
299        clear
300        echo "To install PYSVN required root (administrator) privileges."
301        echo "Enter your password to proceed."
302        exec sudo "$0"
303    fi
304
305    kit_dir=$( dirname "$0" )
306
307    echo "Installing pysvn Extension %(pysvn_version_string)s for Python %(pymaj)s.%(pymin)s"
308
309    tar xzf "${kit_dir}/%(pkg_filename)s.tar.gz" -C "%(install_dir)s"
310
311    echo "Installation complete. Press RETURN to exit."
312    read A
313
314''' % locals() )
315    f.close()
316    os.system( 'chmod +x "tmp/%s/Install PYSVN"' % (pkg_filename,) )
317
318    cmd = [ 'tar',
319            'czf',
320            'tmp/%s/%s.tar.gz' % (pkg_filename, pkg_filename),
321            '-C' 'tmp/Contents',
322            'pysvn']
323
324    os.system( ' '.join( cmd ) )
325
326    print( 'Info: Make Disk Image' )
327    os.system( 'hdiutil create -srcfolder tmp/%s tmp/tmp.dmg' % pkg_filename )
328    os.system( 'hdiutil convert tmp/tmp.dmg -format UDZO -imagekey zlib-level=9 '
329            '-o tmp/%s.dmg' % pkg_filename )
330