source: trunk/base/src/port1.0/portpackage.tcl @ 1595

Last change on this file since 1595 was 1595, checked in by kevin, 18 years ago

Add new mpkg target.

  • Property svn:eol-style set to native
File size: 12.1 KB
Line 
1# et:ts=4
2# portpackage.tcl
3#
4# Copyright (c) 2002 Apple Computer, Inc.
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15# 3. Neither the name of Apple Computer, Inc. nor the names of its contributors
16#    may be used to endorse or promote products derived from this software
17#    without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29# POSSIBILITY OF SUCH DAMAGE.
30#
31
32package provide portpackage 1.0
33package require portutil 1.0
34
35set com.apple.package [target_new com.apple.package package_main]
36${com.apple.package} set runtype always
37${com.apple.package} provides package
38${com.apple.package} requires registry
39
40# define options
41options package.type package.destpath
42
43# Set defaults
44default package.type pkg
45default package.destpath {${workpath}}
46
47set UI_PREFIX "---> "
48
49proc package_main {args} {
50    global portname portversion package.type package.destpath UI_PREFIX
51
52    set rfile [registry_exists $portname $portversion]
53    if ![string length $rfile] {
54        ui_error "Package ${portname}-${portversion} not installed on this system"
55        return -code error "Package ${portname}-${portversion} not installed on this system"
56    }
57    ui_msg "$UI_PREFIX Creating ${package.type} format package for ${portname}-${portversion}"
58    if [regexp .bz2$ $rfile] {
59        set fd [open "|bunzip2 -c $rfile" r]
60    } else {
61        set fd [open $rfile r]
62    }
63    set entry [read $fd]
64    close $fd
65
66    # Make sure the destination path exists.
67    system "mkdir -p ${package.destpath}"
68
69    # For now we only support pkg and tarball package types.
70    switch -exact -- ${package.type} {
71        pkg {
72            return [package_pkg $portname $portversion $entry]
73        }
74        tarball {
75            return [package_tarball $portname $portversion $entry]
76        }
77        default {
78            ui_error "Do not know how to generate package of type ${package.type}"
79            return -code error "Unknown package type: ${package.type}"
80        }
81    }
82}
83
84# Make a tarball version of a package.  This is our "built-in" packaging
85# method.
86proc package_tarball {portname portversion entry} {
87    global portdbpath package.destpath
88
89    set rfile [registry_exists $portname $portversion]
90    set ix [lsearch $entry contents]
91    if {$ix >= 0} {
92        set contents [lindex $entry [incr ix]]
93        set plist [mkstemp /tmp/XXXXXXXX]
94        set pfile [lindex $plist 0]
95        foreach f $contents {
96            set fname [lindex $f 0]
97            puts $pfile $fname
98        }
99        puts $pfile $rfile
100        close $pfile
101
102        set ptarget ${package.destpath}/${portname}-${portversion}.tar.gz
103        if [catch {system "gnutar -T [lindex $plist 1] -czPpf ${ptarget}"} err] {
104            ui_error "Package creation failed - gnutar returned error status: $err"
105            ui_info "Failed packing list left in [lindex $plist 1]"
106            return -code error "Package creation failed - gnutar returned error status: $err"
107        }
108        exec rm [lindex $plist 1]
109    } else {
110        ui_error "Bad registry entry for ${portname}-${portversion}, no contents"
111        return -code error "Bad registry entry for ${portname}-${portversion}, no contents"
112    }
113    return 0
114}
115
116proc package_pkg {portname portversion entry} {
117    global portdbpath destpath workpath contents prefix portresourcepath description package.destpath long_description homepage
118
119    set resourcepath ${workpath}/pkg_resources
120    set rfile [registry_exists $portname $portversion]
121    set ix [lsearch $entry contents]
122    # If contents entry exists, transplant installed files into ${destpath}
123    # Otherwise, presume that they are already installed in ${destpath} path
124    if {$ix >= 0} {
125        set plist [mkstemp ${workpath}/.${portname}.plist.XXXXXXXXX]
126        set pfile [lindex $plist 0]
127
128        foreach f $contents {
129            set fname [lindex $f 0]
130            puts $pfile $fname
131        }
132        close $pfile
133
134        if {![file isdirectory $destpath]} {
135            if {[catch {file mkdir $destpath} result]} {
136                ui_error "Unable to create destination root path: $result"
137                return -code error "Unable to create destination root path: $result"
138            }
139        }
140
141        if [catch {system "(cd ${prefix} && gnutar -T [lindex $plist 1] -cPpf -) | (cd ${destpath} && tar xvf -)"} return] {
142            ui_error "Package creation failed - gnutar returned error status: $return"
143            file delete [lindex $plist 1]
144            return -code error "Package creation failed - gnutar returned error status: $return"
145        }
146        file delete [lindex $plist 1]
147    }
148    if {![file isdirectory $resourcepath]} {
149        if {[catch {file mkdir $resourcepath} result]} {
150            ui_error "Unable to create package resource directory: $result"
151            return -code error "Unable to create package resource directory: $result"
152        }
153    }
154
155    # XXX: we need to support .lproj in resources.
156    set pkgpath ${package.destpath}/${portname}.pkg
157    system "mkdir -p -m 0755 ${pkgpath}/Contents/Resources"
158    write_PkgInfo ${pkgpath}/Contents/PkgInfo
159    write_info_file ${pkgpath}/Contents/Resources/${portname}.info $portname $portversion $description $prefix
160    write_info_plist ${pkgpath}/Contents/Info.plist $portname $portversion $prefix
161    write_description_plist ${pkgpath}/Contents/Resources/Description.plist $portname $portversion $description
162    # long_description, description, or homepage may not exist
163    foreach variable {long_description description homepage} {
164        if {![info exists $variable]} {
165            set pkg_$variable ""
166        } else {
167            set pkg_$variable [set $variable]
168        }
169    }
170    write_welcome_rtf ${pkgpath}/Contents/Resources/Welcome.rtf $portname $portversion $pkg_long_description $pkg_description $pkg_homepage
171    file copy -force -- ${portresourcepath}/package/background.tiff ${pkgpath}/Contents/Resources/background.tiff
172    system "mkbom ${destpath} ${pkgpath}/Contents/Archive.bom"
173    system "cd ${pkgpath}/Contents/Resources/ && ln -fs ../Archive.bom ${portname}.bom"
174    system "cd ${destpath} && pax -w -z . > ${pkgpath}/Contents/Archive.pax.gz"
175    system "cd ${pkgpath}/Contents/Resources/ && ln -fs ../Archive.pax.gz ${portname}.pax.gz"
176
177    write_sizes_file ${pkgpath}/Contents/Resources/${portname}.sizes ${portname} ${pkgpath} ${destpath}
178
179    return 0
180}
181
182proc dirSize {dir} {
183    set size    0;
184    foreach file [readdir $dir] {
185        if {$file == "." || $file == ".."} {
186            continue
187        }
188        if {[file isdirectory [file join $dir $file]]} {
189            incr size [dirSize [file join $dir $file]]
190        } else {
191            incr size [file size [file join $dir $file]];
192        }
193    }
194    return $size;
195}
196
197proc write_PkgInfo {infofile} {
198        set infofd [open ${infofile} w+]
199        puts $infofd "pmkrpkg1"
200        close $infofd
201}
202
203proc write_info_file {infofile portname portversion description destination} {
204        if {[string index $destination end] != "/"} {
205                append destination /
206        }
207
208        set infofd [open ${infofile} w+]
209        puts $infofd "Title ${portname}
210Version ${portversion}
211Description ${description}
212DefaultLocation ${destination}
213DeleteWarning
214
215### Package Flags
216
217NeedsAuthorization YES
218Required NO
219Relocatable NO
220RequiresReboot NO
221UseUserMask YES
222OverwritePermissions NO
223InstallFat NO
224RootVolumeOnly NO"
225        close $infofd
226}
227
228proc write_info_plist {infofile portname portversion destination} {
229        set vers [split $portversion "."]
230        set major [lindex $vers 0]
231        set minor [lindex $vers 1]
232        if {$major == ""} {set major "0"}
233        if {$minor == ""} {set minor "0"}
234               
235        if {[string index $destination end] != "/"} {
236                append destination /
237        }
238
239        set infofd [open ${infofile} w+]
240        puts $infofd {<?xml version="1.0" encoding="UTF-8"?>
241<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
242<plist version="1.0">
243}
244        puts $infofd "<dict>
245        <key>CFBundleGetInfoString</key>
246        <string>${portname} ${portversion}</string>
247        <key>CFBundleIdentifier</key>
248        <string>org.opendarwin.darwinports.${portname}</string>
249        <key>CFBundleName</key>
250        <string>${portname}</string>
251        <key>CFBundleShortVersionString</key>
252        <string>${portversion}</string>
253        <key>IFMajorVersion</key>
254        <integer>${major}</integer>
255        <key>IFMinorVersion</key>
256        <integer>${minor}</integer>
257        <key>IFPkgFlagAllowBackRev</key>
258        <true/>
259        <key>IFPkgFlagAuthorizationAction</key>
260        <string>RootAuthorization</string>
261        <key>IFPkgFlagDefaultLocation</key>
262        <string>${destination}</string>
263        <key>IFPkgFlagInstallFat</key>
264        <false/>
265        <key>IFPkgFlagIsRequired</key>
266        <false/>
267        <key>IFPkgFlagRelocatable</key>
268        <false/>
269        <key>IFPkgFlagRestartAction</key>
270        <string>NoRestart</string>
271        <key>IFPkgFlagRootVolumeOnly</key>
272        <false/>
273        <key>IFPkgFlagUpdateInstalledLanguages</key>
274        <false/>
275        <key>IFPkgFormatVersion</key>
276        <real>0.10000000149011612</real>
277</dict>
278</plist>"
279        close $infofd
280}
281
282proc write_description_plist {infofile portname portversion description} {
283        set infofd [open ${infofile} w+]
284        puts $infofd {<?xml version="1.0" encoding="UTF-8"?>
285<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
286<plist version="1.0">
287}
288        puts $infofd "<dict>
289        <key>IFPkgDescriptionDeleteWarning</key>
290        <string></string>
291        <key>IFPkgDescriptionDescription</key>
292        <string>${description}</string>
293        <key>IFPkgDescriptionTitle</key>
294        <string>${portname}</string>
295        <key>IFPkgDescriptionVersion</key>
296        <string>${portversion}</string>
297</dict>
298</plist>"
299        close $infofd
300}
301
302proc write_welcome_rtf {filename portname portversion long_description description homepage} {
303    set fd [open ${filename} w+]
304    if {$long_description == ""} {
305        set long_description $description
306    }
307    puts $fd \
308"{\\rtf1\\mac\\ansicpg10000\\cocoartf102
309{\\fonttbl\\f0\\fswiss\\fcharset77 Helvetica-Bold;\\f1\\fswiss\\fcharset77 Helvetica;}
310{\\colortbl;\\red255\\green255\\blue255;\\red1\\green1\\blue1;}
311\\vieww9000\\viewh9000\\viewkind0
312\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\ql\\qnatural
313
314\\f0\\b\\fs24 \\cf2 Welcome to the ${portname} for Mac OS X Installer\\
315\\
316\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\ql\\qnatural
317"
318    puts $fd "\\f1\\b0 \\cf2 ${long_description} \\\n\\"
319    if {$homepage != ""} {
320        puts $fd "${homepage} \\\n\\"
321    }
322    puts $fd "This installer guides you through the steps necessary to install ${portname} ${portversion} for Mac OS X. To get started, click Continue.\\\n}"
323
324    close $fd
325}
326
327proc write_sizes_file {sizesfile portname pkgpath destpath} {
328   
329    if {[catch {set numFiles [exec lsbom -s ${pkgpath}/Contents/Archive.bom | wc -l]} result]} {
330        return -code error "Reading package bom failed: $result"
331    }
332    if {[catch {set compressedSize [expr [dirSize ${pkgpath}] / 1024]} result]} {
333        return -code error "Error determining compressed size: $result"
334    }
335    if {[catch {set installedSize [expr [dirSize ${destpath}] / 1024]} result]} {
336        return -code error "Error determining installed size: $result"
337    }
338    if {[catch {set infoSize [file size ${pkgpath}/Contents/Resources/${portname}.info]} result]} {
339        return -code error "Error determining info file size: $result"
340    }
341    if {[catch {set bomSize [file size ${pkgpath}/Contents/Archive.bom]} result]} {
342        return -code error "Error determining bom file size: $result"
343    }
344    incr installedSize $infoSize
345    incr installedSize $bomSize
346       
347    set fd [open ${sizesfile} w+]
348    puts $fd "NumFiles $numFiles
349InstalledSize $installedSize
350CompressedSize $compressedSize"
351    close $fd
352}
Note: See TracBrowser for help on using the repository browser.