File: addVersion.py

package info (click to toggle)
lucene9 9.10.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 114,036 kB
  • sloc: java: 775,336; python: 6,157; xml: 1,464; perl: 448; sh: 353; makefile: 11
file content (197 lines) | stat: -rwxr-xr-x 8,089 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
sys.path.append(os.path.dirname(__file__))
from scriptutil import *

import argparse
import re
from configparser import ConfigParser, ExtendedInterpolation
from textwrap import dedent

def update_changes(filename, new_version, init_changes, headers):
  print('  adding new section to %s...' % filename, end='', flush=True)
  matcher = re.compile(r'\d+\.\d+\.\d+\s+===')
  def edit(buffer, match, line):
    if new_version.dot in line:
      return None
    match = new_version.previous_dot_matcher.search(line)
    if match is not None:
      buffer.append(line.replace(match.group(0), new_version.dot))
      buffer.append(init_changes)
      for header in headers:
        buffer.append('%s\n---------------------\n(No changes)\n\n' % header)
    buffer.append(line)
    return match is not None
     
  changed = update_file(filename, matcher, edit)
  print('done' if changed else 'uptodate')

def add_constant(new_version, deprecate):
  filename = 'lucene/core/src/java/org/apache/lucene/util/Version.java'
  print('  adding constant %s...' % new_version.constant, end='', flush=True)
  constant_prefix = 'public static final Version LUCENE_'
  matcher = re.compile(constant_prefix)
  prev_matcher = new_version.make_previous_matcher(prefix=constant_prefix, sep='_')

  def ensure_deprecated(buffer):
    last = buffer[-1]
    if last.strip() != '@Deprecated':
      spaces = ' ' * (len(last) - len(last.lstrip()) - 1)
      del buffer[-1] # Remove comment closer line
      if (len(buffer) >= 4 and re.search('for Lucene.\s*$', buffer[-1]) != None):
        del buffer[-3:] # drop the trailing lines '<p> / Use this to get the latest ... / ... for Lucene.'
      buffer.append(( '{0} * @deprecated ({1}) Use latest\n'
                    + '{0} */\n'
                    + '{0}@Deprecated\n').format(spaces, new_version))

  def buffer_constant(buffer, line):
    spaces = ' ' * (len(line) - len(line.lstrip()))
    buffer.append(( '\n{0}/**\n'
                  + '{0} * Match settings and bugs in Lucene\'s {1} release.\n')
                  .format(spaces, new_version))
    if deprecate:
      buffer.append('%s * @deprecated Use latest\n' % spaces)
    else:
      buffer.append(( '{0} * <p>Use this to get the latest &amp; greatest settings, bug fixes, etc, for Lucene.\n').format(spaces))
    buffer.append('%s */\n' % spaces)
    if deprecate:
      buffer.append('%s@Deprecated\n' % spaces)
    buffer.append('{0}public static final Version {1} = new Version({2}, {3}, {4});\n'.format
                  (spaces, new_version.constant, new_version.major, new_version.minor, new_version.bugfix))
  
  class Edit(object):
    found = -1
    def __call__(self, buffer, match, line):
      if new_version.constant in line:
        return None # constant already exists
      # outer match is just to find lines declaring version constants
      match = prev_matcher.search(line)
      if match is not None:
        ensure_deprecated(buffer) # old version should be deprecated
        self.found = len(buffer) + 1 # extra 1 for buffering current line below
      elif self.found != -1:
        # we didn't match, but we previously had a match, so insert new version here
        # first find where to insert (first empty line before current constant)
        c = []
        buffer_constant(c, line)
        tmp = buffer[self.found:]
        buffer[self.found:] = c
        buffer.extend(tmp)
        buffer.append(line)
        return True

      buffer.append(line)
      return False
  
  changed = update_file(filename, matcher, Edit())
  print('done' if changed else 'uptodate')

def update_build_version(new_version):
  print('  changing baseVersion...', end='', flush=True)
  filename = 'build.gradle'
  def edit(buffer, match, line):
    if new_version.dot in line:
      return None
    buffer.append('  String baseVersion = \'' + new_version.dot + '\'\n')
    return True

  version_prop_re = re.compile(r'baseVersion\s*=\s*([\'"])(.*)\1')
  changed = update_file(filename, version_prop_re, edit)
  print('done' if changed else 'uptodate')

def update_latest_constant(new_version):
  print('  changing Version.LATEST to %s...' % new_version.constant, end='', flush=True)
  filename = 'lucene/core/src/java/org/apache/lucene/util/Version.java'
  matcher = re.compile('public static final Version LATEST')
  def edit(buffer, match, line):
    if new_version.constant in line:
      return None
    buffer.append(line.rpartition('=')[0] + ('= %s;\n' % new_version.constant))
    return True

  changed = update_file(filename, matcher, edit)
  print('done' if changed else 'uptodate')

def onerror(x):
  raise x

def check_lucene_version_tests():
  print('  checking lucene version tests...', end='', flush=True)
  run('./gradlew -p lucene/core test --tests TestVersion')
  print('ok')

def read_config(current_version):
  parser = argparse.ArgumentParser(description='Add a new version to CHANGES, to Version.java and build.gradle files')
  parser.add_argument('version', type=Version.parse)
  newconf = parser.parse_args()

  newconf.branch_type = find_branch_type()
  newconf.is_latest_version = newconf.version.on_or_after(current_version)

  print ("branch_type is %s " % newconf.branch_type)

  return newconf

# Hack ConfigParser, designed to parse INI files, to parse & interpolate Java .properties files
def parse_properties_file(filename):
  contents = open(filename, encoding='ISO-8859-1').read().replace('%', '%%') # Escape interpolation metachar
  parser = ConfigParser(interpolation=ExtendedInterpolation())               # Handle ${property-name} interpolation
  parser.read_string("[DUMMY_SECTION]\n" + contents)                         # Add required section
  return dict(parser.items('DUMMY_SECTION'))


def main():
  if not os.path.exists('build.gradle'):
    sys.exit("Tool must be run from the root of a source checkout.")
  current_version = Version.parse(find_current_version())
  newconf = read_config(current_version)
  is_bugfix = newconf.version.is_bugfix_release()

  print('\nAdding new version %s' % newconf.version)
  # See LUCENE-8883 for some thoughts on which categories to use
  update_changes('lucene/CHANGES.txt', newconf.version, '\n',
                 ['Bug Fixes'] if is_bugfix else ['API Changes', 'New Features', 'Improvements', 'Optimizations', 'Bug Fixes', 'Other'])

  latest_or_backcompat = newconf.is_latest_version or current_version.is_back_compat_with(newconf.version)
  if latest_or_backcompat:
    add_constant(newconf.version, not newconf.is_latest_version)
  else:
    print('\nNot adding constant for version %s because it is no longer supported' % newconf.version)

  if newconf.is_latest_version:
    print('\nUpdating latest version')
    update_build_version(newconf.version)
    update_latest_constant(newconf.version)

  if newconf.version.is_major_release():
    print('\nTODO: ')
    print('  - Move backcompat oldIndexes to unsupportedIndexes in TestBackwardsCompatibility')
    print('  - Update IndexFormatTooOldException throw cases')
  elif latest_or_backcompat:
    print('\nTesting changes')
    check_lucene_version_tests()

  print()

if __name__ == '__main__':
  try:
    main()
  except KeyboardInterrupt:
    print('\nReceived Ctrl-C, exiting early')