| OLD | NEW | 
|---|
| 1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be | 
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. | 
| 4 """Defines class Rietveld to easily access a rietveld instance. | 4 """Defines class Rietveld to easily access a rietveld instance. | 
| 5 | 5 | 
| 6 Security implications: | 6 Security implications: | 
| 7 | 7 | 
| 8 The following hypothesis are made: | 8 The following hypothesis are made: | 
| 9 - Rietveld enforces: | 9 - Rietveld enforces: | 
| 10   - Nobody else than issue owner can upload a patch set | 10   - Nobody else than issue owner can upload a patch set | 
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 114     url = '/download/issue%s_%s_%s.diff' % (issue, patchset, item) | 114     url = '/download/issue%s_%s_%s.diff' % (issue, patchset, item) | 
| 115     return self.get(url) | 115     return self.get(url) | 
| 116 | 116 | 
| 117   def get_patch(self, issue, patchset): | 117   def get_patch(self, issue, patchset): | 
| 118     """Returns a PatchSet object containing the details to apply this patch.""" | 118     """Returns a PatchSet object containing the details to apply this patch.""" | 
| 119     props = self.get_patchset_properties(issue, patchset) or {} | 119     props = self.get_patchset_properties(issue, patchset) or {} | 
| 120     out = [] | 120     out = [] | 
| 121     for filename, state in props.get('files', {}).iteritems(): | 121     for filename, state in props.get('files', {}).iteritems(): | 
| 122       logging.debug('%s' % filename) | 122       logging.debug('%s' % filename) | 
| 123       status = state.get('status') | 123       status = state.get('status') | 
| 124       if status is None: | 124       if not status: | 
| 125         raise patch.UnsupportedPatchFormat( | 125         raise patch.UnsupportedPatchFormat( | 
| 126             filename, 'File\'s status is None, patchset upload is incomplete.') | 126             filename, 'File\'s status is None, patchset upload is incomplete.') | 
|  | 127       if status[0] not in ('A', 'D', 'M'): | 
|  | 128         raise patch.UnsupportedPatchFormat( | 
|  | 129             filename, 'Change with status \'%s\' is not supported.' % status) | 
| 127 | 130 | 
| 128       if status[0] == 'D': | 131       svn_props = self.parse_svn_properties( | 
| 129         if status[0] != status.strip(): | 132           state.get('property_changes', ''), filename) | 
| 130           raise patch.UnsupportedPatchFormat( | 133 | 
| 131               filename, 'Deleted file shouldn\'t have property change.') | 134       if state.get('is_binary'): | 
| 132         # Ignore the diff. | 135         if status[0] == 'D': | 
| 133         out.append(patch.FilePatchDelete(filename, state['is_binary'])) | 136           if status[0] != status.strip(): | 
| 134       elif status[0] in ('A', 'M'): | 137             raise patch.UnsupportedPatchFormat( | 
| 135         svn_props = self.parse_svn_properties( | 138                 filename, 'Deleted file shouldn\'t have property change.') | 
| 136             state.get('property_changes', ''), filename) | 139           out.append(patch.FilePatchDelete(filename, state['is_binary'])) | 
| 137         if state['is_binary']: | 140         else: | 
| 138           out.append(patch.FilePatchBinary( | 141           out.append(patch.FilePatchBinary( | 
| 139               filename, | 142               filename, | 
| 140               self.get_file_content(issue, patchset, state['id']), | 143               self.get_file_content(issue, patchset, state['id']), | 
| 141               svn_props, | 144               svn_props, | 
| 142               is_new=(status[0] == 'A'))) | 145               is_new=(status[0] == 'A'))) | 
| 143         else: | 146         continue | 
| 144           # Ignores num_chunks since it may only contain an header. | 147 | 
| 145           diff = None | 148       try: | 
| 146           try: | 149         diff = self.get_file_diff(issue, patchset, state['id']) | 
| 147             diff = self.get_file_diff(issue, patchset, state['id']) | 150       except urllib2.HTTPError, e: | 
| 148           except urllib2.HTTPError, e: | 151         if e.code == 404: | 
| 149             if e.code == 404: | 152           raise patch.UnsupportedPatchFormat( | 
| 150               raise patch.UnsupportedPatchFormat( | 153               filename, 'File doesn\'t have a diff.') | 
| 151                   filename, 'File doesn\'t have a diff.') | 154         raise | 
| 152             raise | 155 | 
| 153           # It may happen on property-only change or svn copy without diff. | 156       # FilePatchDiff() will detect file deletion automatically. | 
| 154           if not diff: | 157       p = patch.FilePatchDiff(filename, diff, svn_props) | 
| 155             # Support this use case if it ever happen. | 158       out.append(p) | 
| 156             raise patch.UnsupportedPatchFormat( | 159       if status[0] == 'A': | 
| 157                 filename, 'Empty diff is not supported yet.\n') | 160         # It won't be set for empty file. | 
| 158           p = patch.FilePatchDiff(filename, diff, svn_props) | 161         p.is_new = True | 
| 159           out.append(p) | 162       if (len(status) > 1 and | 
| 160           if status[0] == 'A': | 163           status[1] == '+' and | 
| 161             # It won't be set for empty file. | 164           not (p.source_filename or p.svn_properties)): | 
| 162             p.is_new = True |  | 
| 163           if (len(status) > 1 and |  | 
| 164               status[1] == '+' and |  | 
| 165               not (p.source_filename or p.svn_properties)): |  | 
| 166             raise patch.UnsupportedPatchFormat( |  | 
| 167                 filename, 'Failed to process the svn properties') |  | 
| 168       else: |  | 
| 169         raise patch.UnsupportedPatchFormat( | 165         raise patch.UnsupportedPatchFormat( | 
| 170             filename, 'Change with status \'%s\' is not supported.' % status) | 166             filename, 'Failed to process the svn properties') | 
| 171 | 167 | 
| 172     return patch.PatchSet(out) | 168     return patch.PatchSet(out) | 
| 173 | 169 | 
| 174   @staticmethod | 170   @staticmethod | 
| 175   def parse_svn_properties(rietveld_svn_props, filename): | 171   def parse_svn_properties(rietveld_svn_props, filename): | 
| 176     """Returns a list of tuple [('property', 'newvalue')]. | 172     """Returns a list of tuple [('property', 'newvalue')]. | 
| 177 | 173 | 
| 178     rietveld_svn_props is the exact format from 'svn diff'. | 174     rietveld_svn_props is the exact format from 'svn diff'. | 
| 179     """ | 175     """ | 
| 180     rietveld_svn_props = rietveld_svn_props.splitlines() | 176     rietveld_svn_props = rietveld_svn_props.splitlines() | 
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 273         if retry >= (maxtries - 1): | 269         if retry >= (maxtries - 1): | 
| 274           raise | 270           raise | 
| 275         if not 'Name or service not known' in e.reason: | 271         if not 'Name or service not known' in e.reason: | 
| 276           # Usually internal GAE flakiness. | 272           # Usually internal GAE flakiness. | 
| 277           raise | 273           raise | 
| 278       # If reaching this line, loop again. Uses a small backoff. | 274       # If reaching this line, loop again. Uses a small backoff. | 
| 279       time.sleep(1+maxtries*2) | 275       time.sleep(1+maxtries*2) | 
| 280 | 276 | 
| 281   # DEPRECATED. | 277   # DEPRECATED. | 
| 282   Send = get | 278   Send = get | 
| OLD | NEW | 
|---|