source: trunk/base/portmgr/packaging/packageall.tcl @ 64641

Last change on this file since 64641 was 51780, checked in by jmr@…, 11 years ago

Add depends_fetch and depends_extract options (#15161)

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 12.2 KB
Line 
1#!/usr/bin/env tclsh
2# packageall.tcl
3# $Id: packageall.tcl 51780 2009-06-03 06:29:12Z jmr@macports.org $
4#
5# Copyright (c) 2003 Kevin Van Vechten <kevin@opendarwin.org>
6# Copyright (c) 2002 Apple Computer, 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 Computer, 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
33package require darwinports
34
35# globals
36set portdir .
37
38# UI Instantiations
39array set ui_options {}
40# ui_options(ports_debug) - If set, output debugging messages.
41# ui_options(ports_verbose) - If set, output info messages (ui_info)
42# ui_options(ports_quiet) - If set, don't output "standard messages"
43
44# ui_options accessor
45proc ui_isset {val} {
46    global ui_options
47    if {[info exists ui_options($val)]} {
48        if {$ui_options($val) == "yes"} {
49            return 1
50        }
51    }
52    return 0
53}
54
55# UI Callback
56
57proc ui_prefix {priority} {
58    switch $priority {
59        debug {
60                return "DEBUG: "
61        }
62        error {
63                return "Error: "
64        }
65        warn {
66                return "Warning: "
67        }
68        default {
69                return ""
70        }
71    }
72}
73
74proc ui_channels {priority} {
75    global logfd
76    switch $priority {
77        debug {
78            if {[ui_isset ports_debug]} {
79                return {stdout}
80            } else {
81                return {}
82            }
83        }
84        info {
85                        # put verbose stuff only to the log file
86            if {[ui_isset ports_verbose]} {
87                return {$logfd}
88            } else {
89                return {}
90                        }
91                }
92        msg {
93            if {[ui_isset ports_quiet]} {
94                return {}
95                        } else {
96                                return {stdout}
97                        }
98                }
99        default {
100                return {stdout}
101        }
102    }
103}
104       
105proc pkg_ui_log {message} {
106    global logfd
107    if {[string length $logfd] > 0 } {
108        log_message $logfd $message
109    }
110}
111
112proc log_message {channel message} {
113    seek $channel 0 end
114    puts $channel $message
115    flush $channel
116}
117
118# Recursive bottom-up approach of building a list of dependencies.
119proc get_dependencies {portname includeBuildDeps} {
120        set result {}
121       
122        if {[catch {set res [mportsearch "^$portname\$"]} error]} {
123                global errorInfo
124                ui_debug "$errorInfo"
125                ui_error "Internal error: port search failed: $error"
126                return {}
127        }
128        foreach {name array} $res {
129                array set portinfo $array
130                if {![info exists portinfo(name)] ||
131                        ![info exists portinfo(version)] || 
132                        ![info exists portinfo(categories)]} {
133                        ui_error "Internal error: $name missing some portinfo keys"
134                        continue
135                }
136               
137                set portname $portinfo(name)
138                set portversion $portinfo(version)
139                set category [lindex $portinfo(categories) 0]
140
141                # Append the package itself to the result list
142                #set pkgpath ${category}/${portname}-${portversion}.pkg
143                lappend result [list $portname $portversion $category]
144
145                # Append the package's dependents to the result list
146                set depends {}
147                if {[info exists portinfo(depends_run)]} { eval "lappend depends $portinfo(depends_run)" }
148                if {[info exists portinfo(depends_lib)]} { eval "lappend depends $portinfo(depends_lib)" }
149                if {$includeBuildDeps != "" && [info exists portinfo(depends_build)]} { 
150                        eval "lappend depends $portinfo(depends_build)"
151                }
152                if {$includeBuildDeps != "" && [info exists portinfo(depends_fetch)]} { 
153                        eval "lappend depends $portinfo(depends_fetch)"
154                }
155                if {$includeBuildDeps != "" && [info exists portinfo(depends_extract)]} { 
156                        eval "lappend depends $portinfo(depends_extract)"
157                }
158               
159                foreach depspec $depends {
160                        set dep [lindex [split $depspec :] end]
161                        set x [get_dependencies $dep $includeBuildDeps]
162                        eval "lappend result $x"
163                        set result [lsort -unique $result]
164                }
165        }
166        return $result
167}
168
169# Install binary packages if they've already been built.  This will
170# speed up the testing, since we won't have to recompile dependencies
171# which have already been compiled.
172
173proc install_binary_if_available {dep basepath} {
174        set portname [lindex $dep 0]
175        set portversion [lindex $dep 1]
176        set category [lindex $dep 2]
177       
178        set pkgpath ${basepath}/${category}/${portname}-${portversion}.pkg
179        if {[file readable $pkgpath]} {
180                ui_msg "installing binary: $pkgpath"
181                if {[catch {system "cd / && gunzip -c ${pkgpath}/Contents/Archive.pax.gz | pax -r"} error]} {
182                        global errorInfo
183                        ui_debug "$errorInfo"
184                        ui_error "Internal error: $error"
185                }
186                # Touch the receipt
187                # xxx: use some variable to describe this path
188                if {[catch {system "touch /opt/local/var/db/dports/receipts/${portname}-${portversion}.bz2"} error]} {
189                        global errorInfo
190                        ui_debug "$errorInfo"
191                        ui_error "Internal error: $error"
192                }
193        }
194}
195
196
197# Standard procedures
198
199proc fatal args {
200    global argv0
201    puts stderr "$argv0: $args"
202    exit
203}
204
205# Main
206array set options [list]
207array set variations [list]
208#       set ui_options(ports_verbose) yes
209
210if {[catch {mportinit ui_options options variations} result]} {
211    puts "Failed to initialize ports system, $result"
212    exit 1
213}
214
215package require Pextlib
216
217# If no arguments were given, default to all ports.
218if {[llength $argv] == 0} {
219        lappend argv ".*"
220}
221
222foreach pname $argv {
223
224if {[catch {set res [mportsearch "^${pname}\$"]} result]} {
225        puts "port search failed: $result"
226        exit 1
227}
228
229set logpath "/darwinports/logs"
230set logfd ""
231
232foreach {name array} $res {
233        array unset portinfo
234        array set portinfo $array
235
236        # Start with verbose output off;
237        # this will prevent the repopulation of /opt/local from getting logged.
238        set ui_options(ports_verbose) no
239
240        if {![info exists portinfo(porturl)]} {
241                puts stderr "Internal error: no porturl for $name"
242                continue
243        }
244       
245        set pkgbase /darwinports/pkgs/
246        set porturl $portinfo(porturl)
247
248        # Skip up-to-date packages
249        if {[regsub {^file://} $portinfo(porturl) "" portpath]} {
250                if {[info exists portinfo(name)] &&
251                        [info exists portinfo(version)] &&
252                        [info exists portinfo(categories)]} {
253                        set portname $portinfo(name)
254                        set portversion $portinfo(version)
255                        set category [lindex $portinfo(categories) 0]
256                        set pkgfile ${pkgbase}/${category}/${portname}-${portversion}.pkg/Contents/Archive.pax.gz
257                        if {[file readable $pkgfile] && ([file mtime ${pkgfile}] > [file mtime ${portpath}/Portfile])} {
258                                puts stderr "Skipping ${portname}-${portversion}; package is up to date."
259                                continue
260                        }
261                }
262        }
263       
264        # Skipt packages which previously failed
265               
266        # Building the port:
267        # - remove /opt/local so it won't pollute the port.
268        # - re-install MacPorts.
269        # - keep distfiles outside /opt/local so we don't have to keep fetching them.
270        # - send out an email to the maintainer if any errors occurred.
271
272        ui_msg "removing /opt/local"
273        #unset ui_options(ports_verbose)
274        if {[catch {system "rm -Rf /opt/local"} error]} {
275                puts stderr "Internal error: $error"
276        }
277        if {[catch {system "rm -Rf /usr/X11R6"} error]} {
278                puts stderr "Internal error: $error"
279        }
280        if {[catch {system "rm -Rf /etc/X11"} error]} {
281                puts stderr "Internal error: $error"
282        }
283        if {[catch {system "rm -Rf /etc/fonts"} error]} {
284                puts stderr "Internal error: $error"
285        }
286        if {[catch {system "cd $env(HOME)/darwinports && make && make install"} error]} {
287                puts stderr "Internal error: $error"
288        }
289        if {[catch {system "rmdir /opt/local/var/db/dports/distfiles"} error]} {
290                puts stderr "Internal error: $error"
291        }
292        if {[catch {system "ln -s /darwinports/distfiles /opt/local/var/db/dports/distfiles"} error]} {
293                puts stderr "Internal error: $error"
294        }
295        #set ui_options(ports_verbose) yes
296
297        # If there was a log file left over from the previous pass,
298        # then the port failed with an error.  Send the log in an
299        # email to the maintainers.
300        if {[string length $logfd] > 0} {
301                close $logfd
302                set logfd ""
303        }
304        #if {[file readable $logfilename]} {
305        #       if {[catch {system "cat $logfilename | /usr/sbin/sendmail -t"} error]} {
306        #               puts stderr "Internal error: $error"
307        #       }
308        #}
309
310        # Open the log file for writing
311        set logfd [open ${logpath}/${name}.log w]
312
313        set valid 1
314
315        set lint_errors {}
316        set portname ""
317        set portversion ""
318        set description ""
319        set category ""
320
321        if {![info exists portinfo(name)]} {
322                lappend lint_errors "missing name key"
323                set valid 0
324        } else {
325                set portname $portinfo(name)
326        }
327       
328        if {![info exists portinfo(description)]} {
329                lappend lint_errors "missing description key"
330                set valid 0
331        } else {
332                set description $portinfo(description)
333        }
334       
335        if {![info exists portinfo(version)]} {
336                lappend lint_errors "missing version key"
337                set valid 0
338        } else {
339                set portversion $portinfo(version)
340        }
341       
342        if {![info exists portinfo(categories)]} {
343                lappend lint_errors "missing categories key"
344                set valid 0
345        } else {
346                set category [lindex $portinfo(categories) 0]
347        }
348       
349        if {![info exists portinfo(maintainers)]} {
350                append lint_errors "missing maintainers key"
351                set valid 0
352                set maintainers kevin@opendarwin.org
353        } else {
354                set maintainers $portinfo(maintainers)
355        }
356       
357        pkg_ui_log "To: [join $maintainers {, }]"
358        pkg_ui_log "From: donotreply@opendarwin.org"
359        pkg_ui_log "Subject: MacPorts $portinfo(name)-$portinfo(version) build failure"
360        pkg_ui_log ""
361        pkg_ui_log "The following is a transcript produced by the MacPorts automated build       "
362        pkg_ui_log "system.  You are receiving this email because you are listed as a maintainer    "
363        pkg_ui_log "of this port, which has failed the automated packaging process.  Please update  "
364        pkg_ui_log "the port as soon as possible."
365        pkg_ui_log ""
366        pkg_ui_log ""
367        pkg_ui_log "Thank you,"
368        pkg_ui_log "The MacPorts Team"
369        pkg_ui_log ""
370        pkg_ui_log "================================================================================"
371        pkg_ui_log ""
372
373        if {!$valid} {
374                foreach error $lint_errors {
375                        ui_error $error
376                }
377        }
378
379        ui_msg "packaging ${category}/${portname}-${portversion}"
380
381        # Install binary dependencies if we can, to speed things up.
382        #set depends {}
383        #if {[info exists portinfo(depends_run)]} { eval "lappend depends $portinfo(depends_run)" }
384        #if {[info exists portinfo(depends_lib)]} { eval "lappend depends $portinfo(depends_lib)" }
385        #if {[info exists portinfo(depends_build)]} { eval "lappend depends $portinfo(depends_build)" }
386        #foreach depspec $depends {
387        #       set dep [lindex [split $depspec :] end]
388                #install_binary_if_available $dep $pkgbase
389        #}
390        set dependencies [get_dependencies $portname 1]
391        set dependencies [lsort -unique $dependencies]
392        foreach dep $dependencies {
393                install_binary_if_available $dep $pkgbase
394        }
395
396        set options(package.type) pkg
397        set options(package.destpath) ${pkgbase}/${category}/
398
399        # Turn on verbose output for the build
400        set ui_options(ports_verbose) yes
401        if {[catch {set workername [mportopen $porturl [array get options] [array get variations] yes]} result] ||
402                $result == 1} {
403                global errorInfo
404                ui_debug "$errorInfo"
405            ui_error "Internal error: unable to open port: $result"
406            continue
407        }       
408        if {[catch {set result [mportexec $workername pkg]} result] ||
409                $result == 1} {
410                global errorInfo
411                ui_debug "$errorInfo"
412            ui_error "port package failed: $result"
413                mportclose $workername
414            continue
415        }
416        set ui_options(ports_verbose) no
417        # Turn verbose output off after the build
418
419        mportclose $workername
420
421        # We made it to the end.  We can delete the log file.
422        close $logfd
423        set logfd ""
424        file delete ${logpath}/${name}.log
425}
426
427}
428# end foreach pname
Note: See TracBrowser for help on using the repository browser.