• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import glob
6import os
7import shutil
8
9from dependency_manager import exceptions
10from dependency_manager import dependency_manager_util
11
12
13class ArchiveInfo(object):
14
15  def __init__(self, archive_file, unzip_path, path_within_archive,
16               stale_unzip_path_glob=None):
17    """ Container for the information needed to unzip a downloaded archive.
18
19    Args:
20        archive_path: Path to the archive file.
21        unzip_path: Path to unzip the archive into. Assumes that this path
22            is unique for the archive.
23        path_within_archive: Specify if and how to handle zip archives
24            downloaded from cloud_storage. Expected values:
25                None: Do not unzip the file downloaded from cloud_storage.
26                '.': Unzip the file downloaded from cloud_storage. The
27                    unzipped file/folder is the expected dependency.
28                file_path: Unzip the file downloaded from cloud_storage.
29                    |file_path| is the path to the expected dependency,
30                    relative to the unzipped archive path.
31        stale_unzip_path_glob: Optional argument specifying a glob matching
32            string which matches directories that should be removed before this
33            archive is extracted (if it is extracted at all).
34    """
35    self._archive_file = archive_file
36    self._unzip_path = unzip_path
37    self._path_within_archive = path_within_archive
38    self._dependency_path = os.path.join(
39        self._unzip_path, self._path_within_archive)
40    self._stale_unzip_path_glob = stale_unzip_path_glob
41    if not self._has_minimum_data:
42      raise ValueError(
43          'Not enough information specified to initialize an archive info.'
44          ' %s' % self)
45
46  def GetUnzippedPath(self):
47    if self.ShouldUnzipArchive():
48      # Remove stale unzip results
49      if self._stale_unzip_path_glob:
50        for path in glob.glob(self._stale_unzip_path_glob):
51          shutil.rmtree(path, ignore_errors=True)
52      # TODO(aiolos): Replace UnzipFile with zipfile.extractall once python
53      # version 2.7.4 or later can safely be assumed.
54      dependency_manager_util.UnzipArchive(
55          self._archive_file, self._unzip_path)
56      if self.ShouldUnzipArchive():
57        raise exceptions.ArchiveError(
58            "Expected path '%s' was not extracted from archive '%s'." %
59            (self._dependency_path, self._archive_file))
60    return self._dependency_path
61
62  def ShouldUnzipArchive(self):
63    if not self._has_minimum_data:
64      raise exceptions.ArchiveError(
65          'Missing needed info to unzip archive. Know data: %s' % self)
66    return not os.path.exists(self._dependency_path)
67
68  @property
69  def _has_minimum_data(self):
70    return all([self._archive_file, self._unzip_path,
71                self._dependency_path])
72
73  def __repr__(self):
74    return (
75        'ArchiveInfo(archive_file=%s, unzip_path=%s, path_within_archive=%s, '
76        'dependency_path =%s)' % (
77            self._archive_file, self._unzip_path, self._path_within_archive,
78            self._dependency_path))
79
80