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

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

update copyright notices

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