1#!/usr/bin/env python
2# Copyright (C) 2010 Google Inc. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7#
8# 1. Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25from __future__ import with_statement
26
27import os
28import shutil
29
30from webkitpy.common.net.remotezip import ZipFileHandle
31from webkitpy.common.system.filesystem import FileSystem
32import webkitpy.common.system.ospath as ospath
33
34
35class DirAsZip(object):
36 """Provides a zipfile-like interface to a local directory"""
37 def __init__(self, path, filesystem=None):
38 self._path = path
39 self._filesystem = filesystem if filesystem != None else FileSystem()
40 if not self._path.endswith(os.path.sep):
41 self._path += os.path.sep
42
43 def _full_path(self, filename):
44 assert self._is_under(self._path, filename)
45 return os.path.join(self._path, filename)
46
47 def _drop_directory_prefix(self, path):
48 return path[len(self._path):]
49
50 def _files_in_directory(self):
51 """Returns a list of all the files in the directory, including the path
52 to the directory"""
53 return [os.path.join(path, filename)
54 for (path, _, filenames) in os.walk(self._path)
55 for filename in filenames]
56
57 def _is_under(self, dir, filename):
58 return ospath.relpath(os.path.join(dir, filename), dir) is not None
59
60 def open(self, filename):
61 return ZipFileHandle(self, filename)
62
63 def namelist(self):
64 return map(self._drop_directory_prefix, self._files_in_directory())
65
66 def read(self, filename):
67 return self._filesystem.read_text_file(self._full_path(filename))
68
69 def extract(self, filename, path):
70 """Extracts a file from this 'zip archive' to the specified directory."""
71 src = self._full_path(filename)
72 dest = os.path.join(path, filename)
73 # As filename may have slashes in it, we must ensure that the same
74 # directory heirarchy exists at the output path.
75 self._filesystem.maybe_make_directory(os.path.split(dest)[0])
76 self._filesystem.copyfile(src, dest)
77
78 def delete(self, filename):
79 filename = self._full_path(filename)
80 self._filesystem.remove(filename)