source: trunk/base/portmgr/packageall.tcl @ 18777

Last change on this file since 18777 was 15338, checked in by jmpp, 15 years ago

Submitted by: jmpp@
Reviewed by: jberry@

The pormgr/ dir is now out of src/, as it doesn't have much to do with our sources.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 11.9 KB
Line 
1#!/usr/bin/env tclsh
2# packageall.tcl
3# $Id: packageall.tcl,v 1.1 2005/12/06 20:47:42 jmpp Exp $
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 [dportsearch "^$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                foreach depspec $depends {
153                        set dep [lindex [split $depspec :] end]
154                        set x [get_dependencies $dep $includeBuildDeps]
155                        eval "lappend result $x"
156                        set result [lsort -unique $result]
157                }
158        }
159        return $result
160}
161
162# Install binary packages if they've already been built.  This will
163# speed up the testing, since we won't have to recompile dependencies
164# which have already been compiled.
165
166proc install_binary_if_available {dep basepath} {
167        set portname [lindex $dep 0]
168        set portversion [lindex $dep 1]
169        set category [lindex $dep 2]
170       
171        set pkgpath ${basepath}/${category}/${portname}-${portversion}.pkg
172        if {[file readable $pkgpath]} {
173                ui_msg "installing binary: $pkgpath"
174                if {[catch {system "cd / && gunzip -c ${pkgpath}/Contents/Archive.pax.gz | pax -r"} error]} {
175                        global errorInfo
176                        ui_debug "$errorInfo"
177                        ui_error "Internal error: $error"
178                }
179                # Touch the receipt
180                # xxx: use some variable to describe this path
181                if {[catch {system "touch /opt/local/var/db/dports/receipts/${portname}-${portversion}.bz2"} error]} {
182                        global errorInfo
183                        ui_debug "$errorInfo"
184                        ui_error "Internal error: $error"
185                }
186        }
187}
188
189
190# Standard procedures
191
192proc fatal args {
193    global argv0
194    puts stderr "$argv0: $args"
195    exit
196}
197
198# Main
199array set options [list]
200array set variations [list]
201#       set ui_options(ports_verbose) yes
202
203if {[catch {dportinit ui_options options variations} result]} {
204    puts "Failed to initialize ports system, $result"
205    exit 1
206}
207
208package require Pextlib
209
210# If no arguments were given, default to all ports.
211if {[llength $argv] == 0} {
212        lappend argv ".*"
213}
214
215foreach pname $argv {
216
217if {[catch {set res [dportsearch "^${pname}\$"]} result]} {
218        puts "port search failed: $result"
219        exit 1
220}
221
222set logpath "/darwinports/logs"
223set logfd ""
224
225foreach {name array} $res {
226        array unset portinfo
227        array set portinfo $array
228
229        # Start with verbose output off;
230        # this will prevent the repopulation of /opt from getting logged.
231        set ui_options(ports_verbose) no
232
233        if {![info exists portinfo(porturl)]} {
234                puts stderr "Internal error: no porturl for $name"
235                continue
236        }
237       
238        set pkgbase /darwinports/pkgs/
239        set porturl $portinfo(porturl)
240
241        # Skip up-to-date packages
242        if {[regsub {^file://} $portinfo(porturl) "" portpath]} {
243                if {[info exists portinfo(name)] &&
244                        [info exists portinfo(version)] &&
245                        [info exists portinfo(categories)]} {
246                        set portname $portinfo(name)
247                        set portversion $portinfo(version)
248                        set category [lindex $portinfo(categories) 0]
249                        set pkgfile ${pkgbase}/${category}/${portname}-${portversion}.pkg/Contents/Archive.pax.gz
250                        if {[file readable $pkgfile] && ([file mtime ${pkgfile}] > [file mtime ${portpath}/Portfile])} {
251                                puts stderr "Skipping ${portname}-${portversion}; package is up to date."
252                                continue
253                        }
254                }
255        }
256       
257        # Skipt packages which previously failed
258               
259        # Building the port:
260        # - remove /opt so it won't pollute the port.
261        # - re-install DarwinPorts.
262        # - keep distfiles outside /opt so we don't have to keep fetching them.
263        # - send out an email to the maintainer if any errors occurred.
264
265        ui_msg "removing /opt"
266        #unset ui_options(ports_verbose)
267        if {[catch {system "rm -Rf /opt"} error]} {
268                puts stderr "Internal error: $error"
269        }
270        if {[catch {system "rm -Rf /usr/X11R6"} error]} {
271                puts stderr "Internal error: $error"
272        }
273        if {[catch {system "rm -Rf /etc/X11"} error]} {
274                puts stderr "Internal error: $error"
275        }
276        if {[catch {system "rm -Rf /etc/fonts"} error]} {
277                puts stderr "Internal error: $error"
278        }
279        if {[catch {system "cd $env(HOME)/darwinports && make && make install"} error]} {
280                puts stderr "Internal error: $error"
281        }
282        if {[catch {system "rmdir /opt/local/var/db/dports/distfiles"} error]} {
283                puts stderr "Internal error: $error"
284        }
285        if {[catch {system "ln -s /darwinports/distfiles /opt/local/var/db/dports/distfiles"} error]} {
286                puts stderr "Internal error: $error"
287        }
288        #set ui_options(ports_verbose) yes
289
290        # If there was a log file left over from the previous pass,
291        # then the port failed with an error.  Send the log in an
292        # email to the maintainers.
293        if {[string length $logfd] > 0} {
294                close $logfd
295                set logfd ""
296        }
297        #if {[file readable $logfilename]} {
298        #       if {[catch {system "cat $logfilename | /usr/sbin/sendmail -t"} error]} {
299        #               puts stderr "Internal error: $error"
300        #       }
301        #}
302
303        # Open the log file for writing
304        set logfd [open ${logpath}/${name}.log w]
305
306        set valid 1
307
308        set lint_errors {}
309        set portname ""
310        set portversion ""
311        set description ""
312        set category ""
313
314        if {![info exists portinfo(name)]} {
315                lappend lint_errors "missing name key"
316                set valid 0
317        } else {
318                set portname $portinfo(name)
319        }
320       
321        if {![info exists portinfo(description)]} {
322                lappend lint_errors "missing description key"
323                set valid 0
324        } else {
325                set description $portinfo(description)
326        }
327       
328        if {![info exists portinfo(version)]} {
329                lappend lint_errors "missing version key"
330                set valid 0
331        } else {
332                set portversion $portinfo(version)
333        }
334       
335        if {![info exists portinfo(categories)]} {
336                lappend lint_errors "missing categories key"
337                set valid 0
338        } else {
339                set category [lindex $portinfo(categories) 0]
340        }
341       
342        if {![info exists portinfo(maintainers)]} {
343                append lint_errors "missing maintainers key"
344                set valid 0
345                set maintainers kevin@opendarwin.org
346        } else {
347                set maintainers $portinfo(maintainers)
348        }
349       
350        pkg_ui_log "To: [join $maintainers {, }]"
351        pkg_ui_log "From: donotreply@opendarwin.org"
352        pkg_ui_log "Subject: DarwinPorts $portinfo(name)-$portinfo(version) build failure"
353        pkg_ui_log ""
354        pkg_ui_log "The following is a transcript produced by the DarwinPorts automated build       "
355        pkg_ui_log "system.  You are receiving this email because you are listed as a maintainer    "
356        pkg_ui_log "of this port, which has failed the automated packaging process.  Please update  "
357        pkg_ui_log "the port as soon as possible."
358        pkg_ui_log ""
359        pkg_ui_log ""
360        pkg_ui_log "Thank you,"
361        pkg_ui_log "The DarwinPorts Team"
362        pkg_ui_log ""
363        pkg_ui_log "================================================================================"
364        pkg_ui_log ""
365
366        if {!$valid} {
367                foreach error $lint_errors {
368                        ui_error $error
369                }
370        }
371
372        ui_msg "packaging ${category}/${portname}-${portversion}"
373
374        # Install binary dependencies if we can, to speed things up.
375        #set depends {}
376        #if {[info exists portinfo(depends_run)]} { eval "lappend depends $portinfo(depends_run)" }
377        #if {[info exists portinfo(depends_lib)]} { eval "lappend depends $portinfo(depends_lib)" }
378        #if {[info exists portinfo(depends_build)]} { eval "lappend depends $portinfo(depends_build)" }
379        #foreach depspec $depends {
380        #       set dep [lindex [split $depspec :] end]
381                #install_binary_if_available $dep $pkgbase
382        #}
383        set dependencies [get_dependencies $portname 1]
384        set dependencies [lsort -unique $dependencies]
385        foreach dep $dependencies {
386                install_binary_if_available $dep $pkgbase
387        }
388
389        set options(package.type) pkg
390        set options(package.destpath) ${pkgbase}/${category}/
391
392        # Turn on verbose output for the build
393        set ui_options(ports_verbose) yes
394        if {[catch {set workername [dportopen $porturl [array get options] [array get variations] yes]} result] ||
395                $result == 1} {
396                global errorInfo
397                ui_debug "$errorInfo"
398            ui_error "Internal error: unable to open port: $result"
399            continue
400        }       
401        if {[catch {set result [dportexec $workername pkg]} result] ||
402                $result == 1} {
403                global errorInfo
404                ui_debug "$errorInfo"
405            ui_error "port package failed: $result"
406                dportclose $workername
407            continue
408        }
409        set ui_options(ports_verbose) no
410        # Turn verbose output off after the build
411
412        dportclose $workername
413
414        # We made it to the end.  We can delete the log file.
415        close $logfd
416        set logfd ""
417        file delete ${logpath}/${name}.log
418}
419
420}
421# end foreach pname
Note: See TracBrowser for help on using the repository browser.