source: trunk/base/src/portmgr/packageall.tcl @ 7156

Last change on this file since 7156 was 7156, checked in by jkh, 16 years ago

Add another (optional) argument to dportopen so that we can defeat the cache in cases where we need to open an existing instance
but set different options for it.
Reviewed by: kvv

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