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