source: trunk/base/src/port1.0/portlint.tcl @ 29040

Last change on this file since 29040 was 29040, checked in by afb@…, 10 years ago

add OpenBSD platform too

File size: 8.9 KB
Line 
1# et:ts=4
2# portlint.tcl
3# $Id: portlint.tcl $
4
5package provide portlint 1.0
6package require portutil 1.0
7
8set org.macports.lint [target_new org.macports.lint lint_main]
9target_runtype ${org.macports.lint} always
10target_provides ${org.macports.lint} lint
11target_requires ${org.macports.lint} main
12target_prerun ${org.macports.lint} lint_start
13
14set_ui_prefix
15
16set lint_portsystem \
17        "1.0"
18
19set lint_platforms [list \
20        "darwin" \
21        "freebsd" \
22        "openbsd" \
23        "linux" \
24        "sunos" \
25        ]
26
27set lint_categories [list \
28        "aqua" \
29        "archivers" \
30        "audio" \
31        "benchmarks" \
32        "cad" \
33        "comms" \
34        "cross" \
35        "databases" \
36        "devel" \
37        "editors" \
38        "emulators" \
39        "fuse" \
40        "games" \
41        "genealogy" \
42        "gnome" \
43        "gnustep" \
44        "graphics" \
45        "irc" \
46        "java" \
47        "kde" \
48        "lang" \
49        "mail" \
50        "math" \
51        "multimedia" \
52        "net" \
53        "news" \
54        "palm" \
55        "perl" \
56        "print" \
57        "python" \
58        "ruby" \
59        "science" \
60        "security" \
61        "shells" \
62        "sysutils" \
63        "tex" \
64        "textproc" \
65        "www" \
66        "x11" \
67        "zope" \
68        ]
69
70set lint_required [list \
71        "name" \
72        "version" \
73        "description" \
74        "long_description" \
75        "categories" \
76        "maintainers" \
77        "platforms" \
78        "homepage" \
79        "master_sites" \
80        "checksums" \
81        ]
82
83set lint_optional [list \
84        "epoch" \
85        "revision" \
86        "worksrcdir" \
87        "distname" \
88        "use_automake" \
89        "use_autoconf" \
90        "use_configure" \
91        ]
92
93
94proc seems_utf8 {str} {
95    set len [string length $str]
96    for {set i 0} {$i<$len} {incr i} {
97        set c [scan [string index $str $i] %c]
98        if {$c < 0x80} {
99            # ASCII
100            continue
101        } elseif {($c & 0xE0) == 0xC0} {
102            set n 1
103        } elseif {($c & 0xF0) == 0xE0} {
104            set n 2
105        } elseif {($c & 0xF8) == 0xF0} {
106            set n 3
107        } elseif {($c & 0xFC) == 0xF8} {
108            set n 4
109        } elseif {($c & 0xFE) == 0xFC} {
110            set n 5
111        } else {
112            return false
113        }
114        for {set j 0} {$j<$n} {incr j} {
115            incr i
116            if {$i == $len} {
117                return false
118            } elseif {([scan [string index $str $i] %c] & 0xC0) != 0x80} {
119                return false
120            }
121        }
122    }
123    return true
124}
125
126
127proc lint_start {args} {
128    global UI_PREFIX portname
129    ui_msg "$UI_PREFIX [format [msgcat::mc "Verifying Portfile for %s"] ${portname}]"
130}
131
132proc lint_main {args} {
133        global UI_PREFIX portname portpath portresourcepath
134        set portfile ${portpath}/Portfile
135        set groupdir ${portresourcepath}/group
136
137        set warnings 0
138        set errors 0
139
140    ###################################################################
141    ui_debug "$portfile"
142
143    set require_blank false
144    set require_after ""
145    set seen_portsystem false
146    set seen_portgroup false
147    set in_description false
148
149    set f [open $portfile RDONLY]
150    # read binary (to check UTF-8)
151    fconfigure $f -encoding binary
152    set lineno 1
153    while {1} {
154        set line [gets $f]
155        if {[eof $f]} {
156            close $f
157            break
158        }
159        ui_debug "$lineno: $line"
160
161        if {![seems_utf8 $line]} {
162            ui_error "Line $lineno seems to contain an invalid UTF-8 sequence"
163            incr errors
164        }
165
166        if {[string equal "PortSystem" $require_after] && \
167            [string match "PortGroup*" $line]} {
168            set require_blank false
169        }
170
171        if {$require_blank && ($line != "")} {
172            ui_warn "Line $lineno should be a newline (after $require_after)"
173            incr warnings
174        }
175        set require_blank false
176
177        if {[string match "* " $line] || [string match "*\t" $line] &&
178            [string trim $line] != "" } {
179            # allow indented blank lines between blocks of code and such
180            ui_warn "Line $lineno has trailing whitespace before newline"
181            incr warnings
182        }
183
184        if {($lineno == 1) && ![string match "*\$Id*" $line]} {
185            ui_warn "Line 1 is missing RCS tag (\$Id)"
186            incr warnings
187        } elseif {($lineno == 1)} {
188            ui_info "OK: Line 1 has RCS tag (\$Id)"
189            set require_blank true
190            set require_after "RCS tag"
191        }
192
193        if {[string match "PortSystem*" $line]} {
194            if {$seen_portsystem} {
195                 ui_error "Line $lineno repeats PortSystem information"
196                 incr errors
197            }
198            regexp {PortSystem\s+([0-9.]+)} $line -> portsystem
199            if {![info exists portsystem]} {
200                 ui_error "Line $lineno has unrecognized PortSystem"
201                 incr errors
202            }
203            set seen_portsystem true
204            set require_blank true
205            set require_after "PortSystem"
206        }
207        if {[string match "PortGroup*" $line]} {
208            if {$seen_portgroup} {
209                 ui_error "Line $lineno repeats PortGroup information"
210                 incr errors
211            }
212            regexp {PortGroup\s+([a-z0-9]+)\s+([0-9.]+)} $line -> portgroup portgroupversion
213            if {![info exists portgroup]} {
214                 ui_error "Line $lineno has unrecognized PortGroup"
215                 incr errors
216            }
217            set seen_portgroup true
218            set require_blank true
219            set require_after "PortGroup"
220        }
221
222        # TODO: check for repeated variable definitions
223        # TODO: check the definition order of variables
224        # TODO: check length of description against max
225
226        if {[string match "long_description*" $line]} {
227            set in_description true
228        }
229        if {$in_description && ([string range $line end end] != "\\")} {
230            set in_description false
231            #set require_blank true
232            #set require_after "long_description"
233        } elseif {$in_description} {
234            set require_blank false
235        }
236
237        ### TODO: more checks to Portfile syntax
238
239        incr lineno
240    }
241
242    ###################################################################
243
244    global os.platform os.arch os.version
245    global portversion portrevision portepoch
246    # hoping for "noarch" :
247    set portarch ${os.arch}
248    global description long_description categories maintainers platforms homepage master_sites checksums
249   
250    global lint_portsystem lint_platforms lint_categories lint_required lint_optional
251
252    if (!$seen_portsystem) {
253        ui_error "Didn't find PortSystem specification"
254        incr errors
255    }  elseif {$portsystem != $lint_portsystem} {
256        ui_error "Unknown PortSystem: $portsystem"
257        incr errors
258    } else {
259        ui_info "OK: Found PortSystem $portsystem"
260    }
261    if (!$seen_portgroup) {
262        # PortGroup is optional, so missing is OK
263    }  elseif {![file exists $groupdir/$portgroup-$portgroupversion.tcl]} {
264        ui_error "Unknown PortGroup: $portgroup-$portgroupversion"
265        incr errors
266    } else {
267        ui_info "OK: Found PortGroup $portgroup-$portgroupversion"
268    }
269
270    foreach req_var $lint_required {
271        if {$req_var == "name"} {
272            set var "portname"
273        } elseif {$req_var == "version"} {
274            set var "portversion"
275        } else {
276            set var $req_var
277        }
278       if {![info exists $var]} {
279            ui_error "Missing required variable: $req_var"
280            incr errors
281        } else {
282            ui_info "OK: Found required variable: $req_var"
283        }
284    }
285
286    foreach opt_var $lint_optional {
287       if {$opt_var == "epoch"} {
288            set var "portepoch"
289        } elseif {$opt_var == "revision"} {
290            set var "portrevision"
291        } else {
292            set var $opt_var
293       }
294       if {[info exists $var]} {
295            # TODO: check whether it was seen (or default)
296            ui_info "OK: Found optional variable: $opt_var"
297       }
298    }
299
300    foreach platform $platforms {
301       if {[lsearch -exact $lint_platforms $platform] == -1} {
302            ui_error "Unknown platform: $platform"
303            incr errors
304        } else {
305            ui_info "OK: Found platform: $platform"
306        }
307    }
308
309    foreach category $categories {
310       if {[lsearch -exact $lint_categories $category] == -1} {
311            ui_error "Unknown category: $category"
312            incr errors
313        } else {
314            ui_info "OK: Found category: $category"
315        }
316    }
317
318    if {![string is integer -strict $portepoch]} {
319        ui_error "Port epoch is not numeric:  $portepoch"
320        incr errors
321    }
322    if {![string is integer -strict $portrevision]} {
323        ui_error "Port revision is not numeric: $portrevision"
324        incr errors
325    }
326
327    if {[string match "*darwinports@opendarwin.org*" $maintainers]} {
328        ui_warn "Using legacy email for no/open maintainer"
329        incr warnings
330    }
331
332    ### TODO: more checks to Tcl variables/sections
333
334    ui_debug "Name: $portname"
335    ui_debug "Epoch: $portepoch"
336    ui_debug "Version: $portversion"
337    ui_debug "Revision: $portrevision"
338    ui_debug "Arch: $portarch"
339    ###################################################################
340
341        ui_msg "$UI_PREFIX [format [msgcat::mc "%d errors and %d warnings found."] $errors $warnings]"
342
343        return {$errors > 0}
344}
Note: See TracBrowser for help on using the repository browser.