3 # Future imports for Python 2.7, mandatory in 3.0
4 from __future__
import division
5 from __future__
import print_function
6 from __future__
import unicode_literals
22 "New system requirements",
25 "Code simplification and refactoring",
27 "Deprecated features",
28 "Directory authority changes",
30 # These aren't preferred, but sortChanges knows how to clean them up.
31 "Code simplifications and refactoring",
32 "Code simplification and refactorings",
33 "Code simplifications and refactorings"])
35 NEEDS_SUBCATEGORIES
= set([
46 def split_tor_version(version
):
48 Return the initial numeric components of the Tor version as a list of ints.
49 For versions earlier than 0.1.0, returns MAJOR, MINOR, and MICRO.
50 For versions 0.1.0 and later, returns MAJOR, MINOR, MICRO, and PATCHLEVEL if present.
52 If the version is malformed, returns None.
54 version_match
= re
.match('([0-9]+)\.([0-9]+)\.([0-9]+)(\.([0-9]+))?', version
)
55 if version_match
is None:
58 version_groups
= version_match
.groups()
59 if version_groups
is None:
61 if len(version_groups
) < 3:
64 if len(version_groups
) != 5:
66 version_components
= version_groups
[0:3]
67 version_components
+= version_groups
[4:5]
70 version_list
= [int(v
) for v
in version_components
if v
is not None]
82 print("{}:".format(fname
))
83 print("\t{}".format(s
))
85 m
= re
.search(r
'(\d{3,})', os
.path
.basename(fname
))
91 with
open(fname
) as f
:
94 if bugnum
and bugnum
not in contents
:
95 warn("bug number {} does not appear".format(bugnum
))
97 m
= re
.match(r
'^[ ]{2}o ([^\(:]*)([^:]*):', contents
)
99 warn("Header not in format expected. (' o Foo:' or ' o Foo (Bar):')")
100 elif m
.group(1).strip() not in KNOWN_GROUPS
:
101 warn("Unrecognized header: %r" % m
.group(1))
102 elif (m
.group(1) in NEEDS_SUBCATEGORIES
and '(' not in m
.group(2)):
103 warn("Missing subcategory on %r" % m
.group(1))
106 isBug
= ("bug" in m
.group(1).lower() or "fix" in m
.group(1).lower())
110 contents
= " ".join(contents
.split())
112 if re
.search(r
'\#\d{2,}', contents
):
113 warn("Don't use a # before ticket numbers. ('bug 1234' not '#1234')")
115 if isBug
and not re
.search(r
'(\d+)', contents
):
116 warn("Ticket marked as bugfix, but does not mention a number.")
117 elif isBug
and not re
.search(r
'Fixes ([a-z ]*)bugs? (\d+)', contents
):
118 warn("Ticket marked as bugfix, but does not say 'Fixes bug XXX'")
120 if re
.search(r
'[bB]ug (\d+)', contents
):
121 if not re
.search(r
'[Bb]ugfix on ', contents
):
122 warn("Bugfix does not say 'bugfix on X.Y.Z'")
123 elif not re
.search('[fF]ixes ([a-z ]*)bugs? (\d+)((, \d+)* and \d+)?; bugfix on ',
125 warn("Bugfix does not say 'Fixes bug X; bugfix on Y'")
126 elif re
.search('tor-([0-9]+)', contents
):
127 warn("Do not prefix versions with 'tor-'. ('0.1.2', not 'tor-0.1.2'.)")
129 bugfix_match
= re
.search('bugfix on ([0-9]+\.[0-9]+\.[0-9]+)', contents
)
130 if bugfix_match
is None:
131 warn("Versions must have at least 3 digits. ('0.1.2', '0.3.4.8', or '0.3.5.1-alpha'.)")
132 elif bugfix_match
.group(0) is None:
133 warn("Versions must have at least 3 digits. ('0.1.2', '0.3.4.8', or '0.3.5.1-alpha'.)")
135 bugfix_match
= re
.search('bugfix on ([0-9a-z][-.0-9a-z]+[0-9a-z])', contents
)
136 bugfix_group
= bugfix_match
.groups() if bugfix_match
is not None else None
137 bugfix_version
= bugfix_group
[0] if bugfix_group
is not None else None
138 package_version
= os
.environ
.get('PACKAGE_VERSION', None)
139 if bugfix_version
is None:
140 # This should be unreachable, unless the patterns are out of sync
141 warn("Malformed bugfix version.")
142 elif package_version
is not None:
143 # If $PACKAGE_VERSION isn't set, skip this check
144 bugfix_split
= split_tor_version(bugfix_version
)
145 package_split
= split_tor_version(package_version
)
146 if bugfix_split
is None:
147 # This should be unreachable, unless the patterns are out of sync
148 warn("Malformed bugfix version: '{}'.".format(bugfix_version
))
149 elif package_split
is None:
150 # This should be unreachable, unless the patterns are out of sync, or the package versioning scheme has changed
151 warn("Malformed $PACKAGE_VERSION: '{}'.".format(package_version
))
152 elif bugfix_split
> package_split
:
153 warn("Bugfixes must be made on earlier versions (or this version). (Bugfix on version: '{}', current tor package version: '{}'.)".format(bugfix_version
, package_version
))
155 return have_warned
!= []
158 """Walk through the arguments: for directories, yield their contents;
159 for files, just yield the files. Only search one level deep, because
160 that's how the changes directory is laid out."""
163 for item
in os
.listdir(f
):
164 if item
.startswith("."): #ignore dotfiles
166 yield os
.path
.join(f
, item
)
170 if __name__
== '__main__':
172 for fname
in files(sys
.argv
[1:]):
173 if fname
.endswith("~"):