create_debian_changelog.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2013, Willow Garage, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of Willow Garage, Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 
33 import argparse
34 import os
35 import sys
36 import traceback
37 import datetime
38 import io
39 import warnings
40 from pkg_resources import parse_version
41 from email.utils import formatdate
42 
43 try:
44  to_unicode = unicode
45 except NameError:
46  to_unicode = str
47 
48 try:
49  from catkin_pkg.changelog import get_changelog_from_path
50  from catkin_pkg.changelog import CHANGELOG_FILENAME
51 except ImportError as err:
52  debug(traceback.format_exc())
53  error("catkin_pkg was not detected, please install it.", exit=True)
54 
55 try:
56  import em
57 except ImportError:
58  debug(traceback.format_exc())
59  error("empy was not detected, please install it.", exit=True)
60 
61 
62 def get_changelogs(package_name,
63  package_maintainer_name,
64  package_maintainer_email,
65  changelog_path,
66  releaser_history=None):
67  if releaser_history is None:
68  warnings.warn("No historical releaser history, using current maintainer name and email for each versioned "
69  "changelog entry.", Warning)
70  releaser_history = {}
71 
72  if os.path.exists(changelog_path):
73  changelog = get_changelog_from_path(changelog_path)
74  changelogs = []
75  maintainer = (package_maintainer_name, package_maintainer_email)
76  for version, date, changes in changelog.foreach_version(reverse=True):
77  changes_str = []
78  date_str = formatdate(float(date.strftime("%s")), date.tzinfo)
79  for item in changes:
80  changes_str.extend([' ' + i for i in to_unicode(item).splitlines()])
81  # Each entry has (version, date, changes, releaser, releaser_email)
82  releaser, email = releaser_history.get(version, maintainer)
83  changelogs.append((
84  version, date_str, '\n'.join(changes_str), releaser, email
85  ))
86  return changelogs
87  else:
88  warnings.warn("No {0} found for package '{1}'".format(CHANGELOG_FILENAME, package_name))
89  return []
90 
91 
92 def save_changelog(package_name,
93  package_version,
94  package_maintainer_name,
95  package_maintainer_email,
96  package_distribution,
97  package_debian_increment,
98  package_changelog_path,
99  output_path):
100  changelogs = get_changelogs(package_name,
101  package_maintainer_name,
102  package_maintainer_email,
103  package_changelog_path)
104  if changelogs and package_version not in [x[0] for x in changelogs]:
105  warnings.warn("""
106  A CHANGELOG.rst was found, but no changelog for this version was found.
107  You REALLY should have a entry (even a blank one) for each version of your package.
108  """)
109  if not changelogs:
110  # Ensure at least a minimal changelog
111  changelogs = []
112  date = datetime.datetime.now()
113  if package_version not in [x[0] for x in changelogs]:
114  changelogs.insert(0, (
115  package_version,
116  formatdate(float(date.strftime("%s")), date.tzinfo),
117  ' * Autogenerated, no changelog for this version found in CHANGELOG.rst.',
118  package_maintainer_name,
119  package_maintainer_email
120  ))
121  bad_changelog = False
122  # Make sure that the first change log is the version being released
123  if package_version != changelogs[0][0]:
124  warnings.warn("""
125  The version of the first changelog entry '{0}' is not the
126  same as the version being currently released '{1}'.
127  """.format(package_version, changelogs[0][0]))
128  bad_changelog = True
129  # Make sure that the current version is the latest in the changelog
130  for changelog in changelogs:
131  if parse_version(package_version) < parse_version(changelog[0]):
132  warnings.warn("""
133  There is at least one changelog entry, '{0}', which has a
134  newer version than the version of package '{1}' being released, '{2}'.
135  """.format(changelog[0], package_name, package_version))
136  bad_changelog = True
137  if bad_changelog:
138  sys.exit("This is almost certainly by mistake, you should really take a\nlook at the changelogs for the package '{0}' you are releasing '{1}'.".format(package_name, package_version))
139 
140  native = False
141  data = {}
142  # Debian Increment Number
143  data['DebianInc'] = '' if native else '-{0}'.format(package_debian_increment)
144  # Package name
145  data['Package'] = package_name
146  # Package changelogs
147  data['changelogs'] = changelogs
148  # Package changelogs
149  data['Distribution'] = package_distribution
150 
151  template = ("@[for change_version, change_date, changelog, main_name, main_email in changelogs]@(Package) (@("
152  "change_version)@(DebianInc)@(Distribution)) @(Distribution); urgency=high\n\n@(changelog)\n\n -- @("
153  "main_name) <@(main_email)> @(change_date)\n\n@[end for]\n")
154 
155  # Expand template
156  result = em.expand(template, **data)
157  # Don't write an empty file
158  if len(result) == 0:
159  error("Failed to expand template")
160  # Write the result
161  if sys.version_info.major == 2:
162  result = result.decode('utf-8')
163  output_path.write(result)
164 
165 
166 if __name__ == '__main__':
167  parser = argparse.ArgumentParser()
168  parser.description = "Convert ROS CHANGELOG.rst to debian changelog"
169  parser.prog = 'create_debian_changelog'
170 
171  parser.add_argument('name', nargs=1, help='The package name', type=str)
172  parser.add_argument('version', nargs=1, help='The package version', type=str)
173  parser.add_argument('maintainer_name', nargs=1, help='The package maintainer name', type=str)
174  parser.add_argument('maintainer_email', nargs=1, help='The package maintainer email', type=str)
175  parser.add_argument('distribution', nargs=1, help='The package distribution', type=str)
176  parser.add_argument('debian_increment', nargs=1, help='The debian increment', type=str)
177  parser.add_argument('changelog_path', nargs=1, help='CHANGELOG.rst file path', type=str)
178  parser.add_argument('-o', '--output', help='Debian changelog output file path', default=sys.stdout,
179  type=argparse.FileType('w'))
180  arguments = parser.parse_args()
181  save_changelog(arguments.name[0],
182  arguments.version[0],
183  arguments.maintainer_name[0],
184  arguments.maintainer_email[0],
185  arguments.distribution[0],
186  arguments.debian_increment[0],
187  arguments.changelog_path[0],
188  arguments.output)
create_debian_changelog.to_unicode
to_unicode
Definition: create_debian_changelog.py:44
create_debian_changelog.save_changelog
def save_changelog(package_name, package_version, package_maintainer_name, package_maintainer_email, package_distribution, package_debian_increment, package_changelog_path, output_path)
Definition: create_debian_changelog.py:92
create_debian_changelog.get_changelogs
def get_changelogs(package_name, package_maintainer_name, package_maintainer_email, changelog_path, releaser_history=None)
Definition: create_debian_changelog.py:62


ros_industrial_cmake_boilerplate
Author(s): Levi Armstrong, George Cave
autogenerated on Wed Feb 12 2025 03:19:13