source: trunk/base/portmgr/packaging/packageall.tcl @ 116518

Last change on this file since 116518 was 116518, checked in by cal@…, 7 years ago

portmgr/packaging: whitespace only, unify whitespace, reindent

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