mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Nicolas Capponi
03.07.2014 e1fc6e590de8875550dcbb521272f45a5c139611
Script to automate code replacement using regular expressions.

Allow to apply dozens of regexes in selected directories in one shot.

1 files added
261 ■■■■■ changed files
opendj-sdk/opendj3-server-dev/replace.rb 261 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/replace.rb
New file
@@ -0,0 +1,261 @@
#!/usr/bin/env ruby
require 'fileutils'
#
# Automate code replacements using regular expressions
#
# To define a new replacement, add a new constant like VALIDATOR.
#
# It should be a ruby Hash with three mandatory keys and one optional key:
#
#  :dirs => a list of directory to run replacements. All subdirs are processed.
#  :extensions => a list of file extensions. Only file with these extensions are processed.
#  :replacements => a list of replacements, lines are processed 2 by 2
#    - first line gives the pattern to replace, as a ruby regexp (see http://rubular.com/ for help and tool)
#    - second line gives the replacement string, using \1, \2, ... to insert matching groups. This is a string,
#       use simple quote if no special char is inserted, or use double quote if using special char like \n
#    Don't forget to put a comma at end of each line, this is the array element separator.
#    It is ok to leave a new line to separate each pair of line for readability.
#    It is ok to use a comment in the array (use # as first non blank character of line).
#
# The optional key is :stopwords => a list of stopword. If any word in this list appears in a file name, the file
#   is not processed. Use it to exclude some files or directory that must not be processed.
#
# Once you have define your replacement, add the constant in REPLACEMENTS array. it will be taken into account when
# running the program (run it at root of project) with command: ./replace.rb
#
class Replace
  # All directories that contains java code
  JAVA_DIRS = ["src/server", "src/quicksetup", "src/ads", "src/guitools", "tests/unit-tests-testng/src"]
  # Replacement for Validator
  # Modify 88 files, for a total of 227 replacements - leaves 21 compilation errors
  VALIDATOR = {
    :dirs => JAVA_DIRS,
    :extensions => ["java"],
    :replacements =>
      [
        /import org.opends.server.util.\*;/,
        "import org.opends.server.util.*;\nimport org.forgerock.util.Reject;",
        /import static org.opends.server.util.Validator.ensureNotNull;/,
        'import static org.forgerock.util.Reject.ifNull;',
        /import static org.opends.server.util.Validator.ensureTrue;/,
        'import static org.forgerock.util.Reject.ifFalse;',
        /import static org.opends.server.util.Validator.\*;/,
        'import static org.forgerock.util.Reject.*;',
        /import org.opends.server.util.Validator;/,
        'import org.forgerock.util.Reject;',
        /(Validator\.| )ensureNotNull\((.*)$/,
        '\1ifNull(\2',
        /(Validator\.| )ensureTrue\((.*)$/,
        '\1ifFalse(\2',
        / Validator\./,
        ' Reject.'
      ]
  }
  # Replacement for messages
  # Modify 1052 files, for a total of 2366 replacements - leaves 10274 compilation errors mostly due to generated messages
  MESSAGES = {
    :dirs => JAVA_DIRS,
    :extensions => ["java"],
    :replacements =>
      [
        /import org.opends.messages.Message;/,
        'import org.forgerock.i18n.LocalizableMessage;',
        /([ <(])Message([ >)(.]|$)/,
        '\1LocalizableMessage\2',
        /import org.opends.messages.MessageBuilder;/,
        'import org.forgerock.i18n.LocalizableMessageBuilder;',
        /([ <(])MessageBuilder([ >)(.]|$)/,
        '\1LocalizableMessageBuilder\2'
      ]
  }
  # Replacement for types
  # Modify 688 files, for a total of 783 replacements - leaves 7605 compilation errors
  TYPES = {
    :dirs => JAVA_DIRS,
    :extensions => ["java"],
    :replacements =>
      [
        /import org.opends.server.types.(DN|RDN|Attribute|ByteString|Entry|ResultCode);/,
        'import org.forgerock.opendj.ldap.\1;',
        /import org.opends.server.(types|api).(AttributeType|MatchingRule);/,
        'import org.forgerock.opendj.ldap.schema.\2;',
      ]
  }
  # Replacement for exceptions
  # Modify 36 files, for a total of 134 replacements - leaves 1277 compilation errors but mostly from generated config
  EXCEPTIONS = {
    :dirs => JAVA_DIRS,
    :extensions => ["java"],
    :replacements =>
      [
        /import org.opends.server.admin.client.AuthorizationException;/,
        'import org.forgerock.opendj.ldap.ErrorResultException;',
        /\bAuthorizationException\b/,
        'ErrorResultException',
        /import org.opends.server.admin.client.CommunicationException;\n/,
        '',
        /throws CommunicationException\b, /,
        'throws ',
        /, CommunicationException\b(, )?/,
        '\1',
        /\bCommunicationException\b/,
        'ErrorResultException',
      ]
  }
  # Replacement for loggers
  # Modify 454 files, for a total of 2427 replacements - leaves 72 compilation errors
  # TODO: add I18N loggers
  LOGGERS = {
    :dirs => JAVA_DIRS,
    :stopwords => ['src/server/org/opends/server/loggers', 'DebugLogPublisher'],
    :extensions => ["java"],
    :replacements =>
      [
        /import org.opends.server.loggers.debug.DebugTracer;/,
        "import org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;",
        /import java.util.logging.Logger;/,
        "import org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;",
        /import java.util.logging.Level;\n/,
        '',
        /import org.opends.server.types.DebugLogLevel;\n/,
        '',
        /import (static )?org.opends.server.loggers.debug.DebugLogger.*;\n/,
        '',
        /DebugTracer TRACER = (DebugLogger.)?getTracer\(\)/,
        "Logger debugLogger = LoggerFactory.getLogger({CLASSNAME}.class)",
        /^\s*\/\*\*\n.*The tracer object for the debug logger.\n\s*\*\/$\n/,
        '',
        /^\s*\/\/\s*The tracer object for the debug logger.$\n/,
        '',
        /if \(debugEnabled\(\)\)\s*{\s* TRACER.debugCaught\(DebugLogLevel.ERROR, (\b.*\b)\);\s*\n\s*}$/,
        'debugLogger.trace("Error", \1);',
        /TRACER\.debugCaught\(DebugLogLevel.ERROR, (\b.*\b)\);/,
        'debugLogger.trace("Error", \1);',
        /TRACER.debug[^(]+\(/,
        'debugLogger.trace(',
        /debugLogger.trace\(DebugLogLevel.\b\w+\b, ?/,
        'debugLogger.trace(',
        /debugLogger.trace\(e\)/,
        'debugLogger.trace("Error", e)',
        /(DebugLogger\.|\b)debugEnabled\(\)/,
        'debugLogger.isTraceEnabled()',
        /(LOG|logger).log\((Level.)?WARNING, ?/,
        '\1.warn(',
        /(LOG|logger).log\((Level.)?CONFIG, ?/,
        '\1.info(',
        /(LOG|logger).log\((Level.)?INFO, ?/,
        '\1.debug(',
        /(LOG|logger).log\((Level.)?SEVERE, ?/,
        '\1.error(',
        /(LOG|logger).log\((Level.)?FINE, ?/,
        '\1.trace(',
        /Logger.getLogger\((\n\s+)?(\b\w+\b).class.getName\(\)\);/,
        'LoggerFactory.getLogger(\2.class);',
      ]
  }
  # List of replacements to run
  REPLACEMENTS = [ VALIDATOR ]
  #REPLACEMENTS = [ VALIDATOR, MESSAGES, TYPES, EXCEPTIONS, LOGGERS ]
  # Run replacements
  def run
    REPLACEMENTS.each { |repl|
      puts "Replacing " + Replace.constants.find{ |name| Replace.const_get(name)==repl }.to_s
      stopwords = repl[:stopwords] || ["--nostopword--"]
      replace_dirs(repl[:replacements], repl[:dirs], stopwords, repl[:extensions])
    }
  end
  def replace_dirs(replacements, dirs, stopwords, extensions)
    count_files = 0
    count_total = 0
    dirs.each { |directory|
      files = files_under_directory(directory, extensions)
      files.each { |file|
        exclude_file = stopwords.any? { |stopword| file.include?(stopword) }
        next if exclude_file
        count = replace_file(file, replacements)
        if count > 0
          count_files += 1
          count_total += count
        end
      }
    }
    puts "Replaced in #{count_files} files, for a total of #{count_total} replacements"
  end
  def replace_file(file, replacements)
    count = 0
    File.open(file) { |source|
      contents = source.read
      (0..replacements.size-1).step(2).each { |index|
        pattern, replace = replacements[index], replacements[index+1]
        replace = replace.gsub('{CLASSNAME}', classname(file))
        is_replaced = contents.gsub!(pattern, replace)
        if is_replaced then count += 1 end
      }
      File.open(file + ".copy", "w+") { |f| f.write(contents) }
    }
    FileUtils.mv(file + ".copy", file, :verbose => false)
    count
  end
  def classname(file)
    name = file.gsub(/.*\/(.*).java$/, '\1')
    if name.nil? then '' else name end
  end
  def files_under_directory(directory, extensions)
    Dir[directory + '/**/*.{' + extensions.join(",") + '}']
  end
end
# Launch replacement
Replace.new.run