Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: third_party/logilab/logilab/common/changelog.py

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 #
4 # This file is part of logilab-common.
5 #
6 # logilab-common is free software: you can redistribute it and/or modify it unde r
7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation, either version 2.1 of the License, or (at your option) an y
9 # later version.
10 #
11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 # details.
15 #
16 # You should have received a copy of the GNU Lesser General Public License along
17 # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
18 """Manipulation of upstream change log files.
19
20 The upstream change log files format handled is simpler than the one
21 often used such as those generated by the default Emacs changelog mode.
22
23 Sample ChangeLog format::
24
25 Change log for project Yoo
26 ==========================
27
28 --
29 * add a new functionality
30
31 2002-02-01 -- 0.1.1
32 * fix bug #435454
33 * fix bug #434356
34
35 2002-01-01 -- 0.1
36 * initial release
37
38
39 There is 3 entries in this change log, one for each released version and one
40 for the next version (i.e. the current entry).
41 Each entry contains a set of messages corresponding to changes done in this
42 release.
43 All the non empty lines before the first entry are considered as the change
44 log title.
45 """
46
47 __docformat__ = "restructuredtext en"
48
49 import sys
50 from stat import S_IWRITE
51
52 from six import string_types
53
54 BULLET = '*'
55 SUBBULLET = '-'
56 INDENT = ' ' * 4
57
58 class NoEntry(Exception):
59 """raised when we are unable to find an entry"""
60
61 class EntryNotFound(Exception):
62 """raised when we are unable to find a given entry"""
63
64 class Version(tuple):
65 """simple class to handle soft version number has a tuple while
66 correctly printing it as X.Y.Z
67 """
68 def __new__(cls, versionstr):
69 if isinstance(versionstr, string_types):
70 versionstr = versionstr.strip(' :') # XXX (syt) duh?
71 parsed = cls.parse(versionstr)
72 else:
73 parsed = versionstr
74 return tuple.__new__(cls, parsed)
75
76 @classmethod
77 def parse(cls, versionstr):
78 versionstr = versionstr.strip(' :')
79 try:
80 return [int(i) for i in versionstr.split('.')]
81 except ValueError as ex:
82 raise ValueError("invalid literal for version '%s' (%s)"%(versionstr , ex))
83
84 def __str__(self):
85 return '.'.join([str(i) for i in self])
86
87 # upstream change log #########################################################
88
89 class ChangeLogEntry(object):
90 """a change log entry, i.e. a set of messages associated to a version and
91 its release date
92 """
93 version_class = Version
94
95 def __init__(self, date=None, version=None, **kwargs):
96 self.__dict__.update(kwargs)
97 if version:
98 self.version = self.version_class(version)
99 else:
100 self.version = None
101 self.date = date
102 self.messages = []
103
104 def add_message(self, msg):
105 """add a new message"""
106 self.messages.append(([msg], []))
107
108 def complete_latest_message(self, msg_suite):
109 """complete the latest added message
110 """
111 if not self.messages:
112 raise ValueError('unable to complete last message as there is no pre vious message)')
113 if self.messages[-1][1]: # sub messages
114 self.messages[-1][1][-1].append(msg_suite)
115 else: # message
116 self.messages[-1][0].append(msg_suite)
117
118 def add_sub_message(self, sub_msg, key=None):
119 if not self.messages:
120 raise ValueError('unable to complete last message as there is no pre vious message)')
121 if key is None:
122 self.messages[-1][1].append([sub_msg])
123 else:
124 raise NotImplementedError("sub message to specific key are not imple mented yet")
125
126 def write(self, stream=sys.stdout):
127 """write the entry to file """
128 stream.write('%s -- %s\n' % (self.date or '', self.version or ''))
129 for msg, sub_msgs in self.messages:
130 stream.write('%s%s %s\n' % (INDENT, BULLET, msg[0]))
131 stream.write(''.join(msg[1:]))
132 if sub_msgs:
133 stream.write('\n')
134 for sub_msg in sub_msgs:
135 stream.write('%s%s %s\n' % (INDENT * 2, SUBBULLET, sub_msg[0]))
136 stream.write(''.join(sub_msg[1:]))
137 stream.write('\n')
138
139 stream.write('\n\n')
140
141 class ChangeLog(object):
142 """object representation of a whole ChangeLog file"""
143
144 entry_class = ChangeLogEntry
145
146 def __init__(self, changelog_file, title=''):
147 self.file = changelog_file
148 self.title = title
149 self.additional_content = ''
150 self.entries = []
151 self.load()
152
153 def __repr__(self):
154 return '<ChangeLog %s at %s (%s entries)>' % (self.file, id(self),
155 len(self.entries))
156
157 def add_entry(self, entry):
158 """add a new entry to the change log"""
159 self.entries.append(entry)
160
161 def get_entry(self, version='', create=None):
162 """ return a given changelog entry
163 if version is omitted, return the current entry
164 """
165 if not self.entries:
166 if version or not create:
167 raise NoEntry()
168 self.entries.append(self.entry_class())
169 if not version:
170 if self.entries[0].version and create is not None:
171 self.entries.insert(0, self.entry_class())
172 return self.entries[0]
173 version = self.version_class(version)
174 for entry in self.entries:
175 if entry.version == version:
176 return entry
177 raise EntryNotFound()
178
179 def add(self, msg, create=None):
180 """add a new message to the latest opened entry"""
181 entry = self.get_entry(create=create)
182 entry.add_message(msg)
183
184 def load(self):
185 """ read a logilab's ChangeLog from file """
186 try:
187 stream = open(self.file)
188 except IOError:
189 return
190 last = None
191 expect_sub = False
192 for line in stream.readlines():
193 sline = line.strip()
194 words = sline.split()
195 # if new entry
196 if len(words) == 1 and words[0] == '--':
197 expect_sub = False
198 last = self.entry_class()
199 self.add_entry(last)
200 # if old entry
201 elif len(words) == 3 and words[1] == '--':
202 expect_sub = False
203 last = self.entry_class(words[0], words[2])
204 self.add_entry(last)
205 # if title
206 elif sline and last is None:
207 self.title = '%s%s' % (self.title, line)
208 # if new entry
209 elif sline and sline[0] == BULLET:
210 expect_sub = False
211 last.add_message(sline[1:].strip())
212 # if new sub_entry
213 elif expect_sub and sline and sline[0] == SUBBULLET:
214 last.add_sub_message(sline[1:].strip())
215 # if new line for current entry
216 elif sline and last.messages:
217 last.complete_latest_message(line)
218 else:
219 expect_sub = True
220 self.additional_content += line
221 stream.close()
222
223 def format_title(self):
224 return '%s\n\n' % self.title.strip()
225
226 def save(self):
227 """write back change log"""
228 # filetutils isn't importable in appengine, so import locally
229 from logilab.common.fileutils import ensure_fs_mode
230 ensure_fs_mode(self.file, S_IWRITE)
231 self.write(open(self.file, 'w'))
232
233 def write(self, stream=sys.stdout):
234 """write changelog to stream"""
235 stream.write(self.format_title())
236 for entry in self.entries:
237 entry.write(stream)
238
OLDNEW
« no previous file with comments | « third_party/logilab/logilab/common/cache.py ('k') | third_party/logilab/logilab/common/clcommands.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698