update_versions.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #!/usr/bin/env python
  2. # Future imports for Python 2.7, mandatory in 3.0
  3. from __future__ import division
  4. from __future__ import print_function
  5. from __future__ import unicode_literals
  6. import io
  7. import os
  8. import re
  9. import sys
  10. import time
  11. def P(path):
  12. """
  13. Give 'path' as a path relative to the abs_top_srcdir environment
  14. variable.
  15. """
  16. return os.path.join(
  17. os.environ.get('abs_top_srcdir', "."),
  18. path)
  19. def warn(msg):
  20. """
  21. Print an warning message.
  22. """
  23. print("WARNING: {}".format(msg), file=sys.stderr)
  24. def find_version(infile):
  25. """
  26. Given an open file (or some other iterator of lines) holding a
  27. configure.ac file, find the current version line.
  28. """
  29. for line in infile:
  30. m = re.search(r'AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)', line)
  31. if m:
  32. return m.group(1)
  33. return None
  34. def update_version_in(infile, outfile, regex, versionline):
  35. """
  36. Copy every line from infile to outfile. If any line matches 'regex',
  37. replace it with 'versionline'. Return True if any line was changed;
  38. false otherwise.
  39. 'versionline' is either a string -- in which case it is used literally,
  40. or a function that receives the output of 'regex.match'.
  41. """
  42. found = False
  43. have_changed = False
  44. for line in infile:
  45. m = regex.match(line)
  46. if m:
  47. found = True
  48. oldline = line
  49. if type(versionline) == type(u""):
  50. line = versionline
  51. else:
  52. line = versionline(m)
  53. if not line.endswith("\n"):
  54. line += "\n"
  55. if oldline != line:
  56. have_changed = True
  57. outfile.write(line)
  58. if not found:
  59. warn("didn't find any version line to replace in {}".format(infile.name))
  60. return have_changed
  61. def replace_on_change(fname, change):
  62. """
  63. If "change" is true, replace fname with fname.tmp. Otherwise,
  64. delete fname.tmp. Log what we're doing to stderr.
  65. """
  66. if not change:
  67. print("No change in {}".format(fname))
  68. os.unlink(fname+".tmp")
  69. else:
  70. print("Updating {}".format(fname))
  71. os.rename(fname+".tmp", fname)
  72. def update_file(fname,
  73. regex,
  74. versionline,
  75. encoding="utf-8"):
  76. """
  77. Replace any line matching 'regex' in 'fname' with 'versionline'.
  78. Do not modify 'fname' if there are no changes made. Use the
  79. provided encoding to read and write.
  80. """
  81. with io.open(fname, "r", encoding=encoding) as f, \
  82. io.open(fname+".tmp", "w", encoding=encoding) as outf:
  83. have_changed = update_version_in(f, outf, regex, versionline)
  84. replace_on_change(fname, have_changed)
  85. # Find out our version
  86. with open(P("configure.ac")) as f:
  87. version = find_version(f)
  88. # If we have no version, we can't proceed.
  89. if version == None:
  90. print("No version found in configure.ac", file=sys.stderr())
  91. sys.exit(1)
  92. print("The version is {}".format(version))
  93. today = time.strftime("%Y-%m-%d", time.gmtime())
  94. # In configure.ac, we replace the definition of APPROX_RELEASE_DATE
  95. # with "{today} for {version}", but only if the version does not match
  96. # what is already there.
  97. def replace_fn(m):
  98. if m.group(1) != version:
  99. # The version changed -- we change the date.
  100. return u'AC_DEFINE(APPROX_RELEASE_DATE, ["{}"], # for {}'.format(today, version)
  101. else:
  102. # No changes.
  103. return m.group(0)
  104. update_file(P("configure.ac"),
  105. re.compile(r'AC_DEFINE\(APPROX_RELEASE_DATE.* for (.*)'),
  106. replace_fn)
  107. # In tor-mingw.nsi.in, we replace the definition of VERSION.
  108. update_file(P("contrib/win32build/tor-mingw.nsi.in"),
  109. re.compile(r'!define VERSION .*'),
  110. u'!define VERSION "{}"'.format(version),
  111. encoding="iso-8859-1")
  112. # In src/win32/orconfig.h, we replace the definition of VERSION.
  113. update_file(P("src/win32/orconfig.h"),
  114. re.compile(r'#define VERSION .*'),
  115. u'#define VERSION "{}"'.format(version))