Skip to content

Commit 7062806

Browse files
committed
add --replace-originals flag to extractcode
Signed-off-by: Maximilian Huber <maximilian.huber@tngtech.com>
1 parent 1637711 commit 7062806

4 files changed

Lines changed: 67 additions & 11 deletions

File tree

src/extractcode/extract.py

Lines changed: 13 additions & 7 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, replace_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, replace_originals=replace_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, kinds, recurse, replace_originals=replace_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, replace_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.
@@ -178,16 +178,22 @@ def extract_file(location, target, kinds=extractcode.default_kinds, verbose=Fals
178178
+ getattr(extractor, '__module__', '')
179179
+ '.' + getattr(extractor, '__name__', ''))
180180
if extractor:
181-
yield ExtractEvent(location, target, done=False, warnings=[], errors=[])
181+
yield ExtractEvent(location, target if not replace_originals else location, done=False, warnings=[], errors=[])
182182
try:
183183
# extract first to a temp directory: if there is an error, the
184184
# extracted files will not be moved to target
185185
tmp_tgt = fileutils.get_temp_dir(prefix='scancode-extract-')
186186
abs_location = abspath(expanduser(location))
187187
warns = extractor(abs_location, tmp_tgt) or []
188188
warnings.extend(warns)
189-
fileutils.copytree(tmp_tgt, target)
190-
fileutils.delete(tmp_tgt)
189+
if not replace_originals:
190+
fileutils.copytree(tmp_tgt, target)
191+
fileutils.delete(tmp_tgt)
192+
else:
193+
if TRACE:
194+
logger.debug('extract_file: replace original with extracted content: %(location)r' % locals())
195+
fileutils.delete(location)
196+
fileutils.copytree(tmp_tgt, location)
191197
except Exception as e:
192198
errors = [str(e).strip(' \'"')]
193199
if verbose:

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, replace_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, replace_originals=replace_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('--replace-originals', is_flag=True, default=False, help='Replace extracted archives by the extracted content.')
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, replace_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, replace_originals=replace_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/a/b/a.txt',
245+
'a/a.tar.gz/a/b/b.txt',
246+
'a/a.tar.gz/a/c/c.txt',
247+
'b/a.txt',
248+
'b/b.tar.gz/b/.svn/all-wcprops',
249+
'b/b.tar.gz/b/.svn/entries',
250+
'b/b.tar.gz/b/.svn/format',
251+
'b/b.tar.gz/b/a/a.txt',
252+
'b/b.tar.gz/b/a/.svn/all-wcprops',
253+
'b/b.tar.gz/b/a/.svn/entries',
254+
'b/b.tar.gz/b/a/.svn/format',
255+
'b/b.tar.gz/b/a/.svn/prop-base/a.tar.gz.svn-base',
256+
'b/b.tar.gz/b/a/.svn/text-base/a.tar.gz.svn-base',
257+
'b/b.tar.gz/b/a/.svn/text-base/a.txt.svn-base',
258+
'b/b.tar.gz/b/a/a.tar.gz/a/b/a.txt',
259+
'b/b.tar.gz/b/a/a.tar.gz/a/b/b.txt',
260+
'b/b.tar.gz/b/a/a.tar.gz/a/c/c.txt',
261+
'b/b.tar.gz/b/b/a.txt',
262+
'b/b.tar.gz/b/b/.svn/all-wcprops',
263+
'b/b.tar.gz/b/b/.svn/entries',
264+
'b/b.tar.gz/b/b/.svn/format',
265+
'b/b.tar.gz/b/b/.svn/text-base/a.txt.svn-base',
266+
'b/b.tar.gz/b/c/a.txt',
267+
'b/b.tar.gz/b/c/.svn/all-wcprops',
268+
'b/b.tar.gz/b/c/.svn/entries',
269+
'b/b.tar.gz/b/c/.svn/format',
270+
'b/b.tar.gz/b/c/.svn/prop-base/a.tar.gz.svn-base',
271+
'b/b.tar.gz/b/c/.svn/text-base/a.tar.gz.svn-base',
272+
'b/b.tar.gz/b/c/.svn/text-base/a.txt.svn-base',
273+
'b/b.tar.gz/b/c/a.tar.gz/a/b/a.txt',
274+
'b/b.tar.gz/b/c/a.tar.gz/a/b/b.txt',
275+
'b/b.tar.gz/b/c/a.tar.gz/a/c/c.txt',
276+
'c/a.txt',
277+
'c/a.tar.gz/a/b/a.txt',
278+
'c/a.tar.gz/a/b/b.txt',
279+
'c/a.tar.gz/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)