diff --git a/gcl.py b/gcl.py index e6638e461..fb355e586 100755 --- a/gcl.py +++ b/gcl.py @@ -20,6 +20,20 @@ import time from third_party import upload import urllib2 +try: + import simplejson as json +except ImportError: + try: + import json + # Some versions of python2.5 have an incomplete json module. Check to make + # sure loads exists. + # pylint: disable=W0104 + json.loads + except (ImportError, AttributeError): + # Import the one included in depot_tools. + sys.path.append(os.path.join(os.path.dirname(__file__), 'third_party')) + import simplejson as json + import breakpad # gcl now depends on gclient. @@ -317,14 +331,13 @@ class ChangeInfo(object): def Save(self): """Writes the changelist information to disk.""" - if self.NeedsUpload(): - needs_upload = "dirty" - else: - needs_upload = "clean" - data = ChangeInfo._SEPARATOR.join([ - "%d, %d, %s" % (self.issue, self.patchset, needs_upload), - "\n".join([f[0] + f[1] for f in self.GetFiles()]), - self.description]) + data = json.dumps({ + 'issue': self.issue, + 'patchset': self.patchset, + 'needs_upload': self.NeedsUpload(), + 'files': self.GetFiles(), + 'description': self.description, + }, sort_keys=True, indent=2) gclient_utils.FileWrite(GetChangelistInfoFile(self.name), data) def Delete(self): @@ -445,12 +458,16 @@ class ChangeInfo(object): content = gclient_utils.FileRead(info_file, 'r') save = False try: - values = ChangeInfo._LoadOldFormat(content) + values = ChangeInfo._LoadNewFormat(content) except ValueError: - ErrorExit( - ('Changelist file %s is corrupt.\n' - 'Either run "gcl delete %s" or manually edit the file') % ( - info_file, changename)) + try: + values = ChangeInfo._LoadOldFormat(content) + save = True + except ValueError: + ErrorExit( + ('Changelist file %s is corrupt.\n' + 'Either run "gcl delete %s" or manually edit the file') % ( + info_file, changename)) files = values['files'] if update_status: for item in files[:]: @@ -497,6 +514,10 @@ class ChangeInfo(object): values['description'] = split_data[2] return values + @staticmethod + def _LoadNewFormat(content): + return json.loads(content) + def GetChangelistInfoFile(changename): """Returns the file that stores information about a changelist.""" diff --git a/tests/gcl_unittest.py b/tests/gcl_unittest.py index fa05cc366..0b62840d9 100755 --- a/tests/gcl_unittest.py +++ b/tests/gcl_unittest.py @@ -53,7 +53,7 @@ class GclUnittest(GclTestsBase): 'RunShell', 'RunShellWithReturnCode', 'SVN', 'SendToRietveld', 'TryChange', 'UnknownFiles', 'Warn', 'attrs', 'breakpad', 'defer_attributes', 'gclient_utils', 'getpass', - 'main', 'need_change', 'need_change_and_args', 'no_args', 'os', + 'json', 'main', 'need_change', 'need_change_and_args', 'no_args', 'os', 'random', 're', 'string', 'subprocess', 'sys', 'tempfile', 'time', 'upload', 'urllib2', ] @@ -166,6 +166,9 @@ class ChangeInfoUnittest(GclTestsBase): gcl.os.path.exists('bleeeh').AndReturn(True) gcl.gclient_utils.FileRead('bleeeh', 'r').AndReturn( gcl.ChangeInfo._SEPARATOR.join(["42, 53", "G b.cc"] + description)) + # Does an upgrade. + gcl.GetChangelistInfoFile('bleh').AndReturn('bleeeh') + gcl.gclient_utils.FileWrite('bleeeh', mox.IgnoreArg()) self.mox.ReplayAll() change_info = gcl.ChangeInfo.Load('bleh', self.fake_root_dir, True, False) @@ -181,6 +184,9 @@ class ChangeInfoUnittest(GclTestsBase): gcl.os.path.exists('bleeeh').AndReturn(True) gcl.gclient_utils.FileRead('bleeeh', 'r').AndReturn( gcl.ChangeInfo._SEPARATOR.join(["", "", ""])) + # Does an upgrade. + gcl.GetChangelistInfoFile('bleh').AndReturn('bleeeh') + gcl.gclient_utils.FileWrite('bleeeh', mox.IgnoreArg()) self.mox.ReplayAll() change_info = gcl.ChangeInfo.Load('bleh', self.fake_root_dir, True, False) @@ -192,22 +198,26 @@ class ChangeInfoUnittest(GclTestsBase): def testSaveEmpty(self): gcl.GetChangelistInfoFile('').AndReturn('foo') + values = { + 'description': '', 'patchset': 2, 'issue': 1, + 'files': [], 'needs_upload': False} gcl.gclient_utils.FileWrite( - 'foo', - gcl.ChangeInfo._SEPARATOR.join(['0, 0, clean', '', ''])) + 'foo', gcl.json.dumps(values, sort_keys=True, indent=2)) self.mox.ReplayAll() - change_info = gcl.ChangeInfo('', 0, 0, '', None, self.fake_root_dir) + change_info = gcl.ChangeInfo('', 1, 2, '', None, self.fake_root_dir) change_info.Save() def testSaveDirty(self): - gcl.GetChangelistInfoFile('').AndReturn('foo') + gcl.GetChangelistInfoFile('n').AndReturn('foo') + values = { + 'description': 'des', 'patchset': 0, 'issue': 0, + 'files': [], 'needs_upload': True} gcl.gclient_utils.FileWrite( - 'foo', - gcl.ChangeInfo._SEPARATOR.join(['0, 0, dirty', '', ''])) + 'foo', gcl.json.dumps(values, sort_keys=True, indent=2)) self.mox.ReplayAll() - change_info = gcl.ChangeInfo('', 0, 0, '', None, self.fake_root_dir, + change_info = gcl.ChangeInfo('n', 0, 0, 'des', None, self.fake_root_dir, needs_upload=True) change_info.Save()