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

Last change on this file since 2213 was 2213, checked in by kevin, 18 years ago

remove x11 goobers between builds.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 13.2 KB
Line 
1#!/usr/bin/env tclsh8.3
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# Output string "str"
54# If you don't want newlines to be output, you must pass "-nonewline"
55# as the second argument.
56
57proc ui_puts {priority str {nonl ""}} {
58        global logfd
59    set channel $logfd
60    switch $priority {
61        debug {
62            if [ui_isset ports_debug] {
63                set str "DEBUG: $str"
64            } else {
65                return
66            }
67        }
68        info {
69                        # put verbose stuff only to the log file
70            if ![ui_isset ports_verbose] {
71                return
72            } else {
73                                set priority "log"
74                        }
75        }
76        msg {
77            if [ui_isset ports_quiet] {
78                return
79            }
80        }
81        error {
82            set str "Error: $str"
83        }
84        warn {
85            set str "Warning: $str"
86        }
87    }
88    if {$nonl == "-nonewline"} {
89                if {[string length $channel] > 0 } {
90                        seek $channel 0 end
91                        puts -nonewline $channel "$str"
92                        flush $channel 
93                }
94                if {$priority != "log"} { puts -nonewline stderr "$str" }
95    } else {
96                if {[string length $channel] > 0 } {
97                        seek $channel 0 end
98                        puts $channel "$str"
99                        flush $channel 
100                }
101                if {$priority != "log"} { puts stderr "$str" }
102    }
103}
104
105# Get a line of input from the user and store in str, returning the
106# number of bytes input.
107proc ui_gets {str} {
108    upvar $str in_string
109        set in_string ""
110}
111
112# Ask a boolean "yes/no" question of the user, using "promptstr" as
113# the prompt.  It should contain a trailing space and/or anything else
114# you want to precede the user's input string.  Returns 1 for "yes" or
115# 0 for "no".  This implementation also assumes an english yes/no or
116# y/n response, but that is not mandated by the spec.  If "defvalue"
117# is passed, it will be used as the default value if none is supplied
118# by the user.
119proc ui_yesno {promptstr {defvalue ""}} {
120        set mystr "y"
121        if {[string length $defvalue] > 0} {
122                set mystr $defvalue
123        }
124        if {[string compare -nocase -length 1 $mystr y] == 0} {
125                set rval 1
126        } elseif {[string compare -nocase -length 1 $mystr n] == 0} {
127                set rval 0
128        }
129        return $rval
130}
131
132# Put up a simple confirmation dialog, requesting nothing more than
133# the user's acknowledgement of the prompt string passed in
134# "promptstr".  There is no return value.
135proc ui_confirm {promptstr} {
136        ui_puts msg "$promptstr"
137}
138
139# Display the contents of a file, ideally in a manner which allows the
140# user to scroll through and read it comfortably (e.g. a license
141# text).  For the "simple UI" version of this, we simply punt this to
142# less(1) since rewriting a complete pager for the simple case would
143# be a waste of time.  It's expected in a more complex UI case, a
144# scrolling display widget of some type will be used.
145proc ui_display {filename} {
146}
147
148# Recursive bottom-up approach of building a list of dependencies.
149proc get_dependencies {portname includeBuildDeps} {
150        set result {}
151       
152        if {[catch {set res [dportsearch "^$portname\$"]} error]} {
153                ui_puts err "Internal error: port search failed: $error"
154                return {}
155        }
156        foreach {name array} $res {
157                array set portinfo $array
158                if {![info exists portinfo(name)] ||
159                        ![info exists portinfo(version)] || 
160                        ![info exists portinfo(categories)]} {
161                        ui_puts err "Internal error: $name missing some portinfo keys"
162                        continue
163                }
164               
165                set portname $portinfo(name)
166                set portversion $portinfo(version)
167                set category [lindex $portinfo(categories) 0]
168
169                # Append the package itself to the result list
170                #set pkgpath ${category}/${portname}-${portversion}.pkg
171                lappend result [list $portname $portversion $category]
172
173                # Append the package's dependents to the result list
174                set depends {}
175                if {[info exists portinfo(depends_run)]} { eval "lappend depends $portinfo(depends_run)" }
176                if {[info exists portinfo(depends_lib)]} { eval "lappend depends $portinfo(depends_lib)" }
177                if {$includeBuildDeps != "" && [info exists portinfo(depends_build)]} { 
178                        eval "lappend depends $portinfo(depends_build)"
179                }
180                foreach depspec $depends {
181                        set dep [lindex [split $depspec :] 2]
182                        set x [get_dependencies $dep $includeBuildDeps]
183                        eval "lappend result $x"
184                        set result [lsort -unique $result]
185                }
186        }
187        return $result
188}
189
190# Install binary packages if they've already been built.  This will
191# speed up the testing, since we won't have to recompile dependencies
192# which have already been compiled.
193
194proc install_binary_if_available {dep basepath} {
195        set portname [lindex $dep 0]
196        set portversion [lindex $dep 1]
197        set category [lindex $dep 2]
198       
199        set pkgpath ${basepath}/${category}/${portname}-${portversion}.pkg
200        if {[file readable $pkgpath]} {
201                ui_puts msg "installing binary: $pkgpath"
202                if {[catch {system "cd / && gunzip -c ${pkgpath}/Contents/Archive.pax.gz | pax -r"} error]} {
203                        ui_puts err "Internal error: $error"
204                }
205                # Touch the receipt
206                # xxx: use some variable to describe this path
207                if {[catch {system "touch /opt/local/var/db/dports/receipts/${portname}-${portversion}.bz2"} error]} {
208                        ui_puts err "Internal error: $error"
209                }
210        }
211}
212
213
214# Standard procedures
215
216proc fatal args {
217    global argv0
218    puts stderr "$argv0: $args"
219    exit
220}
221
222# Main
223array set options [list]
224array set variations [list]
225#       set ui_options(ports_verbose) yes
226
227if {[catch {dportinit} result]} {
228    puts "Failed to initialize ports system, $result"
229    exit 1
230}
231
232package require Pextlib
233
234# If no arguments were given, default to all ports.
235if {[llength $argv] == 0} {
236        lappend argv ".*"
237}
238
239foreach pname $argv {
240
241if {[catch {set res [dportsearch "^${pname}\$"]} result]} {
242        puts "port search failed: $result"
243        exit 1
244}
245
246set logpath "/darwinports/logs"
247set logfd ""
248
249foreach {name array} $res {
250        array unset portinfo
251        array set portinfo $array
252
253        # Start with verbose output off;
254        # this will prevent the repopulation of /opt from getting logged.
255        set ui_options(ports_verbose) no
256
257        if ![info exists portinfo(porturl)] {
258                puts stderr "Internal error: no porturl for $name"
259                continue
260        }
261       
262        set pkgbase /darwinports/pkgs/
263        set porturl $portinfo(porturl)
264
265        # Skip up-to-date packages
266        if {[regsub {^file://} $portinfo(porturl) "" portpath]} {
267                if {[info exists portinfo(name)] &&
268                        [info exists portinfo(version)] &&
269                        [info exists portinfo(categories)]} {
270                        set portname $portinfo(name)
271                        set portversion $portinfo(version)
272                        set category [lindex $portinfo(categories) 0]
273                        set pkgfile ${pkgbase}/${category}/${portname}-${portversion}.pkg/Contents/Archive.pax.gz
274                        if {[file readable $pkgfile] && ([file mtime ${pkgfile}] > [file mtime ${portpath}/Portfile])} {
275                                puts stderr "Skipping ${portname}-${portversion}; package is up to date."
276                                continue
277                        }
278                }
279        }
280       
281        # Skipt packages which previously failed
282               
283        # Building the port:
284        # - remove /opt so it won't pollute the port.
285        # - re-install DarwinPorts.
286        # - keep distfiles outside /opt so we don't have to keep fetching them.
287        # - send out an email to the maintainer if any errors occurred.
288
289        ui_puts msg "removing /opt"
290        #unset ui_options(ports_verbose)
291        if {[catch {system "rm -Rf /opt"} error]} {
292                puts stderr "Internal error: $error"
293        }
294        if {[catch {system "rm -Rf /usr/X11R6"} error]} {
295                puts stderr "Internal error: $error"
296        }
297        if {[catch {system "rm -Rf /etc/X11"} error]} {
298                puts stderr "Internal error: $error"
299        }
300        if {[catch {system "rm -Rf /etc/fonts"} error]} {
301                puts stderr "Internal error: $error"
302        }
303        if {[catch {system "cd $env(HOME)/darwinports && make && make install"} error]} {
304                puts stderr "Internal error: $error"
305        }
306        if {[catch {system "rmdir /opt/local/var/db/dports/distfiles"} error]} {
307                puts stderr "Internal error: $error"
308        }
309        if {[catch {system "ln -s /darwinports/distfiles /opt/local/var/db/dports/distfiles"} error]} {
310                puts stderr "Internal error: $error"
311        }
312        #set ui_options(ports_verbose) yes
313
314        # If there was a log file left over from the previous pass,
315        # then the port failed with an error.  Send the log in an
316        # email to the maintainers.
317        if {[string length $logfd] > 0} {
318                close $logfd
319                set logfd ""
320        }
321        #if {[file readable $logfilename]} {
322        #       if {[catch {system "cat $logfilename | /usr/sbin/sendmail -t"} error]} {
323        #               puts stderr "Internal error: $error"
324        #       }
325        #}
326
327        # Open the log file for writing
328        set logfd [open ${logpath}/${name}.log w]
329
330        set valid 1
331
332        set lint_errors {}
333        set portname ""
334        set portversion ""
335        set description ""
336        set category ""
337
338        if ![info exists portinfo(name)] {
339                lappend lint_errors "missing name key"
340                set valid 0
341        } else {
342                set portname $portinfo(name)
343        }
344       
345        if ![info exists portinfo(description)] {
346                lappend lint_errors "missing description key"
347                set valid 0
348        } else {
349                set description $portinfo(description)
350        }
351       
352        if ![info exists portinfo(version)] {
353                lappend lint_errors "missing version key"
354                set valid 0
355        } else {
356                set portversion $portinfo(version)
357        }
358       
359        if ![info exists portinfo(categories)] {
360                lappend lint_errors "missing categories key"
361                set valid 0
362        } else {
363                set category [lindex $portinfo(categories) 0]
364        }
365       
366        if ![info exists portinfo(maintainers)] {
367                append lint_errors "missing maintainers key"
368                set valid 0
369                set maintainers kevin@opendarwin.org
370        } else {
371                set maintainers $portinfo(maintainers)
372        }
373       
374        ui_puts log "To: [join $maintainers {, }]"
375        ui_puts log "From: donotreply@opendarwin.org"
376        ui_puts log "Subject: DarwinPorts $portinfo(name)-$portinfo(version) build failure"
377        ui_puts log ""
378        ui_puts log "The following is a transcript produced by the DarwinPorts automated build       "
379        ui_puts log "system.  You are receiving this email because you are listed as a maintainer    "
380        ui_puts log "of this port, which has failed the automated packaging process.  Please update  "
381        ui_puts log "the port as soon as possible."
382        ui_puts log ""
383        ui_puts log ""
384        ui_puts log "Thank you,"
385        ui_puts log "The DarwinPorts Team"
386        ui_puts log ""
387        ui_puts log "================================================================================"
388        ui_puts log ""
389
390        if {!$valid} {
391                foreach error $lint_errors {
392                        ui_puts error $error
393                }
394        }
395
396        ui_puts msg "packaging ${category}/${portname}-${portversion}"
397
398        # Install binary dependencies if we can, to speed things up.
399        #set depends {}
400        #if {[info exists portinfo(depends_run)]} { eval "lappend depends $portinfo(depends_run)" }
401        #if {[info exists portinfo(depends_lib)]} { eval "lappend depends $portinfo(depends_lib)" }
402        #if {[info exists portinfo(depends_build)]} { eval "lappend depends $portinfo(depends_build)" }
403        #foreach depspec $depends {
404        #       set dep [lindex [split $depspec :] 2]
405                #install_binary_if_available $dep $pkgbase
406        #}
407        set dependencies [get_dependencies $portname 1]
408        set dependencies [lsort -unique $dependencies]
409        foreach dep $dependencies {
410                install_binary_if_available $dep $pkgbase
411        }
412
413        set options(package.type) pkg
414        set options(package.destpath) ${pkgbase}/${category}/
415
416        # Turn on verbose output for the build
417        set ui_options(ports_verbose) yes
418        if {[catch {set workername [dportopen $porturl [array get options] [array get variations]]} result] ||
419                $result == 1} {
420            ui_puts error "Internal error: unable to open port: $result"
421            continue
422        }       
423        if {[catch {set result [dportexec $workername package]} result] ||
424                $result == 1} {
425            ui_puts error "port package failed: $result"
426                dportclose $workername
427            continue
428        }
429        set ui_options(ports_verbose) no
430        # Turn verbose output off after the build
431
432        dportclose $workername
433
434        # We made it to the end.  We can delete the log file.
435        close $logfd
436        set logfd ""
437        file delete ${logpath}/${name}.log
438}
439
440}
441# end foreach pname
Note: See TracBrowser for help on using the repository browser.