You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2013/12/17 17:10:38 UTC

svn commit: r1551599 - in /httpcomponents/httpclient-android/trunk: build.gradle buildSrc/src/main/groovy/HC.groovy buildSrc/src/main/groovy/Replacement.groovy buildSrc/src/main/groovy/Svn.groovy

Author: olegk
Date: Tue Dec 17 16:10:38 2013
New Revision: 1551599

URL: http://svn.apache.org/r1551599
Log:
Added a task to 'shade' overlapping implementation classes and a task to
perform regex based code adjustments

Added:
    httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Replacement.groovy
Modified:
    httpcomponents/httpclient-android/trunk/build.gradle
    httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/HC.groovy
    httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Svn.groovy

Modified: httpcomponents/httpclient-android/trunk/build.gradle
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient-android/trunk/build.gradle?rev=1551599&r1=1551598&r2=1551599&view=diff
==============================================================================
--- httpcomponents/httpclient-android/trunk/build.gradle (original)
+++ httpcomponents/httpclient-android/trunk/build.gradle Tue Dec 17 16:10:38 2013
@@ -12,6 +12,9 @@ dependencies {
 String branchName = 'test-branch'
 URI branchUri = new URI("${REPO_ROOT}/httpclient-android/branches/${branchName}")
 File localDir = file("$buildDir/${branchName}")
+File srcRoot = new File(localDir, 'src/main/java')
+File allClassesFile = file("$buildDir/all-classes.txt")
+File reservedClassesFile = file("$buildDir/reserved-classes.txt")
 
 task createSvnBranch {
     group = 'SVN'
@@ -40,21 +43,154 @@ task checkout(dependsOn: createSvnBranch
     }
 }
 
-task rewrite(dependsOn: checkout) {
+task prepare(dependsOn: checkout) {
+    group = 'Code'
+    description = "Prepares code migration"
+    onlyIf {
+        !allClassesFile.exists() || !reservedClassesFile.exists()
+    }
     doLast {
-        def jars = configurations.hcApi.resolvedConfiguration.resolvedArtifacts.collect { ResolvedArtifact artifact ->
+        Collection<File> jars = configurations.hcApi.resolvedConfiguration.resolvedArtifacts.collect { ResolvedArtifact artifact ->
             artifact.file
         }
-        def allClasses = HC.getClassesFromJars(jars)
+        Set<Class<?>> allClasses = HC.getClasses('org.apache.http', jars)
+        Set<Class<?>> reservedClasses = HC.getApiClasses(allClasses)
+        TreeSet<String> allClassNames = new TreeSet()
+        allClasses.each { Class<?> clazz ->
+            allClassNames.add(clazz.name)
+        }
 
-        File srcRoot = new File(localDir, 'src/main/java')
-        allClasses.each { Class clazz ->
-            if (!clazz.memberClass && !clazz.anonymousClass) {
-                String name = clazz.canonicalName.replaceAll('\\.', '/')
-                File file = new File(srcRoot, name + '.java')
-                if (file.exists()) {
-                    println file
+        TreeSet<String> reservedClassNames = new TreeSet()
+        reservedClasses.each { Class<?> clazz ->
+            reservedClassNames.add(clazz.name)
+        }
+        allClassNames.each { String line ->
+            if (line ==~ /^org\.apache\.http\.\w+$/) {
+                reservedClassNames.add(line)
+            } else if (line ==~ /^org\.apache\.http\.message\.\w+$/) {
+                if (!(line ==~ /^org\.apache\.http\.message\.Basic\w+(Parser|Formatter)$/)) {
+                    reservedClassNames.add(line)
                 }
+            } else if (line ==~ /^org\.apache\.http\.conn\.routing\.\w+$/) {
+                reservedClassNames.add(line)
+            } else if (line ==~ /^org\.apache\.http\.conn\.scheme\.\w+$/) {
+                reservedClassNames.add(line)
+            } else if (line ==~ /^org\.apache\.http\.cookie\.\w+$/) {
+                reservedClassNames.add(line)
+            } else if (line ==~ /^org\.apache\.http\.auth\.\w+$/) {
+                if (line != 'org.apache.http.auth.AuthState') {
+                    reservedClassNames.add(line)
+                }
+            } else if (line ==~ /^org\.apache\.http\.impl\.conn\.tsccm\.\w+$/) {
+                reservedClassNames.add(line)
+            } else if (line ==~ /^org\.apache\.http(\.\w+)*Params$/) {
+                reservedClassNames.add(line)
+            } else if (line ==~ /^org\.apache\.http(\.\w+)*Exception$/) {
+                reservedClassNames.add(line)
+            }
+        }
+        reservedClassNames.addAll([
+                'org.apache.http.util.ByteArrayBuffer',
+                'org.apache.http.util.EncodingUtils',
+                'org.apache.http.util.LangUtils',
+                'org.apache.http.entity.EntityTemplate',
+                'org.apache.http.protocol.HTTP',
+                'org.apache.http.protocol.HttpRequestExecutor',
+                'org.apache.http.protocol.HttpService',
+                'org.apache.http.protocol.RequestExpectContinue',
+                'org.apache.http.protocol.ResponseContent',
+                'org.apache.http.protocol.ResponseDate',
+                'org.apache.http.protocol.ResponseServer',
+                'org.apache.http.protocol.UriPatternMatcher',
+                'org.apache.http.protocol.HttpDateGenerator',
+                'org.apache.http.protocol.UriHttpRequestHandlerMapper',
+                'org.apache.http.conn.ssl.SSLSocketFactory',
+                'org.apache.http.impl.client.RequestWrapper',
+                'org.apache.http.impl.HttpConnectionMetricsImpl',
+                'org.apache.http.impl.io.HttpTransportMetricsImpl',
+                'org.apache.http.impl.cookie.DateUtils'
+        ])
+
+        String lineDelimiter = System.getProperty('line.separator')
+        allClassesFile.withWriter { Writer w ->
+            allClassNames.each { String s ->
+                w << s + lineDelimiter
+            }
+        }
+        reservedClassesFile.withWriter { Writer w ->
+            reservedClassNames.each { String s ->
+                w << s + lineDelimiter
+            }
+        }
+    }
+}
+
+task moveCode(dependsOn: prepare) {
+    group = 'SVN'
+    description = "Updates local SVN checkout"
+    doLast {
+        Set<String> classesToRemove = []
+        reservedClassesFile.eachLine { String line ->
+            classesToRemove.add(line)
+        }
+        List<File> filesToRemove = []
+        classesToRemove.each{ String line ->
+            String name = line.replaceAll('\\.', '/')
+            File file = new File(srcRoot, name + '.java')
+            if (file.exists()) {
+                filesToRemove.add(file)
+            }
+        }
+        if (!filesToRemove.empty) {
+            Svn.scheduleForRemoval(filesToRemove)
+        }
+        allClassesFile.eachLine { String line ->
+            String name = line.replaceAll('\\.', '/')
+            File src = new File(srcRoot, name + '.java')
+            if (src.exists()) {
+                File dst = new File(srcRoot, name + 'HC4.java')
+                Svn.move(src, dst)
+            }
+        }
+    }
+}
+
+task rewriteCode(dependsOn: moveCode) {
+    group = 'Code'
+    description = "Rewrites code"
+    doLast {
+        Set<String> allClasses = []
+        allClassesFile.eachLine { String line ->
+            allClasses.add(line)
+        }
+        Set<String> removedClasses = []
+        reservedClassesFile.eachLine { String line ->
+            removedClasses.add(line)
+        }
+        Set<String> movedClasses = allClasses - removedClasses
+
+        List<Replacement> replacements = []
+        movedClasses.each { String line ->
+            int i = line.lastIndexOf('.')
+            String className = i != -1 ? line.substring(i + 1) : line
+            replacements.add(new Replacement(~/([ \.\(\!\#])(${className})(([ \(\)\<\.;#]|$))/, '$1$2HC4$3'))
+        }
+        replacements.addAll([
+                new Replacement(~/HttpMessageWriter\<.*\>/, 'HttpMessageWriter'),
+                new Replacement(~/HttpMessageParser\<.*\>/, 'HttpMessageParser'),
+                new Replacement(~/AbstractMessageParser\<.*\>/, 'AbstractMessageParser'),
+                new Replacement(~/AbstractMessageWriter\<.*\>/, 'AbstractMessageWriter'),
+                new Replacement(~/HttpMessageParser\<Http(Request|Response)\>/, 'HttpMessageParser'),
+                new Replacement(~/HttpMessageWriter\<Http(Request|Response)\>/, 'HttpMessageWriter'),
+                new Replacement(~/HTTP\.DEF_CONTENT_CHARSET/, 'Charset.forName(HTTP.DEFAULT_CONTENT_CHARSET)'),
+                new Replacement(~/HTTP\#DEF_CONTENT_CHARSET/, 'HTTP#DEFAULT_CONTENT_CHARSET'),
+                new Replacement(~/route\.getLocalSocketAddress\(\)/, 'route.getLocalAddress() != null ? new InetSocketAddress(route.getLocalAddress(), 0) : null;'),
+                new Replacement(~/new AuthScope\((proxy|target|host)([,)])/, 'new AuthScope($1.getHostName(), $1.getPort()$2'),
+                new Replacement(~/new Base64\(0\)/, 'new Base64()')
+        ])
+        srcRoot.traverse(namefilter: ~/.*\.java$/) { File file ->
+            if (!file.directory) {
+                HC.replacePatterns(file, replacements)
             }
         }
     }

Modified: httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/HC.groovy
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/HC.groovy?rev=1551599&r1=1551598&r2=1551599&view=diff
==============================================================================
--- httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/HC.groovy (original)
+++ httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/HC.groovy Tue Dec 17 16:10:38 2013
@@ -25,6 +25,9 @@
  *
  */
 
+
+
+
 import com.google.common.collect.Multimap
 import org.reflections.Reflections
 import org.reflections.util.ClasspathHelper
@@ -32,8 +35,13 @@ import org.reflections.util.Configuratio
 import org.tmatesoft.svn.core.io.ISVNEditor
 import org.tmatesoft.svn.core.io.SVNRepository
 
+import java.lang.reflect.Method
+import java.util.regex.Matcher
+
 class HC {
 
+    static String LINE_DELIM = System.getProperty("line.separator")
+
     static void createAndroidBranch(
             URI repoRoot,
             String coreVersion,
@@ -95,22 +103,80 @@ class HC {
         }
     }
 
-    static Set<Class<?>> getClassesFromJars(Collection<File> jars) {
+    static Set<Class<?>> getClasses(String namespace, Collection<File> jars) {
         URL[] urls = jars.collect { File file ->
             file.toURI().toURL()
         }
         URLClassLoader urlClassLoader = new URLClassLoader(urls)
 
         Reflections reflections = new ConfigurationBuilder()
-                .setUrls(ClasspathHelper.forPackage("org.apache.http", urlClassLoader))
+                .setUrls(ClasspathHelper.forPackage(namespace, urlClassLoader))
                 .setScanners(new GetAllScanner())
                 .build()
         Multimap<String, String> multimap = reflections.getStore().get(GetAllScanner)
         Set<Class<?>> allClasses = new HashSet<Class<?>>()
         for (String key: multimap.keySet()) {
-            allClasses.add(urlClassLoader.loadClass(key))
+            Class<?> clazz = urlClassLoader.loadClass(key)
+            if (!clazz.memberClass && !clazz.anonymousClass) {
+                allClasses.add(clazz)
+            }
         }
         allClasses
     }
 
+    static Set<Class<?>> getApiClasses(Set<Class<?>> allClasses) {
+        Set<Class<?>> apiClasses = new HashSet<Class<?>>()
+        for (Class<?> clazz: allClasses) {
+            if (clazz.interface) {
+                apiClasses.add(clazz)
+                Method[] methods = clazz.methods
+                for (Method method: methods) {
+                    Class<?>[] parameterTypes = method.parameterTypes
+                    for (Class<?> parameterType: parameterTypes) {
+                        if (allClasses.contains(parameterType)) {
+                            apiClasses.add(parameterType)
+                        }
+                    }
+                    Class<?> returnType = method.returnType
+                    if (returnType && allClasses.contains(returnType)) {
+                        apiClasses.add(returnType)
+                    }
+                    Class<?>[] exceptionTypes = method.exceptionTypes
+                    for (Class<?> exceptionType: exceptionTypes) {
+                        if (allClasses.contains(exceptionType)) {
+                            apiClasses.add(exceptionType)
+                        }
+                    }
+                }
+            }
+        }
+        apiClasses
+    }
+
+    static void replacePatterns(File file, List<Replacement> replacements) {
+        File tmpFile = File.createTempFile('temp', ".java")
+        try {
+            boolean modified = false
+            tmpFile.withWriter { Writer w ->
+                file.eachLine { String line ->
+                    for (Replacement replacement in replacements) {
+                        Matcher m = line =~ replacement.pattern
+                        if (m.find()) {
+                            modified = true
+                            line = m.replaceAll(replacement.text)
+                        }
+                    }
+                    w << line + LINE_DELIM
+                }
+            }
+            if (modified) {
+                file.bytes = tmpFile.bytes
+            }
+        } finally {
+            if (tmpFile.exists()) {
+                tmpFile.delete()
+            }
+        }
+    }
+
 }

Added: httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Replacement.groovy
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Replacement.groovy?rev=1551599&view=auto
==============================================================================
--- httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Replacement.groovy (added)
+++ httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Replacement.groovy Tue Dec 17 16:10:38 2013
@@ -0,0 +1,40 @@
+import java.util.regex.Pattern
+
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+final class Replacement {
+
+    final Pattern pattern;
+    final String text;
+
+    Replacement(Pattern pattern, String text) {
+        this.pattern = pattern
+        this.text = text
+    }
+
+}

Modified: httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Svn.groovy
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Svn.groovy?rev=1551599&r1=1551598&r2=1551599&view=diff
==============================================================================
--- httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Svn.groovy (original)
+++ httpcomponents/httpclient-android/trunk/buildSrc/src/main/groovy/Svn.groovy Tue Dec 17 16:10:38 2013
@@ -43,6 +43,7 @@ import org.tmatesoft.svn.core.wc.SVNWCUt
 import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver
 import org.tmatesoft.svn.core.wc2.SvnCheckout
 import org.tmatesoft.svn.core.wc2.SvnCommit
+import org.tmatesoft.svn.core.wc2.SvnCopy
 import org.tmatesoft.svn.core.wc2.SvnCopySource
 import org.tmatesoft.svn.core.wc2.SvnGetStatus
 import org.tmatesoft.svn.core.wc2.SvnOperationFactory
@@ -50,6 +51,7 @@ import org.tmatesoft.svn.core.wc2.SvnRem
 import org.tmatesoft.svn.core.wc2.SvnRemoteDelete
 import org.tmatesoft.svn.core.wc2.SvnRevert
 import org.tmatesoft.svn.core.wc2.SvnScheduleForAddition
+import org.tmatesoft.svn.core.wc2.SvnScheduleForRemoval
 import org.tmatesoft.svn.core.wc2.SvnStatus
 import org.tmatesoft.svn.core.wc2.SvnTarget
 import org.tmatesoft.svn.core.wc2.SvnUpdate
@@ -158,6 +160,7 @@ class Svn {
             schedulingOp.setSingleTarget(SvnTarget.fromFile(dir))
             schedulingOp.setDepth(SVNDepth.INFINITY)
             schedulingOp.setForce(true)
+            schedulingOp.setAddParents(true)
             schedulingOp.setIncludeIgnored(false)
             schedulingOp.run()
         } finally {
@@ -165,6 +168,54 @@ class Svn {
         }
     }
 
+    static void scheduleForAddition(Collection<File> files) {
+        SVNCommandEnvironment env = getSVNCommandEnvironment()
+        SvnOperationFactory opfactory = createOperationFactory(env)
+        try {
+            SvnScheduleForAddition schedulingOp = opfactory.createScheduleForAddition()
+            files.each { File file ->
+                schedulingOp.addTarget(SvnTarget.fromFile(file))
+            }
+            schedulingOp.setDepth(SVNDepth.INFINITY)
+            schedulingOp.setAddParents(true)
+            schedulingOp.setForce(true)
+            schedulingOp.setIncludeIgnored(false)
+            schedulingOp.run()
+        } finally {
+            opfactory.dispose()
+        }
+    }
+
+    static void scheduleForRemoval(File file) {
+        SVNCommandEnvironment env = getSVNCommandEnvironment()
+        SvnOperationFactory opfactory = createOperationFactory(env)
+        try {
+            SvnScheduleForRemoval schedulingOp = opfactory.createScheduleForRemoval()
+            schedulingOp.addTarget(SvnTarget.fromFile(file))
+            schedulingOp.setDepth(SVNDepth.INFINITY)
+            schedulingOp.setDeleteFiles(true)
+            schedulingOp.run()
+        } finally {
+            opfactory.dispose()
+        }
+    }
+
+    static void scheduleForRemoval(Collection<File> files) {
+        SVNCommandEnvironment env = getSVNCommandEnvironment()
+        SvnOperationFactory opfactory = createOperationFactory(env)
+        try {
+            SvnScheduleForRemoval schedulingOp = opfactory.createScheduleForRemoval()
+            files.each { File file ->
+                schedulingOp.addTarget(SvnTarget.fromFile(file))
+            }
+            schedulingOp.setDepth(SVNDepth.INFINITY)
+            schedulingOp.setDeleteFiles(true)
+            schedulingOp.run()
+        } finally {
+            opfactory.dispose()
+        }
+    }
+
     static long commit(File dir, String message) {
         SVNCommandEnvironment env = getSVNCommandEnvironment()
         SvnOperationFactory opfactory = createOperationFactory(env)
@@ -180,19 +231,35 @@ class Svn {
         }
     }
 
-    static long copyLocal(File dir, URI dst, String message) {
+    static void copy(File src, File dst, String message) {
         SVNCommandEnvironment env = getSVNCommandEnvironment()
         SvnOperationFactory opfactory = createOperationFactory(env)
         try {
-            SvnRemoteCopy copyOp = opfactory.createRemoteCopy()
+            SvnCopy copyOp = opfactory.createCopy()
             copyOp.addCopySource(
-                    SvnCopySource.create(SvnTarget.fromFile(dir), SVNRevision.WORKING))
-            copyOp.setSingleTarget(SvnTarget.fromURL(SVNURL.parseURIEncoded(dst.toASCIIString())))
+                    SvnCopySource.create(SvnTarget.fromFile(src), SVNRevision.WORKING))
+            copyOp.setSingleTarget(SvnTarget.fromFile(dst))
             copyOp.setFailWhenDstExists(true)
-            copyOp.setDisableLocalModifications(false)
-            copyOp.setCommitMessage(message)
-            SVNCommitInfo result = copyOp.run()
-            result.newRevision
+            copyOp.setMakeParents(true)
+            copyOp.setMove(false)
+            copyOp.run()
+        } finally {
+            opfactory.dispose()
+        }
+    }
+
+    static void move(File src, File dst) {
+        SVNCommandEnvironment env = getSVNCommandEnvironment()
+        SvnOperationFactory opfactory = createOperationFactory(env)
+        try {
+            SvnCopy copyOp = opfactory.createCopy()
+            copyOp.addCopySource(
+                    SvnCopySource.create(SvnTarget.fromFile(src), SVNRevision.WORKING))
+            copyOp.setSingleTarget(SvnTarget.fromFile(dst))
+            copyOp.setFailWhenDstExists(true)
+            copyOp.setMakeParents(true)
+            copyOp.setMove(true)
+            copyOp.run()
         } finally {
             opfactory.dispose()
         }