├── .gitignore ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── log-recover-app ├── build.gradle └── src │ └── main │ └── kotlin │ └── com │ └── getui │ └── rewrite │ └── LogRecoverApp.kt ├── log-rewrite-app ├── build.gradle ├── config.toml ├── config_multi.toml └── src │ ├── main │ └── kotlin │ │ └── com │ │ └── getui │ │ └── rewrite │ │ ├── LogRewriteApp.kt │ │ └── config.kt │ └── test │ └── kotlin │ └── com │ └── getui │ └── rewrite │ └── appTests.kt ├── log-rewrite-core ├── build.gradle └── src │ ├── main │ └── kotlin │ │ └── com │ │ └── getui │ │ └── rewrite │ │ └── LogRewriter.kt │ └── test │ └── kotlin │ └── com │ └── getui │ └── rewrite │ └── tests.kt ├── log-rewrite-gradle ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ ├── kotlin │ │ └── com │ │ │ └── getui │ │ │ ├── LogRewritePlugin.kt │ │ │ └── LogRewriter.kt.bak │ └── resources │ │ └── META-INF │ │ └── gradle-plugins │ │ └── getui.log-rewrite.properties │ └── test │ └── kotlin │ └── com │ └── getui │ └── LogRewritePluginIntegrationSpec.kt ├── rewrite-test-android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── getui │ │ └── test │ │ ├── MainActivity.java │ │ └── MainApplication.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── sym_keyboard_feedback_return.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── rewrite-test-java ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── getui │ └── rewrite │ └── test │ ├── App.java │ ├── LogUtil.java │ ├── RewriteTarget.java │ ├── notjavaExt.nojava │ └── plan.txt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .idea 3 | .gradle 4 | .gradletasknamecache 5 | !.gitignore 6 | *.iml 7 | .project 8 | .classpath 9 | .settings -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # log rewrite 2 | ## log-rewrite-app 3 | 项目根目录运行 4 | `gradle :log-rewrite-app:distZip` 5 | 6 | `log-rewrite-app/build/distributions/log-rewrite-app.zip`为目标打包应用 7 | 8 | 解压之后`bin`目录下有可执行脚本文件 9 | 10 | 然后运行脚本`./log-rewrite-app -c config-path` 11 | 配置文件格式见下面详细说明 12 | 13 | ## log-recover-app 14 | 项目根目录运行 15 | `gradle :log-recover-app:distZip` 16 | 同上然后运行脚本`./log-recover-app -m mapping-1.txt -m mapping-2.txt -l f1.log -l f2.log -d the/dist/dir` 17 | 便可恢复日志。 `-m` `-l` 后可以多次添加map、日志文件;`-d`为恢复后的日志输出文件夹路劲。 18 | 19 | 20 | # 配置文件说明 21 | 22 | 23 | # 格式为toml 24 | 25 | ```toml 26 | 27 | projectShortName="grd" #the shot name for target project 28 | versionCode=1 29 | 30 | [[unit]] 31 | [[unit.signatures]] 32 | sign="com.getui.rewrite.test.LogUtil log(String)" 33 | argsIndex=[0] 34 | 35 | [[unit.signatures]] 36 | sign="com.getui.rewrite.test.LogUtil log(String,String)" 37 | argsIndex=[1] 38 | 39 | [[unit.signatures]] 40 | sign="com.getui.rewrite.test.LogUtil log(String,String)" 41 | argsIndex=[0] 42 | isTag=true 43 | 44 | [[unit.signatures]] 45 | sign="com.getui.rewrite.test.LogUtil debug(String)" 46 | # ## default is argsIndex=[0] 47 | 48 | [unit.source] 49 | dirs=[ 50 | "/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/src/main/java" 51 | ] 52 | 53 | [unit.distribution] 54 | dir="/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/build/rewrite/src/main/java" 55 | mappingDir="/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/build/rewrite/mapping" 56 | ``` 57 | 58 | ### 字段说明 59 | * `projectShortName` 模块名简称,一个项目里有多模块的时候区分各模块,比如`sdk` `gks` `etc`,如果只有一个模块就写项目名简称,字符尽量短 比如 `gy` 60 | 61 | * `versionCode` 版本号,每次发版的时候递增1, 用来区分不同版本的日志 62 | 63 | * `unit.signatures.sign` 日志函数签名, 参数若为其他类型需要加上完整包名 64 | `demo.LogUtil log(String,String,com.getui.LogInfo)` 65 | 66 | * `unit.signatures.argsIndex` 需要混淆的参数index , 用中括号包围起来 eg: `[1]` 67 | * `unit.source.dirs` 源代码路径,若为相对路径则为 `log-rewrite-app`脚本的相对路径 68 | * `unit.distribution.dir` 重写后存放代码的路径 69 | * `unit.distribution.mappingDir` 重写后存放映射表的路径 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.1.1' 3 | 4 | repositories { 5 | jcenter() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | // dependencies { 12 | // classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | // } 14 | } 15 | apply plugin: 'kotlin' 16 | repositories { 17 | mavenCentral() 18 | } 19 | dependencies { 20 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" 21 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Apr 17 16:57:29 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | ndk.dir=/usr/local/opt/android-sdk/ndk-bundle 2 | sdk.dir=/usr/local/opt/android-sdk -------------------------------------------------------------------------------- /log-recover-app/build.gradle: -------------------------------------------------------------------------------- 1 | version 'unspecified' 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.1.1' 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | apply plugin: 'kotlin' 15 | apply plugin: 'idea' 16 | apply plugin: 'application' 17 | 18 | mainClassName = 'com.getui.rewrite.LogRecoverAppKt' 19 | 20 | repositories { 21 | jcenter() 22 | mavenCentral() 23 | } 24 | 25 | run { 26 | args = [ 27 | '-m', 28 | '../build/tmp/sdk_v1_1_log_mapping.txt', 29 | '-l', "${rootDir}/build/tmp/31.log", 30 | '-d', "$rootDir/build" 31 | ] 32 | } 33 | 34 | dependencies { 35 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" 36 | compile 'com.xenomachina:kotlin-argparser:2.0.0' 37 | compile "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlin_version" 38 | 39 | testCompile 'junit:junit:4.12' 40 | testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" 41 | } 42 | -------------------------------------------------------------------------------- /log-recover-app/src/main/kotlin/com/getui/rewrite/LogRecoverApp.kt: -------------------------------------------------------------------------------- 1 | package com.getui.rewrite 2 | 3 | import com.xenomachina.argparser.ArgParser 4 | import org.jetbrains.kotlin.com.intellij.util.containers.MultiMap 5 | import java.io.File 6 | import java.util.* 7 | import java.util.regex.Pattern 8 | 9 | /** 10 | * Created by fox on 24/04/2017. 11 | */ 12 | 13 | fun main(args: Array): Unit { 14 | val parser = ArgParser(args) 15 | val app = App(parser) 16 | app.run { 17 | recover() 18 | } 19 | } 20 | 21 | class App(parser: ArgParser) { 22 | val verbose by parser.flagging("-v", "--verbose", help = "enable verbose mode") 23 | val mappingFiles by parser.adding("-m", "--mapping", help = "the mapping files") { File(this) } 24 | val logFiles by parser.adding("-l", "--log", help = "the log files") { File(this) } 25 | val distDir by parser.storing("-d", "--dist", help = "the dist dir") { File(this) } 26 | 27 | // val version by parser.storing("-V", "--version", help = "target version code [number]") { toInt() } 28 | val mapping = LinkedHashMap>() 29 | 30 | //https://regex101.com/r/a3QaYz/1 31 | val normalPattern = Pattern.compile("()") 32 | 33 | //https://regex101.com/r/vTJGaw/4 34 | val formatPattern = Pattern.compile("()") 35 | 36 | val formatArgsPattern = Pattern.compile("(%(?:[scbdxofaegh%n]|tx))") 37 | private fun fullFormatPattern(mappingItem: MappingItem): Regex { 38 | //https://regex101.com/r/RFrFuT/4 39 | return Regex("(?:)+") 40 | } 41 | 42 | fun recover(): Unit { 43 | readMapping() 44 | 45 | logFiles.forEach { file -> 46 | file.bufferedReader().use { reader -> 47 | File(distDir, file.name).bufferedWriter().use { writer -> 48 | var line: String 49 | while (true) { 50 | line = reader.readLine() 51 | if (line == null) break 52 | val matcher = normalPattern.matcher(line) 53 | var newLine: String = line + "" 54 | while (matcher.find()) { //normal recover 55 | val token = matcher.group(1) 56 | val projectName = matcher.group(2) 57 | val appVersion = matcher.group(3).toInt() 58 | val targetVersion = matcher.group(4).toInt() 59 | val id = matcher.group(5).toLong() 60 | val replaceMent = findReplacement(projectName, appVersion, targetVersion, id) ?: "<------can not find check mapping or report bug----->" 61 | newLine = newLine.replace(token, replaceMent) 62 | } 63 | // recover format 64 | val formatMatcher = formatPattern.matcher(line) 65 | var formatTokenList = LinkedList() 66 | while (formatMatcher.find()) { 67 | val token = formatMatcher.group(1) 68 | val projectName = formatMatcher.group(2) 69 | val appVersion = formatMatcher.group(3).toInt() 70 | val targetVersion = formatMatcher.group(4).toInt() 71 | val id = formatMatcher.group(5).toLong() 72 | val replaceMent = formatMatcher.group(6) 73 | formatTokenList.add(MappingItem(id, replaceMent, projectName, appVersion, targetVersion)) 74 | } 75 | formatTokenList.groupBy { it.id }.forEach { id, items -> 76 | val first = items.first() 77 | val mappingReplacement = findReplacement(first.projectName, first.appVersion, first.targetVersion, id) 78 | if (mappingReplacement != null) { 79 | val argsMattcher = formatArgsPattern.matcher(mappingReplacement) 80 | var newReplace = mappingReplacement + "" 81 | var index = 0 82 | while (argsMattcher.find()) { 83 | newReplace = newReplace.replaceFirst(argsMattcher.group(1), items[index++].replaceMent) 84 | } 85 | newLine = newLine.replace(fullFormatPattern(first), newReplace) 86 | } 87 | } 88 | writer.write(newLine) 89 | writer.newLine() 90 | } 91 | } 92 | } 93 | } 94 | 95 | } 96 | 97 | private fun findReplacement(projectName: String?, appVersion: Int, targetVersion: Int, id: Long): String? { 98 | val projectMapping = mapping.get(projectName) 99 | return projectMapping?.get(id)?.filter { item -> 100 | item.appVersion == appVersion 101 | && item.targetVersion == targetVersion 102 | }?.first()?.replaceMent 103 | } 104 | 105 | private fun readMapping() { 106 | mappingFiles.forEach { file -> 107 | file.bufferedReader().use { reader -> 108 | var first = reader.readLine() 109 | if (!first.startsWith("#") && !first.contains(":")) { 110 | throw RuntimeException("the mapping file has error format,without header. [${file.absolutePath}]") 111 | } 112 | first = first.trimStart('#') 113 | val meta = first.split(":") 114 | val projectName = meta[0] 115 | val appVersion = meta[1] 116 | val targetVersion = meta[2] 117 | var line: String? 118 | while (true) { 119 | line = reader.readLine() 120 | if (line == null) break 121 | if (!line.startsWith("#")) { 122 | try { 123 | val pair = line.split("=", limit = 2) 124 | val id = pair[0].toLong() 125 | val replaceMent = pair[1] 126 | var projMapping = mapping.get(projectName) 127 | if (projMapping == null) { 128 | projMapping = MultiMap() 129 | mapping.put(projectName, projMapping) 130 | } 131 | projMapping.putValue(id, MappingItem(id, replaceMent, projectName, appVersion.toInt(), targetVersion.toInt())) 132 | } catch (e: Exception) { 133 | e.printStackTrace() 134 | } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | 141 | class MappingItem(val id: Long, val replaceMent: String, val projectName: String, val appVersion: Int, val targetVersion: Int) 142 | } -------------------------------------------------------------------------------- /log-rewrite-app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.1.1' 3 | 4 | repositories { 5 | mavenCentral() 6 | } 7 | dependencies { 8 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 9 | } 10 | } 11 | 12 | apply plugin: 'kotlin' 13 | apply plugin: 'idea' 14 | apply plugin: 'application' 15 | version 'unspecified' 16 | mainClassName = 'com.getui.rewrite.LogRewriteAppKt' 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | } 21 | 22 | dependencies { 23 | compile project(':log-rewrite-core') 24 | compile 'com.xenomachina:kotlin-argparser:2.0.0' 25 | compile 'com.moandjiezana.toml:toml4j:0.7.1' 26 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" 27 | 28 | testCompile 'junit:junit:4.12' 29 | testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" 30 | } 31 | -------------------------------------------------------------------------------- /log-rewrite-app/config.toml: -------------------------------------------------------------------------------- 1 | 2 | projectShortName="grd" #the shot name for target project 3 | versionCode=1 4 | 5 | [[unit]] 6 | [[unit.signatures]] 7 | sign="com.getui.rewrite.test.LogUtil log(String)" 8 | argsIndex=[0] 9 | 10 | [[unit.signatures]] 11 | sign="com.getui.rewrite.test.LogUtil log(String,String)" 12 | argsIndex=[1] 13 | 14 | [[unit.signatures]] 15 | sign="com.getui.rewrite.test.LogUtil log(String,String)" 16 | argsIndex=[0] 17 | isTag=true 18 | 19 | [[unit.signatures]] 20 | sign="com.getui.rewrite.test.LogUtil debug(String)" 21 | # ## default is argsIndex=[0] 22 | 23 | [unit.source] 24 | dirs=[ 25 | "/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/src/main/java" 26 | ] 27 | 28 | [unit.distribution] 29 | dir="/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/build/rewrite/src/main/java" 30 | mappingDir="/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/build/rewrite/mapping" 31 | -------------------------------------------------------------------------------- /log-rewrite-app/config_multi.toml: -------------------------------------------------------------------------------- 1 | 2 | projectShotName="grd" #the shot name for target project 3 | versionCode=1 4 | 5 | [[unit]] 6 | [[unit.signatures]] 7 | sign="" 8 | argsIndex=[1] 9 | 10 | [[unit.signatures]] 11 | sign="" 12 | argsIndex=[1] 13 | 14 | [unit.source] 15 | dirs=[ 16 | "/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/src/main/java" 17 | ] 18 | #includeExt=[".java"] #ignore include all 19 | #excludeExt=[] #ignore or empty will exclude none 20 | 21 | [unit.distribution] 22 | dir="/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-java/build/rewrite/src/main/java" 23 | 24 | ########################################################################################## 25 | 26 | # another rewrite unit 27 | [[unit]] 28 | [[unit.signatures]] 29 | sign="" 30 | argsIndex=[1] # 31 | 32 | [[unit.signatures]] 33 | sign="" 34 | argsIndex=[1] 35 | 36 | [unit.source] 37 | dirs=[ 38 | "/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-android/src/main/java" 39 | ] 40 | includeExt=[ 41 | ".java" 42 | ] 43 | #excludeExt=[] 44 | 45 | [unit.distribution] 46 | dir="/Users/fox/workspace/getui/tools/log-rewrite/rewrite-test-android/build/rewrite/src/main/java" 47 | 48 | -------------------------------------------------------------------------------- /log-rewrite-app/src/main/kotlin/com/getui/rewrite/LogRewriteApp.kt: -------------------------------------------------------------------------------- 1 | package com.getui.rewrite 2 | 3 | import com.getui.LogRewriter 4 | import com.getui.RewriteOption 5 | import com.xenomachina.argparser.ArgParser 6 | import org.apache.commons.lang.StringUtils 7 | //import org.apache.commons.cli.* 8 | import java.io.File 9 | 10 | /** 11 | * Created by fox on 17/04/2017. 12 | */ 13 | 14 | fun main(args: Array): Unit { 15 | // args?.forEach(::println) 16 | var path = "config.toml" 17 | if (args.size > 0) { 18 | val parser = ArgParser(args) 19 | val myargs = App.Args(parser) 20 | myargs.run { 21 | if (StringUtils.isNotEmpty(config)) { 22 | path = config 23 | } 24 | val file = File(path) 25 | if (file.exists()) { 26 | App(file).rewrite() 27 | } 28 | } 29 | } else { 30 | App(File("/Users/fox/workspace/getui/getui-sdkframework-android-as/gks/log_rewrite_config.toml")).rewrite() 31 | // println("config file not found:[${file.absolutePath}]") 32 | println("usage |-c --config the config file path.") 33 | } 34 | 35 | 36 | /* 37 | val options = Options() 38 | val cfgOption = Option("c", "config", true, "the config file path") 39 | cfgOption.isRequired = false 40 | options.addOption(cfgOption) 41 | val parser = DefaultParser() 42 | 43 | val cmd: CommandLine? 44 | var configPath: String = "config.toml" 45 | try { 46 | cmd = parser.parse(options, args) 47 | println("opt===:${cmd.getOptionValue(cfgOption.opt)}") 48 | println("longOpt===:${cmd.getOptionValue(cfgOption.longOpt)}") 49 | configPath = cmd.getOptionValue(cfgOption.longOpt) 50 | println("the path is :[$configPath]") 51 | } catch (e: ParseException) { 52 | println("parse command argument failure") 53 | printHelp(options) 54 | } catch (e: Exception) { 55 | e.printStackTrace() 56 | } 57 | val cfgFile = File(configPath) 58 | if (cfgFile.exists()) { 59 | App(cfgFile).rewrite() 60 | } else { 61 | println("config file not found:[${cfgFile.absolutePath}]") 62 | printHelp(options) 63 | System.exit(1) 64 | 65 | } 66 | */ 67 | } 68 | 69 | 70 | /* 71 | fun printHelp(options: Options) { 72 | val formatter = HelpFormatter() 73 | formatter.printHelp("utility-name", options) 74 | } 75 | */ 76 | 77 | 78 | class App(val config: File) { 79 | class Args(parser: ArgParser) { 80 | val verbose by parser.flagging("-v", "--verbose", help = "enable verbose mode") 81 | val config by parser.storing("-c", "--config", help = "the config file path") 82 | // val version by parser.storing("-V", "--version", help = "target version code [number]") { toInt() } 83 | } 84 | 85 | fun rewrite(): kotlin.Unit { 86 | val cfg = Config.read(config) 87 | cfg.unit.forEach { unit -> 88 | val options = unit.signatures.map { sign -> 89 | val signature = sign.sign 90 | val argsIndex = sign.argsIndex 91 | val index = if (argsIndex == null) { 92 | 0 93 | } else { 94 | argsIndex[0] 95 | } 96 | RewriteOption(signature, index, true) 97 | } 98 | val dist = unit.distribution 99 | val distDir = File(dist.dir) 100 | val mappingDir = dist.mappingDir 101 | val distMappingDir = if (StringUtils.isEmpty(mappingDir)) { 102 | distDir.parentFile 103 | } else { 104 | distDir.parentFile 105 | } 106 | LogRewriter(options, File(unit.source.dirs[0]), distDir, distMappingDir, targetVersionCode = cfg.versionCode,projectName = cfg.projectShortName).rewrite() 107 | } 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /log-rewrite-app/src/main/kotlin/com/getui/rewrite/config.kt: -------------------------------------------------------------------------------- 1 | package com.getui.rewrite 2 | 3 | import com.google.gson.GsonBuilder 4 | import com.google.gson.JsonObject 5 | import com.google.gson.reflect.TypeToken 6 | import com.moandjiezana.toml.Toml 7 | import java.io.File 8 | import java.io.FileNotFoundException 9 | 10 | /** 11 | * Created by fox on 18/04/2017. 12 | */ 13 | 14 | object Config { 15 | fun read(config: File): Configuration { 16 | if (!config.exists()) { 17 | throw ConfigErrorException("config file not found", 18 | FileNotFoundException("file on path:[${config.absolutePath}] can not found") 19 | ) 20 | } 21 | val toml: Toml 22 | try { 23 | toml = Toml().read(config) 24 | return toml.to(Configuration::class.java) 25 | // val gson = GsonBuilder() 26 | // .create() 27 | // val jsonTree = gson.toJsonTree(toml.toMap()) as JsonObject 28 | // val jsonArray = JsonArray() 29 | // jsonTree.entrySet().forEach { jsonArray.add(it.value) } 30 | // val unitList = gson.fromJson>(jsonTree.get("unit"), object : TypeToken>() {}.type) 31 | // = toml.to(ConfigUnitList::class.java) 32 | // return unitList 33 | } catch (e: Exception) { 34 | throw ConfigErrorException(e) 35 | } 36 | } 37 | 38 | class ConfigErrorException : Exception { 39 | constructor(msg: String) : super(msg) 40 | constructor(e: Throwable) : super(e) 41 | constructor(msg: String, throwable: Throwable) : super(msg, throwable) 42 | } 43 | 44 | class Configuration(val unit: List, val projectShortName: String, val versionCode: Int) 45 | class Unit(val signatures: Array, val source: Source, val distribution: Distribution) 46 | class Signature(val sign: String, val argsIndex: IntArray = intArrayOf(0), val isStatic: Boolean = true) 47 | class Source(val dirs: Array, val includeExt: Array?, val excludeExt: Array?) 48 | data class Distribution(val dir: String, val mappingDir: String? = null) 49 | } -------------------------------------------------------------------------------- /log-rewrite-app/src/test/kotlin/com/getui/rewrite/appTests.kt: -------------------------------------------------------------------------------- 1 | package com.getui.rewrite 2 | 3 | import org.junit.Test 4 | import java.io.File 5 | 6 | /** 7 | * Created by fox on 18/04/2017. 8 | */ 9 | 10 | 11 | class ConfigReadTest { 12 | @Test fun readConfig(): kotlin.Unit { 13 | val configPath = "config.toml" 14 | // val configPath = "config_multi.toml" 15 | val cfgFile = File(configPath) 16 | try { 17 | val cfg = Config.read(cfgFile) 18 | println(cfg) 19 | } catch (e: Exception) { 20 | println(e) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /log-rewrite-core/build.gradle: -------------------------------------------------------------------------------- 1 | version '0.0.1-SNAPSHOT' 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.1.1' 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | apply plugin: 'kotlin' 15 | 16 | repositories { 17 | jcenter() 18 | mavenCentral() 19 | } 20 | 21 | configurations { 22 | // compile.extendsFrom antlr4 23 | compile.extendsFrom compileShaded 24 | } 25 | 26 | dependencies { 27 | compileShaded files("${System.getProperty('java.home')}/../lib/tools.jar") 28 | compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" 29 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" 30 | compile 'com.netflix.devinsight.rewrite:rewrite-core:1.0.0' 31 | compile "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlin_version" 32 | testCompile 'junit:junit:4.12' 33 | testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" 34 | } 35 | -------------------------------------------------------------------------------- /log-rewrite-core/src/main/kotlin/com/getui/rewrite/LogRewriter.kt: -------------------------------------------------------------------------------- 1 | package com.getui 2 | 3 | import com.netflix.rewrite.ast.Expression 4 | import com.netflix.rewrite.ast.Tr 5 | import com.netflix.rewrite.ast.Type 6 | import com.netflix.rewrite.parse.OracleJdkParser 7 | import com.netflix.rewrite.parse.Parser 8 | import com.netflix.rewrite.refactor.Refactor 9 | import org.apache.commons.lang.StringUtils 10 | import org.jetbrains.kotlin.com.intellij.util.containers.ConcurrentMultiMap 11 | import java.io.File 12 | import java.nio.file.Paths 13 | import java.util.* 14 | import java.util.concurrent.ConcurrentLinkedDeque 15 | import java.util.concurrent.atomic.AtomicLong 16 | import java.util.function.Consumer 17 | import java.util.regex.Pattern 18 | import kotlin.streams.asStream 19 | 20 | /** 21 | * Created by fox on 12/04/2017. 22 | */ 23 | 24 | const val VERSION_CODE = 1 25 | val formatArgsPattern = Pattern.compile("(%(?:[scbdxofaegh%n]|tx))") 26 | 27 | class LogRewriter(val options: Collection, val source: File, val dist: File, val distDir: File, val targetVersionCode: Int = 1, val projectName: String = "") { 28 | val parser: Parser = OracleJdkParser() 29 | val logMapping = LogMapping(distDir, targetVersionCode, projectName) 30 | 31 | fun rewrite(): Unit { 32 | val treeWalk = source.walk() 33 | val javaSources = treeWalk 34 | .apply { 35 | filter { it.isFile && !it.name.endsWith(".java") } 36 | .forEach { 37 | val newFile = transformDistPath(it, source, dist) 38 | it.copyTo(newFile, true) 39 | } 40 | } 41 | .filter { it.name.endsWith(".java", true) } 42 | .map { Paths.get(it.toURI()) } 43 | // .asStream() 44 | // .parallel() 45 | .toList() 46 | val parserResult = parser.parse(javaSources) 47 | parserResult 48 | .forEach { unit -> 49 | unit.refactor(Consumer { tx -> 50 | unit.classes.forEach { clazz -> 51 | options.forEach { option -> 52 | if (option.isStaticMethod) { 53 | clazz.findMethodCalls(option.signature) 54 | .forEach { mc -> 55 | val args = mc.args.args 56 | if (args.lastIndex < option.argumentIndex) throw RewriteOptionIllegalException( 57 | """ 58 | |on file :[${unit.sourcePath}] 59 | |on class: [${clazz.javaClass.canonicalName}] 60 | | the method [${mc.type?.declaringType?.fullyQualifiedName}] found by signature :[${option.signature}] 61 | | the argument maxIndex:[${args.lastIndex}] less than your config :[${option.argumentIndex}] 62 | |-> ${mc.simpleName} 63 | """.trimMargin()) 64 | val expression = args[option.argumentIndex] 65 | logMapping.refactor(clazz, expression, tx) 66 | } 67 | } 68 | } 69 | } 70 | val fix = tx.fix() 71 | val newFile = transformDistPath(File(unit.sourcePath), source, dist) 72 | newFile.writeText(fix.print()) 73 | }) 74 | } 75 | logMapping.finish() 76 | } 77 | } 78 | 79 | fun transformDistPath(srcFile: File, srcDir: File, dist: File): File { 80 | val fullPathStr = srcFile.absolutePath 81 | val newPathStr = fullPathStr.replace(srcDir.absolutePath, dist.absolutePath) 82 | val newFile = File(newPathStr) 83 | val dir = newFile.parentFile 84 | if (!dir.exists()) dir.mkdirs() 85 | return newFile 86 | } 87 | 88 | 89 | class LogMapping(val distDir: File, val targetVersionCode: Int, val projectName: String) { 90 | val TOKEN = "$projectName|${VERSION_CODE}_$targetVersionCode:" 91 | val PREFIX = "" 93 | val FORMAT_PREFIX = fun(id: Long): String { return "" 95 | private fun rewriteNormal(id: Long): String { 96 | return "$PREFIX${TOKEN}$id$POSTFIX" 97 | } 98 | 99 | // val IDENT_PREFIX = "" 101 | 102 | data class Item(val clazz: Tr.ClassDecl, val placement: String, val id: Long) 103 | 104 | val mapping: ConcurrentLinkedDeque = ConcurrentLinkedDeque() 105 | val originMapping: ConcurrentMultiMap = ConcurrentMultiMap() 106 | 107 | val ID_GENERATOR = AtomicLong(0) 108 | fun refactor(clazz: Tr.ClassDecl, target: Expression, refactor: Refactor): Unit { 109 | val originSb = StringBuilder() 110 | refactor(clazz, target, refactor, originSb) 111 | originMapping.putValue(clazz, originSb.toString()) 112 | } 113 | 114 | fun finish(): Unit { 115 | //todo write mapping to disk 116 | val parent = distDir.parentFile 117 | if (!parent.exists()) { 118 | parent.mkdirs() 119 | } 120 | val prefix = "${projectName}_v${VERSION_CODE}_$targetVersionCode" 121 | 122 | File(distDir, "${prefix}_log_mapping.txt").bufferedWriter().use { out -> 123 | out.write("#$projectName:$VERSION_CODE:$targetVersionCode") 124 | out.newLine() 125 | mapping.groupBy { it.clazz } 126 | .forEach { t, u -> 127 | out.write("#${(t.type as Type.Class).fullyQualifiedName}") 128 | out.newLine() 129 | u.forEach { 130 | out.write("${it.id}=${it.placement}") 131 | out.newLine() 132 | } 133 | } 134 | } 135 | 136 | File(distDir, "${prefix}_human_mapping.txt").bufferedWriter().use { out -> 137 | originMapping.entrySet().forEach { t -> 138 | out.write((t.key.type as Type.Class).fullyQualifiedName) 139 | out.newLine() 140 | t.value?.forEach { 141 | out.write(" $it") 142 | } 143 | } 144 | } 145 | } 146 | 147 | private fun pushMapping(clazz: Tr.ClassDecl, placement: String): Long { 148 | val id = ID_GENERATOR.getAndIncrement() 149 | mapping.add(Item(clazz, placement, id)) 150 | return id 151 | } 152 | 153 | 154 | private fun refactor(clazz: Tr.ClassDecl, target: Expression, refactor: Refactor, originSb: StringBuilder): Unit { 155 | when (target) { 156 | is Tr.Literal -> { 157 | refactor.changeLiteral(target) { t -> 158 | when (t) { 159 | is String -> { 160 | val id = pushMapping(clazz, t) 161 | originSb.append("$PREFIX$t$POSTFIX") 162 | // originMapping.putValue(clazz, originSb.toString()) 163 | return@changeLiteral rewriteNormal(id) 164 | } 165 | else -> return@changeLiteral t 166 | } 167 | } 168 | } 169 | is Tr.Binary -> { 170 | refactor(clazz, target.left, refactor, originSb) 171 | refactor(clazz, target.right, refactor, originSb) 172 | } 173 | is Tr.MethodInvocation -> { 174 | if (StringUtils.equals("java.lang.String", target.type?.declaringType?.fullyQualifiedName) 175 | && StringUtils.equals("format", target.type?.name)) { 176 | var argFormat: Tr.Literal? = null 177 | 178 | val arg0 = target.args.args[0] 179 | when (arg0) { 180 | is Tr.Ident -> { 181 | if (isLocaleIdent(arg0)) { 182 | argFormat = target.args.args[1] as Tr.Literal 183 | } 184 | } 185 | is Tr.FieldAccess -> { 186 | val argTarget = arg0.target 187 | when (argTarget) { 188 | is Tr.Ident -> { 189 | if (isLocaleIdent(argTarget)) { 190 | argFormat = target.args.args[1] as Tr.Literal 191 | } 192 | } 193 | } 194 | } 195 | is Tr.Literal -> argFormat = arg0 196 | } 197 | if (argFormat != null) { 198 | refactor.changeLiteral(argFormat) { t -> 199 | t as String 200 | val id = pushMapping(clazz, t) 201 | 202 | val matcher = formatArgsPattern.matcher(t) 203 | val builder = StringBuilder() 204 | while (matcher.find()) { 205 | for (i in 1..matcher.groupCount()) { 206 | builder.append(FORMAT_PREFIX(id)) 207 | .append(matcher.group(i)) 208 | .append(FORMAT_POSTFIX) 209 | } 210 | originSb.append("String::format($t ,...)") 211 | } 212 | // originMapping.putValue(clazz, originSb.toString()) 213 | return@changeLiteral builder.toString() 214 | } 215 | } 216 | } 217 | } 218 | } 219 | } 220 | } 221 | 222 | 223 | fun isLocaleIdent(target: Tr.Ident): Boolean { 224 | val fullName = Locale::class.qualifiedName 225 | val targetName = (target.type as Type.Class).fullyQualifiedName 226 | return StringUtils.equals(fullName, targetName) 227 | } 228 | 229 | class RewriteOptionIllegalException(override val message: String?) : RuntimeException() 230 | 231 | 232 | data class RewriteOption(val signature: String 233 | , val argumentIndex: Int = 0 234 | , val isStaticMethod: Boolean = true) -------------------------------------------------------------------------------- /log-rewrite-core/src/test/kotlin/com/getui/rewrite/tests.kt: -------------------------------------------------------------------------------- 1 | package com.getui.rewrite 2 | 3 | import com.getui.LogRewriter 4 | import com.getui.RewriteOption 5 | import org.junit.Test 6 | import java.io.File 7 | import java.nio.file.Paths 8 | 9 | /** 10 | * Created by fox on 17/04/2017. 11 | */ 12 | 13 | class TestRewriteSource { 14 | val rootProjectPath = "/Users/fox/workspace/getui/tools/log-rewrite" 15 | @Test fun rewriteByDir(): Unit { 16 | val source = Paths.get(rootProjectPath, "rewrite-test-java", "src", "main", "java") 17 | val dist = Paths.get(rootProjectPath, "rewrite-test-java", "build", "rewrite", "src", "main", "java") 18 | val logRewriter = LogRewriter( 19 | listOf(RewriteOption(signature = "com.getui.rewrite.test.LogUtil log(String)", argumentIndex = 0) 20 | , RewriteOption(signature = "com.getui.rewrite.test.LogUtil log(String,String)", argumentIndex = 1) 21 | , RewriteOption(signature = "com.getui.rewrite.test.LogUtil debug(String)", argumentIndex = 0) 22 | ) 23 | , source.toFile() 24 | , dist.toFile() 25 | , Paths.get(rootProjectPath, "rewrite-test-java", "build", "rewrite").toFile() 26 | , 3 27 | , "demo" 28 | ) 29 | logRewriter.rewrite() 30 | } 31 | } -------------------------------------------------------------------------------- /log-rewrite-gradle/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.1.1' 3 | 4 | repositories { 5 | mavenCentral() 6 | } 7 | dependencies { 8 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 9 | } 10 | // dependencies { 11 | // classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | // } 13 | } 14 | plugins { 15 | id "com.gradle.plugin-publish" version "0.9.7" 16 | // id "nebula.nebula-release" version "4.0.1" 17 | // id 'nebula.plugin-plugin' version '5.6.0' 18 | id "nebula.kotlin" version "1.1.1" 19 | id 'idea' 20 | } 21 | 22 | group 'com.getui' 23 | version '1.0-SNAPSHOT' 24 | description 'rewrite the java log code....' 25 | 26 | 27 | sourceCompatibility = 1.8 28 | 29 | repositories { 30 | jcenter() 31 | mavenCentral() 32 | } 33 | 34 | dependencies { 35 | // compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" 36 | compile gradleApi() 37 | compile 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.1' 38 | compile 'org.jetbrains.kotlin:kotlin-reflect:1.1.1' 39 | compile 'com.android.tools.build:gradle:2.3.1' 40 | compile 'com.netflix.devinsight.rewrite:rewrite-core:1.0.0' 41 | testCompile group: 'junit', name: 'junit', version: '4.12' 42 | } 43 | 44 | pluginBundle { 45 | plugins { 46 | logRewrite { 47 | id = 'getui.log-rewrite' 48 | displayName = 'java log rewrite plugin' 49 | description = project.description 50 | tags = ['rewrite', 'log'] 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /log-rewrite-gradle/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/log-rewrite-gradle/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /log-rewrite-gradle/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 12 15:13:09 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip 7 | -------------------------------------------------------------------------------- /log-rewrite-gradle/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /log-rewrite-gradle/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /log-rewrite-gradle/src/main/kotlin/com/getui/LogRewritePlugin.kt: -------------------------------------------------------------------------------- 1 | package com.getui 2 | 3 | import com.android.build.gradle.BaseExtension 4 | import org.gradle.api.DefaultTask 5 | import org.gradle.api.Plugin 6 | import org.gradle.api.Project 7 | import com.android.build.gradle.LibraryPlugin; 8 | import com.android.build.gradle.LibraryExtension; 9 | import org.gradle.api.plugins.JavaPlugin 10 | import org.gradle.api.tasks.TaskAction 11 | import java.io.File 12 | 13 | /** 14 | * Created by fox on 12/04/2017. 15 | */ 16 | 17 | class LogRewritePlugin : Plugin { 18 | override fun apply(project: Project) { 19 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 20 | project.plugins.withType(LibraryPlugin::class.java) { 21 | val create = project.tasks.create("logRewrite", LoRewriteTask::class.java) 22 | val task = project.tasks.findByName("preBuild") 23 | if (task != null) { 24 | task.dependsOn.add(create) 25 | } 26 | } 27 | } 28 | 29 | } 30 | 31 | open class LoRewriteTask : DefaultTask() { 32 | @TaskAction 33 | fun rewriteLog() { 34 | val targetPath = File(project.buildDir,"rewrite") 35 | val androidExtension = project.extensions.getByName("android") as BaseExtension 36 | val sourceSets = androidExtension.sourceSets 37 | for (ss in sourceSets) { 38 | val java = ss.java 39 | val name = ss.name 40 | val srcDirs = java.srcDirs 41 | val file = File(targetPath, name) 42 | file.mkdirs() 43 | 44 | 45 | } 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /log-rewrite-gradle/src/main/kotlin/com/getui/LogRewriter.kt.bak: -------------------------------------------------------------------------------- 1 | package com.getui 2 | 3 | import com.netflix.rewrite.ast.Expression 4 | import com.netflix.rewrite.ast.Tr 5 | import com.netflix.rewrite.parse.OracleJdkParser 6 | import com.netflix.rewrite.parse.Parser 7 | import com.netflix.rewrite.refactor.Refactor 8 | import org.apache.commons.lang.StringUtils 9 | import org.jetbrains.kotlin.com.intellij.util.containers.ConcurrentMultiMap 10 | import java.io.File 11 | import java.nio.file.Paths 12 | import java.util.concurrent.ConcurrentLinkedDeque 13 | import java.util.concurrent.atomic.AtomicLong 14 | import java.util.function.Consumer 15 | import java.util.regex.Pattern 16 | import kotlin.streams.asStream 17 | 18 | /** 19 | * Created by fox on 12/04/2017. 20 | */ 21 | class LogRewriter(val options: Collection, val source: File, val dist: File) { 22 | val parser: Parser = OracleJdkParser() 23 | 24 | fun rewrite(): Unit { 25 | val treeWalk = source.walk() 26 | val javaSources = treeWalk.filter { it.name.endsWith(".java", true) } 27 | .map { Paths.get(it.toURI()) } 28 | .asStream().parallel() 29 | .map { path -> 30 | val parserResult= parser.parse(listOf(path)) 31 | parserResult 32 | .forEach { unit -> 33 | unit.refactor(Consumer { tx -> 34 | unit.classes.forEach { clazz -> 35 | options.forEach { option -> 36 | if (option.isStaticMethod) { 37 | clazz.findMethodCalls(option.signature) 38 | .forEach { mc -> 39 | val args = mc.args.args 40 | if (args.lastIndex < option.argumentIndex) throw RewriteOptionIllegalException( 41 | """ 42 | |on file :[$path] 43 | |on class: [${clazz.javaClass.canonicalName}] 44 | | the method [${mc.type?.declaringType?.fullyQualifiedName}] found by signature :[${option.signature}] 45 | | the argument maxIndex:[${args.lastIndex}] less than your config :[${option.argumentIndex}] 46 | |-> ${mc.simpleName} 47 | """.trimMargin()) 48 | val expression = args[option.argumentIndex] 49 | LogMapping.refactor(clazz, expression, tx) 50 | } 51 | } 52 | } 53 | } 54 | val fix = tx.fix() 55 | val fullPathStr = path.toFile().absolutePath 56 | val newPathStr = fullPathStr.replace(source.absolutePath, dist.absolutePath) 57 | val newFile=File(newPathStr) 58 | val dir = newFile.parentFile 59 | if(!dir.exists()) dir.mkdirs() 60 | newFile.writeText(fix.print()) 61 | }) 62 | } 63 | return@map parserResult 64 | } 65 | .forEach{} 66 | } 67 | } 68 | 69 | 70 | object LogMapping { 71 | const val PREFIX = "" 73 | val FORMAT_PREFIX = fun(id: Long): String { return "" 75 | 76 | const val IDENT_PREFIX = "" 78 | 79 | data class Item(val clazz: Tr.ClassDecl, val placement: String, val id: Long) 80 | 81 | val mapping: ConcurrentLinkedDeque = ConcurrentLinkedDeque() 82 | val originMapping: ConcurrentMultiMap = ConcurrentMultiMap() 83 | 84 | val ID_GENERATOR = AtomicLong(0) 85 | fun refactor(clazz: Tr.ClassDecl, target: Expression, refactor: Refactor): Unit { 86 | val originSb = StringBuilder() 87 | refactor(clazz, target, refactor, originSb) 88 | originMapping.putValue(clazz, originSb.toString()) 89 | } 90 | 91 | fun finish(): Unit { 92 | //todo write mapping to disk 93 | } 94 | 95 | private fun pushMapping(clazz: Tr.ClassDecl, placement: String): Long { 96 | val id = ID_GENERATOR.getAndIncrement() 97 | mapping.add(Item(clazz, placement, id)) 98 | return id 99 | } 100 | 101 | private fun refactor(clazz: Tr.ClassDecl, target: Expression, refactor: Refactor, originSb: StringBuilder): Unit { 102 | when (target) { 103 | is Tr.Literal -> { 104 | refactor.changeLiteral(target) { t -> 105 | when (t) { 106 | is String -> { 107 | val id = pushMapping(clazz, t) 108 | originSb.append("$PREFIX$t$POSTFIX") 109 | return@changeLiteral "$PREFIX$id$POSTFIX" 110 | } 111 | else -> { 112 | originSb.append(t) 113 | return@changeLiteral t 114 | } 115 | } 116 | } 117 | } 118 | is Tr.Binary -> { 119 | refactor(clazz, target.left, refactor, originSb) 120 | refactor(clazz, target.right, refactor, originSb) 121 | } 122 | is Tr.MethodInvocation -> { 123 | if (StringUtils.equals("java.lang.String", target.type?.declaringType?.fullyQualifiedName) 124 | && StringUtils.equals("format", target.type?.name)) { 125 | var argFormat: Tr.Literal? = null 126 | 127 | val arg0 = target.args.args[0] 128 | when (arg0) { 129 | is Tr.Ident -> { 130 | if (StringUtils.equals("locale", arg0.simpleName)) { 131 | argFormat = target.args.args[1] as Tr.Literal 132 | } 133 | } 134 | is Tr.Literal -> argFormat = arg0 135 | } 136 | if (argFormat != null) { 137 | refactor.changeLiteral(argFormat) { t -> 138 | t as String 139 | val id = pushMapping(clazz, t) 140 | 141 | val matcher = Pattern.compile("(?:.*?(%(?:[scbdxofaegh%n]|tx)).*?)+").matcher(t) 142 | if (matcher.find()) { 143 | val builder = StringBuilder() 144 | for (i in 1..matcher.groupCount()) { 145 | builder.append(FORMAT_PREFIX(id)) 146 | .append(matcher.group(i)) 147 | .append(FORMAT_POSTFIX) 148 | } 149 | originSb.append("String::format($t ,...)") 150 | return@changeLiteral builder.toString() 151 | } 152 | return@changeLiteral t 153 | } 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | 161 | 162 | class RewriteOptionIllegalException(override val message: String?) : RuntimeException() 163 | 164 | 165 | data class RewriteOption(val signature: String 166 | , val argumentIndex: Int = 0 167 | , val isStaticMethod: Boolean = true) -------------------------------------------------------------------------------- /log-rewrite-gradle/src/main/resources/META-INF/gradle-plugins/getui.log-rewrite.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.getui.LogRewritePlugin -------------------------------------------------------------------------------- /log-rewrite-gradle/src/test/kotlin/com/getui/LogRewritePluginIntegrationSpec.kt: -------------------------------------------------------------------------------- 1 | package com.getui 2 | /** 3 | * Created by fox on 12/04/2017. 4 | */ 5 | class LogRewritePluginIntegrationSpec { 6 | 7 | } -------------------------------------------------------------------------------- /rewrite-test-android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:2.3.0' 7 | //classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' 8 | //classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' 9 | // NOTE: Do not place your application dependencies here; they belong 10 | // in the individual module build.gradle files 11 | } 12 | } 13 | 14 | apply plugin: 'com.android.application' 15 | 16 | sourceCompatibility = 1.8 17 | 18 | repositories { 19 | jcenter() 20 | mavenCentral() 21 | } 22 | 23 | dependencies { 24 | compile 'com.android.support:appcompat-v7:25.+' 25 | compile 'com.android.support:design:25.+' 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | testCompile 'junit:junit:4.12' 28 | } 29 | 30 | android{ 31 | compileSdkVersion 25 32 | buildToolsVersion '25.0.2' 33 | 34 | defaultConfig { 35 | minSdkVersion 14 36 | targetSdkVersion 25 37 | versionCode 1 38 | versionName '0.0.1' 39 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 40 | } 41 | lintOptions { 42 | abortOnError false 43 | } 44 | packagingOptions { 45 | exclude 'META-INF/LICENSE.txt' 46 | exclude 'META-INF/NOTICE.txt' 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/java/com/getui/test/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.getui.test; 2 | import android.os.Bundle; 3 | import android.support.design.widget.FloatingActionButton; 4 | import android.support.design.widget.Snackbar; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Button; 10 | /** 11 | * Created by fox on 18/04/2017. 12 | */ 13 | public class MainActivity extends AppCompatActivity { 14 | FloatingActionButton fab; 15 | ViewGroup container; 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | // Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 21 | // setSupportActionBar(toolbar); 22 | 23 | // fab = (FloatingActionButton) findViewById(R.id.fab); 24 | // fab.setOnClickListener(new View.OnClickListener() { 25 | // @Override 26 | // public void onClick(View view) { 27 | // //to do something 28 | // } 29 | // }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/java/com/getui/test/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.getui.test; 2 | 3 | import android.app.Application; 4 | /** 5 | * Created by fox on 18/04/2017. 6 | */ 7 | public class MainApplication extends Application { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 15 | 16 | 22 | 27 | 33 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/rewrite-test-android/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/mipmap-hdpi/sym_keyboard_feedback_return.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/rewrite-test-android/src/main/res/mipmap-hdpi/sym_keyboard_feedback_return.png -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/rewrite-test-android/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/rewrite-test-android/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foxundermoon/log-rewrite/3e38e6ec5c8c0e1ab6fb4a5ae5aabc365a0ee688/rewrite-test-android/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 64dp 7 | 8 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #009688 4 | #00796B 5 | #B2DFDB 6 | #FF0000 7 | #448AFF 8 | #212121 9 | #727272 10 | #FFFFFF 11 | #B6B6B6 12 | 13 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 16dp 7 | 8 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | log-rewrite-test 3 | 4 | -------------------------------------------------------------------------------- /rewrite-test-android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |