xref: /aosp_15_r20/external/cronet/build/extract_from_cab.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker# Copyright 2012 The Chromium Authors
3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
5*6777b538SAndroid Build Coastguard Worker
6*6777b538SAndroid Build Coastguard Worker"""Extracts a single file from a CAB archive."""
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Workerimport os
10*6777b538SAndroid Build Coastguard Workerimport shutil
11*6777b538SAndroid Build Coastguard Workerimport subprocess
12*6777b538SAndroid Build Coastguard Workerimport sys
13*6777b538SAndroid Build Coastguard Workerimport tempfile
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Workerdef run_quiet(*args):
16*6777b538SAndroid Build Coastguard Worker  """Run 'expand' suppressing noisy output. Returns returncode from process."""
17*6777b538SAndroid Build Coastguard Worker  popen = subprocess.Popen(args, stdout=subprocess.PIPE)
18*6777b538SAndroid Build Coastguard Worker  out, _ = popen.communicate()
19*6777b538SAndroid Build Coastguard Worker  if popen.returncode:
20*6777b538SAndroid Build Coastguard Worker    # expand emits errors to stdout, so if we fail, then print that out.
21*6777b538SAndroid Build Coastguard Worker    print(out)
22*6777b538SAndroid Build Coastguard Worker  return popen.returncode
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Workerdef main():
25*6777b538SAndroid Build Coastguard Worker  if len(sys.argv) != 4:
26*6777b538SAndroid Build Coastguard Worker    print('Usage: extract_from_cab.py cab_path archived_file output_dir')
27*6777b538SAndroid Build Coastguard Worker    return 1
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker  [cab_path, archived_file, output_dir] = sys.argv[1:]
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker  # Expand.exe does its work in a fixed-named temporary directory created within
32*6777b538SAndroid Build Coastguard Worker  # the given output directory. This is a problem for concurrent extractions, so
33*6777b538SAndroid Build Coastguard Worker  # create a unique temp dir within the desired output directory to work around
34*6777b538SAndroid Build Coastguard Worker  # this limitation.
35*6777b538SAndroid Build Coastguard Worker  temp_dir = tempfile.mkdtemp(dir=output_dir)
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker  try:
38*6777b538SAndroid Build Coastguard Worker    # Invoke the Windows expand utility to extract the file.
39*6777b538SAndroid Build Coastguard Worker    level = run_quiet('expand', cab_path, '-F:' + archived_file, temp_dir)
40*6777b538SAndroid Build Coastguard Worker    if level == 0:
41*6777b538SAndroid Build Coastguard Worker      # Move the output file into place, preserving expand.exe's behavior of
42*6777b538SAndroid Build Coastguard Worker      # paving over any preexisting file.
43*6777b538SAndroid Build Coastguard Worker      output_file = os.path.join(output_dir, archived_file)
44*6777b538SAndroid Build Coastguard Worker      try:
45*6777b538SAndroid Build Coastguard Worker        os.remove(output_file)
46*6777b538SAndroid Build Coastguard Worker      except OSError:
47*6777b538SAndroid Build Coastguard Worker        pass
48*6777b538SAndroid Build Coastguard Worker      os.rename(os.path.join(temp_dir, archived_file), output_file)
49*6777b538SAndroid Build Coastguard Worker  finally:
50*6777b538SAndroid Build Coastguard Worker    shutil.rmtree(temp_dir, True)
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Worker  if level != 0:
53*6777b538SAndroid Build Coastguard Worker    return level
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker  # The expand utility preserves the modification date and time of the archived
56*6777b538SAndroid Build Coastguard Worker  # file. Touch the extracted file. This helps build systems that compare the
57*6777b538SAndroid Build Coastguard Worker  # modification times of input and output files to determine whether to do an
58*6777b538SAndroid Build Coastguard Worker  # action.
59*6777b538SAndroid Build Coastguard Worker  os.utime(os.path.join(output_dir, archived_file), None)
60*6777b538SAndroid Build Coastguard Worker  return 0
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
64*6777b538SAndroid Build Coastguard Worker  sys.exit(main())
65