1#!/usr/bin/env python3
2#
3# Copyright 2021 The Abseil Authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      https://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""A script to do source transformations to create a new LTS release.
17
18   Usage: ./create_lts.py YYYYMMDD
19"""
20
21import sys
22
23
24def ReplaceStringsInFile(filename, replacement_dict):
25  """Performs textual replacements in a file.
26
27  Rewrites filename with the keys in replacement_dict replaced with
28  their values. This function assumes the file can fit in memory.
29
30  Args:
31    filename: the filename to perform the replacement on
32    replacement_dict: a dictionary of key strings to be replaced with their
33      values
34
35  Raises:
36    Exception: A failure occured
37  """
38  f = open(filename, 'r')
39  content = f.read()
40  f.close()
41
42  for key, value in replacement_dict.items():
43    original = content
44    content = content.replace(key, value)
45    if content == original:
46      raise Exception('Failed to find {} in {}'.format(key, filename))
47
48  f = open(filename, 'w')
49  f.write(content)
50  f.close()
51
52
53def StripContentBetweenTags(filename, strip_begin_tag, strip_end_tag):
54  """Strip contents from a file.
55
56  Rewrites filename with by removing all content between
57  strip_begin_tag and strip_end_tag, including the tags themselves.
58
59  Args:
60    filename: the filename to perform the replacement on
61    strip_begin_tag: the start of the content to be removed
62    strip_end_tag: the end of the content to be removed
63
64  Raises:
65    Exception: A failure occured
66  """
67  f = open(filename, 'r')
68  content = f.read()
69  f.close()
70
71  while True:
72    begin = content.find(strip_begin_tag)
73    if begin == -1:
74      break
75    end = content.find(strip_end_tag, begin + len(strip_begin_tag))
76    if end == -1:
77      raise Exception('{}: imbalanced strip begin ({}) and '
78                      'end ({}) tags'.format(filename, strip_begin_tag,
79                                             strip_end_tag))
80    content = content.replace(content[begin:end + len(strip_end_tag)], '')
81
82  f = open(filename, 'w')
83  f.write(content)
84  f.close()
85
86
87def main(argv):
88  if len(argv) != 2:
89    print('Usage: {} YYYYMMDD'.format(sys.argv[0], file=sys.stderr))
90    sys.exit(1)
91
92  datestamp = sys.argv[1]
93  if len(datestamp) != 8 or not datestamp.isdigit():
94    raise Exception(
95        'datestamp={} is not in the YYYYMMDD format'.format(datestamp))
96
97  # Replacement directives go here.
98  ReplaceStringsInFile(
99      'absl/base/config.h', {
100          '#undef ABSL_LTS_RELEASE_VERSION':
101              '#define ABSL_LTS_RELEASE_VERSION {}'.format(datestamp),
102          '#undef ABSL_LTS_RELEASE_PATCH_LEVEL':
103              '#define ABSL_LTS_RELEASE_PATCH_LEVEL 0'
104      })
105  ReplaceStringsInFile(
106      'absl/base/options.h', {
107          '#define ABSL_OPTION_USE_INLINE_NAMESPACE 0':
108              '#define ABSL_OPTION_USE_INLINE_NAMESPACE 1',
109          '#define ABSL_OPTION_INLINE_NAMESPACE_NAME head':
110              '#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_{}'.format(
111                  datestamp)
112      })
113  ReplaceStringsInFile(
114      'CMakeLists.txt', {
115          'project(absl LANGUAGES CXX)':
116              'project(absl LANGUAGES CXX VERSION {})'.format(datestamp)
117      })
118  # Set the SOVERSION to YYMM.0.0 - The first 0 means we only have ABI
119  # compatible changes, and the second 0 means we can increment it to
120  # mark changes as ABI-compatible, for patch releases.  Note that we
121  # only use the last two digits of the year and the month because the
122  # MacOS linker requires the first part of the SOVERSION to fit into
123  # 16 bits.
124  # https://www.sicpers.info/2013/03/how-to-version-a-mach-o-library/
125  ReplaceStringsInFile(
126      'CMake/AbseilHelpers.cmake',
127      {'SOVERSION 0': 'SOVERSION "{}.0.0"'.format(datestamp[2:6])})
128  StripContentBetweenTags('CMakeLists.txt', '# absl:lts-remove-begin',
129                          '# absl:lts-remove-end')
130
131
132if __name__ == '__main__':
133  main(sys.argv)
134