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

Last change on this file since 2426 was 2426, checked in by landonf (Landon Fuller), 18 years ago

Allow DarwinPorts to build out of the box on newer Darwin releases with Tcl 8.4

  • Remove references to 'tclsh8.3', replacing them with 'tclsh'. This will work everywhere except FreeBSD
  • Remove compile.sh, link.sh, and tcldir.sh, replacing them with config.sh. config.sh references the config data provided by TEA and allows us to steer clear of autoconf.
  • Modify all Makefiles to use config.sh
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 13.2 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# 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.