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()
}