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

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

Might as well remap package -> pkg here too (though this whole file probably
need mucho lovin' to be useful again).

  • 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]]} 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.