xref: /aosp_15_r20/external/skia/infra/bots/zip_utils.py (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/env python
2*c8dee2aaSAndroid Build Coastguard Worker#
3*c8dee2aaSAndroid Build Coastguard Worker# Copyright 2016 Google Inc.
4*c8dee2aaSAndroid Build Coastguard Worker#
5*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
6*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file.
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Worker"""Utilities for zipping and unzipping files."""
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker
12*c8dee2aaSAndroid Build Coastguard Workerfrom __future__ import print_function
13*c8dee2aaSAndroid Build Coastguard Workerimport fnmatch
14*c8dee2aaSAndroid Build Coastguard Workerimport ntpath
15*c8dee2aaSAndroid Build Coastguard Workerimport os
16*c8dee2aaSAndroid Build Coastguard Workerimport posixpath
17*c8dee2aaSAndroid Build Coastguard Workerimport zipfile
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker
20*c8dee2aaSAndroid Build Coastguard Workerdef filtered(names, to_skip):
21*c8dee2aaSAndroid Build Coastguard Worker  """Filter the list of file or directory names."""
22*c8dee2aaSAndroid Build Coastguard Worker  rv = names[:]
23*c8dee2aaSAndroid Build Coastguard Worker  for pattern in to_skip:
24*c8dee2aaSAndroid Build Coastguard Worker    rv = [n for n in rv if not fnmatch.fnmatch(n, pattern)]
25*c8dee2aaSAndroid Build Coastguard Worker  return rv
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Workerdef zip(target_dir, zip_file, to_skip=None):  # pylint: disable=W0622
29*c8dee2aaSAndroid Build Coastguard Worker  """Zip the given directory, write to the given zip file."""
30*c8dee2aaSAndroid Build Coastguard Worker  if not os.path.isdir(target_dir):
31*c8dee2aaSAndroid Build Coastguard Worker    raise IOError('%s does not exist!' % target_dir)
32*c8dee2aaSAndroid Build Coastguard Worker  to_skip = to_skip or []
33*c8dee2aaSAndroid Build Coastguard Worker  with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED, True) as z:
34*c8dee2aaSAndroid Build Coastguard Worker    for r, d, f in os.walk(target_dir, topdown=True):
35*c8dee2aaSAndroid Build Coastguard Worker      d[:] = filtered(d, to_skip)
36*c8dee2aaSAndroid Build Coastguard Worker      for filename in filtered(f, to_skip):
37*c8dee2aaSAndroid Build Coastguard Worker        filepath = os.path.join(r, filename)
38*c8dee2aaSAndroid Build Coastguard Worker        zi = zipfile.ZipInfo(filepath)
39*c8dee2aaSAndroid Build Coastguard Worker        zi.filename = os.path.relpath(filepath, target_dir)
40*c8dee2aaSAndroid Build Coastguard Worker        if os.name == 'nt':
41*c8dee2aaSAndroid Build Coastguard Worker          # Dumb path separator replacement for Windows.
42*c8dee2aaSAndroid Build Coastguard Worker          zi.filename = zi.filename.replace(ntpath.sep, posixpath.sep)
43*c8dee2aaSAndroid Build Coastguard Worker        try:
44*c8dee2aaSAndroid Build Coastguard Worker          perms = os.stat(filepath).st_mode
45*c8dee2aaSAndroid Build Coastguard Worker        except OSError:
46*c8dee2aaSAndroid Build Coastguard Worker          if os.path.islink(filepath):
47*c8dee2aaSAndroid Build Coastguard Worker            print('Skipping symlink %s' % filepath)
48*c8dee2aaSAndroid Build Coastguard Worker            continue
49*c8dee2aaSAndroid Build Coastguard Worker          else:
50*c8dee2aaSAndroid Build Coastguard Worker            raise
51*c8dee2aaSAndroid Build Coastguard Worker        zi.external_attr = perms << 16
52*c8dee2aaSAndroid Build Coastguard Worker        zi.compress_type = zipfile.ZIP_DEFLATED
53*c8dee2aaSAndroid Build Coastguard Worker        with open(filepath, 'rb') as f:
54*c8dee2aaSAndroid Build Coastguard Worker          content = f.read()
55*c8dee2aaSAndroid Build Coastguard Worker        z.writestr(zi, content)
56*c8dee2aaSAndroid Build Coastguard Worker      for dirname in d:
57*c8dee2aaSAndroid Build Coastguard Worker        dirpath = os.path.join(r, dirname)
58*c8dee2aaSAndroid Build Coastguard Worker        z.write(dirpath, os.path.relpath(dirpath, target_dir))
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker
61*c8dee2aaSAndroid Build Coastguard Workerdef unzip(zip_file, target_dir):
62*c8dee2aaSAndroid Build Coastguard Worker  """Unzip the given zip file into the target dir."""
63*c8dee2aaSAndroid Build Coastguard Worker  if not os.path.isdir(target_dir):
64*c8dee2aaSAndroid Build Coastguard Worker    os.makedirs(target_dir)
65*c8dee2aaSAndroid Build Coastguard Worker  with zipfile.ZipFile(zip_file, 'r', zipfile.ZIP_DEFLATED, True) as z:
66*c8dee2aaSAndroid Build Coastguard Worker    for zi in z.infolist():
67*c8dee2aaSAndroid Build Coastguard Worker      dst_subpath = zi.filename
68*c8dee2aaSAndroid Build Coastguard Worker      if os.name == 'nt':
69*c8dee2aaSAndroid Build Coastguard Worker        # Dumb path separator replacement for Windows.
70*c8dee2aaSAndroid Build Coastguard Worker        dst_subpath = dst_subpath.replace(posixpath.sep, ntpath.sep)
71*c8dee2aaSAndroid Build Coastguard Worker      dst_path = os.path.join(target_dir, dst_subpath)
72*c8dee2aaSAndroid Build Coastguard Worker      if dst_path.endswith(os.path.sep):
73*c8dee2aaSAndroid Build Coastguard Worker        os.mkdir(dst_path)
74*c8dee2aaSAndroid Build Coastguard Worker      else:
75*c8dee2aaSAndroid Build Coastguard Worker        with open(dst_path, 'wb') as f:
76*c8dee2aaSAndroid Build Coastguard Worker          f.write(z.read(zi))
77*c8dee2aaSAndroid Build Coastguard Worker      perms = zi.external_attr >> 16
78*c8dee2aaSAndroid Build Coastguard Worker      os.chmod(dst_path, perms)
79