1# Copyright 2013 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 5from caching_file_system import CachingFileSystem 6from gitiles_file_system import GitilesFileSystem 7from local_file_system import LocalFileSystem 8from offline_file_system import OfflineFileSystem 9from gitiles_file_system import GitilesFileSystem 10from third_party.json_schema_compiler.memoize import memoize 11 12 13class HostFileSystemProvider(object): 14 '''Provides host file systems ("host" meaning the file system that hosts the 15 server's source code and templates) tracking master, or any branch. 16 17 File system instances are memoized to maintain the in-memory caches across 18 multiple callers. 19 ''' 20 def __init__(self, 21 object_store_creator, 22 pinned_commit=None, 23 default_master_instance=None, 24 offline=False, 25 constructor_for_test=None): 26 ''' 27 |object_store_creator| 28 Provides caches for file systems that need one. 29 |pinned_commit| 30 If not None, the commit at which a 'master' file system will be created. 31 If None, 'master' file systems will use HEAD. 32 |default_master_instance| 33 If not None, 'master' file systems provided by this class without a 34 specific commit will return |default_master_instance| instead. 35 |offline| 36 If True all provided file systems will be wrapped in an OfflineFileSystem. 37 |constructor_for_test| 38 Provides a custom constructor rather than creating GitilesFileSystems. 39 ''' 40 self._object_store_creator = object_store_creator 41 self._pinned_commit = pinned_commit 42 self._default_master_instance = default_master_instance 43 self._offline = offline 44 self._constructor_for_test = constructor_for_test 45 46 @memoize 47 def GetMaster(self, commit=None): 48 '''Gets a file system tracking 'master'. Use this method rather than 49 GetBranch('master') because the behaviour is subtly different; 'master' can 50 be pinned to a specific commit (|pinned_commit| in constructor) and can have 51 have its default instance overridden (|default_master_instance| in the 52 constructor). 53 54 |commit| if non-None determines a specific commit to pin the host file 55 system at, though it will be ignored if it's newer than |pinned_commit|. 56 If None then |commit| will track |pinned_commit| if is has been 57 set, or just HEAD (which might change during server runtime!). 58 ''' 59 if commit is None: 60 if self._default_master_instance is not None: 61 return self._default_master_instance 62 return self._Create('master', commit=self._pinned_commit) 63 if self._pinned_commit is not None: 64 # XXX(ahernandez): THIS IS WRONG. Should be 65 # commit = Oldest(commit, self._pinned_commit). 66 commit = min(commit, self._pinned_commit) 67 return self._Create('master', commit=commit) 68 69 @memoize 70 def GetBranch(self, branch): 71 '''Gets a file system tracking |branch|, for example '1150' - anything other 72 than 'master', which must be constructed via the GetMaster() method. 73 74 Note: Unlike GetMaster this function doesn't take a |commit| argument 75 since we assume that branches hardly ever change, while master frequently 76 changes. 77 ''' 78 assert isinstance(branch, basestring), 'Branch %s must be a string' % branch 79 assert branch != 'master', ( 80 'Cannot specify branch=\'master\', use GetMaster()') 81 return self._Create(branch) 82 83 def _Create(self, branch, commit=None): 84 '''Creates Gitiles file systems (or if in a test, potentially whatever 85 |self._constructor_for_test specifies). Wraps the resulting file system in 86 an Offline file system if the offline flag is set, and finally wraps it in 87 a Caching file system. 88 ''' 89 if self._constructor_for_test is not None: 90 file_system = self._constructor_for_test(branch=branch, commit=commit) 91 else: 92 file_system = GitilesFileSystem.Create(branch=branch, commit=commit) 93 if self._offline: 94 file_system = OfflineFileSystem(file_system) 95 return CachingFileSystem(file_system, self._object_store_creator) 96 97 @staticmethod 98 def ForLocal(object_store_creator, **optargs): 99 '''Used in creating a server instance on localhost. 100 ''' 101 return HostFileSystemProvider( 102 object_store_creator, 103 constructor_for_test=lambda **_: LocalFileSystem.Create(), 104 **optargs) 105 106 @staticmethod 107 def ForTest(file_system, object_store_creator, **optargs): 108 '''Used in creating a test server instance. The HostFileSystemProvider 109 returned here will always return |file_system| when its Create() method is 110 called. 111 ''' 112 return HostFileSystemProvider( 113 object_store_creator, 114 constructor_for_test=lambda **_: file_system, 115 **optargs) 116