source: trunk/base/src/package1.0/portmpkg.tcl @ 134837

Last change on this file since 134837 was 134837, checked in by jmr@…, 5 years ago

replace eval with {*} in the last few applicable places

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.8 KB
Line 
1# et:ts=4
2# portmpkg.tcl
3# $Id: portmpkg.tcl 134837 2015-04-08 14:51:23Z jmr@macports.org $
4#
5# Copyright (c) 2005, 2007 - 2013 The MacPorts Project
6# Copyright (c) 2002 - 2004 Apple Inc.
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions
11# are met:
12# 1. Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14# 2. Redistributions in binary form must reproduce the above copyright
15#    notice, this list of conditions and the following disclaimer in the
16#    documentation and/or other materials provided with the distribution.
17# 3. Neither the name of Apple Inc. nor the names of its contributors
18#    may be used to endorse or promote products derived from this software
19#    without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31# POSSIBILITY OF SUCH DAMAGE.
32#
33
34package provide portmpkg 1.0
35package require portutil 1.0
36
37set org.macports.mpkg [target_new org.macports.mpkg portmpkg::mpkg_main]
38target_runtype ${org.macports.mpkg} always
39target_provides ${org.macports.mpkg} mpkg
40target_requires ${org.macports.mpkg} pkg
41
42namespace eval portmpkg {
43}
44
45# define options
46options package.destpath package.flat
47
48set_ui_prefix
49
50proc portmpkg::mpkg_main {args} {
51    global subport epoch version revision os.major package.destpath package.flat UI_PREFIX
52
53    if {!${package.flat} || ${os.major} < 10} {
54        # Make sure the destination path exists.
55        file mkdir ${package.destpath}
56    }
57
58    return [package_mpkg $subport $epoch $version $revision]
59}
60
61proc portmpkg::make_dependency_list {portname destination} {
62    global requested_variations prefix package.destpath package.flat
63    set result {}
64    if {[catch {set res [mport_lookup $portname]} error]} {
65        global errorInfo
66        ui_debug "$errorInfo"
67        return -code error "port lookup failed: $error"
68    }
69    array set portinfo [lindex $res 1]
70
71    if {[getuid] == 0 && [geteuid] != 0} {
72        seteuid 0; setegid 0
73        set deprivileged 1
74    }
75
76    set mport [mport_open $portinfo(porturl) [list prefix $prefix package.destpath ${destination} package.flat ${package.flat} subport $portinfo(name)] [array get requested_variations]]
77
78    if {[info exists deprivileged]} {
79        global macportsuser
80        setegid [uname_to_gid "$macportsuser"]
81        seteuid [name_to_uid "$macportsuser"]
82    }
83
84    unset portinfo
85    array set portinfo [mport_info $mport]
86
87    # get the union of depends_run and depends_lib
88    set depends {}
89    if {[info exists portinfo(depends_run)]} { lappend depends {*}$portinfo(depends_run) }
90    if {[info exists portinfo(depends_lib)]} { lappend depends {*}$portinfo(depends_lib) }
91
92    foreach depspec $depends {
93        set dep [_get_dep_port $depspec]
94        if {$dep ne ""} {
95            lappend result {*}[make_dependency_list $dep $destination]
96        }
97    }
98
99    lappend result [list $portinfo(name) $portinfo(epoch) $portinfo(version) $portinfo(revision) $mport]
100    return $result
101}
102
103proc portmpkg::make_one_package {portname mport} {
104    if {[getuid] == 0 && [geteuid] != 0} {
105        seteuid 0; setegid 0
106        set deprivileged 1
107    }
108
109    ui_debug "building dependency package: $portname"
110    set result [mport_exec $mport pkg]
111    mport_close $mport
112    if {$result} {
113        error "Processing of port $portname failed"
114    }
115
116    if {[info exists deprivileged]} {
117        global macportsuser
118        setegid [uname_to_gid "$macportsuser"]
119        seteuid [name_to_uid "$macportsuser"]
120    }
121}
122
123proc portmpkg::epoch_namestr {portepoch} {
124    set portepoch_namestr ""
125    if {${portepoch} != 0} {
126        set portepoch_namestr "${portepoch}_"
127    }
128    return ${portepoch_namestr}
129}
130
131proc portmpkg::revision_namestr {portrevision} {
132    set portrevision_namestr ""
133    if {${portrevision} != 0} {
134        set portrevision_namestr "_${portrevision}"
135    }
136    return ${portrevision_namestr}
137}
138
139proc portmpkg::mpkg_path {portname portepoch portversion portrevision} {
140    global package.destpath
141    set portepoch_namestr [portmpkg::epoch_namestr ${portepoch}]
142    set portrevision_namestr [portmpkg::revision_namestr ${portrevision}]
143    set mpkgpath ${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.mpkg
144    return $mpkgpath
145}
146
147proc portmpkg::package_mpkg {portname portepoch portversion portrevision} {
148    global portdbpath os.major destpath workpath prefix porturl description package.destpath package.flat long_description homepage depends_run depends_lib
149
150    set mpkgpath [portmpkg::mpkg_path $portname $portepoch $portversion $portrevision]
151
152    set portepoch_namestr [portmpkg::epoch_namestr ${portepoch}]
153    set portrevision_namestr [portmpkg::revision_namestr ${portrevision}]
154    if {${package.flat} && ${os.major} >= 10} {
155        set pkgpath ${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}-component.pkg
156        set packages_path ${workpath}/mpkg_packages
157        set resources_path ${workpath}/mpkg_resources
158    } else {
159        set pkgpath ${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.pkg
160        set packages_path ${mpkgpath}/Contents/Packages
161        set resources_path ${mpkgpath}/Contents/Resources
162    }
163    system "mkdir -p -m 0755 ${packages_path}"
164    system "mkdir -p -m 0755 ${resources_path}"
165
166    set dependencies {}
167    # get deplist
168    set deps [make_dependency_list $portname $packages_path]
169    set deps [lsort -unique $deps]
170    foreach dep $deps {
171        set name [lindex $dep 0]
172        set epoch [lindex $dep 1]
173        set epoch_namestr ""
174        if {$epoch != 0} {
175            set epoch_namestr "${epoch}_"
176        }
177        set vers [lindex $dep 2]
178        set rev [lindex $dep 3]
179        set rev_namestr ""
180        if {$rev != 0} {
181            set rev_namestr "_${rev}"
182        }
183        set mport [lindex $dep 4]
184        # don't re-package ourself
185        if {$name != $portname} {
186            make_one_package $name $mport
187            if {${package.flat} && ${os.major} >= 10} {
188                lappend dependencies org.macports.${name} ${name}-${epoch_namestr}${vers}${rev_namestr}-component.pkg
189            } else {
190                lappend dependencies ${name}-${epoch_namestr}${vers}${rev_namestr}.pkg
191            }
192        }
193    }
194    if {${package.flat} && ${os.major} >= 10} {
195        lappend dependencies org.macports.${portname} ${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}-component.pkg
196    } else {
197        lappend dependencies ${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.pkg
198    }
199
200    # copy our own pkg into the mpkg
201    system "cp -PR ${pkgpath} ${packages_path}"
202
203    if {!${package.flat} || ${os.major} < 10} {
204        portpkg::write_PkgInfo ${mpkgpath}/Contents/PkgInfo
205        mpkg_write_info_plist ${mpkgpath}/Contents/Info.plist $portname $portversion $portrevision $prefix $dependencies
206        portpkg::write_description_plist ${mpkgpath}/Contents/Resources/Description.plist $portname $portversion $description
207        set resources_path ${mpkgpath}/Contents/Resources
208    }
209    # long_description, description, or homepage may not exist
210    foreach variable {long_description description homepage} {
211        if {![info exists $variable]} {
212            set pkg_$variable ""
213        } else {
214            set pkg_$variable [set $variable]
215        }
216    }
217    portpkg::write_welcome_html ${resources_path}/Welcome.html $portname $portepoch $portversion $portrevision $pkg_long_description $pkg_description $pkg_homepage
218    file copy -force -- [getportresourcepath $porturl "port1.0/package/background.tiff"] ${resources_path}/background.tiff
219
220    if {${package.flat} && ${os.major} >= 10} {
221        write_distribution ${workpath}/Distribution $portname $dependencies
222        set productbuild [findBinary productbuild]
223        set v [portpkg::mp_version_to_apple_version $portepoch $portversion $portrevision]
224        set cmdline "$productbuild --resources ${resources_path} --identifier org.macports.mpkg.${portname} --distribution ${workpath}/Distribution --package-path ${packages_path} --version ${v} ${mpkgpath}"
225        ui_debug "Running command line: $cmdline"
226        system $cmdline
227    }
228
229    return 0
230}
231
232proc portmpkg::write_distribution {dfile portname dependencies} {
233    global macosx_deployment_target
234    set portname [xml_escape $portname]
235    set dfd [open $dfile w+]
236    puts $dfd "<?xml version=\"1.0\" encoding=\"utf-8\"?>
237<installer-gui-script minSpecVersion=\"1\">
238    <title>${portname}</title>
239    <options customize=\"never\"/>
240    <allowed-os-versions><os-version min=\"${macosx_deployment_target}\"/></allowed-os-versions>
241    <background file=\"background.tiff\" mime-type=\"image/tiff\" alignment=\"bottomleft\" scaling=\"none\"/>
242    <welcome mime-type=\"text/html\" file=\"Welcome.html\"/>
243    <choices-outline>
244    <line choice=\"default\">
245        <line choice=\"org.macports.mpkg.${portname}\"/>
246    </line>
247    </choices-outline>
248    <choice id=\"default\"/>
249    <choice id=\"org.macports.mpkg.${portname}\" visible=\"false\">
250"
251    foreach {identifier package} $dependencies {
252        set id [xml_escape $identifier]
253        set pkg [xml_escape $package]
254        puts $dfd "        <pkg-ref id=\"${id}\"/>"
255        lappend pkgrefs "<pkg-ref id=\"${id}\">${pkg}</pkg-ref>"
256    }
257    puts $dfd "    </choice>"
258    foreach pkgref $pkgrefs {
259        puts $dfd "    $pkgref"
260    }
261    puts $dfd "</installer-gui-script>"
262    close $dfd
263}
264
265proc portmpkg::xml_escape {s} {
266    regsub -all {&} $s {\&amp;} s
267    regsub -all {<} $s {\&lt;} s
268    regsub -all {>} $s {\&gt;} s
269    return $s
270}
271
272proc portmpkg::mpkg_write_info_plist {infofile portname portversion portrevision destination dependencies} {
273    set vers [split $portversion "."]
274
275    if {[string index $destination end] ne "/"} {
276        append destination /
277    }
278
279    set depxml ""
280    foreach dep $dependencies {
281        set dep [xml_escape $dep]
282        append depxml "<dict>
283            <key>IFPkgFlagPackageLocation</key>
284            <string>${dep}</string>
285            <key>IFPkgFlagPackageSelection</key>
286            <string>selected</string>
287        </dict>
288        "
289    }
290
291    set portname [xml_escape $portname]
292    set portversion [xml_escape $portversion]
293    set portrevision [xml_escape $portrevision]
294
295    set infofd [open ${infofile} w+]
296    puts $infofd {<?xml version="1.0" encoding="UTF-8"?>
297<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
298<plist version="1.0">
299}
300    puts $infofd "<dict>
301    <key>CFBundleGetInfoString</key>
302    <string>${portname} ${portversion}</string>
303    <key>CFBundleIdentifier</key>
304    <string>org.macports.mpkg.${portname}</string>
305    <key>CFBundleName</key>
306    <string>${portname}</string>
307    <key>CFBundleShortVersionString</key>
308    <string>${portversion}</string>
309    <key>IFMajorVersion</key>
310    <integer>${portrevision}</integer>
311    <key>IFMinorVersion</key>
312    <integer>0</integer>
313    <key>IFPkgFlagComponentDirectory</key>
314    <string>./Contents/Packages</string>
315    <key>IFPkgFlagPackageList</key>
316    <array>
317        ${depxml}</array>
318    <key>IFPkgFormatVersion</key>
319    <real>0.10000000149011612</real>
320</dict>
321</plist>"
322    close $infofd
323}
Note: See TracBrowser for help on using the repository browser.