OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2012 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 |
| 5 import json |
| 6 import os |
| 7 |
| 8 import appengine_blobstore as blobstore |
| 9 import appengine_memcache as memcache |
| 10 import file_system |
| 11 from io import BytesIO |
| 12 from future import Future |
| 13 from zipfile import ZipFile |
| 14 |
| 15 ZIP_KEY = 'zipball' |
| 16 |
| 17 def _MakeKey(version): |
| 18 return ZIP_KEY + '.' + str(version) |
| 19 |
| 20 class _AsyncFetchFutureZip(object): |
| 21 def __init__(self, fetcher, blobstore, new_version, old_version): |
| 22 self._fetch = fetcher.FetchAsync(ZIP_KEY) |
| 23 self._blobstore = blobstore |
| 24 self._new_version = new_version |
| 25 self._old_version = old_version |
| 26 |
| 27 def Get(self): |
| 28 blob = self._fetch.Get().content |
| 29 self._blobstore.Set(_MakeKey(self._new_version), |
| 30 blob, |
| 31 blobstore.BLOBSTORE_GITHUB) |
| 32 self._blobstore.Delete(_MakeKey(self._old_version), |
| 33 blobstore.BLOBSTORE_GITHUB) |
| 34 return ZipFile(BytesIO(blob)) |
| 35 |
| 36 class GithubFileSystem(file_system.FileSystem): |
| 37 """FileSystem implementation which fetches resources from github. |
| 38 """ |
| 39 def __init__(self, fetcher, memcache, blobstore): |
| 40 self._fetcher = fetcher |
| 41 self._memcache = memcache |
| 42 self._blobstore = blobstore |
| 43 self._version = self.Stat(ZIP_KEY).version |
| 44 self._GetZip(self._version) |
| 45 |
| 46 def _GetZip(self, version): |
| 47 blob = self._blobstore.Get(_MakeKey(version), blobstore.BLOBSTORE_GITHUB) |
| 48 if blob is not None: |
| 49 self._zip_file = Future(value=ZipFile(BytesIO(blob))) |
| 50 else: |
| 51 self._zip_file = Future(delegate=_AsyncFetchFutureZip(self._fetcher, |
| 52 self._blobstore, |
| 53 version, |
| 54 self._version)) |
| 55 self._version = version |
| 56 |
| 57 def _ReadFile(self, path): |
| 58 zip_file = self._zip_file.Get() |
| 59 prefix = zip_file.namelist()[0][:-1] |
| 60 return zip_file.read(prefix + path) |
| 61 |
| 62 def _ListDir(self, path): |
| 63 filenames = self._zip_file.Get().namelist() |
| 64 # Take out parent directory name (GoogleChrome-chrome-app-samples-c78a30f) |
| 65 filenames = [f[len(filenames[0]) - 1:] for f in filenames] |
| 66 # Remove the path of the directory we're listing from the filenames. |
| 67 filenames = [f[len(path):] for f in filenames |
| 68 if f != path and f.startswith(path)] |
| 69 # Remove all files not directly in this directory. |
| 70 return [f for f in filenames if f[:-1].count('/') == 0] |
| 71 |
| 72 def Read(self, paths, binary=False): |
| 73 version = self.Stat(ZIP_KEY).version |
| 74 if version != self._version: |
| 75 self._GetZip(version) |
| 76 result = {} |
| 77 for path in paths: |
| 78 if path.endswith('/'): |
| 79 result[path] = self._ListDir(path) |
| 80 else: |
| 81 result[path] = self._ReadFile(path) |
| 82 return Future(value=result) |
| 83 |
| 84 def Stat(self, path): |
| 85 version = self._memcache.Get(path, memcache.MEMCACHE_GITHUB_STAT) |
| 86 if version is not None: |
| 87 return self.StatInfo(version) |
| 88 version = json.loads( |
| 89 self._fetcher.Fetch('commits/HEAD').content)['commit']['tree']['sha'] |
| 90 self._memcache.Set(path, version, memcache.MEMCACHE_GITHUB_STAT) |
| 91 return self.StatInfo(version) |
OLD | NEW |