diff --git a/.travis.yml b/.travis.yml
index ecff4723b90..a6db53a1075 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,5 +7,5 @@ install:
- source configure
script:
- - py.test -n 2 -vs src tests/commoncode tests/extractcode tests/textcode tests/typecode tests/cluecode tests/licensedcode/test_detect.py tests/licensedcode/test_index.py tests/licensedcode/test_legal.py tests/licensedcode/test_models.py
+ - py.test -n 2 -vs src tests/commoncode tests/extractcode tests/textcode tests/typecode tests/cluecode tests/scancode tests/licensedcode/test_detect.py tests/licensedcode/test_index.py tests/licensedcode/test_legal.py tests/licensedcode/test_models.py
diff --git a/src/scancode/cli.py b/src/scancode/cli.py
index cd4b3181a5a..227a745e183 100644
--- a/src/scancode/cli.py
+++ b/src/scancode/cli.py
@@ -39,7 +39,6 @@
from scancode.api import get_licenses
from scancode.api import HtmlAppAssetCopyWarning
from scancode.api import HtmlAppAssetCopyError
-import textwrap
info_text = '''
@@ -187,19 +186,32 @@ def print_version(ctx, param, value):
'''
+short_help = '''Usage: scancode [OPTIONS]
+Try 'scancode --help' for more information.'''
+
+
formats = ['json', 'html', 'html-app']
+
class ScanCommand(click.Command):
"""
Workaround click 4.0 bug https://github.com/mitsuhiko/click/issues/365
"""
def get_usage(self, ctx):
- formatted = '''Usage: scancode [OPTIONS]
-Try 'scancode --help' for more information'''
- return formatted
+ return short_help
+
+
+def validate_extract(ctx, param, value):
+ if not value or ctx.resilient_parsing:
+ return
+ click.echo(ctx.params)
+ ctx.fail('''The '--extract' option cannot be combined with other scanning options.
+Use '--extract' alone to extract, then run a scan on the extracted files.''')
+ ctx.exit()
@click.command(name='scancode', epilog=epilog_text, cls=ScanCommand)
+@click.pass_context
@click.argument('input', metavar='', type=click.Path(exists=True, readable=True))
@click.argument('output_file', default='-', metavar='', type=click.File('wb'))
@click.option('-c', '--copyright', is_flag=True, default=False, help='Scan for copyrights. [default]')
@@ -218,23 +230,30 @@ def get_usage(self, ctx):
@click.option('--verbose', is_flag=True, default=False, help='Show verbose scan progress messages.')
@click.option('--version', is_flag=True, is_eager=True, callback=print_version,
help=('Show the version and exit.'))
-def scancode(input, output_file, extract, copyright, license, format, verbose, *args, **kwargs):
+def scancode(ctx, input, output_file, extract, copyright, license, format, verbose, *args, **kwargs):
"""scan the file or directory for origin and license and save results to the .
The scan results are printed on terminal if is not provided.
"""
+ scans = [copyright, license]
if extract:
+ if any(scans):
+ # exclusive, ignoring other options.
+ # FIXME: this should turned into a sub-command
+ ctx.fail('''The '--extract' option cannot be combined with other scanning options.
+Use '--extract' alone to extract , then run a scan on the extracted files.''')
+ ctx.exit(1)
+
click.secho('Extracting archives...', fg='green')
extract_errors = get_extract(input)
if extract_errors:
# FIXME: Provide a better way to report errors and we need to report progress
click.secho('\n'.join(extract_errors), fg='red')
click.secho('Extracting done.', fg='green')
- # exclusive, ignoring other options.
return
# Default scan when no options is provided
- if not any((copyright, license)):
+ if not any(scans):
copyright = True
license = True
diff --git a/tests/scancode/data/copyright/copyright_acme_c-c.c b/tests/scancode/data/copyright/copyright_acme_c-c.c
new file mode 100644
index 00000000000..23dbd722d5d
--- /dev/null
+++ b/tests/scancode/data/copyright/copyright_acme_c-c.c
@@ -0,0 +1 @@
+/* Copyright © 2000 ACME, Inc., All Rights Reserved */
\ No newline at end of file
diff --git a/tests/scancode/data/extract/some.tar.gz b/tests/scancode/data/extract/some.tar.gz
new file mode 100644
index 00000000000..904ce06d81f
Binary files /dev/null and b/tests/scancode/data/extract/some.tar.gz differ
diff --git a/tests/scancode/data/license/apache-1.0.txt b/tests/scancode/data/license/apache-1.0.txt
new file mode 100644
index 00000000000..9ebec838ee0
--- /dev/null
+++ b/tests/scancode/data/license/apache-1.0.txt
@@ -0,0 +1,55 @@
+====================================================================
+Copyright (c) The Apache Group. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+ "This product includes software developed by the Apache Group
+ for use in the Apache HTTP server project (http://www.apache.org/)."
+
+ 4. The names "Apache Server" and "Apache Group" must not be used to
+ endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache"
+ nor may "Apache" appear in their names without prior written
+ permission of the Apache Group.
+
+ 6. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes software developed by the Apache Group
+ for use in the Apache HTTP server project (http://www.apache.org/)."
+
+ THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
+ ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+====================================================================
+
+ This software consists of voluntary contributions made by many
+ individuals on behalf of the Apache Group and was originally based
+ on public domain software written at the National Center for
+ Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ For more information on the Apache Group and the Apache HTTP server
+ project, please see .
+
\ No newline at end of file
diff --git a/tests/scancode/test_cli.py b/tests/scancode/test_cli.py
new file mode 100644
index 00000000000..5f523eb22bc
--- /dev/null
+++ b/tests/scancode/test_cli.py
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2015 nexB Inc. and others. All rights reserved.
+# http://nexb.com and https://github.com/nexB/scancode-toolkit/
+# The ScanCode software is licensed under the Apache License version 2.0.
+# Data generated with ScanCode require an acknowledgment.
+# ScanCode is a trademark of nexB Inc.
+#
+# You may not use this software except in compliance with the License.
+# You may obtain a copy of the License at: http://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.
+#
+# When you publish or redistribute any data created with ScanCode or any ScanCode
+# derivative work, you must accompany this data with the following acknowledgment:
+#
+# Generated with ScanCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
+# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
+# ScanCode should be considered or used as legal advice. Consult an Attorney
+# for any legal advice.
+# ScanCode is a free software code scanning tool from nexB Inc. and others.
+# Visit https://github.com/nexB/scancode-toolkit/ for support and download.
+
+from __future__ import absolute_import, print_function
+
+import os
+
+from click.testing import CliRunner
+
+from commoncode.testcase import FileBasedTesting
+from scancode import cli
+
+
+class TestCommandLine(FileBasedTesting):
+ test_data_dir = os.path.join(os.path.dirname(__file__), 'data')
+
+ def test_extract_option_is_exclusive_of_other_options(self):
+ test_dir = self.get_temp_dir()
+ runner = CliRunner()
+ result = runner.invoke(cli.scancode, ['--extract', '--copyright', test_dir])
+ assert result.exit_code == 2
+ assert 'option cannot be combined with other scanning options' in result.output
+
+ result = runner.invoke(cli.scancode, ['--copyright', '--extract', test_dir])
+ assert result.exit_code == 2
+ assert 'option cannot be combined with other scanning options' in result.output
+
+ result = runner.invoke(cli.scancode, ['--extract', '--license', test_dir])
+ assert result.exit_code == 2
+ assert 'option cannot be combined with other scanning options' in result.output
+
+ result = runner.invoke(cli.scancode, ['--extract', '--license', '--copyright', test_dir])
+ assert result.exit_code == 2
+ assert 'option cannot be combined with other scanning options' in result.output
+
+ def test_extract_option_can_take_an_empty_directory(self):
+ test_dir = self.get_temp_dir()
+ runner = CliRunner()
+ result = runner.invoke(cli.scancode, ['--extract', test_dir])
+ assert result.exit_code == 0
+ assert 'Extracting done' in result.output
+
+ def test_extract_option_does_extract(self):
+ test_dir = self.get_test_loc('extract', copy=True)
+ runner = CliRunner()
+ result = runner.invoke(cli.scancode, ['--extract', test_dir])
+ assert result.exit_code == 0
+ assert 'Extracting done' in result.output
+ assert os.path.exists(os.path.join(test_dir, 'some.tar.gz-extract'))
+
+ def test_copyright_option_detects_copyrights(self):
+ test_dir = self.get_test_loc('copyright', copy=True)
+ runner = CliRunner()
+ output_json = self.get_temp_file('json')
+ result = runner.invoke(cli.scancode, ['--copyright', test_dir, output_json])
+ assert result.exit_code == 0
+ assert 'Scanning done' in result.output
+ assert os.path.exists(output_json)
+ assert len(open(output_json).read()) > 10
+
+ def test_license_option_detects_licenses(self):
+ test_dir = self.get_test_loc('license', copy=True)
+ runner = CliRunner()
+ output_json = self.get_temp_file('json')
+ result = runner.invoke(cli.scancode, ['--license', test_dir, output_json])
+ assert result.exit_code == 0
+ assert 'Scanning done' in result.output
+ assert os.path.exists(output_json)
+ assert len(open(output_json).read()) > 10