/tools/relic/relic
Python | 2491 lines | 2324 code | 38 blank | 129 comment | 84 complexity | 7af0a6d52a286b932e70663517416222 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD
Large files files are truncated, but you can click here to view the full file
- #!/usr/bin/python
- # ***** BEGIN LICENSE BLOCK *****
- # Version: MPL 1.1/GPL 2.0/LGPL 2.1
- #
- # The contents of this file are subject to the Mozilla Public License Version
- # 1.1 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- # http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS IS" basis,
- # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- # for the specific language governing rights and limitations under the
- # License.
- #
- # The Original Code is the relic relicensing tool.
- #
- # The Initial Developer of the Original Code is
- # Trent Mick <TrentM@ActiveState.com>.
- # Portions created by the Initial Developer are Copyright (C) 2003-2005
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- # Gervase Markham <gerv@gerv.net>
- # Patrick Fey <bugzilla@nachtarbeiter.net>
- #
- # Alternatively, the contents of this file may be used under the terms of
- # either the GNU General Public License Version 2 or later (the "GPL"), or
- # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- # in which case the provisions of the GPL or the LGPL are applicable instead
- # of those above. If you wish to allow use of your version of this file only
- # under the terms of either the GPL or the LGPL, and not to allow others to
- # use your version of this file under the terms of the MPL, indicate your
- # decision by deleting the provisions above and replace them with the notice
- # and other provisions required by the GPL or the LGPL. If you do not delete
- # the provisions above, a recipient may use your version of this file under
- # the terms of any one of the MPL, the GPL or the LGPL.
- #
- # ***** END LICENSE BLOCK *****
- # Adapted from the 'lick' and 'ripl' Python scripts. (See:
- # <http://bugzilla.mozilla.org/show_bug.cgi?id=98089>)
- """
- relic - RE-LICense a given file, set of files, or directory of files
- from the Mozilla source tree
- Usage:
- relic [options...] [files...]
- relic [options...] < files...
- Options to Select Mode (use one):
- <none> List the licenses in each file.
- -s, --statistics Should a summary table of licenses in each file.
- The -x, --extended option may be added to show
- some additional detail to the stats.
- -r, --relicense Modify the given files to include to
- appropriate Mozilla license, where
- "appropriate" is either the NPL/GPL/LPGL
- tri-license if was already under the NPL or
- the MPL/LPGL/GPL license in all other cases.
- -R, --force-relicense
- Relicenses files (as -r|--relicense), but
- does NOT skip files that already appear to
- have a complete license.
- -A, --add Add a license to files that do not appear to
- have one.
- -I, --initial-developers
- Display initial developer for each file.
- General Options:
- -h, --help dump this help and exit
- -V, --version dump this script's version and exit
- -v, --verbose verbose output
- -d, --debug more verbose output
- -f, --force Continue processing after an error. (Errors
- are summarized at end.)
- -q, --quick Quick scanning. Use only basic license checks
- (only use in report mode).
- -M, --MPL Replace NPL licenses with MPL ones.
- -a, --all Check all files (only skip CVS directories).
- --dry-run Go through motions but don't actually change
- any files.
- --backup Make backups of changes files with
- relicensing. Backup filenames are the
- original filename suffixed with a ~# where
- "#" is the lowest number to avoid a file
- conflict.
- -o <orig_code_is> Provide fallback value for the "Original
- Code is" block.
- -D <orig_code_date> Provide fallback value for the date
- that is part of the "Original Code is" block.
- -i <initial_dev> Provide fallback value for the "Initial
- Developer of the Original Code is" block.
- -y <year> Provide fallback value for "Initial
- Developer" copyright year.
- --defaults Use the following default fallback values:
- original_code_is: "mozilla.org Code"
- initial_copyright_date: "2001"
- initial_developer: "Netscape Communications
- Corporation"
- Note: the "Original Code" date is generally
- not required, so a default is not included
- here.
- Examples:
- # List license in files under mozilla/js/src.
- relic mozilla/js/src # list licenses in files
- relic -s mozilla/js/src # show summary stats on licenses
- relic -r mozilla/js/src # re-license files
- """
- import os
- import sys
- import re
- import getopt
- import pprint
- import shutil
- class RelicError(Exception):
- pass
- #---- setup logging
- try:
- # This package will be std in Python 2.3, but many Python 2.2
- # installation will not have it.
- import logging
- logging.basicConfig()
- except ImportError:
- # Local fallback logging module.
- try:
- import _logging as logging
- except ImportError:
- sys.stderr.write("Your Python installation does not have the logging "
- "package, nor could the fallback _logging module be "
- "found. One of the two is required to run this "
- "script.\n\n")
- raise
- log = logging.getLogger("relic")
- #---- globals
- _version_ = (0, 7, 2)
- # When processing files, 'relic' skips files and directories according
- # to these settings. Note: files identified in .cvsignore files are also
- # skipped.
- _g_skip_exts = [".mdp", ".order", ".dsp", ".dsw", ".uf"]
- _g_skip_file_basenames = [
- # Used by CVS (and this script)
- ".cvsignore",
-
- # GPL with autoconf exception
- "config.guess",
- "config.sub",
- # Auto-generated from other files
- "configure",
- # license and readme files
- "license",
- "readme",
- "copyright",
- "LICENSE-MPL",
- "MPL-1.1.txt",
- ]
- _g_skip_files = [
- # TODO: update with MPL block - or CVS remove (check history)
- "tools/wizards/templates/licenses/MPL/lic.mak",
- "tools/wizards/templates/licenses/MPL/lic.pl",
- ###########################################################################
- # Everything in _g_skip_files below this line needs no further work.
- ###########################################################################
-
- # Files containing copies of licence text which confuses the script
- "LICENSE",
- "js2/COPYING",
- "security/svrcore/LICENSE",
- "extensions/xmlterm/doc/MPL",
- "gfx/cairo/cairo/COPYING-LGPL-2.1",
- "gfx/cairo/cairo/COPYING-MPL-1.1",
-
- # Files containing global licensing information
- "xpfe/global/resources/content/license.html",
- "toolkit/content/license.html",
-
- # Ben Bucksch - files are tri-licensed with an extra clause.
- "netwerk/streamconv/converters/mozTXTToHTMLConv.cpp",
- "netwerk/streamconv/converters/mozTXTToHTMLConv.h",
- "netwerk/streamconv/public/mozITXTToHTMLConv.idl",
-
- # GPLed build tools
- "config/preprocessor.pl",
- "intl/uconv/tools/parse-mozilla-encoding-table.pl",
- "intl/uconv/tools/gen-big5hkscs-2001-mozilla.pl",
- "js2/missing",
-
- # Files which the script doesn't handle well. All have been relicensed
- # manually.
- "xpinstall/wizard/windows/builder/readme.txt",
- "xpfe/bootstrap/icons/windows/readme.txt",
- "embedding/qa/testembed/README.TXT",
- "security/nss/lib/freebl/ecl/README.FP",
- "nsprpub/pkg/linux/sun-nspr.spec",
- "security/nss/pkg/linux/sun-nss.spec",
- "security/jss/pkg/linux/sun-jss.spec",
- "security/nss/lib/freebl/mpi/utils/README",
- "security/nss/lib/freebl/ecl/README",
- "security/nss/lib/freebl/mpi/README",
- "lib/mac/UserInterface/Tables/TableClasses.doc",
- "parser/htmlparser/tests/html/bug23680.html",
- "security/nss/lib/freebl/mpi/montmulfv9.s",
- "tools/performance/pageload/base/lxr.mozilla.org/index.html",
- "testing/performance/win32/page_load_test/" +\
- "base/lxr.mozilla.org/index.html",
- "testing/performance/win32/page_load_test/" +\
- "base/lxr.mozilla.org/20001028.html.orig",
-
- # Not sure what to do with this...
- "gfx/cairo/stdint.diff",
-
- # GPL with autoconf exception (same license as files distributed with)
- "build/autoconf/codeset.m4",
- "toolkit/airbag/airbag/autotools/depcomp",
- "toolkit/airbag/airbag/autotools/missing",
- "toolkit/airbag/airbag/autotools/ltmain.sh",
- "js/tamarin/pcre/ltmain.sh",
- "security/svrcore/compile",
- "security/svrcore/ltmain.sh",
- "security/svrcore/missing",
- "security/svrcore/depcomp",
- "security/svrcore/aclocal.m4",
-
- # Public domain or equivalent
- "nsprpub/config/nspr.m4",
- "toolkit/airbag/airbag/aclocal.m4",
- "security/nss/lib/freebl/mpi/mp_comba_amd64_sun.s",
-
- # GSSAPI has BSD-like licence requiring some attribution
- "extensions/auth/gssapi.h",
- # This script
- "tools/relic/relic",
- ]
- _g_skip_dir_basenames = [
- "CVS",
- ]
- _g_skip_dir_basenames_cvs_only = [
- "CVS",
- ]
- # Complete path from mozilla dir to a dir to skip.
- _g_skip_dirs = [
- # Test files for this script, which cause it to crash!
- "tools/relic/test",
-
- # License template files (TODO: this directory may disappear)
- "tools/wizards/templates/licenses",
-
- # As per the "New Original Source Files" section of:
- # http://www.mozilla.org/MPL/license-policy.html
- # with obsolete or now-relicensed directories removed
- "apache", # Obsolete mod_gzip code
- "cck", # mkaply's baby; not core code anyway.
- "dbm",
- "js/rhino", # Currently MPL/GPL - may end up BSD
- "webtools", # Various MPLed webtools
-
- # These could be done, but no-one's clamouring for it, and it's a hassle
- # sorting it all out, so let sleeping dogs lie.
- "msgsdk",
- "java",
- "privacy",
- # These have their own BSD-like license
- "media/libjpeg",
-
- # The following are not supposed to be relicensed, but they do have a
- # few files in we care about (like makefiles)
- "media/libpng",
- "modules/zlib",
- "gc/boehm",
- "other-licenses",
-
- # Copy of GPLed tool
- "tools/buildbot",
-
- # Other directories we want to exclude
- "embedding/tests", # Agreed as BSD
- "calendar/libical", # LGPL/MPL
- "gfx/cairo/cairo/src", # LGPL/MPL
- ]
- _g_basename_to_comment_info = {
- "configure": (["dnl"], ),
- "Makefile": (["#"], ),
- "makefile": (["#"], ),
- "nfspwd": (["#"], ),
- "typemap": (["#"], ),
- "xmplflt.conf": (["#"], ),
- "ldapfriendly": (["#"], ),
- "ldaptemplates.conf": (["#"], ),
- "ldapsearchprefs.conf": (["#"], ),
- "ldapfilter.conf": (["#"], ),
- "README.configure": (["#"], ),
- "Options.txt": (["#"], ),
- "fdsetsize.txt": (["#"], ),
- "prototype": (["#"], ),
- "prototype_i386": (["#"], ),
- "prototype3_i386": (["#"], ),
- "prototype_com": (["#"], ),
- "prototype3_com": (["#"], ),
- "prototype_sparc": (["#"], ),
- "prototype3_sparc": (["#"], ),
- "nglayout.mac": (["#"], ),
- "pkgdepend": (["#"], ),
- "Maketests": (["#"], ),
- "depend": (["#"], ),
- "csh-aliases": (["#"], ),
- "csh-env": (["#"], ),
- ".cshrc": (["#"], ),
- "MANIFEST": (["#"], ),
- "mozconfig": (["#"], ),
- "makecommon": (["#"], ),
- "bld_awk_pkginfo": (["#"], ),
- "prototype_i86pc": (["#"], ),
- "pkgdepend_5_6": (["#"], ),
- "awk_pkginfo-i386": (["#"], ),
- "awk_pkginfo-sparc": (["#"], ),
- "pkgdepend_64bit": (["#"], ),
- "WIN32": (["#"], ),
- "WIN16": (["#"], ),
- "Makefile.linux": (["#"], ),
- "README": ([""], ["#"]),
- "copyright": ([""], ),
- "xptcstubs_asm_ppc_darwin.s.m4": (["/*", "*", "*/"], ),
- "xptcstubs_asm_mips.s.m4": (["/*", "*", "*/"], ),
- "nsIDocCharsetTest.txt": (["<!--", "-", "-->"], ),
- "nsIFontListTest.txt": (["<!--", "-", "-->"], ),
- "ComponentListTest.txt": (["<!--", "-", "-->"], ),
- "nsIWebBrowserPersistTest1.txt": (["<!--", "-", "-->"], ),
- "nsIWebBrowserPersistTest2.txt": (["<!--", "-", "-->"], ),
- "nsIWebBrowserPersistTest3.txt": (["<!--", "-", "-->"], ),
- "plugins.txt": (["<!--", "-", "-->"], ),
- "NsISHistoryTestCase1.txt": (["<!--", "-", "-->"], ),
- "EmbedSmokeTest.txt": (["<!--", "-", "-->"], ),
- "lineterm_LICENSE": (["/*", "*", "*/"], ),
- "XMLterm_LICENSE": (["/*", "*", "*/"], ),
- "BrowserView.cpp.mod": (["/*", "*", "*/"], ),
- "header_template": (["/*", "*", "*/"], ),
- "cpp_template": (["/*", "*", "*/"], ),
- "abcFormat470.txt": (["//"], ),
- "opcodes.tbl": (["//"], ),
- }
- _g_ext_to_comment_info = {
- ".txt": (["##", "#", ], ["#"]),
- ".TXT": (["##", "#", ]),
- ".doc": (["", ]),
- ".build": (["", ]),
- ".1st": (["", ]),
- ".lsm": (["", ]),
- ".FP": (["", ]),
- ".spec": (["", ]),
- ".CPP": (["/*", "*", "*/"], ),
- ".cpp": (["/*", "*", "*/"], ),
- ".H": (["/*", "*", "*/"], ),
- ".h": (["/*", "*", "*/"], ),
- ".hxx": (["/*", "*", "*/"], ),
- ".c": (["/*", "*", "*/"], ),
- ".css": (["/*", "*", "*/"], ['#']),
- ".js": (["/*", "*", "*/"], ['#']),
- ".idl": (["/*", "*", "*/"], ),
- ".ut": (["/*", "*", "*/"], ),
- ".rc": (["/*", "*", "*/"], ),
- ".rc2": (["/*", "*", "*/"], ),
- ".RC": (["/*", "*", "*/"], ),
- ".Prefix": (["/*", "*", "*/"], ),
- ".prefix": (["/*", "*", "*/"], ),
- ".cfg": (["/*", "*", "*/"], ["#"]),
- ".cp": (["/*", "*", "*/"], ),
- ".cs": (["/*", "*", "*/"], ),
- ".java": (["/*", "*", "*/"], ),
- ".jst": (["/*", "*", "*/"], ),
- ".tbl": (["/*", "*", "*/"], ),
- ".tab": (["/*", "*", "*/"], ),
- ".cc": (["/*", "*", "*/"], ),
- ".msg": (["/*", "*", "*/"], ),
- ".y": (["/*", "*", "*/"], ),
- ".r": (["/*", "*", "*/"], ),
- ".mm": (["/*", "*", "*/"], ),
- ".x-ccmap":(["/*", "*", "*/"], ),
- ".ccmap": (["/*", "*", "*/"], ),
- ".sql": (["/*", "*", "*/"], ),
- ".pch++": (["/*", "*", "*/"], ),
- ".xpm": (["/*", "*", "*/"], ),
- ".uih": (["/*", "*", "*/"], ),
- ".uil": (["/*", "*", "*/"], ),
- ".ccmap": (["/*", "*", "*/"], ),
- ".map": (["/*", "*", "*/"], ),
- ".win98": (["/*", "*", "*/"], ),
- ".php": (["/*", "*", "*/"], ),
- ".m": (["/*", "*", "*/"], ),
- ".jnot": (["/*", "*", "*/"], ),
- ".l": (["/*", "*", "*/"], ),
- ".htp": (["/*", "*", "*/"], ),
- ".xs": (["/*", "*", "*/"], ),
- ".as": (["/*", "*", "*/"], ),
- ".api": (["/*", "*", "*/"], ['#']),
- ".applescript": (["(*", "*", "*)"], ["--"], ["#"]),
- ".html": (["<!--", "-", "-->"], ["#"]),
- ".xml": (["<!--", "-", "-->"], ["#"]),
- ".xbl": (["<!--", "-", "-->"], ["#"]),
- ".xsl": (["<!--", "-", "-->"], ),
- ".xul": (["<!--", "-", "-->"], ["#"]),
- ".dtd": (["<!--", "-", "-->"], ["#"]),
- ".rdf": (["<!--", "-", "-->"], ["#"]),
- ".htm": (["<!--", "-", "-->"], ),
- ".out": (["<!--", "-", "-->"], ),
- ".resx": (["<!--", "-", "-->"], ),
- ".bl": (["<!--", "-", "-->"], ),
- ".xif": (["<!--", "-", "-->"], ),
- ".xhtml":(["<!--", "-", "-->"], ["#"]),
- ".inc": (["<!--", "-", "-->"],
- ["#"],
- ["@!"],
- ["/*", "*", "*/"]),
- ".properties": (["#"], ),
- ".win": (["#"], ),
- ".dsp": (["#"], ),
- ".exp": (["#"], ),
- ".mk": (["#"], ),
- ".mn": (["#"], ),
- ".mak": (["#"], ),
- ".MAK": (["#"], ),
- ".perl": (["#"], ),
- ".pl": (["#"], ),
- ".PL": (["#"], ),
- ".sh": (["#"], ),
- ".dsw": (["#"], ),
- ".cgi": (["#"], ),
- ".pm": (["#"], ),
- ".pod": (["#"], ),
- ".src": (["#"], ),
- ".csh": (["#"], ),
- ".DLLs": (["#"], ),
- ".ksh": (["#"], ),
- ".toc": (["#"], ),
- ".am": (["#"], ),
- ".df": (["#"], ),
- ".client": (["#"], ),
- ".ref": (["#"], ), # all of them "Makefile.ref"
- ".ldif": (["#"], ),
- ".ex": (["#"], ),
- ".reg": (["#"], ),
- ".py": (["#"], ),
- ".adb": (["#"], ),
- ".dtksh": (["#"], ),
- ".pkg": (["#"], ),
- ".et": (["#"], ),
- ".stub": (["#"], ),
- ".nss": (["#"], ),
- ".os2": (["#"], ),
- ".Solaris": (["#"], ),
- ".rep": (["#"], ),
- ".NSS": (["#"], ),
- ".server": (["#"], ),
- ".awk": (["#"], ),
- ".targ": (["#"], ),
- ".gnuplot": (["#"], ),
- ".bash": (["#"], ),
- ".tmpl": (["#"], ),
- ".com": (["#"], ),
- ".dat": (["#"], ),
- ".rpm": (["#"], ),
- ".nsi": (["#"], ),
- ".nsh": (["#"], ),
- ".template": (["#"], ),
- ".ldkd": (["#"], ),
- ".ldku": (["#"], ),
- ".arm": (["#"], ),
- ".tdf": ([";"], ),
- ".def": ([";+#"], [";"]),
- ".DEF": ([";+#"], [";"]),
- ".ini": ([";"], ),
- ".it": ([";"], ),
- ".lisp": ([";;;"], ),
- ".cmd": (["rem"], ["REM"]),
- ".bat": (["rem"], ["REM"]),
- ".tex": (["%"], ),
- ".texi": (["%"], ),
- ".m4": (["dnl"], ),
- ".asm": ([";"], ),
- ".vbs": (["'"], ),
- ".il": (["!"], ),
- ".ad": (["!"], ),
- ".script": (["(*", " *", "*)"], ),
- ".3x": (['.\\"'], ),
-
- # What a mess...
- ".s": (["#"], ["//"], ["/*", "*", "*/"], ["!"], [";"], ["/"]),
- }
- _g_shebang_pattern_to_comment_info = [
- (re.compile(ur'\A#!.*/bin/(ba)?sh.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*perl.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*php.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*python.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*ruby.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*tclsh.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*wish.*$', re.IGNORECASE), (["#"], )),
- (re.compile(ur'\A#!.*expect.*$', re.IGNORECASE), (["#"], )),
- ]
- _g_trilicense_parts = {
- "mpl": """\
- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
- """,
- "npl": """\
- ***** BEGIN LICENSE BLOCK *****
- Version: NPL 1.1/GPL 2.0/LGPL 2.1
- The contents of this file are subject to the Netscape Public License
- Version 1.1 (the "License"); you may not use this file except in
- compliance with the License. You may obtain a copy of the License at
- http://www.mozilla.org/NPL/
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
- """,
- "original_code_is": """\
- The Original Code is %(original_code_is)s.
- """,
- "original_code_is_with_date": """\
- The Original Code is %(original_code_is)s, released
- %(original_code_date)s.
- """,
- "initial_developer": """\
- The Initial Developer of the Original Code is
- %(initial_developer)s.
- Portions created by the Initial Developer are Copyright (C) %(initial_copyright_date)s
- the Initial Developer. All Rights Reserved.
- """,
- "contributors": """\
- Contributor(s):
- %s
- """,
- "gpl for mpl": """\
- Alternatively, the contents of this file may be used under the terms of
- the GNU General Public License Version 2 or later (the "GPL"), in which
- case the provisions of the GPL are applicable instead of those above. If
- you wish to allow use of your version of this file only under the terms of
- the GPL and not to allow others to use your version of this file under the
- MPL, indicate your decision by deleting the provisions above and replacing
- them with the notice and other provisions required by the GPL. If you do
- not delete the provisions above, a recipient may use your version of this
- file under either the MPL or the GPL.
- ***** END LICENSE BLOCK *****""",
- "gpl for npl": """\
- Alternatively, the contents of this file may be used under the terms of
- the GNU General Public License Version 2 or later (the "GPL"), in which
- case the provisions of the GPL are applicable instead of those above. If
- you wish to allow use of your version of this file only under the terms of
- the GPL and not to allow others to use your version of this file under the
- NPL, indicate your decision by deleting the provisions above and replacing
- them with the notice and other provisions required by the GPL. If you do
- not delete the provisions above, a recipient may use your version of this
- file under either the NPL or the GPL.
- ***** END LICENSE BLOCK *****""",
- "gpl/lgpl for mpl": """\
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
- ***** END LICENSE BLOCK *****""",
- "gpl/lgpl for npl": """\
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the NPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the NPL, the GPL or the LGPL.
- ***** END LICENSE BLOCK *****""",
- }
- _g_dry_run = 0 # iff true, don't modify any files
- _g_force = 0
- _g_check_all = 0
- #---- internal support routines
- def _is_binary(filename):
- """Return true iff the given filename is binary.
- Raises an EnvironmentError if the file does not exist or cannot be
- accessed.
- """
- fin = open(filename, 'rb')
- try:
- CHUNKSIZE = 1024
- while 1:
- chunk = fin.read(CHUNKSIZE)
- if '\0' in chunk: # found null byte
- return 1
- if len(chunk) < CHUNKSIZE:
- break # done
- finally:
- fin.close()
- return 0
- _g_cvsignore_cache = {} # optimization: keep a cache of .cvsignore content
- def _should_skip_according_to_cvsignore(path):
- dirname, basename = os.path.split(path)
- cvsignore = os.path.join(dirname, ".cvsignore")
- if not os.path.exists(cvsignore):
- return 0
- elif cvsignore not in _g_cvsignore_cache:
- fin = open(cvsignore, 'r')
- to_ignore = []
- try:
- for f in fin:
- if f[-1] == "\n": f = f[:-1] # chomp
- if not f: continue # skip empty lines
- to_ignore.append(f)
- finally:
- fin.close()
- _g_cvsignore_cache[cvsignore] = to_ignore
- # At this point .cvsignore exists and its contents are in the cache.
- to_ignore = _g_cvsignore_cache[cvsignore]
- if basename in to_ignore:
- return 1
- else:
- return 0
- _g_backup_pattern = re.compile("~\d+$")
- def _should_skip_file(path):
- log.debug("_should_skip_file(path='%s')", path)
- if _g_check_all:
- return 0
- ext = os.path.splitext(path)[1]
- if ext in _g_skip_exts:
- log.info("Skipping '%s' (according to '_g_skip_exts').", path)
- return 1
- xpath = '/'.join(path.split(os.sep)) # use same sep as in _g_skip_files
- for sf in _g_skip_files:
- if xpath.endswith(sf):
- log.info("Skipping '%s' (according to '_g_skip_files').", path)
- return 1
- if os.path.basename(path) in _g_skip_file_basenames:
- log.info("Skipping '%s' (according to '_g_skip_file_basenames').", path)
- return 1
- if _should_skip_according_to_cvsignore(path):
- log.info("Skipping '%s' (according to .cvsignore).", path)
- return 1
- if _g_backup_pattern.search(path):
- log.info("Skipping '%s' (looks like backup file).", path)
- return 1
- return 0
- def _should_skip_dir(path):
- log.debug("_should_skip_dir(path='%s')", path)
- if _g_check_all:
- if os.path.basename(path) in _g_skip_dir_basenames_cvs_only:
- return 1
- return 0
- if os.path.basename(path) in _g_skip_dir_basenames:
- log.info("Skipping '%s' (according to _g_skip_dir_basenames).", path)
- return 1
- xpath = '/'.join(path.split(os.sep)) # use same sep as in _g_skip_dirs
- # These could do with being a proper path canonicalisation function...
- if xpath[-1] == '/': xpath = xpath[:-1] # treat "calendar/" the same as "calendar"
- if xpath[0:2] == './': xpath = xpath[2:] # treat "./calendar" the same as "calendar"
- for sd in _g_skip_dirs:
- # Changed by gerv to make skip_dirs require whole path
- if xpath == sd:
- log.info("Skipping '%s' (according to _g_skip_dirs).", path)
- return 1
- if _should_skip_according_to_cvsignore(path):
- log.info("Skipping '%s' (according to .cvsignore).", path)
- return 1
- return 0
- def _get_license_info(filename, show_initial=0, quick=0):
- """Return license block information for the given file.
- "filename" is the path to the file to scan.
- "show_initial" is a boolean that indicates if initial developer info
- should be displayed.
- "quick" is a boolean that can be set for a quick scan. In this
- case, only the "parts" field of the return dictionary will
- be filled out.
-
- Returns a dictionary adequately describing the license block in the
- given file for the purpose of determining whether to patch the
- license block and how. Returns a dictionary of the following form:
- {"parts": <list of zero or more of "mpl", "npl", "gpl", "lgpl",
- "unknown", "block_begin", "block_end" in the
- order in which they were found>,
- # if necessary, the following keys are included as well
- "begin_line": <(0-based) index at which license block starts>,
- "end_line": <(0-based) index at which license block ends>,
- "first_prefix": <prefix to use for new license block first line>,
- "subsequent_prefix": <prefix to use for subsequent lines>,
- "last_suffix": <suffix to use for last line>,
- # The following fields are correspond to the file specific
- # portions of the license template as described here:
- # http://www.mozilla.org/MPL/relicensing-faq.html#new-license
- # If the associated block is not found, then the value is None.
- "original_code_is": ...,
- "original_code_date": ...,
- "initial_developer": ...,
- "initial_copyright_date": ...,
- "contributors": ...,
- }
- precondition: should not be called on binary files
- """
- lic_info = {
- "parts": [],
- }
- fin = open(filename, 'r')
- try:
- content = fin.read()
- finally:
- fin.close()
-
- # Help me find filena
- log.info("Next file is: %s", filename)
- # do quick search to see if any of the desired licenses is in here
- # - if it looks like all the parts are there, good, done
- # - if some but not all parts, continue
- parts_pattern = re.compile("""(
- (?P<block_begin>\*\*\*\*\*\ BEGIN\ LICENSE\ BLOCK\ \*\*\*\*\*)
- | (?P<mpl>The\ contents\ of\ this\ file\ are\ subject\ to\ the\ Mozilla)
- | (?P<npl>The\ contents\ of\ this\ file\ are\ subject\ to\ the\ Netscape)
- | (?P<gpl>GNU\ (General\ )?Public\ License)
- | (?P<lgpl>(Library|Lesser)\ General\ Public\ License)
- | (?P<block_end>\*\*\*\*\*\ END\ LICENSE\ BLOCK\ \*\*\*\*\*)
- )""",
- re.VERBOSE)
- parts = [] # found license parts in this file
- start = 0
- blocks = 0
- while 1:
- match = parts_pattern.search(content, start)
- if match:
- # Skip this block, if the last license block is more than 10 lines
- # away (file is probably used for autogeneration of files then).
- if blocks == 1 and (match.start()-start) > 10:
- break
- else:
- parts = match.groupdict()
- for part in parts:
- if parts[part]:
- lic_info["parts"].append(part)
- log.info("%s license/delimeter found", part)
- start = match.end()
- if part == "block_end":
- blocks = blocks + 1
- else:
- blocks = 0
- break
- else:
- raise RelicError("unexpected license part: %r" % parts)
- else:
- break
- # no license block at all
- if not parts:
- # - if not, check to see if License or Copyright shows up in the
- # file; if so, then error out; if not, skip out
- any_lic_pattern = re.compile("(Copyright|Licen[sc]e)", re.IGNORECASE)
- match = any_lic_pattern.search(content)
- if match:
- lic_info["parts"].append("unknown")
- log.info("unknown license found: %r",
- content[max(match.start()-20,0):match.end()+20])
- else:
- log.info("no license found")
- return lic_info
- # license block with non-tri-license version headers
- elif lic_info["parts"] == ["block_begin", "block_end"]:
- lic_info["parts"].append("unknown")
- log.info("unknown license found (license block with non-tri-license)")
- return lic_info
- # license block with tri-license version headers
- elif (lic_info["parts"] == ["block_begin", "mpl", "gpl", "lgpl", "block_end"] or
- lic_info["parts"] == ["block_begin", "npl", "gpl", "lgpl", "block_end"]):
- log.info("license looks good, no changes necessary")
- if quick:
- return lic_info
- # Otherwise, the license needs to be fixed, so gather more detailed
- # information. Here is the algorithm we will use:
- # - find first license line
- # - find the end of this comment block (assumption: from the first
- # license line to the end of the comment block is the full
- # license block)
- # This is a bad assumption in two cases and steps have been taken
- # to try to deal with those cases:
- # - There could be a trailing part bit of comment that is
- # NOT part of the license but is part of the same comment
- # block. A common example are the:
- # This Original Code has been modified by IBM...
- # files (about 130 of them in the moz tree).
- # (c.f. test_relicense_ibm_copyright_suffix.c)
- # - Some files have split up the license paragraphs into
- # multiple comment blocks, e.g.
- # "mozilla/build/unix/abs2rel.pl":
- # # The contents of this file are subject to the
- # # ...
- # # the License at http://www.mozilla.org/MPL/
- #
- # # The Initial Developer of the Original Code
- # # ...
- # # Rights Reserved.
- # (c.f. test_relicense_separated_license_comment_blocks.pl)
- # - these are the lines to replace
- # - gather embedded lic data
- # - use second line to determine line prefix
- # ? Should we only allow processing of unknown-delimiter-files with
- # an option?
- # Get comment delimiter info for this file.
- comment_delim_sets = _get_comment_delim_sets(filename)
- # - find first license line (and determine which set of comment
- # delimiters are in use)
- lines = content.splitlines()
- for comment_delims in comment_delim_sets:
- if len(comment_delims) == 3:
- # Note: allow for whitespace before continuation character
- prefix_pattern = "%s|\s*%s|" % (re.escape(comment_delims[0]),
- re.escape(comment_delims[1]))
- suffix_pattern = "%s" % re.escape(comment_delims[2])
- elif len(comment_delims) == 2:
- prefix_pattern = "%s|" % re.escape(comment_delims[0])
- suffix_pattern = "%s" % re.escape(comment_delims[1])
- elif len(comment_delims) == 1:
- prefix_pattern = re.escape(comment_delims[-1])
- suffix_pattern = ""
- else: # len(comment_delims) == 0
- prefix_pattern = ""
- suffix_pattern = ""
- lic_begin_pattern = re.compile("""
- ^(?P<prefix>%s)
- (?P<space>\s*)
- (\*+\ BEGIN\ LICENSE\ BLOCK\ \*+
- |\-+\ BEGIN\ LICENSE\ BLOCK\ \-+
- | Version:\ MPL\ \d+\.\d+/GPL\ \d+\.\d+/LGPL\ \d+\.\d+
- | The\ contents\ of\ this\ file\ are\ subject\ to\ the\ Mozilla[\w ]*
- | The\ contents\ of\ this\ file\ are\ subject\ to\ the\ Netscape[\w ]*
- | Alternatively,\ the\ contents\ of\ this\ file\ may\ be\ used\ under\ the[\w ]*)
- (?P<suffix>%s|)\s*?$
- """ % (prefix_pattern, suffix_pattern), re.VERBOSE)
- for i in range(len(lines)):
- match = lic_begin_pattern.search(lines[i])
- if match:
- beginline = {
- "content": lines[i],
- "linenum": i,
- "prefix": match.group("prefix"),
- "space": match.group("space"),
- "suffix": match.group("suffix")
- }
- # Optimization: If the line before the "beginline" is simply
- # a block comment open the include that line in parsed out
- # license block. E.g.,
- # <!--
- # - ***** BEGIN LICENSE BLOCK *****
- # ...
- if (len(comment_delims) > 1 # only for block comments
- and beginline["prefix"] != comment_delims[0]
- and i-1 >= 0
- and lines[i-1].strip() == comment_delims[0]):
- beginline["linenum"] -= 1
- beginline["prefix"] = comment_delims[0]
- break
- if match: break
- else:
- raise RelicError("couldn't find start line with this pattern (even "
- "though it looks like there is a license block in "
- "%s): %s" % (filename, lic_begin_pattern.pattern))
- log.info("comment delimiters: %s", comment_delims)
- log.debug("beginline dict: %s", beginline)
- lic_info["comment_delims"] = comment_delims
- lic_info["begin_line"] = beginline["linenum"]
- lic_info["first_prefix"] = beginline["prefix"]
- log.info("prefix for first line: '%s'", beginline["prefix"])
- # - get second license line
- lic_middle_pattern = re.compile("""
- ^(?P<prefix>%s|)
- (?P<space>\s*)
- (?P<content>.*)
- (?P<suffix>%s|)\s*?$
- """ % (prefix_pattern, suffix_pattern),
- re.VERBOSE)
- # skip empty lines which might result in bogus scanning later, e.g.:
- # mozilla/layout/html/tests/table/marvin/x_thead_align_center.xml
- second_linenum = beginline["linenum"]+1
- while second_linenum < len(lines):
- if lines[second_linenum].strip():
- break
- log.debug("skip blank 'second' line: %d", second_linenum)
- second_linenum +=1
- else:
- raise RelicError("all lines after the first license block line (%d) "
- "were empty" % (beginline["linenum"]+1))
- match = lic_middle_pattern.search(lines[second_linenum])
- if match:
- secondline = {
- "content": lines[second_linenum],
- "linenum": second_linenum,
- "prefix": match.group("prefix"),
- "space": match.group("space"),
- "suffix": match.group("suffix")
- }
- else:
- raise RelicError("didn't find second line with pattern: %s"
- % lic_middle_pattern.pattern)
- log.debug("secondline dict: %s", secondline)
- lic_info["subsequent_prefix"] = secondline["prefix"]
- log.info("prefix for subsequent lines: '%s'", secondline["prefix"])
- # - find block comment end
- orig_code_modified_pattern = re.compile("This Original Code has been "
- "modified", re.I)
- non_lic_content_in_same_comment_block = 0
- if len(comment_delims) == 1:
- # line-style comments: The comment block "end" is defined as the
- # last line before a line NOT using the block comment delimiter.
- #XXX:BUG: This is not good enough for:
- # test/inputs/separated_license_comment_blocks.pl
- if comment_delims[0] == "":
- raise RelicError(
- "Don't know how to find the end of a line-style comment "
- "block when the delimiter is the empty string. (Basically "
- "this script cannot handle this type of file.)")
- for i in range(beginline["linenum"]+1, len(lines)):
- if not lines[i].startswith(comment_delims[0]):
- endlinenum = i-1
- break
- elif lines[i].find("END LICENSE BLOCK") != -1:
- endlinenum = i
- break
- # As per "test_relicense_trailing_orig_code_modified.pl", a
- # paragraph starting with:
- # This Original Code has been modified
- # is deemed to be OUTside the license block, i.e. it is not
- # replaced for relicensing.
- if orig_code_modified_pattern.search(lines[i]):
- non_lic_content_in_same_comment_block = 1
- # The endline is the first non-blank line before this one.
- endlinenum = i-1
- while 1:
- line = lines[endlinenum]
- match = lic_middle_pattern.search(line)
- if not match:
- raise RelicError("Line did not match lic_middle_pattern "
- "unexpectedly: %r" % line)
- if match.group("content").strip(): # non-empty line
- break
- endlinenum -= 1
- break
- else:
- raise RelicError("Could not find license comment block end "
- "line in '%s'." % filename)
- elif len(comment_delims) >= 2: # block-style comments
- for i in range(beginline["linenum"]+1, len(lines)):
- if lines[i].find(comment_delims[-1]) != -1:
- endlinenum = i
- break
- elif lines[i].find("END LICENSE BLOCK") != -1:
- endlinenum = i
- non_lic_content_in_same_comment_block = 1
- break
- # As per "test_relicense_ibm_copyright_suffix.c", a
- # paragraph starting with:
- # This Original Code has been modified
- # is deemed to be OUTside the license block, i.e. it is not
- # replaced for relicensing.
- if orig_code_modified_pattern.search(lines[i]):
- non_lic_content_in_same_comment_block = 1
- # The endline is the first non-blank line before this one.
- endlinenum = i-1
- while 1:
- line = lines[endlinenum]
- match = lic_middle_pattern.search(line)
- if not match:
- raise RelicError("Line did not match lic_middle_pattern "
- "unexpectedly: %r" % line)
- if match.group("content").strip(): # non-empty line
- break
- endlinenum -= 1
- break
- else:
- raise RelicError("Could not find license comment block end "
- "line in '%s'." % filename)
- if not non_lic_content_in_same_comment_block\
- and not lines[endlinenum].strip().endswith(comment_delims[-1]):
- raise RelicError(
- "There is text AFTER the license block comment end "
- "delimiter, but on the SAME LINE. This is unexpected. "
- "Bailing.\n%s:%s:%r"
- % (filename, endlinenum, lines[endlinenum]))
- else: # len(comment_delims) == 0
- # For files without a comment character to help out, we ONLY
- # successfully break one the full correct "END LICENSE BLOCK"
- # token.
- for i in range(beginline["linenum"]+1, len(lines)):
- if lines[i].find("END LICENSE BLOCK") != -1:
- endlinenum = i
- break
- elif i > beginline["linenum"]+1+50:
- raise RelicError("Haven't found 'END LICENSE BLOCK' marker "
- "within 50 lines of the start of the "
- "license block on line %d. Aborting."
- % (beginline["linenum"]+1))
- # As per "test_relicense_trailing_orig_code_modified.pl", a
- # paragraph starting with:
- # This Original Code has been modified
- # is deemed to be OUTside the license block, i.e. it is not
- # replaced for relicensing.
- if orig_code_modified_pattern.search(lines[i]):
- non_lic_content_in_same_comment_block = 1
- # The endline is the first non-blank line before this one.
- endlinenum = i-1
- while 1:
- line = lines[endlinenum]
- match = lic_middle_pattern.search(line)
- if not match:
- raise RelicError("Line did not match lic_middle_pattern "
- "unexpectedly: %r" % line)
- if match.group("content").strip(): # non-empty line
- break
- endlinenum -= 1
- break
- else:
- raise RelicError("Could not find license comment block end "
- "line in '%s'." % filename)
- # Test case: test_relicense_separated_license_comment_blocks.pl
- # It is possible that a separate comment block immediately following
- # the license block we just parsed should be included in the license
- # block.
- if (not non_lic_content_in_same_comment_block
- and len(comment_delims) == 1): # only do this for line-style comments
- lic_indicators = [
- re.compile("^The content of this file are subject to", re.I),
- re.compile("^Software distributed under the License", re.I),
- re.compile("^The Original Code is", re.I),
- re.compile("^The Initial Developer", re.I),
- re.compile("^Contributor", re.I),
- re.compile("^Alternatively, the content of this file", re.I),
- ]
- comment_line_pattern = re.compile("""
- ^(?P<prefix>%s|)
- (?P<space>\s*)
- (?P<content>.*)
- (?P<suffix>%s|)\s*?$
- """ % (prefix_pattern, suffix_pattern),
- re.VERBOSE)
- i = endlinenum
- while i+1 < len(lines):
- i += 1; line = lines[i]
- comment_index = line.find(comment_delims[0])
- if comment_index != -1:
- content = line[:comment_index].strip()
- comment = line[comment_index+len(comment_delims[0]):].strip()
- else:
- content = line.strip()
- comment = ""
- if content: # if non-comment content, then skip out
- break
- if not comment:
- continue
- for indicator in lic_indicators:
- if indicator.search(comment):
- # include this paragraph in the lic block
- while i < len(lines):
- i += 1; line = lines[i]
- if not line.strip().startswith(comment_delims[0]):
- break
- if not line.strip()[len(comment_delims[0]):]:
- break
- endlinenum = i-1
- break
- else:
- break # this is a non-lic-related comment
-
- # Get the end-line data.
- if non_lic_content_in_same_comment_block:
- lic_end_pattern = re.compile(
- "^(?P<prefix>%s)(?P<space>\s*).*?\s*?$"
- % prefix_pattern)
- else:
- lic_end_pattern = re.compile(
- "^(?P<prefix>%s)(?P<space>\s*).*?(?P<suffix>%s)\s*?$"
- % (prefix_pattern, suffix_pattern))
- match = lic_end_pattern.match(lines[endlinenum])
- if match:
- endline = {
- "content": lines[endlinenum],
- "linenum": endlinenum,
- "prefix": match.group("prefix"),
- "space": match.group("space"),
- "suffix": match.groupdict().get("suffix", ""),
- }
- else:
- raise RelicError("license block end line did not match: line='%s', "
- "pattern='%s'"
- % (lines[endlinenum], lic_end_pattern.pattern))
- log.debug("endline dict: %s", endline)
- lic_info["last_suffix"] = endline["suffix"]
- log.info("suffix for last line: '%s'", endline["suffix"])
- lic_info["end_line"] = endline["linenum"]
- log.info("license lines: %d-%d", beginline["linenum"], endline["linenum"])
- # So at this point we have the beginline, secondline, and endline
- # dicts describing and bounding the license block.
-
- # - gather embedded lic data
- # As described here:
- # http://www.mozilla.org/MPL/relicensing-faq.html#new-license
- # we have to parse out the following possible fields:
- # original_code_is
- # original_code_date
- # initial_developer
- # initial_copyright_date
- # contributors
- lic_line_pattern = re.compile( # regex to parse out the line _body_
- "^(?P<prefix>%s)(?P<space>\s*)(?P<body>.*?)(?P<suffix>%s|)\s*?$"
- % (prefix_pattern, suffix_pattern))
- original_code_is = None
- original_code_date = None
- # Parse out the "The Original Code is ..." paragraph _content_.
- paragraph = ""
- in_paragraph = 0
- for i in range(beginline["linenum"], endline["linenum"]+1):
- body = lic_line_pattern.match(lines[i]).group("body")
- if (not in_paragraph and body.startswith("The Original Code is")):
- in_paragraph = 1
- if in_paragraph:
- if not body.strip(): # i.e. a blank line, end of paragraph
- break
- # ensure one space btwn lines
- if paragraph: paragraph = paragraph.rstrip() + " "
- paragraph += body
- if paragraph:
- pattern1 = re.compile('^The Original Code is (.*), released (.*)\.')
- match = pattern1.search(paragraph)
- if match:
- original_code_is = match.group(1)
- original_code_date = match.group(2)
- else:
- pattern2 = re.compile('^The Original Code is (.*?)\.?$')
- match = pattern2.search(paragraph)
- if match:
- original_code_is = match.group(1)
- else:
- raise RelicError(
- "%s: 'The Original Code is' paragraph did not match the "
- "expected patterns. paragraph=\n\t%r\n"
- "pattern1=\n\t%r\npattern2=\n\t%r"
- % (filename, paragraph, pattern1.pattern, pattern2.pattern))
- lic_info["original_code_is"] = original_code_is
- lic_info["original_code_date"] = original_code_date
- log.info("original code is: %s", original_code_is)
- log.info("original_code_date: %s", original_code_date)
- initial_developer = None
- initial_copyright_date = None
- # Parse out the "The Initial Developer..." paragraph _content_.
- paragraph = ""
- in_paragraph = 0
- for i in range(beginline["linenum"], endline["linenum"]+1):
- body = lic_line_pattern.match(lines[i]).group("body")
- if (not in_paragraph and
- …
Large files files are truncated, but you can click here to view the full file