Files
AndroidIDE/app/src/main/java/com/itsaky/androidide/managers/ToolsManager.java
T
2021-09-06 19:14:53 +05:30

331 lines
13 KiB
Java

package com.itsaky.androidide.managers;
import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.ResourceUtils;
import com.blankj.utilcode.util.ZipUtils;
import com.itsaky.androidide.app.StudioApp;
import com.itsaky.androidide.models.ConstantsBridge;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.Logger;
import java.io.File;
import java.io.IOException;
import java.util.List;
import net.lingala.zip4j.ZipFile;
public class ToolsManager {
private static PreferenceManager prefs;
public static final int JLS_VERSION = 1;
public static final int LOGSENDER_VERSION = 1;
public static final int CLEANER_VERSION = 1;
public static final int GRADLE_API_VERSION = 2;
public static final String KEY_JLS_VERSION = "tools_jlsVersion";
public static final String KEY_LOGSENDER_VERSION = "tools_logsenderVersion";
public static final String KEY_CLEANER_VERSION = "tools_cleanerVersion";
public static final String KEY_GRADLE_API_VERSION = "tools_gradleApiVersion";
public static void init(StudioApp app, Runnable onFinish) {
prefs = app.getPrefManager();
copyBusyboxIfNeeded();
extractJlsIfNeeded();
extractLogsenderIfNeeded();
writeInitScript();
writeBashrc();
if(onFinish != null)
onFinish.run();
}
private static void copyBusyboxIfNeeded() {
File exec = Environment.BUSYBOX;
if(exec.exists()) return;
Environment.mkdirIfNotExits(exec.getParentFile());
ResourceUtils.copyFileFromAssets("data/busybox", exec.getAbsolutePath());
if(!exec.canExecute()) {
exec.setExecutable(true);
}
}
private static void writeBashrc() {
File rc = Environment.BASHRC;
if(!rc.exists()) {
FileIOUtils.writeFileFromString(rc, BASHRC);
}
}
private static void writeInitScript() {
FileIOUtils.writeFileFromString(Environment.INIT_SCRIPT, INIT_SCRIPT);
}
private static void extractJlsIfNeeded() {
boolean gson = false, jls = false, proto = false;
final List<File> files = FileUtils.listFilesInDir(Environment.JLS_HOME, true);
for(File f : files) {
gson = gson == true ? gson : f.getName().equals("gson.jar");
jls = jls == true ? jls : f.getName().equals("jls.jar");
proto = proto == true ? proto : f.getName().equals("protobuf.jar");
}
final boolean exists = gson && jls && proto;
final boolean isOld = JLS_VERSION > prefs.getInt(KEY_JLS_VERSION, 0);
if(!exists || isOld) {
try {
extractJls();
} catch (Throwable e) {}
}
}
private static void extractJls(){
final File jlsZip = new File(Environment.JLS_HOME, "jls.zip");
ResourceUtils.copyFileFromAssets("data/jls.zip", jlsZip.getAbsolutePath());
try {
ZipFile file = new ZipFile(jlsZip, ConstantsBridge.JLS_ZIP_PASSWORD_HASH.toCharArray());
file.extractAll(Environment.JLS_HOME.getAbsolutePath());
FileUtils.delete(jlsZip);
prefs.putInt(KEY_JLS_VERSION, JLS_VERSION);
} catch (Throwable th) {}
}
private static void extractLogsenderIfNeeded() {
try {
final boolean isOld = LOGSENDER_VERSION > prefs.getInt(KEY_LOGSENDER_VERSION, 0);
if(isOld) {
final File logsenderZip = new File(Environment.JLS_HOME, "logsender.zip");
ResourceUtils.copyFileFromAssets("data/logsender.zip", logsenderZip.getAbsolutePath());
ZipUtils.unzipFile(logsenderZip, Environment.HOME);
prefs.putInt(KEY_LOGSENDER_VERSION, LOGSENDER_VERSION);
}
} catch (IOException e) {}
}
private static final String BASHRC =
"PROMPT_DIRTRIM=2" +
"PS1=\'\\[\\e[0;34m\\]\\w\\[\\e[0m\\] \\[\\e[0;97m\\]$\\[\\e[0m\\] \'";
private static final String INIT_SCRIPT =
"import org.gradle.api.Plugin"
+ "\nimport org.gradle.api.Project"
+ "\nimport groovy.json.*"
+ "\n"
+ "\ngradle.projectsLoaded {"
+ "\n rootProject.subprojects.forEach { sub ->"
+ "\n sub.afterEvaluate {"
+ "\n sub.apply plugin: AndroidIDEPlugin"
+ "\n }"
+ "\n }"
+ "\n}"
+ "\n"
+ "\ngradle.projectsEvaluated {"
+ "\n IDEProject project = new IDEProject()"
+ "\n project.name = rootProject.getName()"
+ "\n project.displayName = rootProject.getDisplayName()"
+ "\n project.description = rootProject.getDescription()"
+ "\n project.path = rootProject.getPath()"
+ "\n "
+ "\n def tasks = rootProject.tasks"
+ "\n if(tasks != null && tasks.size() > 0) {"
+ "\n addTasks(project, rootProject)"
+ "\n }"
+ "\n "
+ "\n rootProject.subprojects.forEach { sub ->"
+ "\n addIDEProject(project, sub);"
+ "\n }"
+ "\n "
+ "\n File out = new File(\"" + Environment.PROJECT_DATA_FILE.getAbsolutePath() + "\")"
+ "\n out << new JsonBuilder( project ).toPrettyString()"
+ "\n "
+ "\n println \">>> PROJECT INITIALIZED <<<\""
+ "\n}"
+ "\n"
+ "\ndef addIDEProject (IDEProject parent, Project sub) {"
+ "\n if(parent == null || sub == null) {"
+ "\n return"
+ "\n }"
+ "\n "
+ "\n def isApp = sub.getPluginManager().hasPlugin(\"com.android.application\")"
+ "\n def isLibrary = sub.getPluginManager().hasPlugin(\"com.android.library\")"
+ "\n "
+ "\n if(!(isApp || isLibrary)) {"
+ "\n return"
+ "\n }"
+ "\n "
+ "\n IDEModule module = new IDEModule()"
+ "\n if(isApp) {"
+ "\n module = new IDEAppModule()"
+ "\n }"
+ "\n "
+ "\n def android = sub.android"
+ "\n def config = android.defaultConfig"
+ "\n "
+ "\n module.name = sub.getName()"
+ "\n module.displayName = sub.getDisplayName()"
+ "\n module.description = sub.getDescription()"
+ "\n module.path = sub.getPath()"
+ "\n module.buildToolsVersion = android.buildToolsVersion"
+ "\n module.compileSdkVersion = android.compileSdkVersion"
+ "\n module.minSdk = config.minSdkVersion"
+ "\n module.targetSdk = config.targetSdkVersion"
+ "\n module.versionCode = config.versionCode"
+ "\n module.versionName = config.versionName"
+ "\n "
+ "\n if(isApp) {"
+ "\n module.applicationId = config.applicationId"
+ "\n }"
+ "\n "
+ "\n def tasks = sub.tasks"
+ "\n if(tasks != null && tasks.size() > 0) {"
+ "\n addTasks(module, sub)"
+ "\n }"
+ "\n "
+ "\n def variants = null"
+ "\n if(isApp) {"
+ "\n variants = project.android.applicationVariants"
+ "\n } else if (isLibrary) {"
+ "\n variants = project.android.libraryVariants"
+ "\n } else {"
+ "\n println \"AndroidIDE: Cannot build variants of project: ${module.name}\""
+ "\n }"
+ "\n "
+ "\n if(variants != null) {"
+ "\n variants.all { variant ->"
+ "\n addDependencies(module, variant);"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n def subs = sub.getSubprojects()"
+ "\n if(subs != null && subs.size() > 0) {"
+ "\n subs.forEach { subOfSub -> "
+ "\n addIDEProject(module, subOfSub)"
+ "\n }"
+ "\n }"
+ "\n parent.modules.add(module)"
+ "\n}"
+ "\n"
+ "\ndef addDependencies(def module, def variant) {"
+ "\n variant.getCompileClasspath().each { dependency ->"
+ "\n def path = dependency.absolutePath"
+ "\n if(!module.dependencies.contains(path)) {"
+ "\n module.dependencies.add(dependency.absolutePath);"
+ "\n }"
+ "\n }"
+ "\n}"
+ "\n"
+ "\ndef addTasks (IDEProject project, Project gradleProject) {"
+ "\n if(project == null || gradleProject == null) {"
+ "\n return"
+ "\n }"
+ "\n "
+ "\n gradleProject.tasks.forEach { gradleTask -> "
+ "\n IDETask task = new IDETask()"
+ "\n task.name = gradleTask.getName()"
+ "\n task.description = gradleTask.getDescription()"
+ "\n task.group = gradleTask.getGroup()"
+ "\n task.path = gradleTask.getPath()"
+ "\n "
+ "\n project.tasks.add(task)"
+ "\n }"
+ "\n}"
+ "\n"
+ "\nclass AndroidIDEPlugin implements Plugin<Project> {"
+ "\n "
+ "\n def AAPT2_VERSION = \"4.0.1-6197926\""
+ "\n"
+ "\n @Override"
+ "\n void apply(Project project) {"
+ "\n "
+ "\n def isApp = project.getPluginManager().hasPlugin(\"com.android.application\")"
+ "\n def isLibrary = project.getPluginManager().hasPlugin(\"com.android.library\")"
+ "\n "
+ "\n if(!(isApp || isLibrary)) {"
+ "\n println \"Project: \" + project.getName() + \" doesn\'t apply Android\'s application or library plugin\""
+ "\n println \"AndroidIDE\'s plugin will not be applied to this project!\""
+ "\n return"
+ "\n }"
+ "\n "
+ "\n project.android {"
+ "\n sourceSets {"
+ "\n main.java.srcDirs += \"${System.getenv(\"HOME\")}/logsender\""
+ "\n }"
+ "\n }"
+ "\n "
+ "\n project.configurations.matching { it.name == \'_internal_aapt2_binary\' }.all { config ->"
+ "\n config.resolutionStrategy.eachDependency { details ->"
+ "\n details.useVersion(\"$AAPT2_VERSION\")"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n def variants = null"
+ "\n if(isApp) {"
+ "\n variants = project.android.applicationVariants"
+ "\n } else if (isLibrary) {"
+ "\n variants = project.android.libraryVariants"
+ "\n } else {"
+ "\n println \"AndroidIDE: Cannot find applicationVariants or libraryVariants\""
+ "\n return"
+ "\n }"
+ "\n "
+ "\n variants.all { variant ->"
+ "\n project.tasks.create(name: \"printDependencies${variant.name.capitalize()}\", group: \"Android IDE\", description: \"[AndroidIDE] List all dependencies in project including those in subprojects for ${variant.name.capitalize()} build.\") {"
+ "\n doLast {"
+ "\n printDependencies(project, variant)"
+ "\n }"
+ "\n }"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n def printDependencies(def project, def variant) {"
+ "\n println \">> DEPENDENCIES START <<\""
+ "\n variant.getCompileClasspath().each { dep ->"
+ "\n println \"{ \\\"file\\\": \\\"${dep.absolutePath}\\\"}\""
+ "\n }"
+ "\n println \"{ \\\"type\\\":\\\"ANDROID_JAR\\\", \\\"file\\\": \\\"${System.getenv(\'ANDROID_HOME\')}/platforms/${project.android.compileSdkVersion}/android.jar\\\"}\""
+ "\n println \">> DEPENDENCIES END <<\""
+ "\n }"
+ "\n}"
+ "\n"
+ "\nclass IDEProject {"
+ "\n def name = \"Not defined\""
+ "\n def displayName = \"Not defined\""
+ "\n def description = \"Not defined\""
+ "\n def path = \"Not defined\""
+ "\n List<IDEProject> modules = new ArrayList<IDEProject>()"
+ "\n List<IDETask> tasks = new ArrayList<IDETask>()"
+ "\n List<String> dependencies = new ArrayList<String>()"
+ "\n}"
+ "\n"
+ "\nclass IDEModule extends IDEProject {"
+ "\n def buildToolsVersion = 0"
+ "\n def compileSdkVersion = 0"
+ "\n def minSdk = 0"
+ "\n def targetSdk = 0"
+ "\n def versionCode = 0"
+ "\n def versionName = \"Not defined\""
+ "\n def isLibrary = true"
+ "\n}"
+ "\n"
+ "\nclass IDEAppModule extends IDEModule {"
+ "\n def applicationId = \"Not defined\""
+ "\n "
+ "\n public IDEAppModule() {"
+ "\n isLibrary = false"
+ "\n }"
+ "\n}"
+ "\n"
+ "\nclass IDETask {"
+ "\n def name = \"Not defined\""
+ "\n def description = \"Not defined\""
+ "\n def group = \"Not defined\""
+ "\n def path = \"Not defined\""
+ "\n}";
private static final Logger LOG = Logger.instance("ToolsManager");
}