installer: use offline bootstraps

This commit is contained in:
Leonid Plyushch 2019-02-25 14:06:37 +02:00
parent bd45837d93
commit d3d8aebd1c
2 changed files with 68 additions and 38 deletions

View file

@ -35,3 +35,10 @@ android {
dependencies { dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
} }
preBuild.doFirst {
assert file("./src/main/assets/bootstrap-aarch64").exists()
assert file("./src/main/assets/bootstrap-arm").exists()
assert file("./src/main/assets/bootstrap-i686").exists()
assert file("./src/main/assets/bootstrap-x86_64").exists()
}

View file

@ -4,6 +4,7 @@ import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager;
import android.os.Build; import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.UserManager; import android.os.UserManager;
@ -79,52 +80,74 @@ final class TermuxInstaller {
deleteFolder(STAGING_PREFIX_FILE); deleteFolder(STAGING_PREFIX_FILE);
} }
final byte[] buffer = new byte[8096]; final byte[] buffer = new byte[16384];
final List<Pair<String, String>> symlinks = new ArrayList<>(50); final List<Pair<String, String>> symlinks = new ArrayList<>(128);
final List<String> executables = new ArrayList<>(128);
final URL zipUrl = determineZipUrl(); final String bootstrapArchiveName = determineZipName();
try (ZipInputStream zipInput = new ZipInputStream(zipUrl.openStream())) { AssetManager assetManager = activity.getAssets();
try (ZipInputStream zipInput = new ZipInputStream(assetManager.open(bootstrapArchiveName))) {
ZipEntry zipEntry; ZipEntry zipEntry;
while ((zipEntry = zipInput.getNextEntry()) != null) { while ((zipEntry = zipInput.getNextEntry()) != null) {
if (zipEntry.getName().equals("SYMLINKS.txt")) { switch (zipEntry.getName()) {
BufferedReader symlinksReader = new BufferedReader(new InputStreamReader(zipInput)); case "EXECUTABLES.txt": {
String line; BufferedReader executablesReader = new BufferedReader(new InputStreamReader(zipInput));
while ((line = symlinksReader.readLine()) != null) { String line;
String[] parts = line.split(""); while ((line = executablesReader.readLine()) != null) {
if (parts.length != 2) executables.add(line);
throw new RuntimeException("Malformed symlink line: " + line); }
String oldPath = parts[0]; break;
String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
symlinks.add(Pair.create(oldPath, newPath));
ensureDirectoryExists(new File(newPath).getParentFile());
} }
} else { case "SYMLINKS.txt": {
String zipEntryName = zipEntry.getName(); BufferedReader symlinksReader = new BufferedReader(new InputStreamReader(zipInput));
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName); String line;
boolean isDirectory = zipEntry.isDirectory(); while ((line = symlinksReader.readLine()) != null) {
String[] parts = line.split("");
ensureDirectoryExists(isDirectory ? targetFile : targetFile.getParentFile()); if (parts.length != 2)
throw new RuntimeException("Malformed symlink line: " + line);
if (!isDirectory) { String oldPath = parts[0];
try (FileOutputStream outStream = new FileOutputStream(targetFile)) { String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
int readBytes; symlinks.add(Pair.create(oldPath, newPath));
while ((readBytes = zipInput.read(buffer)) != -1) ensureDirectoryExists(new File(newPath).getParentFile());
outStream.write(buffer, 0, readBytes);
} }
if (zipEntryName.startsWith("bin/") || zipEntryName.startsWith("libexec") || zipEntryName.startsWith("lib/apt/methods")) { break;
//noinspection OctalInteger }
Os.chmod(targetFile.getAbsolutePath(), 0700); default: {
String zipEntryName = zipEntry.getName();
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName);
boolean isDirectory = zipEntry.isDirectory();
ensureDirectoryExists(isDirectory ? targetFile : targetFile.getParentFile());
if (!isDirectory) {
try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
int readBytes;
while ((readBytes = zipInput.read(buffer)) != -1)
outStream.write(buffer, 0, readBytes);
}
} }
break;
} }
} }
} }
} }
if (symlinks.isEmpty()) if (!executables.isEmpty()) {
throw new RuntimeException("No SYMLINKS.txt encountered"); for (String executable : executables) {
for (Pair<String, String> symlink : symlinks) { //noinspection OctalInteger
Os.symlink(symlink.first, symlink.second); Os.chmod(STAGING_PREFIX_PATH + "/" + executable, 0700);
}
} else {
throw new RuntimeException("Installer: no EXECUTABLES.txt found while extracting environment archive.");
}
if (!symlinks.isEmpty()) {
for (Pair<String, String> symlink : symlinks) {
Os.symlink(symlink.first, symlink.second);
}
} else {
throw new RuntimeException("Installer: no SYMLINKS.txt found while extracting environment archive.");
} }
if (!STAGING_PREFIX_FILE.renameTo(PREFIX_FILE)) { if (!STAGING_PREFIX_FILE.renameTo(PREFIX_FILE)) {
@ -167,10 +190,10 @@ final class TermuxInstaller {
} }
} }
/** Get bootstrap zip url for this systems cpu architecture. */ /** Get bootstrap zip file name for this systems cpu architecture. */
private static URL determineZipUrl() throws MalformedURLException { private static String determineZipName() {
String archName = determineTermuxArchName(); String archName = determineTermuxArchName();
return new URL("https://termux.net/bootstrap/bootstrap-" + archName + ".zip"); return "bootstrap-" + archName;
} }
private static String determineTermuxArchName() { private static String determineTermuxArchName() {