Esempio n. 1
0
def main(argv=sys.argv[1:]):
    extensions = [
        'c',
        'cc',
        'cpp',
        'cxx',
        'h',
        'hh',
        'hpp',
        'hxx',
        'cmake',
        'py',
    ]

    parser = argparse.ArgumentParser(
        description='Check code files for copyright and license information.',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        'paths',
        nargs='*',
        default=[os.curdir],
        help='The files or directories to check. For directories files ending '
        "in %s will be considered (except directories starting with '.' "
        "or '_' and 'setup.py' files beside 'package.xml' files)." %
        ', '.join(["'.%s'" % e for e in extensions]))
    parser.add_argument('--exclude',
                        metavar='filename',
                        nargs='*',
                        dest='excludes',
                        help='The filenames to exclude.')
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--add-missing',
        nargs=2,
        metavar=('COPYRIGHT_NAME', 'LICENSE'),
        help=('Add missing copyright notice and license information using the '
              'passed copyright holder and license'))
    group.add_argument(
        '--add-copyright-year',
        nargs='*',
        type=int,
        help='Add the current year to existing copyright notices')
    group.add_argument('--list-copyright-names',
                       action='store_true',
                       help='List names of known copyright holders')
    group.add_argument('--list-licenses',
                       action='store_true',
                       help='List names of known licenses')
    parser.add_argument(
        '--verbose',
        action='store_true',
        help=
        'Show all files instead of only the ones with errors / modifications')
    # not using a file handle directly
    # in order to prevent leaving an empty file when something fails early
    group.add_argument('--xunit-file',
                       help='Generate a xunit compliant XML file')
    args = parser.parse_args(argv)

    names = get_copyright_names()
    if args.list_copyright_names:
        for key in sorted(names.keys()):
            print('%s: %s' % (key, names[key]))
        return 0

    licenses = get_licenses()
    if args.list_licenses:
        for key in sorted(licenses.keys()):
            print('%s: %s' % (key, licenses[key].name))
        return 0

    if args.xunit_file:
        start_time = time.time()

    filenames = get_files(args.paths, extensions)
    if args.excludes:
        filenames = [
            f for f in filenames if os.path.basename(f) not in args.excludes
        ]
    if not filenames:
        print('No repository roots and files found', file=sys.stderr)
        return 0

    file_descriptors = {}
    for filename in sorted(filenames):
        file_descriptors[filename] = parse_file(filename)

    if args.add_missing:
        name = names.get(args.add_missing[0], args.add_missing[0])
        if args.add_missing[1] not in licenses:
            parser.error(
                "'LICENSE' argument must be a known license name. "
                "Use the '--list-licenses' options to see alist of valid license names."
            )
        license = licenses[args.add_missing[1]]
        add_missing_header(file_descriptors, name, license, args.verbose)
        return 0

    if args.add_copyright_year is not None:
        if not args.add_copyright_year:
            args.add_copyright_year.append(time.strftime('%Y'))
        args.add_copyright_year = [
            int(year) for year in args.add_copyright_year
        ]
        add_copyright_year(file_descriptors, args.add_copyright_year,
                           args.verbose)
        return 0

    report = []

    # check each directory for CONTRIBUTING.md and LICENSE files
    for path in sorted(file_descriptors.keys()):
        file_descriptor = file_descriptors[path]
        message = None
        has_error = False

        if file_descriptor.filetype == SOURCE_FILETYPE:
            if not file_descriptor.exists:
                message = 'file not found'
                has_error = True

            elif not file_descriptor.content:
                message = 'file empty'

            elif not file_descriptor.copyright_identifiers:
                message = 'could not find copyright notice'
                has_error = True

            else:
                message = 'copyright=%s, license=%s' % \
                    (', '.join([str(c) for c in file_descriptor.copyrights]),
                     file_descriptor.license_identifier)
                has_error = file_descriptor.license_identifier == UNKNOWN_IDENTIFIER

        elif file_descriptor.filetype in [
                CONTRIBUTING_FILETYPE, LICENSE_FILETYPE
        ]:
            if not file_descriptor.exists:
                message = 'file not found'
                has_error = True

            elif not file_descriptor.content:
                message = 'file empty'
                has_error = True

            elif file_descriptor.license_identifier:
                message = file_descriptor.license_identifier
                has_error = file_descriptor.license_identifier == UNKNOWN_IDENTIFIER

            else:
                assert False, file_descriptor

        else:
            assert False, 'Unknown filetype: ' + file_descriptor.filetype

        if args.verbose or has_error:
            print('%s: %s' % (file_descriptor.path, message),
                  file=sys.stderr if has_error else sys.stdout)
        report.append((file_descriptor.path, not has_error, message))

    # output summary
    error_count = len([r for r in report if not r[1]])
    if not error_count:
        print('No errors, checked %d files' % len(report))
        rc = 0
    else:
        print('%d errors, checked %d files' % (error_count, len(report)),
              file=sys.stderr)
        rc = 1

    # generate xunit file
    if args.xunit_file:
        folder_name = os.path.basename(os.path.dirname(args.xunit_file))
        file_name = os.path.basename(args.xunit_file)
        suffix = '.xml'
        if file_name.endswith(suffix):
            file_name = file_name[0:-len(suffix)]
            suffix = '.xunit'
            if file_name.endswith(suffix):
                file_name = file_name[0:-len(suffix)]
        testname = '%s.%s' % (folder_name, file_name)

        xml = get_xunit_content(report, testname, time.time() - start_time)
        path = os.path.dirname(os.path.abspath(args.xunit_file))
        if not os.path.exists(path):
            os.makedirs(path)
        with open(args.xunit_file, 'w') as f:
            f.write(xml)

    return rc
Esempio n. 2
0
def main(argv=sys.argv[1:]):
    extensions = [
        'c', 'cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'hxx',
        'cmake',
        'py',
    ]

    parser = argparse.ArgumentParser(
        description='Check code files for copyright and license information.',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        'paths',
        nargs='*',
        default=[os.curdir],
        help='The files or directories to check. For directories files ending '
             "in %s will be considered (except directories starting with '.' "
             "or '_' and 'setup.py' files beside 'package.xml' files)." %
             ', '.join(["'.%s'" % e for e in extensions]))
    parser.add_argument(
        '--exclude',
        metavar='filename',
        nargs='*',
        dest='excludes',
        help='The filenames to exclude.')
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--add-missing',
        nargs=2,
        metavar=('COPYRIGHT_NAME', 'LICENSE'),
        help=(
            'Add missing copyright notice and license information using the '
            'passed copyright holder and license'))
    group.add_argument(
        '--add-copyright-year',
        nargs='*',
        type=int,
        help='Add the current year to existing copyright notices')
    group.add_argument(
        '--list-copyright-names',
        action='store_true',
        help='List names of known copyright holders')
    group.add_argument(
        '--list-licenses',
        action='store_true',
        help='List names of known licenses')
    parser.add_argument(
        '--verbose',
        action='store_true',
        help='Show all files instead of only the ones with errors / modifications')
    # not using a file handle directly
    # in order to prevent leaving an empty file when something fails early
    group.add_argument(
        '--xunit-file',
        help='Generate a xunit compliant XML file')
    args = parser.parse_args(argv)

    names = get_copyright_names()
    if args.list_copyright_names:
        for key in sorted(names.keys()):
            print('%s: %s' % (key, names[key]))
        return 0

    licenses = get_licenses()
    if args.list_licenses:
        for key in sorted(licenses.keys()):
            print('%s: %s' % (key, licenses[key].name))
        return 0

    if args.xunit_file:
        start_time = time.time()

    filenames = get_files(args.paths, extensions)
    if args.excludes:
        filenames = [f for f in filenames if os.path.basename(f) not in args.excludes]
    if not filenames:
        print('No repository roots and files found', file=sys.stderr)
        return 0

    file_descriptors = {}
    for filename in sorted(filenames):
        file_descriptors[filename] = parse_file(filename)

    if args.add_missing:
        name = names.get(args.add_missing[0], args.add_missing[0])
        if args.add_missing[1] not in licenses:
            parser.error(
                "'LICENSE' argument must be a known license name. "
                "Use the '--list-licenses' options to see alist of valid license names.")
        license = licenses[args.add_missing[1]]
        add_missing_header(file_descriptors, name, license, args.verbose)
        return 0

    if args.add_copyright_year is not None:
        if not args.add_copyright_year:
            args.add_copyright_year.append(time.strftime('%Y'))
        args.add_copyright_year = [int(year) for year in args.add_copyright_year]
        add_copyright_year(file_descriptors, args.add_copyright_year, args.verbose)
        return 0

    report = []

    # check each directory for CONTRIBUTING.md and LICENSE files
    for path in sorted(file_descriptors.keys()):
        file_descriptor = file_descriptors[path]
        message = None
        has_error = False

        if file_descriptor.filetype == SOURCE_FILETYPE:
            if not file_descriptor.exists:
                message = 'file not found'
                has_error = True

            elif not file_descriptor.content:
                message = 'file empty'

            elif not file_descriptor.copyright_identifiers:
                message = 'could not find copyright notice'
                has_error = True

            else:
                message = 'copyright=%s, license=%s' % \
                    (', '.join([str(c) for c in file_descriptor.copyrights]),
                     file_descriptor.license_identifier)
                has_error = file_descriptor.license_identifier == UNKNOWN_IDENTIFIER

        elif file_descriptor.filetype in [CONTRIBUTING_FILETYPE, LICENSE_FILETYPE]:
            if not file_descriptor.exists:
                message = 'file not found'
                has_error = True

            elif not file_descriptor.content:
                message = 'file empty'
                has_error = True

            elif file_descriptor.license_identifier:
                message = file_descriptor.license_identifier
                has_error = file_descriptor.license_identifier == UNKNOWN_IDENTIFIER

            else:
                assert False, file_descriptor

        else:
            assert False, 'Unknown filetype: ' + file_descriptor.filetype

        if args.verbose or has_error:
            print('%s: %s' % (file_descriptor.path, message),
                  file=sys.stderr if has_error else sys.stdout)
        report.append((file_descriptor.path, not has_error, message))

    # output summary
    error_count = len([r for r in report if not r[1]])
    if not error_count:
        print('No errors, checked %d files' % len(report))
        rc = 0
    else:
        print('%d errors, checked %d files' % (error_count, len(report)), file=sys.stderr)
        rc = 1

    # generate xunit file
    if args.xunit_file:
        folder_name = os.path.basename(os.path.dirname(args.xunit_file))
        file_name = os.path.basename(args.xunit_file)
        suffix = '.xml'
        if file_name.endswith(suffix):
            file_name = file_name[0:-len(suffix)]
            suffix = '.xunit'
            if file_name.endswith(suffix):
                file_name = file_name[0:-len(suffix)]
        testname = '%s.%s' % (folder_name, file_name)

        xml = get_xunit_content(report, testname, time.time() - start_time)
        path = os.path.dirname(os.path.abspath(args.xunit_file))
        if not os.path.exists(path):
            os.makedirs(path)
        with open(args.xunit_file, 'w') as f:
            f.write(xml)

    return rc