OLD | NEW |
(Empty) | |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this server2 code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import logging |
| 6 from object_store_creator import ObjectStoreCreator |
| 7 import random |
| 8 |
| 9 class _Info(object): |
| 10 '''Info about the revision pinning. Properties: |
| 11 |server2_version| The last known version of server2 source. |
| 12 |fs_version | The current safe version of the file system. This isn't |
| 13 necessarily related to |server2_version|. |
| 14 |pinned| None if there is no pin. The password (string) to unpin it |
| 15 if it is pinned. |
| 16 ''' |
| 17 def __init__(self, server2_version, root_version, pinned=None): |
| 18 self.server2_version = server2_version |
| 19 self.root_version = root_version |
| 20 self.pinned = pinned |
| 21 |
| 22 # TODO(kalman): RevisionInfo? VersionInfo? VersionPinner? |
| 23 class RevisionPinner(object): |
| 24 '''Tracks the subversion version that each branch is pinned to. |
| 25 |
| 26 Responsible for pausing branches when any of the directories that server2 |
| 27 server2 is pulled from changes. |
| 28 |
| 29 Generates and exposes a method to unpin those values. |
| 30 ''' |
| 31 @staticmethod |
| 32 def CreateForSubversion(branch, |
| 33 svn_file_system, |
| 34 object_store_creator_factory): |
| 35 server2_dirs = [ |
| 36 'chrome/common/extensions/docs/server2/', |
| 37 'third_party/handlebar/', |
| 38 'tools/json_schema_compiler/' |
| 39 'tools/json_schema_eater/' |
| 40 ] |
| 41 return RevisionPinner(branch, |
| 42 svn_file_system, |
| 43 object_store_creator_factory, |
| 44 server2_dirs) |
| 45 |
| 46 def __init__(self, |
| 47 branch, |
| 48 file_system, |
| 49 object_store_creator_factory, |
| 50 server2_dirs): |
| 51 self._branch = branch |
| 52 self._file_system = file_system |
| 53 self._object_store = ( |
| 54 object_store_creator_factory.Create(RevisionPinner).Create( |
| 55 category=file_system.GetName())) |
| 56 self._server2_dirs = server2_dirs |
| 57 |
| 58 def Update(self): |
| 59 '''Checks to see whether there have been any changes to the server2 dirs. |
| 60 If so, pin at the current version with an option to unpin. |
| 61 Otherwise, bump the version. |
| 62 ''' |
| 63 server2_version = max( |
| 64 int(self._file_system.Stat(server2_dir).version) |
| 65 for server2_dir in self._server2_dirs) |
| 66 root_version = int(self._file_system.Stat('/').version) |
| 67 logging.info('server2_version: %s, root_version: %s' % ( |
| 68 server2_version, root_version)) |
| 69 |
| 70 info = self._object_store.Get('info') |
| 71 |
| 72 if info is None: |
| 73 logging.info('No existing info') |
| 74 info = _Info(server2_version, root_version) |
| 75 elif info.pinned: |
| 76 logging.info('Still pinned at %s' % info.root_version) |
| 77 info = _Info(server2_version, info.root_version, pinned=info.pinned) |
| 78 elif server2_version <= info.server2_version: |
| 79 logging.info('No change in server2 version') |
| 80 # Ok, the version probably isn't going to *regress* but be safe anyway. |
| 81 # Who knows what might happen to SVN. |
| 82 info = _Info(server2_version, root_version) |
| 83 else: |
| 84 logging.info('server2 version increased from %s to %s' % ( |
| 85 server2_version, info.server2_version)) |
| 86 # New version of server2! Pin it: root_version doesn't increase, and |
| 87 # the pin bit is flipped. |
| 88 password = self._GeneratePassword() |
| 89 info = _Info(server2_version, info.root_version, pinned=password) |
| 90 self._NotifyPinned(info.root_version, password) |
| 91 |
| 92 self._object_store.Set('info', info) |
| 93 |
| 94 def _GeneratePassword(self): |
| 95 # TODO(kalman): generate a prettier password using full alphanumerics. |
| 96 return ''.join(map(str, random.sample(xrange(100, 999), 10))) |
| 97 |
| 98 def _OnPinned(self, revision, pinned): |
| 99 '''Called when the file system is pinned at |revision| using |password|. |
| 100 Set up a way to unpin it: send email to kalman@ with an unlock pin. |
| 101 ''' |
| 102 logging.warning('PINNED AT %s' % self._GenerateUnlockURL(pinned)) |
| 103 |
| 104 def _GenerateUnlockURL(self, pinned): |
| 105 assert pinned |
| 106 # TODO(kalman): Include hostname. |
| 107 return '/_unpin/%s/%s' % (branch, pinned) |
| 108 |
| 109 def GetRevision(self): |
| 110 '''Gets the revision that |file_system| is currently pinned at. |
| 111 ''' |
| 112 return self._object_store.Get('info').Get().root_version |
| 113 |
| 114 def GetPinned(self): |
| 115 '''Gets the pinned password if |file_system| is pinned, None if not. |
| 116 ''' |
| 117 return self._object_store.Get('info').Get().pinned |
| 118 |
| 119 def Unpin(self, password): |
| 120 '''Unpins using |password|. Returns true if successful, false if not. |
| 121 ''' |
| 122 if self.GetPinned() != password: |
| 123 return False |
| 124 self._object_store.Del('info') |
| 125 self.Update() |
| 126 return True |
OLD | NEW |