source: trunk/base/src/portmgr/rpmall.tcl @ 3411

Last change on this file since 3411 was 3411, checked in by fkr, 17 years ago

Bug:
Submitted by:
Reviewed by:
Approved by:
Obtained from:

look in ${prefix}/src/apple/RPMS instead of hard-coded /opt/local

  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 13.4 KB
Line 
1#!/usr/bin/env tclsh
2# rpmall.tcl
3#
4# Copyright (c) 2003 Benjamin Reed <ranger@befunk.com>
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
39# ui_options(ports_debug) - If set, output debugging messages.
40# ui_options(ports_verbose) - If set, output info messages (ui_info)
41# ui_options(ports_quiet) - If set, don't output "standard messages"
42
43# ui_options accessor
44proc ui_isset {val} {
45    global ui_options
46    if {[info exists ui_options($val)]} {
47        if {$ui_options($val) == "yes"} {
48            return 1
49        }
50    }
51    return 0
52}
53
54set options(package.destpath) "/darwinports/rpms"
55
56# UI Callback
57
58proc ui_puts {messagelist} {
59    global logfd
60    set channel $logfd
61    array set message $messagelist
62    switch $message(priority) {
63        debug {
64            if {[ui_isset ports_debug]} {
65                set str "DEBUG: $message(data)"
66            } else {
67                return
68            }
69        }
70        info {
71            # put verbose stuff only to the log file
72            if {![ui_isset ports_verbose]} {
73                return
74            } else {
75                if {[string length $channel] > 0} {
76                    log_message $channel $message(data)
77                }
78                return
79            }
80        }
81        msg {
82            if {[ui_isset ports_quiet]} {
83                return
84            }
85            set str $message(data)
86        }
87        error {
88            set str "Error: $message(data)"
89        }
90        warn {
91            set str "Warning: $message(data)"
92        }
93    }
94    if {[string length $channel] > 0 } {
95        log_message $channel $str
96    }
97    puts stderr $str
98}
99
100proc pkg_ui_log {message} {
101    global logfd
102    if {[string length $logfd] > 0 } {
103        log_message $logfd $message
104    }
105}
106
107proc log_message {channel message} {
108    seek $channel 0 end
109    puts $channel $message
110    flush $channel
111}
112
113# Recursive bottom-up approach of building a list of dependencies.
114proc get_dependencies {portname includeBuildDeps} {
115        set result {}
116       
117        if {[catch {set search [dportsearch "^$portname\$"]} error]} {
118                ui_error "Internal error: port search failed: $error"
119                return {}
120        }
121        foreach {name array} $search {
122                array set portinfo $array
123                if {![info exists portinfo(name)] ||
124                        ![info exists portinfo(version)] || 
125                        ![info exists portinfo(categories)]} {
126                        ui_error "Internal error: $name missing some portinfo keys"
127                        continue
128                }
129                if {![info exists portinfo(revision)]} {
130                        set portinfo(revision) 0
131                }
132               
133                set portname $portinfo(name)
134                set portversion $portinfo(version)
135                set revision $portinfo(revision)
136
137                # Append the package itself to the result list
138                lappend result [list $portname $portversion $revision]
139
140                # Append the package's dependents to the result list
141                set depends {}
142                if {[info exists portinfo(depends_run)]} { eval "lappend depends $portinfo(depends_run)" }
143                if {[info exists portinfo(depends_lib)]} { eval "lappend depends $portinfo(depends_lib)" }
144                if {$includeBuildDeps != "" && [info exists portinfo(depends_build)]} { 
145                        eval "lappend depends $portinfo(depends_build)"
146                }
147                foreach depspec $depends {
148                        set dep [lindex [split $depspec :] 2]
149                        set x [get_dependencies $dep $includeBuildDeps]
150                        eval "lappend result $x"
151                        set result [lsort -unique $result]
152                }
153        }
154        return $result
155}
156
157# Install binary packages if they've already been built.  This will
158# speed up the testing, since we won't have to recompile dependencies
159# which have already been compiled.
160
161proc install_binary_if_available {dep} {
162        set portname [lindex $dep 0]
163        set portversion [lindex $dep 1]
164        set revision [lindex $dep 2]
165
166        foreach dir {"${prefix}/src/apple/RPMS" "/usr/src/apple/RPMS" "/darwinports/rpms/RPMS"} {
167                foreach arch {"ppc" "i386" "fat"} {
168                        set rpmpath "${dir}/${arch}/${portname}-${portversion}-${revision}.${arch}.rpm"
169                        if {[file readable $rpmpath]} {
170                                ui_msg "Installing binary: $rpmpath"
171                                if {[catch {system "rpm -Uvh --force $rpmpath"} error ]} {
172                                        ui_error "Internal error: $error"
173                                } else {
174                                        return true
175                                }
176                        }
177                }
178        }
179        return false
180}
181
182
183# Standard procedures
184
185proc fatal args {
186    global argv0
187    puts stderr "$argv0: $args"
188    exit
189}
190
191# Main
192array set options [list]
193array set variations [list]
194#       set ui_options(ports_verbose) yes
195if {![file exists /usr/bin/sw_vers]} {
196        set variations(puredarwin) "+"
197}
198
199if {[catch {dportinit} result]} {
200    puts "Failed to initialize ports system, $result"
201    exit 1
202}
203
204package require Pextlib
205
206# If no arguments were given, default to all ports.
207if {[llength $argv] == 0} {
208        lappend argv ".*"
209}
210
211foreach pname $argv {
212
213if {[catch {set allpackages [dportsearch "^${pname}\$"]} result]} {
214        puts "port search failed: $result"
215        exit 1
216}
217
218set logpath "/darwinports/logs"
219set logfd ""
220
221foreach {name array} $allpackages {
222        array unset portinfo
223        array set portinfo $array
224
225        #ui_msg "foo $portinfo(porturl)"
226
227        # Start with verbose output off;
228        # this will prevent the repopulation of /opt from getting logged.
229        set ui_options(ports_verbose) no
230
231        if {![info exists portinfo(porturl)]} {
232                puts stderr "Internal error: no porturl for $name"
233                continue
234        }
235        if {![info exists portinfo(revision)]} {
236                set portinfo(revision) 0
237        }
238
239        set porturl $portinfo(porturl)
240
241        # this is used to short-circuit the RPM check and
242        # move on to the next package
243
244        global exit_loop
245        set exit_loop false
246
247        # Skip up-to-date packages
248        if {[regsub {^file://} $portinfo(porturl) "" portpath]} {
249                if {[info exists portinfo(name)] &&
250                        [info exists portinfo(version)] &&
251                        [info exists portinfo(revision)]} {
252                        set portname $portinfo(name)
253                        set portversion $portinfo(version)
254                        set revision $portinfo(revision)
255
256                        foreach dir {"/opt/local/src/apple/RPMS" "/usr/src/apple/RPMS" "/darwinports/rpms/RPMS"} {
257                                foreach arch {"ppc" "i386" "fat"} {
258                                        set rpmpath "${dir}/${arch}/${portname}-${portversion}-${revision}.${arch}.rpm"
259                                        #ui_msg "trying ${rpmpath}"
260                                        if {[file readable $rpmpath] && ([file mtime ${rpmpath}] >= [file mtime ${portpath}/Portfile])} {
261                                                puts stderr "->    skipping ${portname}-${portversion}; package is up to date."
262                                                set exit_loop true
263                                                break
264                                        }
265                                }
266                                if {${exit_loop}} {
267                                        break
268                                }
269                        }
270                }
271        }
272        if {${exit_loop}} {
273                continue
274        }
275       
276        # Skip packages which previously failed
277        set exit_loop false
278               
279        # Skip up-to-date packages
280        if {[regsub {^file://} $portinfo(porturl) "" portpath]} {
281                if {[info exists portinfo(name)] &&
282                        [info exists portinfo(version)] &&
283                        [info exists portinfo(revision)]} {
284                        set portname $portinfo(name)
285                        set portversion $portinfo(version)
286                        set revision $portinfo(revision)
287
288                        set logfilepath "${logpath}/${portname}.log"
289                        if {[file readable ${logfilepath}] && ([file mtime ${logfilepath}] > [file mtime ${portpath}/Portfile])} {
290                                puts stderr "->    skipping ${portname}-${portversion}; package failed, but has not changed."
291                                set exit_loop true
292                        }
293                }
294        }
295        if {${exit_loop}} {
296                continue
297        }
298       
299        # Building the port:
300        # - remove /opt so it won't pollute the port.
301        # - re-install DarwinPorts.
302        # - keep distfiles outside /opt so we don't have to keep fetching them.
303        # - send out an email to the maintainer if any errors occurred.
304
305        set remove_files ""
306        foreach dir {"/opt/local/src/apple/RPMS" "/usr/src/apple/RPMS" "/darwinports/rpms/RPMS"} {
307                foreach arch {"ppc" "i386" "fat"} {
308                        set remove_files "${remove_files} '${dir}/${arch}/'*.rpm"
309                }
310        }
311        system "rpm -q --queryformat='%{name} ' -p ${remove_files} | xargs rpm -e || true"
312
313        ui_msg "->    Removing /opt"
314        #unset ui_options(ports_verbose)
315        if {[catch {system "rm -Rf /opt"} error]} {
316                puts stderr "Internal error: $error"
317        }
318        # this is bad on pure darwin  :)
319        #if {[catch {system "rm -Rf /usr/X11R6"} error]} {
320        #       puts stderr "Internal error: $error"
321        #}
322        #if {[catch {system "rm -Rf /etc/X11"} error]} {
323        #       puts stderr "Internal error: $error"
324        #}
325        #if {[catch {system "rm -Rf /etc/fonts"} error]} {
326        #       puts stderr "Internal error: $error"
327        #}
328        ui_msg "->    Installing darwinports"
329        if {[catch {system "cd $env(HOME)/darwinports && make && make install"} error]} {
330                puts stderr "Internal error: $error"
331        }
332        if {[catch {system "rmdir /opt/local/var/db/dports/distfiles"} error]} {
333                puts stderr "Internal error: $error"
334        }
335        if {[catch {system "ln -s /darwinports/distfiles /opt/local/var/db/dports/distfiles"} error]} {
336                puts stderr "Internal error: $error"
337        }
338        #set ui_options(ports_verbose) yes
339
340        # If there was a log file left over from the previous pass,
341        # then the port failed with an error.  Send the log in an
342        # email to the maintainers.
343        if {[string length $logfd] > 0} {
344                close $logfd
345                set logfd ""
346        }
347        #if {[file readable $logfilename]} {
348        #       if {[catch {system "cat $logfilename | /usr/sbin/sendmail -t"} error]} {
349        #               puts stderr "Internal error: $error"
350        #       }
351        #}
352
353        # Open the log file for writing
354        set logfd [open ${logpath}/${name}.log w]
355
356        set valid 1
357
358        set lint_errors {}
359        set portname ""
360        set portversion ""
361        set description ""
362        set category ""
363
364        if {![info exists portinfo(name)]} {
365                lappend lint_errors "missing name key"
366                set valid 0
367        } else {
368                set portname $portinfo(name)
369        }
370       
371        if {![info exists portinfo(description)]} {
372                lappend lint_errors "missing description key"
373                set valid 0
374        } else {
375                set description $portinfo(description)
376        }
377       
378        if {![info exists portinfo(version)]} {
379                lappend lint_errors "missing version key"
380                set valid 0
381        } else {
382                set portversion $portinfo(version)
383        }
384       
385        if {![info exists portinfo(categories)]} {
386                lappend lint_errors "missing categories key"
387                set valid 0
388        } else {
389                set category [lindex $portinfo(categories) 0]
390        }
391       
392        if {![info exists portinfo(maintainers)]} {
393                append lint_errors "missing maintainers key"
394                set valid 0
395                set maintainers kevin@opendarwin.org
396        } else {
397                set maintainers $portinfo(maintainers)
398        }
399       
400        pkg_ui_log "To: [join $maintainers {, }]"
401        pkg_ui_log "From: donotreply@opendarwin.org"
402        pkg_ui_log "Subject: DarwinPorts $portinfo(name)-$portinfo(version) build failure"
403        pkg_ui_log ""
404        pkg_ui_log "The following is a transcript produced by the DarwinPorts automated build       "
405        pkg_ui_log "system.  You are receiving this email because you are listed as a maintainer    "
406        pkg_ui_log "of this port, which has failed the automated packaging process.  Please update  "
407        pkg_ui_log "the port as soon as possible."
408        pkg_ui_log ""
409        pkg_ui_log ""
410        pkg_ui_log "Thank you,"
411        pkg_ui_log "The DarwinPorts Team"
412        pkg_ui_log ""
413        pkg_ui_log "================================================================================"
414        pkg_ui_log ""
415
416        if {!$valid} {
417                foreach error $lint_errors {
418                        ui_error $error
419                }
420        }
421
422        ui_msg "-->   Packaging ${category}/${portname}-${portversion}"
423
424        foreach prebuild {"ccache" "rpm" "unzip"} {
425                if {![file exists /bin/${prebuild}] && ![file exists /usr/bin/${prebuild}]} {
426                        ui_msg "--->  Pre-installing ${prebuild}"
427                        if {[catch {set search [dportsearch "^${prebuild}\$"]} error]} {
428                                ui_error "Internal error: port search ${prebuild} failed: $error"
429                        }
430                        array set prebuildinfo [lindex $search 1]
431                        set ui_options(ports_verbose) yes
432                        if {[catch {set workername [dportopen $prebuildinfo(porturl) [array get options] [array get variations]]} result] ||
433                                $result == 1} {
434                                ui_error "Internal error: unable to install ${prebuild}... exiting"
435                                exit 1
436                        }
437                        if {[catch {set result [dportexec $workername install]} result] ||
438                                $result == 1} {
439                                ui_error "installation of ${prebuild} failed: $result"
440                                dportclose $workername
441                                exit 1
442                        }
443                }
444        }
445
446        # Turn on verbose output for the build
447        set ui_options(ports_verbose) yes
448        if {[catch {set workername [dportopen $porturl [array get options] [array get variations]]} result] ||
449                $result == 1} {
450            ui_error "Internal error: unable to open port: $result"
451            continue
452        }
453        if {[catch {set result [dportexec $workername rpmpackage]} result] ||
454                $result == 1} {
455            ui_error "port package failed: $result"
456                dportclose $workername
457            continue
458        }
459        set ui_options(ports_verbose) no
460        # Turn verbose output off after the build
461
462        dportclose $workername
463
464        # We made it to the end.  We can delete the log file.
465        close $logfd
466        set logfd ""
467        file delete ${logpath}/${name}.log
468}
469
470}
471# end foreach pname
Note: See TracBrowser for help on using the repository browser.