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

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

change output order

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