#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # '''mouse is a lighter, friendlier version of RAT (the ASF Release Audit Tool). mouse is intended to replace RAT as a tool for checking license compliance within source code repositories, release archives, and directory trees. It is intended to be modular, so as to be invoked from any number of places, including build scripts and post-commit hooks. mouse generates reports in the same format as RAT, and accepts the same arguments, excepting the fact that mouse does not modify files as part of its operation. mouse will not attempt to insert missing license headers, but it will notify the user of their absence. For information about how to use mouse, run 'mouse.py --help'.''' import os import sys import optparse import xml.etree.cElementTree as ElementTree import sources import match # Some constants VERSION = '0.1' resources_path = os.path.join(sys.path[0], 'resources') class Resource(object): def __init__(self, item, result): self._item = item self._result = result def to_element(self): elem = ElementTree.Element('resource') elem.set('name', self._item.name) if hasattr(self._result, 'include_sample') and self._result.include_sample: child = ElementTree.SubElement(elem, 'header-sample') child.text = self._item.get_content().read() if hasattr(self._result, 'header_name') and self._result.header_name: child = ElementTree.SubElement(elem, 'header-type') child.set('name', self._result.header_name) if hasattr(self._result, 'license_family') and self._result.license_family: child = ElementTree.SubElement(elem, 'license-family') child.set('name', self._result.license_family) if hasattr(self._result, 'license_approved'): child = ElementTree.SubElement(elem, 'license-approval') if self._result.license_approved: child.set('name', 'true') else: child.set('name', 'false') child = ElementTree.SubElement(elem, 'type') child.set('name', self._result.type_name) return elem def generate_report(items): '''Return a generator which will produce Resource objects for each item in ITEMS. ITEMS is a generator (or other callable which will produce an iterable) which returns objects which mouse is to process. ITEMS should return objects of type Item (which see for details).''' def report_generator(): for item in items(): yield Resource(item, match.do_match(item)) return report_generator def process_report(report): '''Given REPORT, generate xml output representing its results.''' root = ElementTree.Element('rat-report') for resource in report(): root.append(resource.to_element()) return ElementTree.tostring(root) def transform_xslt(input_xml, stylesheet): '''Transform OUTPUT_XML, which should be valid xml (usually the result of calling process_report_xml()), according to the rules given in STYLESHEET.''' # Do the import here so that if people don't want to do xslt transforms, # they aren't required too import libxml2 import libxslt styledoc = libxml2.parseFile(stylesheet) style = libxslt.parseStylesheetDoc(styledoc) doc = libxml2.parseMemory(input_xml, len(input_xml)) result = style.applyStylesheet(doc, None) output_xml = style.saveResultToString(result) style.freeStylesheet() doc.freeDoc() result.freeDoc() return output_xml def filter_excludes(items, excludes): '''Return a filtered version of ITEMS, according to EXCLUDES. EXCLUDES should be a list of regular expression objects.''' def filter_generator(): for item in items(): matched = False for exclude in excludes: if exclude.match(item.name): matched = True break if matched: continue else: yield item return filter_generator def main(): 'Parse the command line arguments, and use them to generate a mouse report.' # set up the option parser usage = 'usage: %prog [options]