Add A Post-Scan Plugin¶
Built-In vs. Optional Installation¶
Built-In¶
Some post-scan plugins are installed when ScanCode itself is installed, e.g., the License Policy Plugin, whose code is located here:
https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/plugin_license_policy.py
These plugins do not require any additional installation steps and can be used as soon as ScanCode is up and running.
Optional¶
ScanCode is also designed to use post-scan plugins that must be installed separately from the installation of ScanCode. The code for this sort of plugin is located here:
https://github.com/nexB/scancode-toolkit/tree/develop/plugins/
This wiki page will focus on optional post-scan plugins.
Example Post-Scan Plugin: Hello ScanCode¶
To illustrate the creation of a simple post-scan plugin, we’ll create a hypothetical plugin named
Hello ScanCode, which will print Hello ScanCode! in your terminal after you’ve run a scan.
Your command will look like something like this:
scancode -i -n 2 <path to target codebase> --hello --json <path to JSON output file>
We’ll start by creating three folders:
Top-level folder –
/scancode-hello/2nd-level folder –
/src/3rd-level folder –
/hello_scancode/
1. Top-level folder – /scancode-hello/¶
In the
/scancode-toolkit/plugins/directory, add a folder with a relevant name, e.g.,scancode-hello. This folder will hold all of your plugin code.Inside the
/scancode-hello/folder you’ll need to add a folder namedsrcand 7 files.
/src/– This folder will contain your primary Python code and is discussed in more detail in the following section.
The 7 Files are:
.gitignore– See, e.g., /plugins/scancode-ignore-binaries/.gitignore
/build/
/dist/
apache-2.0.LICENSE– See, e.g., /plugins/scancode-ignore-binaries/apache-2.0.LICENSEMANIFEST.in
graft src
include setup.py
include setup.cfg
include .gitignore
include README.md
include MANIFEST.in
include NOTICE
include apache-2.0.LICENSE
global-exclude *.py[co] __pycache__ *.*~
NOTICE– See, e.g., /plugins/scancode-ignore-binaries/NOTICEREADME.mdsetup.cfg
[metadata]
license_file = NOTICE
[bdist_wheel]
universal = 1
[aliases]
release = clean --all bdist_wheel
setup.py– This is an example of what oursetup.pyfile would look like:
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from glob import glob
from os.path import basename
from os.path import join
from os.path import splitext
from setuptools import find_packages
from setuptools import setup
desc = '''A ScanCode post-scan plugin to to illustrate the creation of a simple post-scan plugin.'''
setup(
name='scancode-hello',
version='1.0.0',
license='Apache-2.0 with ScanCode acknowledgment',
description=desc,
long_description=desc,
author='nexB',
author_email='info@aboutcode.org',
url='https://github.com/nexB/scancode-toolkit/plugins/scancode-categories',
packages=find_packages('src'),
package_dir={'': 'src'},
py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
include_package_data=True,
zip_safe=False,
classifiers=[
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Topic :: Utilities',
],
keywords=[
'scancode', 'plugin', 'post-scan'
],
install_requires=[
'scancode-toolkit',
],
entry_points={
'scancode_post_scan': [
'hello = hello_scancode.hello_scancode:SayHello',
],
}
)
2. 2nd-level folder – /src/¶
Add an
__init__.pyfile inside thesrcfolder. This file can be empty, and is used to indicate that the folder should be treated as a Python package directory.Add a folder that will contain our primary code – we’ll name the folder
hello_scancode. If you look at the example of thesetup.pyfile above, you’ll see this line in theentry_pointssection:
'hello = hello_scancode.hello_scancode:SayHello',
hellorefers to the name of the command flag.The first
hello_scancodeis the name of the folder we just created.The second
hello_scancodeis the name of the.pyfile containing our code (discussed in the next section).SayHellois the name of thePostScanPluginclass we create in that file (see sample code below).
3. 3rd-level folder – /hello_scancode/¶
Add an
__init__.pyfile inside thehello_scancodefolder. As noted above, this file can be empty.Add a
hello_scancode.pyfile.
Imports¶
from plugincode.post_scan import PostScanPlugin
from plugincode.post_scan import post_scan_impl
from scancode import CommandLineOption
from scancode import POST_SCAN_GROUP
Create a PostScanPlugin class¶
The PostScanPlugin class
PostScanPlugin code)
inherits from the CodebasePlugin class (see
CodebasePlugin code),
which inherits from the BasePlugin class (see
BasePlugin code).
@post_scan_impl
class SayHello(PostScanPlugin):
"""
Illustrate a simple "Hello World" post-scan plugin.
"""
options = [
CommandLineOption(('--hello',),
is_flag=True, default=False,
help='Generate a simple "Hello ScanCode" greeting in the terminal.',
help_group=POST_SCAN_GROUP)
]
def is_enabled(self, hello, **kwargs):
return hello
def process_codebase(self, codebase, hello, **kwargs):
"""
Say hello.
"""
if not self.is_enabled(hello):
return
print('Hello ScanCode!!')
Load the plugin¶
To load and use the plugin in the normal course, navigate to the plugin’s root folder (in this example:
/plugins/scancode-hello/) and runpip install .(don’t forget the final.).If you’re developing and want to test your work, save your edits and run
pip install -e .from the same folder.
More-complex examples¶
This Hello ScanCode example is quite simple. For examples of more-complex structures and functionalities you can take a look at the other post-scan plugins for guidance and ideas.
One good example is the License Policy post-scan plugin. This plugin is installed when ScanCode
is installed and consequently is not located in the /plugins/ directory used for
manually-installed post-scan plugins. The code for the License Policy plugin can be found at
/scancode-toolkit/src/licensedcode/plugin_license_policy.py
and illustrates how a plugin can be used to analyze the results of a ScanCode scan using external
data files and add the results of that analysis as a new field in the ScanCode JSON output file.