Example #1
0
 def identify_license(self, content, license_part):
     for name, license in get_licenses().items():
         if content is not None and getattr(license,
                                            license_part) == content:
             self.license_identifier = name
             break
     else:
         self.license_identifier = UNKNOWN_IDENTIFIER
Example #2
0
    def identify_license(self, content, license_part):
        if content is None:
            return

        for name, license_ in get_licenses().items():
            template = getattr(license_, license_part).replace('\n', ' ').strip()
            last_index = -1
            for license_section in template.split('{copyright_holder}'):
                # OK, now look for each section of the license in the incoming
                # content.
                index = content.replace('\n', ' ').strip().find(license_section.strip())
                if index == -1 or index <= last_index:
                    # Some part of the license is not in the content, or the license
                    # is rearranged, this license doesn't match.
                    break
                last_index = index
            else:
                # We found the license, so set it
                self.license_identifier = name
                break
Example #3
0
    def identify_license(self, content, license_part):
        if content is None:
            return

        for name, license_ in get_licenses().items():
            template = remove_formatting(getattr(license_, license_part))
            last_index = -1
            for license_section in template.split('{copyright_holder}'):
                # OK, now look for each section of the license in the incoming
                # content.
                index = remove_formatting(content).find(
                    license_section.strip())
                if index == -1 or index <= last_index:
                    # Some part of the license is not in the content, or the license
                    # is rearranged, this license doesn't match.
                    break
                last_index = index
            else:
                # We found the license, so set it
                self.license_identifier = name
                break
Example #4
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
Example #5
0
    def main(self, *, args):
        available_licenses = {}
        for shortname, entry in ament_copyright.get_licenses().items():
            available_licenses[entry.spdx] = entry.license_files

        if args.license == '?':
            print('Supported licenses:\n%s' % ('\n'.join(available_licenses)))
            sys.exit(0)

        maintainer = Person(args.maintainer_name)

        if args.maintainer_email:
            maintainer.email = args.maintainer_email
        else:
            # try getting the email from the global git config
            git = shutil.which('git')
            if git is not None:
                p = subprocess.Popen([git, 'config', 'user.email'],
                                     stdout=subprocess.PIPE)
                resp = p.communicate()
                email = resp[0].decode().rstrip()
                if email:
                    maintainer.email = email
            if not maintainer.email:
                maintainer.email = maintainer.name + '@todo.todo'

        node_name = None
        library_name = None
        if args.library_name:
            library_name = args.library_name
        if args.node_name:
            node_name = args.node_name
            if args.node_name == args.library_name:
                node_name = args.node_name + '_node'
                print(
                    '[WARNING] node name can not be equal to the library name',
                    file=sys.stderr)
                print('[WARNING] renaming node to %s' % node_name,
                      file=sys.stderr)

        buildtool_depends = []
        if args.build_type == 'ament_cmake':
            if args.library_name:
                buildtool_depends = ['ament_cmake_ros']
            else:
                buildtool_depends = ['ament_cmake']

        test_dependencies = []
        if args.build_type == 'ament_cmake':
            test_dependencies = ['ament_lint_auto', 'ament_lint_common']
        if args.build_type == 'ament_python':
            test_dependencies = [
                'ament_copyright', 'ament_flake8', 'ament_pep257',
                'python3-pytest'
            ]

        if args.build_type == 'ament_python' and args.package_name == 'test':
            # If the package name is 'test', there will be a conflict between
            # the directory the source code for the package goes in and the
            # directory the tests for the package go in.
            return "Aborted since 'ament_python' packages can't be named 'test'. Please " + \
                'choose a different package name.'

        package = Package(
            package_format=args.package_format,
            name=args.package_name,
            version='0.0.0',
            description=args.description,
            maintainers=[maintainer],
            licenses=[args.license],
            buildtool_depends=[Dependency(dep) for dep in buildtool_depends],
            build_depends=[Dependency(dep) for dep in args.dependencies],
            test_depends=[Dependency(dep) for dep in test_dependencies],
            exports=[Export('build_type', content=args.build_type)])

        package_path = os.path.join(args.destination_directory, package.name)
        if os.path.exists(package_path):
            return '\nAborted!\nThe directory already exists: ' + package_path + '\nEither ' + \
                'remove the directory or choose a different destination directory or package name'

        print('going to create a new package')
        print('package name:', package.name)
        print('destination directory:',
              os.path.abspath(args.destination_directory))
        print('package format:', package.package_format)
        print('version:', package.version)
        print('description:', package.description)
        print('maintainer:',
              [str(maintainer) for maintainer in package.maintainers])
        print('licenses:', package.licenses)
        print('build type:', package.get_build_type())
        print('dependencies:',
              [str(dependency) for dependency in package.build_depends])
        if node_name:
            print('node_name:', node_name)
        if library_name:
            print('library_name:', library_name)

        package_directory, source_directory, include_directory = \
            create_package_environment(package, args.destination_directory)
        if not package_directory:
            return 'unable to create folder: ' + args.destination_directory

        if args.build_type == 'cmake':
            populate_cmake(package, package_directory, node_name, library_name)

        if args.build_type == 'ament_cmake':
            populate_ament_cmake(package, package_directory, node_name,
                                 library_name)

        if args.build_type == 'ament_python':
            if not source_directory:
                return 'unable to create source folder in ' + args.destination_directory
            populate_ament_python(package, package_directory, source_directory,
                                  node_name)
            if node_name:
                populate_python_node(package, source_directory, node_name)
            if library_name:
                populate_python_libary(package, source_directory, library_name)

        if args.build_type == 'ament_cmake' or args.build_type == 'cmake':
            if node_name:
                if not source_directory:
                    return 'unable to create source folder in ' + args.destination_directory
                populate_cpp_node(package, source_directory, node_name)
            if library_name:
                if not source_directory or not include_directory:
                    return 'unable to create source or include folder in ' + \
                            args.destination_directory
                populate_cpp_library(package, source_directory,
                                     include_directory, library_name)

        if args.license in available_licenses:
            with open(os.path.join(package_directory, 'LICENSE'),
                      'w') as outfp:
                for lic in available_licenses[args.license]:
                    outfp.write(lic)
        else:
            print(
                "\n[WARNING]: Unknown license '%s'.  This has been set in the package.xml, but "
                'no LICENSE file has been created.\nIt is recommended to use one of the ament '
                'license identitifers:\n%s' %
                (args.license, '\n'.join(available_licenses)))
Example #6
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