From 86eaf5e03289e45a95514b4f6011157972016e9d Mon Sep 17 00:00:00 2001 From: fuzzyray Date: Thu, 30 Apr 2009 21:52:45 +0000 Subject: Tagging the gentoolkit-0.2.4 release svn path=/tags/gentoolkit-0.2.4/; revision=564 --- src/lintool/AUTHORS | 1 + src/lintool/COPYING | 340 ++++++++++++++++++++++++++++++++++++++ src/lintool/ChangeLog | 71 ++++++++ src/lintool/NEWS | 0 src/lintool/README | 23 +++ src/lintool/lintool.1 | 41 +++++ src/lintool/lintool.py | 320 +++++++++++++++++++++++++++++++++++ src/lintool/lintool/__init__.py | 3 + src/lintool/lintool/changelog.py | 105 ++++++++++++ src/lintool/lintool/digest.py | 28 ++++ src/lintool/lintool/ebuild.py | 349 +++++++++++++++++++++++++++++++++++++++ src/lintool/lintool/test.py | 30 ++++ 12 files changed, 1311 insertions(+) create mode 100644 src/lintool/AUTHORS create mode 100644 src/lintool/COPYING create mode 100644 src/lintool/ChangeLog create mode 100644 src/lintool/NEWS create mode 100644 src/lintool/README create mode 100644 src/lintool/lintool.1 create mode 100755 src/lintool/lintool.py create mode 100644 src/lintool/lintool/__init__.py create mode 100644 src/lintool/lintool/changelog.py create mode 100644 src/lintool/lintool/digest.py create mode 100644 src/lintool/lintool/ebuild.py create mode 100644 src/lintool/lintool/test.py (limited to 'src/lintool') diff --git a/src/lintool/AUTHORS b/src/lintool/AUTHORS new file mode 100644 index 0000000..fe436cb --- /dev/null +++ b/src/lintool/AUTHORS @@ -0,0 +1 @@ +Karl Trygve Kalleberg diff --git a/src/lintool/COPYING b/src/lintool/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/src/lintool/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/lintool/ChangeLog b/src/lintool/ChangeLog new file mode 100644 index 0000000..0e8c1e9 --- /dev/null +++ b/src/lintool/ChangeLog @@ -0,0 +1,71 @@ +2004-02-18 Karl Trygve Kalleberg + * Moved from separate CVS module to be part of gentoolkit-dev + +2002-10-31 Karl Trygve Kalleberg + * Fixed \$Header$ comment + * Fixed off-by-one in line numbering + +2002-10-30 Karl Trygve Kalleberg + * Now defaults to showing all details + * Added --no-details + * Better LICENSE parsing + * Better references to policy. + * Line numbers for whitespace testing. + * Released 0.2.4 + +2002-08-12 Karl Trygve Kalleberg + * Added more header tests + * Added initial tests for SLOT, KEYWORD and LICENSE + +2002-08-10 Karl Trygve Kalleberg + * Spurious space checker works again. + * Added Makefile, COPYING, README, AUTHORS, NEWS + +2002-07-22 Karl Trygve Kalleberg + * Changed A=${P}.tar.gz check to ^A=.*, as per Seemant's suggestion. + +2002-07-17 Karl Trygve Kalleberg + * Added TestLicense to ebuild.py + * Added --aux-license-dir= + * Added MunchieFormatter + * Added --formatter= + +2002-07-10 Karl Trygve Kalleberg + * Refactored; split tests into changelog, digest and ebuild-specific + * Added TestSyntax test to digest.py + * Added TestHeaders, TestConstructPresence, TestIndentation to + changelog.py + +2002-05-15 Karl Trygve Kalleberg + + * Fixed test for Author: and Maintainer: to warn about their + deprecation and recommend the use of ChangeLog instead. + * Added (E) and (W) prefixes to messages printed by --show-details + * Added --tests=- to allow turning off a + particular test easily. + * Added statistics output at the bottom. + * Updated man page to reflect new option feature. + * Fixed the --show-details, --show-separate annoyance. + * Fixed use flags parsing to disregard some false positives. + +2002-05-13 Karl Trygve Kalleberg + * Fixed --list-tests which was incorrectly --listTests + +2002-04-30 Karl Trygve Kalleberg + * Added 's cleanups + * Improved error reporting; now separates into errors and + warnings. + * Improved TestSpaces to check for non-conformant + line-continuations. + * Added TestUseFlags that checks that an ebuild only uses + sanctioned use flags (read from /usr/portage/profiles/use.desc) + * Added SLOT= to list desired env vars (warns if missing) + * Added LICENSE= to list of required env vars (errors if missing) + * Improved error messages + * Added --tests= option to allow the user to specify which tests + to run + * Added --list-tests option that lists available tests + * Updated man page. + +2002-03-22 Karl Trygve Kalleberg + * Added this ChangeLog diff --git a/src/lintool/NEWS b/src/lintool/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/src/lintool/README b/src/lintool/README new file mode 100644 index 0000000..1494aad --- /dev/null +++ b/src/lintool/README @@ -0,0 +1,23 @@ + +Package: Lintool +Version: 0.1.3 +Author : Karl Trygve Kalleberg + + +MOTIVATION + +Lintool is a "lint" utility for the Gentoo Linux distribution. It is a +tool that tests ebuilds, changelogs and package digests for +well-formedness. It's intended to aid Gentoo Linux developers avoid most +common mistakes when packaging software for Gentoo. + +MECHANICS + +To check an ebuild, do lintool --ebuild +To check a ChangeLog, do lintool --changelog +To check a package digest, do lintoo --digest + +IMPROVEMENTS + +Any suggestions for improvements should be sent to karltk@gentoo.org, or +added as a bug assigned to me. diff --git a/src/lintool/lintool.1 b/src/lintool/lintool.1 new file mode 100644 index 0000000..11883e8 --- /dev/null +++ b/src/lintool/lintool.1 @@ -0,0 +1,41 @@ +.TH lintool "1" "March 2002" "gentoolkit 0.1.3" +.SH NAME +lintool \- manual page for the lintool program, a program that checks the +santity of ebuild scripts. +.SH SYNOPSIS +.B lintool +\fI\fR \fIebuilds...\fR +.SH DESCRIPTION +Lintool checks if a set of +.I ebuilds +conforms to the ebuild style guide. This is not +(yet) an exhaustive test, so your ebuild might be broken even if lintool +thinks it's okay. +.PP +.SH OPTIONS +.TP +\fB--no-summary\fI +Turn off total summary for all tests run on all ebuilds. +.TP +\fB--show-separate\fI +Show short summary of tests for each ebuild checked. +.TP +\fB--show-details\fI +Show full details of tests for each ebuild checked +.TP +\fB--tests=test1,test2,..\fI +Run only the tests specified to this option. Default is to run all +tests. One can turn off a particular test by pretending it with minus (e.g. +.I --tests=-TestUseFlags,-TestSpaces +). A list of tests can be obtained from +.I --list-tests +.TP +\fB--list-tests\fI +List available tests. +.SH AUTHORS +Karl Trygve Kalleberg , 2002 +.SH "SEE ALSO" +ebuild(5) +.TP +The \fI/usr/sbin/lintool\fR script. + diff --git a/src/lintool/lintool.py b/src/lintool/lintool.py new file mode 100755 index 0000000..721c744 --- /dev/null +++ b/src/lintool/lintool.py @@ -0,0 +1,320 @@ +#! /usr/bin/python +# +# Copyright 2002 Gentoo Technologies, Inc +# Distributed under the terms of the GNU General Public License v2.0 +# Author Karl Trygve Kalleberg +# +# About: +# lintool aims to check the stylistic and syntactical correctness for +# ebuilds, changelogs and digest files for the Gentoo packaging system. +# +# TODO +# +# - Make HTMLFormatter +# + +VERSION="0.2.4" + +import sys +import getopt + +from lintool import ebuild, changelog, digest + +class TextFormatter: + def section(self, s): + print "\n" + "-"*79 + print " " + s + "\n" + def bullet(self, s): + print "* " + s + def sub(self, s): + print "- " + s + def subwarn(self, s): + print "- (W) " + s + def suberr(self, s): + print "- (E) " + s + def subsub(self, s): + print " |" + s + def subsubwarn(self, s): + print " (W) |" + s + def subsuberr(self, s): + print " (E) |" + s + def line(self,s): + print s + def div(self, left, right): + l = len(left) + r = len(right) + return left + " " * (78-l-r) + right + +class MunchieFormatter: + def section(self, s): + print "[lintool] " + "-" * (78 - len("[lintool] ")) + print "[lintool] " + s + "\n" + def bullet(self, s): + print "[lintool] * " + s + def sub(self, s): + print "[lintool] - " + s + def subwarn(self, s): + print "[lintool] - (W) " + s + def suberr(self, s): + print "[lintool] - (E) " + s + def subsub(self, s): + print "[lintool] |" + s + def subsubwarn(self, s): + print "[lintool] (W) |" + s + def subsuberr(self, s): + print "[lintool] (E) |" + s + def line(self,s): + print "[lintool] " + s + def div(self, left, right): + l = len("[lintool] " + left) + r = len(right) + return left + " " * (78-l-r) + right + +formatters = { "text" : TextFormatter(), "munchie" : MunchieFormatter() } + +def extractFilename(path): + return path + +def runTests(tests,results,ins): + for j in tests: + j.reset() + + ln = 1 + for i in ins.readlines(): + for j in tests: + j.checkLine(i, ln) + ln += 1 + + hasWarning = 0 + hasError = 0 + for j in xrange(len(tests)): + if tests[j].hasErrors(): + results[j][0] += 1 + hasError = 1 + if tests[j].hasWarnings(): + results[j][1] += 1 + hasWarning = 1 + return (hasError, hasWarning) + +def showStatus(options,tests,formatter,file): + if options['showDetails'] or options['showSeparate']: + formatter.section("Status for " + file) + for j in tests: + if options['showSeparate'] or options['showDetails']: + l = len(j.getDesc()) + formatter.bullet(formatter.div(j.getDesc(), ": " + j.getStatus())) + if options['showDetails']: + j.report() + elif options['showShort']: + allOK = 1 + for j in tests: + if j.hasErrors(): + allOK = 0 + break + if allOK: + formatter.div(file, ": OK") + else: + formatter.div(file, ": Not OK") + # else fall through the bottom + +def usage(opts): + print sys.argv[0], "[options] ebuild [ebuild ebuild ... ]" + print + + if opts: + print "Where [options] include:" + for (short,long_,desc) in opts: + short_ = '' + for s in short: + short_ = short_ + '-' + s + ',' + long_ = '--' + long_ + opt = short_ + long_ + opt = opt.rjust(18) + print opt + ' ' + desc + print + +def parse_opts(argv): + options = { 'showSeparate': 0, + 'showTotal': 1, + 'showDetails': 1, + 'showShort': 1, + 'listTests': 0, + 'desiredTests': 0, + 'testMode' : "ebuild", + 'licenseDirs' : [ "/usr/portage/licenses" ], + 'formatter' : 'text' + } + + opts = (('', 'show-separate', + 'Show short summary of tests for each ebuild checked'), + + ('v', 'version', + 'Show program version'), + + ('', 'no-summary', + 'Do not show total summary'), + + ('', 'no-details', + 'Do not show full details of tests for each ebuild checked'), + + ('', 'ebuild', + 'Files to check are ebuilds'), + + ('', 'changelog', + 'Files to check are changelogs'), + + ('', 'digest', + 'Files to check are digests'), + + ('', 'tests=', + 'Comma-separated list of tests to run'), + + ('', 'list-tests', + 'List available tests'), + + ('', 'from-file=', + 'Read ebuilds from '), + + ('', 'formatter=', + "Use 'text' (default) or 'munchie' formatter"), + + ('', 'aux-license-dir=', + 'Add to directories to search for licenses'), + + ('?h', 'help', + 'Show this help'), + ) + + short_options = '' + long_options = [] + for (short,long_,desc) in opts: + short_options = short_options + short + if '=' in long_: + long_ = long_.split('=', 1)[0] + '=' + long_options.append(long_) + + try: + (option_list,args) = getopt.getopt(sys.argv[1:], short_options, long_options) + except getopt.GetoptError, details: + print 'Error parsing command line:',str(details) + sys.exit(1) + + for (option,value) in option_list: + if option in [ '--no-details' ]: + options['showShort'] = 1 + options['showDetails'] = 0 + elif option in [ '--show-separate' ]: + options['showShort'] = 0 + options['showSeparate'] = 1 + elif option in [ '--no-summary']: + options['showTotal'] = 0 + elif option in [ '--from-file' ]: + lines = open(value, 'r').readlines() + lines = [o.strip() for o in lines] + args = lines + args + elif option in [ '--tests' ]: + options['desiredTests'] = value.split(",") + elif option in [ '--formatter' ]: + options['formatter'] = value + elif option in [ '--list-tests' ]: + options['listTests'] = 1 + elif option in [ '--ebuild' ]: + options['testMode'] = 'ebuild' + elif option in [ '--changelog' ]: + options['testMode'] = 'changelog' + elif option in [ '--digest' ]: + options['testMode'] = 'digest' + elif option in [ '--aux-license-dir' ]: + options['licenseDirs'].append(value) + elif option in [ '-v', '--version' ]: + print "Lintool " + VERSION + sys.exit(0) + elif option in [ '-h', '-?', '--help' ]: + usage(opts) + sys.exit(0) + else: + # shouldn't ever happen. better to be safe + print "Unknown option - '%s'!" % (option) + sys.exit(1) + + return (options,args) + +def main(): + (options,args) = parse_opts(sys.argv[1:]) + + formatter = formatters[options['formatter']] + + # Get test suite for given mode + if options['testMode'] == "ebuild": + available_tests = ebuild.getTests(formatter, options) + elif options['testMode'] == "changelog": + available_tests = changelog.getTests(formatter, options) + elif options['testMode'] == "digest": + available_tests = digest.getTests(formatter, options) + + # List available tests, if that was the users request + if options['listTests']: + maxlen = 0 + for i in available_tests: + maxlen = max(len(i.__class__.__name__), maxlen) + for i in available_tests: + n = i.__class__.__name__ + print n + " " * (maxlen - len(n)) + " - " + i.getDesc() + + # Quit with short usage string, if no params given + if len(args) == 0: + usage(None) + sys.exit(1) + + # Create final list of tests to run + tests = [] + notTests = [] + if options['desiredTests']: + for i in options['desiredTests']: + for j in available_tests: + if len(i) and i[0] == "-": + notTests.append(i[1:]) + if j.__class__.__name__ == i: + tests.append(j) + else: + tests = available_tests + + if len(notTests): + for i in available_tests: + if i.__class__.__name__ not in notTests: + tests.append(i) + + results = [[0, 0] for x in range(len(tests))] + + # Set up for test run + numFiles = 0 + totalErrors = 0 + totalWarnings = 0 + + # Iterate through all files given as arguments, testing each file + # against the final list of tests + for i in args: + fn = extractFilename(i) + ins = open(i, "r") + numFiles += 1 + (hasError, hasWarning) = runTests(tests,results,ins) + totalErrors += hasError + totalWarnings += hasWarning + showStatus(options,tests,formatter,fn) + + # Show totals, if options allow it + if options['showTotal']: + formatter.section(formatter.div("Summary for all " + str(numFiles) + " " + options['testMode'] + "(s) checked", "#errors/warns")) + for i in xrange(len(tests)): + l = len(tests[i].getDesc()) + formatter.line(formatter.div(tests[i].getDesc(), ": %3d / %3d" % (results[i][0], results[i][1]))) + formatter.line(formatter.div("Total number of ebuilds with errors", \ + "%3d (%3d%%)" % (totalErrors, totalErrors*100/numFiles))) + formatter.line(formatter.div("Total number of ebuilds with warnings", \ + "%3d (%3d%%)" % (totalWarnings, totalWarnings*100/numFiles))) + if totalErrors: + sys.exit(1) + +if __name__ == "__main__": + main() + diff --git a/src/lintool/lintool/__init__.py b/src/lintool/lintool/__init__.py new file mode 100644 index 0000000..4d2e3a6 --- /dev/null +++ b/src/lintool/lintool/__init__.py @@ -0,0 +1,3 @@ +import ebuild +import changelog +import digest diff --git a/src/lintool/lintool/changelog.py b/src/lintool/lintool/changelog.py new file mode 100644 index 0000000..1dad779 --- /dev/null +++ b/src/lintool/lintool/changelog.py @@ -0,0 +1,105 @@ +# Copyright 2002 Gentoo Technologies, Inc +# Distributed under the terms of the GNU General Public License v2.0 +# Author Karl Trygve Kalleberg + +from test import Test, Regex +import re + +class TestHeaders(Test): + def __init__(self, formatter,options): + Test.__init__(self,formatter,options) + self.desc = "Testing for malformed headers" + self.re = [ (1, # append result of regex match + re.compile("^(# Copyright 1999-(2000|2001).*)"), + "Suspect copyright year"), + (1, + re.compile("^(# /home.*)"), + "Suspect path in header"), + (0, # don't append result of regex match + re.compile("^(# Author.*)"), + "Use of Author field in the header is deprecated. Put name in ChangeLog"), + (0, + re.compile("^(# Maintainer.*)"), + "Use of Maintainer field in the header is deprecated. Put name in ChangeLog"), + (1, + re.compile("^(# /space.*)"), + "Suspect path in header")] + + def checkLine(self, s, ln): + for i in self.re: + k = i[1].match(s) + if k and i[0]: + self.warnings.append(i[2] + ": " + k.groups()[0] ) + elif k and not i[0]: + self.warnings.append(i[2]) + + def report(self): + if len(self.warnings): + self.formatter.subwarn("Has illegal or suspect headers:") + for i in self.warnings: + self.formatter.subsub(i) + +class TestConstructPresence(Test): + + def __init__(self, formatter,options): + Test.__init__(self,formatter,options) + self.desc = "Testing for presence of required constructs" + self.required = [ ["# ChangeLog for " + Regex.category + "/" + Regex.PN, + None, + None, + "proper ChangeLog line" + ], + + ["\*" + Regex.P + " \([0-9]+ [A-Z][a-z][a-z] 2002\).*", + None, + None, + "proper release entry on the form *package-1.0.0 (01 Apr 2000)" + ], + + [" [0-9]+ [A-Z][a-z][a-z] 2002; .* <.*@.*> .*:", + None, + None, + "proper changelog entry" + ] + ] + + for i in self.required: + i[1] = re.compile("^(" + i[0] + ")") + + def checkLine(self, s, ln): + for i in self.required: + k = i[1].match(s) + if k: + i[2] = 1 + + def report(self): + for i in self.required: + if not i[2]: + self.formatter.suberr("Missing " + i[3]) + + def hasErrors(self): + for i in self.required: + if not i[2]: + return 1 + +class TestIndentation(Test): + + def __init__(self, formatter,options): + Test.__init__(self,formatter,options) + self.desc = "Testing for proper indentation" + self.re = re.compile("^( |[#*].|\n).*") + + def checkLine(self, s, ln): + k = self.re.match(s) + if not k: + self.errors.append(s) + + def report(self): + for i in self.errors: + print i.replace(' ','%') + +def getTests(formatter,options): + return [ TestHeaders(formatter,options), + TestConstructPresence(formatter,options), + TestIndentation(formatter,options) + ] diff --git a/src/lintool/lintool/digest.py b/src/lintool/lintool/digest.py new file mode 100644 index 0000000..5f174ae --- /dev/null +++ b/src/lintool/lintool/digest.py @@ -0,0 +1,28 @@ +# Copyright 2002 Gentoo Technologies, Inc +# Distributed under the terms of the GNU General Public License v2.0 +# Author Karl Trygve Kalleberg + +from test import Test +import re + +class TestSyntax(Test): + + def __init__(self,formatter,options): + Test.__init__(self,formatter,options) + self.desc = "Testing for correct syntax" + self.re = [ re.compile("^(MD5 [a-z0-9]+ [a-zA-Z0-9_+.-]+ [0-9]+)") ] + self.errors = [] + + def checkLine(self, s, ln): + for i in self.re: + k = i.match(s) + if not k: + self.errors.append("Invalid line in digest\n |" + s) + + def report(self): + for i in self.errors: + self.formatter.suberr(i) + + +def getTests(formatter,options): + return [ TestSyntax(formatter,options) ] diff --git a/src/lintool/lintool/ebuild.py b/src/lintool/lintool/ebuild.py new file mode 100644 index 0000000..c8df0a2 --- /dev/null +++ b/src/lintool/lintool/ebuild.py @@ -0,0 +1,349 @@ +# Copyright 2002 Gentoo Technologies, Inc +# Distributed under the terms of the GNU General Public License v2.0 +# Author Karl Trygve Kalleberg + +from test import Test +import re +import os +import os.path + +class TestSpaces(Test): + + def __init__(self, formatter, options): + Test.__init__(self, formatter, options) + self.desc = "Testing for correct formatting" + self.re_spaces = [ re.compile("^([ ][ ]*)([a-zA-Z\.].*)"), + re.compile("(.*)([ \t]+)\n") ] + self.re_backslash = re.compile("([^#]*\S)((\s\s+|\t))\\\\") + self.reset() + + def checkLine(self, s, ln): + for r in self.re_spaces: + k = r.match(s) + if k: + spcs = k.groups()[1] + rest = k.groups()[0] + self.spaces.append((ln, spcs.replace(" ", "%").replace("\t","%") + rest)) + else: + k = self.re_backslash.match(s) + if k: + head = k.group(1) + spcs = k.group(2) + tail = "\\" + self.backslashes.append((ln, head + len(spcs) * "%" + tail)) + + def hasErrors(self): + return 0 + def hasWarnings(self): + return len(self.spaces) + len(self.backslashes) + + def reset(self): + self.spaces = [] + self.backslashes = [] + + def report(self): + if len(self.spaces): + self.formatter.subwarn("Has illegal space characters (marked by %):") + for i in self.spaces: + self.formatter.subsub("[line " + str(i[0]) + "]:" + i[1]) + if len(self.backslashes): + self.formatter.subwarn("Has illegal white space (marked by %), only one space character allowed:") + for i in self.backslashes: + self.formatter.subsub("[line " + str(i[0]) + "]:" + i[1]) + +class TestHeaders(Test): + + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for malformed headers" + self.want = [ [ 0, # count + re.compile("^(# Copyright .*2002.*)"), + "Copyright statement" ], + [ 0, # count + re.compile("^(# " + "\$" + "Header:.*" + "\$)"), # Don't want CVS to fix this + "$" + "Header:" + "$" ], # Don't want CVS to fix this either + [ 0, # count + re.compile("^(# Distributed under the terms of the GNU General Public License.*)"), + "GPL license" ] ] + self.dontwant = [ (1, # append result of regex match + re.compile("^(# Copyright 1999-(2000|2001).*)"), + "Suspect copyright year"), + (1, + re.compile("^(# /home.*)"), + "Suspect path in header"), + (0, # don't append result of regex match + re.compile("^(# Author.*)"), + "Use of Author field in the header is deprecated. Put name in ChangeLog"), + (0, + re.compile("^(# Maintainer.*)"), + "Use of Maintainer field in the header is deprecated. Put name in ChangeLog"), + (1, + re.compile("^(# /space.*)"), + "Suspect path in header")] + + def reset(self): + for i in self.want: + i[0] = 0 + self.errors = [] + self.warnings = [] + + def hasErrors(self): + num_error = 0 + for i in self.want: + if i[0] == 0: + num_error += 1 + return num_error + + def checkLine(self, s, ln): + for i in self.dontwant: + k = i[1].match(s) + if k and i[0]: + self.warnings.append(i[2] + ": " + k.groups()[0] ) + elif k and not i[0]: + self.warnings.append(i[2]) + for i in self.want: + k = i[1].match(s) + if k: + i[0] += 1 + + def report(self): + illegal_headers = len(self.warnings) + for i in self.want: + if i[0] == 0: + illegal_headers += 1 + if illegal_headers: + self.formatter.subwarn("Has illegal or suspect headers:") + for i in self.warnings: + self.formatter.subwarn(i) + for i in self.want: + if i[0] == 0: + self.formatter.suberr("Missing " + i[2]) + +class TestTry(Test): + + def __init__(self,formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for occurence of deprecated try" + self.re = [ re.compile("^([ \t][ \t]*try.*)"), + re.compile("(.*=.* try .*)") ] + + def checkLine(self, s, ln): + for i in self.re: + k = i.match(s) + if k: + self.errors.append(k.groups()[0]) + + def report(self): + if len(self.errors): + self.formatter.suberr("Uses try, which is deprecated") + for i in self.errors: + self.formatter.subsub(i) + +class TestA(Test): + + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for superfluous A=${P}.tar.gz" + self.re = re.compile("(^A=.*)") + + def checkLine(self, s, ln): + k = self.re.match(s) + if k: + self.errors.append(k.groups()[0]) + + def report(self): + if len(self.errors): + self.formatter.suberr("Contains superfluous " + self.errors[0]) + +class TestDepend(Test): + + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for empty DEPEND" + self.re = re.compile("DEPEND=\"\"") + + def checkLine(self, s, ln): + k = self.re.match(s) + if k: + self.warnings.append("") + + def report(self): + if len(self.warnings): + self.formatter.subwarn("DEPEND is suspiciously empty") + +class TestHomepage(Test): + + def __init__(self, formatter,options): + Test.__init__(self,formatter,options) + self.desc = "Testing for empty HOMEPAGE" + self.re = re.compile("HOMEPAGE=\"\"") + + def checkLine(self, s, ln): + k = self.re.match(s) + if k: + self.warnings.append("") + + def report(self): + if len(self.warnings): + self.formatter.subwarn("Is HOMEPAGE really supposed to be empty ?") + +class TestDescription(Test): + + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for empty DESCRIPTION" + self.re = re.compile("DESCRIPTION=\"\"") + + def checkLine(self, s, ln): + k = self.re.match(s) + if k: + self.errors.append("") + + def report(self): + if len(self.errors): + self.formatter.suberr("DESCRIPTION must not be empty") + +class TestEnvVarPresence(Test): + + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for presence of env vars" + self.re = [] + self.found = [] + self.required = [ ("SRC_URI", "See 2.4"), + ("DESCRIPTION", "See policy, 2.8"), + ("HOMEPAGE", "See policy, 2.8"), + ("DEPEND", "See policy, 2.2"), + ("LICENSE", "See policy, 2.6"), + ("SLOT", "See policy, 2.5"), + ("KEYWORDS", "See policy, 2.3"), + ("IUSE", "See policy, 2.7") + ] + self.desired = [ ("RDEPEND", "Is RDEPEND == DEPEND ? See policy, 2.2") ] + + + for i in self.required: + self.re.append(re.compile("^(" + i[0] + ")=")) + for i in self.desired: + self.re.append(re.compile("^(" + i[0] + ")=")) + + def checkLine(self, s, ln): + for i in self.re: + k = i.match(s) + if k: + self.found.append(k.group(1)) + + def report(self): + for i in self.required: + if i[0] not in self.found: + self.formatter.suberr("Missing " + i[0] + ". " + i[1]) + for i in self.desired: + if i[0] not in self.found: + self.formatter.subwarn("Missing " + i[0] + ". " + i[1]) + + def hasWarnings(self): + for i in self.desired: + if i[0] not in self.found: + return 1 + + def hasErrors(self): + for i in self.required: + if i[0] not in self.found: + return 1 + +class TestLicense(Test): + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for proper LICENSE" + self.re = re.compile("^LICENSE=\"(.*)\"") + self.license_dirs = options['licenseDirs'] + self.licenses = self.loadLicenses() + + def loadLicenses(self): + licenses = [] + for i in self.license_dirs: + try: + candidates = os.listdir(i) + except: + self.formatter.line("!!! License directory '" + i + "' does not exist") + continue + for j in candidates: + if os.path.isfile(i + "/" + j): + licenses.append(j) + return licenses + + def checkLine(self, s, ln): + k = self.re.match(s) + if k: + print k.group(1) + licenses = k.group(1).split(" ") + for i in licenses: + if i not in self.licenses: + self.errors.append("License '" + i + "' not known") + + def report(self): + for i in self.errors: + self.formatter.suberr(i) + +class TestUseFlags(Test): + def __init__(self, formatter, options): + Test.__init__(self,formatter, options) + self.desc = "Testing for sane USE flag usage" + self.re = re.compile("[^#]*use ([a-z0-9\+]+).*") + self.useflags = self.loadUseFlags() + + def loadUseFlags(self): + ins = open("/usr/portage/profiles/use.desc") + rex = re.compile("^([a-z0-9]+)[ \t]+-.*"); + useflags = [] + for i in ins.readlines(): + k = rex.match(i) + if k: + useflags.append(k.group(1)) + return useflags + + def checkLine(self, s, ln): + k = self.re.match(s) + if k: + flag = k.group(1) + if flag not in self.useflags: + l = k.start(1) + # We want to try and figure pretty exactly if we've hit a real instnce + # of the use command or just some random mumbling inside a string + numApostrophes = 0 + numBackticks = 0 + numTicks = 0 + for i in xrange(l,0,-1): + if s[i] == '\"' and (i == 0 or (i > 0 and s[i-1] != '\\')): + numApostrophes += 1 + if s[i] == '\'' and (i == 0 or (i > 0 and s[i-1] != '\\')): + numTicks += 1 + if s[i] == '`' and (i == 0 or (i > 0 and s[i-1] != '\\')): + numBackticks += 1 + + if numApostrophes % 2 == 0: + foundError = 1 + elif numBackticks % 2 and numTicks % 2 == 0: + foundError = 1 + else: + foundError = 0 + + if foundError: + self.errors.append("Unknown USE flag '" + flag + "'") + + def report(self): + for i in self.errors: + self.formatter.suberr(i) + + +def getTests(formatter,options): + return [ TestSpaces(formatter,options), + TestHeaders(formatter,options), + TestTry(formatter,options), + TestA(formatter,options), + TestDepend(formatter,options), + TestHomepage(formatter,options), + TestDescription(formatter,options), + TestEnvVarPresence(formatter,options), + TestUseFlags(formatter,options), + TestLicense(formatter,options) ] diff --git a/src/lintool/lintool/test.py b/src/lintool/lintool/test.py new file mode 100644 index 0000000..0cc56ff --- /dev/null +++ b/src/lintool/lintool/test.py @@ -0,0 +1,30 @@ +# Copyright 2002 Gentoo Technologies, Inc +# Distributed under the terms of the GNU General Public License v2.0 +# Author Karl Trygve Kalleberg + +class Test: + def __init__(self, formatter,options=None): + self.formatter = formatter + self.errors = [] + self.warnings = [] + def reset(self): + self.errors = [] + self.warnings = [] + def hasWarnings(self): + return len(self.warnings) + def hasErrors(self): + return len(self.errors) + def getDesc(self): + return self.desc + def getStatus(self): + if self.hasErrors(): + return "failed" + else: + return "passed" + +class Regex: + PN = "[a-zA-Z_.-]+" + PV = "[a-z0-9A-Z_.-]+" + P = PN + "-" + PV + "(-r[0-9]+)?" + category = "[a-z0-9]+-[a-z0-9]+" + full = category + "/" + P -- cgit v1.2.3-65-gdbad