Skip to content

Commit 06b5a08

Browse files
committed
add --remove-originals flag to extractcode
This flag enables the removal of the original files, that were extracted. This means that instead of ``` a/a.tar.gz a/a.txt a/a.tar.gz-extract/a/b/a.txt a/a.tar.gz-extract/a/b/b.txt a/a.tar.gz-extract/a/c/c.txt ``` one would get ``` a/a.txt a/a.tar.gz-extract/a/b/a.txt a/a.tar.gz-extract/a/b/b.txt a/a.tar.gz-extract/a/c/c.txt ``` Signed-off-by: Maximilian Huber <maximilian.huber@tngtech.com>
1 parent 1637711 commit 06b5a08

4 files changed

Lines changed: 62 additions & 8 deletions

File tree

src/extractcode/extract.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
ExtractEvent = namedtuple('ExtractEvent', 'source target done warnings errors')
9898

9999

100-
def extract(location, kinds=extractcode.default_kinds, recurse=False):
100+
def extract(location, kinds=extractcode.default_kinds, recurse=False, remove_originals=False):
101101
"""
102102
Walk and extract any archives found at `location` (either a file or
103103
directory). Extract only archives of a kind listed in the `kinds` kind tuple.
@@ -151,21 +151,21 @@ def extract(location, kinds=extractcode.default_kinds, recurse=False):
151151
target = join(abspath(top), extractcode.get_extraction_path(loc))
152152
if TRACE:
153153
logger.debug('extract:target: %(target)r' % locals())
154-
for xevent in extract_file(loc, target, kinds):
154+
for xevent in extract_file(loc, target, kinds, remove_originals=remove_originals):
155155
if TRACE:
156156
logger.debug('extract:walk:extraction event: %(xevent)r' % locals())
157157
yield xevent
158158

159159
if recurse:
160160
if TRACE:
161161
logger.debug('extract:walk: recursing on target: %(target)r' % locals())
162-
for xevent in extract(target, kinds, recurse):
162+
for xevent in extract(target if remove_originals else localtion, kinds, recurse, remove_originals=remove_originals):
163163
if TRACE:
164164
logger.debug('extract:walk:recurse:extraction event: %(xevent)r' % locals())
165165
yield xevent
166166

167167

168-
def extract_file(location, target, kinds=extractcode.default_kinds, verbose=False):
168+
def extract_file(location, target, kinds=extractcode.default_kinds, verbose=False, remove_originals=False):
169169
"""
170170
Extract a single archive at `location` in the `target` directory if it is
171171
of a kind supported in the `kinds` kind tuple.
@@ -186,6 +186,10 @@ def extract_file(location, target, kinds=extractcode.default_kinds, verbose=Fals
186186
abs_location = abspath(expanduser(location))
187187
warns = extractor(abs_location, tmp_tgt) or []
188188
warnings.extend(warns)
189+
if remove_originals:
190+
if TRACE:
191+
logger.debug('extract_file:rm-original: remove original after it was extracted: %(location)r' % locals())
192+
fileutils.delete(location)
189193
fileutils.copytree(tmp_tgt, target)
190194
fileutils.delete(tmp_tgt)
191195
except Exception as e:

src/scancode/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ def get_file_info(location, **kwargs):
312312
return result
313313

314314

315-
def extract_archives(location, recurse=True):
315+
def extract_archives(location, recurse=True, remove_originals=False):
316316
"""
317317
Yield ExtractEvent while extracting archive(s) and compressed files at
318318
`location`. If `recurse` is True, extract nested archives-in-archives
@@ -323,5 +323,5 @@ def extract_archives(location, recurse=True):
323323
"""
324324
from extractcode.extract import extract
325325
from extractcode import default_kinds
326-
for xevent in extract(location, kinds=default_kinds, recurse=recurse):
326+
for xevent in extract(location, kinds=default_kinds, recurse=recurse, remove_originals=remove_originals):
327327
yield xevent

src/scancode/extract_cli.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,12 @@ class ExtractCommand(utils.BaseCommand):
8989
@click.option('--verbose', is_flag=True, default=False, help='Print verbose file-by-file progress messages.')
9090
@click.option('--quiet', is_flag=True, default=False, help='Do not print any summary or progress message.')
9191
@click.option('--shallow', is_flag=True, default=False, help='Do not extract recursively nested archives (e.g. not archives in archives).')
92+
@click.option('--remove-originals', is_flag=True, default=False, help='Remove original archives after they were extracted.')
9293

9394
@click.help_option('-h', '--help')
9495
@click.option('--about', is_flag=True, is_eager=True, callback=print_about, help='Show information about ScanCode and licensing and exit.')
9596
@click.option('--version', is_flag=True, is_eager=True, callback=print_version, help='Show the version and exit.')
96-
def extractcode(ctx, input, verbose, quiet, shallow, *args, **kwargs): # NOQA
97+
def extractcode(ctx, input, verbose, quiet, shallow, remove_originals, *args, **kwargs): # NOQA
9798
"""extract archives and compressed files found in the <input> file or directory tree.
9899
99100
Use this command before scanning proper as an <input> preparation step.
@@ -157,7 +158,7 @@ def display_extract_summary():
157158

158159
extract_results = []
159160
has_extract_errors = False
160-
extractibles = extract_archives(abs_location, recurse=not shallow)
161+
extractibles = extract_archives(abs_location, recurse=not shallow, remove_originals=remove_originals)
161162

162163
if not quiet:
163164
echo_stderr('Extracting archives...', fg='green')

tests/extractcode/test_extract.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,55 @@ def test_extract_tree_recursive(self):
238238
check_no_error(result)
239239
check_files(test_dir, expected)
240240

241+
def test_extract_tree_recursive_remove_originals(self):
242+
expected = (
243+
'a/a.txt',
244+
'a/a.tar.gz-extract/a/b/a.txt',
245+
'a/a.tar.gz-extract/a/b/b.txt',
246+
'a/a.tar.gz-extract/a/c/c.txt',
247+
'b/a.txt',
248+
'b/b.tar.gz-extract/b/.svn/all-wcprops',
249+
'b/b.tar.gz-extract/b/.svn/entries',
250+
'b/b.tar.gz-extract/b/.svn/format',
251+
'b/b.tar.gz-extract/b/a/a.txt',
252+
'b/b.tar.gz-extract/b/a/.svn/all-wcprops',
253+
'b/b.tar.gz-extract/b/a/.svn/entries',
254+
'b/b.tar.gz-extract/b/a/.svn/format',
255+
'b/b.tar.gz-extract/b/a/.svn/prop-base/a.tar.gz.svn-base',
256+
'b/b.tar.gz-extract/b/a/.svn/text-base/a.tar.gz.svn-base',
257+
'b/b.tar.gz-extract/b/a/.svn/text-base/a.txt.svn-base',
258+
'b/b.tar.gz-extract/b/a/a.tar.gz-extract/a/b/a.txt',
259+
'b/b.tar.gz-extract/b/a/a.tar.gz-extract/a/b/b.txt',
260+
'b/b.tar.gz-extract/b/a/a.tar.gz-extract/a/c/c.txt',
261+
'b/b.tar.gz-extract/b/b/a.txt',
262+
'b/b.tar.gz-extract/b/b/.svn/all-wcprops',
263+
'b/b.tar.gz-extract/b/b/.svn/entries',
264+
'b/b.tar.gz-extract/b/b/.svn/format',
265+
'b/b.tar.gz-extract/b/b/.svn/text-base/a.txt.svn-base',
266+
'b/b.tar.gz-extract/b/c/a.txt',
267+
'b/b.tar.gz-extract/b/c/.svn/all-wcprops',
268+
'b/b.tar.gz-extract/b/c/.svn/entries',
269+
'b/b.tar.gz-extract/b/c/.svn/format',
270+
'b/b.tar.gz-extract/b/c/.svn/prop-base/a.tar.gz.svn-base',
271+
'b/b.tar.gz-extract/b/c/.svn/text-base/a.tar.gz.svn-base',
272+
'b/b.tar.gz-extract/b/c/.svn/text-base/a.txt.svn-base',
273+
'b/b.tar.gz-extract/b/c/a.tar.gz-extract/a/b/a.txt',
274+
'b/b.tar.gz-extract/b/c/a.tar.gz-extract/a/b/b.txt',
275+
'b/b.tar.gz-extract/b/c/a.tar.gz-extract/a/c/c.txt',
276+
'c/a.txt',
277+
'c/a.tar.gz-extract/a/b/a.txt',
278+
'c/a.tar.gz-extract/a/b/b.txt',
279+
'c/a.tar.gz-extract/a/c/c.txt',
280+
)
281+
test_dir = self.get_test_loc('extract/tree', copy=True)
282+
result = list(extract.extract(test_dir, recurse=True, replace_originals=True))
283+
check_no_error(result)
284+
check_files(test_dir, expected)
285+
# again
286+
result = list(extract.extract(test_dir, recurse=True))
287+
check_no_error(result)
288+
check_files(test_dir, expected)
289+
241290
def test_extract_tree_shallow_then_recursive(self):
242291
shallow = (
243292
'a/a.tar.gz',

0 commit comments

Comments
 (0)