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