19 Commits
1 .. 1.3
Author SHA1 Message Date
josephsmendoza 8c29691361 UI & search improvements 2019-10-17 01:17:50 -07:00
josephsmendoza c392631339 fix "failed to load curl" 2019-10-11 02:14:14 -07:00
josephsmendoza c5de32f6dd fix windows search path 2019-10-11 02:04:59 -07:00
josephsmendoza 2df8f900d6 fixed installer issues 2019-10-11 01:00:25 -07:00
josephsmendoza 73abfb8fa8 GUI done, abi needs fix before release 2019-10-10 15:33:35 -07:00
Joseph mendozaandGitHub a62f1e998f Delete build.sh 2019-09-23 23:58:59 -07:00
Joseph mendozaandGitHub 7821de4bb4 Delete build.ps1 2019-09-23 23:58:50 -07:00
Joseph Mendoza 97a89f4382 basic gui alost done 2 2019-09-23 23:58:09 -07:00
Joseph Mendoza 7aab701aa1 basic gui almost done 2019-09-23 23:57:09 -07:00
josephsmendoza b8686d4a04 proper dub project structure 2019-09-11 05:40:28 -07:00
Joseph mendozaandGitHub 2be4c47213 Update README.md 2019-09-10 19:26:44 -07:00
Joseph mendozaandGitHub d5582d17e3 Delete gui.d 2019-09-10 19:18:10 -07:00
Joseph mendozaandGitHub ba1ba3937d Delete cli.d 2019-09-10 19:17:55 -07:00
Joseph mendozaandGitHub fef18f8b68 Delete build.sh 2019-09-10 19:17:45 -07:00
Joseph mendozaandGitHub d137448a7b Delete build.cmd 2019-09-10 19:17:34 -07:00
Joseph mendozaandGitHub 4ce50aa635 Delete adbi.d 2019-09-10 19:17:23 -07:00
Joseph mendozaandGitHub ed5f4d7813 Delete adbi.cmd 2019-09-10 19:17:07 -07:00
josephsmendoza 433330f743 Merge branch 'master' of https://github.com/josephsmendoza/ADB-Installer 2019-09-10 19:08:33 -07:00
josephsmendoza e7f00bdff7 pre-gui work 2019-09-10 19:07:57 -07:00
14 changed files with 391 additions and 172 deletions
+3
View File
@@ -0,0 +1,3 @@
bin
res
.dub
+1 -1
View File
@@ -1,4 +1,4 @@
# ADB-Installer
# Android Debug Bridge Installer
Download from [Releases](https://github.com/josephsmendoza/ADB-Installer/releases)
This is a re-implementation of the [15 seconds ADB Installer](https://forum.xda-developers.com/showthread.php?t=2588979)
-130
View File
@@ -1,130 +0,0 @@
/+ dub.sdl:
targetPath "bin/$PLATFORM/$ARCH"
+/
import std.path;
import std.stdio : writeln;
import std.algorithm.searching : canFind;
import std.process : environment;
bool sys,user,silent,verbose;
string installDir;
int installTools(){
import std.zip,std.conv,std.file,std.net.curl,std.conv : octal;
version(Windows) string url="https://dl.google.com/android/repository/platform-tools-latest-windows.zip";
version(OSX) string url="https://dl.google.com/android/repository/platform-tools-latest-darwin.zip";
version(linux) string url="https://dl.google.com/android/repository/platform-tools-latest-linux.zip";
ubyte[] data;
auto http=HTTP(url);
http.onReceive=(ubyte[] response){
data~=response;
return response.length;
};
http.perform();
"Download complete".writeln();
auto zip=new ZipArchive(data);
foreach (x;zip.directory){
auto path=buildNormalizedPath(installDir,x.name[15 .. $]);
if(x.compressedSize!=0){
if(!path.dirName.exists) path.dirName.mkdirRecurse();
if(path.exists) path.remove();
zip.expand(x);
write(path, x.expandedData);
setAttributes(path,octal!775);
} else {
try if(path.isFile) {
path.remove;
path.mkdirRecurse;
} catch (Exception e) path.mkdirRecurse;
}
}
"Extraction complete".writeln();
return 0;
}
int installPath(){
string path=environment.get("PATH");
if(path.canFind(installDir)){
"Install folder is already in PATH".writeln;
return 0;
}
version(Windows){
import std.windows.registry;
Key env;
if(user){
env=Registry.currentUser.getKey("Environment",REGSAM.KEY_ALL_ACCESS);
}
if(sys){
env=Registry.localMachine.getKey("SYSTEM").getKey("CurrentControlSet")
.getKey("Control").getKey("Session Manager").getKey("Environment",REGSAM.KEY_ALL_ACCESS);
}
path=env.getValue("Path").value_SZ;
path~=pathSeparator~installDir;
env.setValue("Path",path);
//import core.sys.windows.winuser; SendNotifyMessageW(HWND_BROADCAST,WM_SETTINGCHANGE,cast(ulong)null,cast(long)"Environment");
} else {
import std.file : append;
if(user) append("~/.profile".expandTilde,"\nexport PATH=$PATH"~pathSeparator~installDir);
if(sys) append("/etc/profile","\nexport PATH=$PATH"~pathSeparator~installDir);
}
"Install folder was added to PATH".writeln();
"logout/login or reboot to coplete install".writeln();
return 0;
}
int install(){
if(user) "Installing for current user".writeln();
if(sys) "Installing for all users".writeln();
("Installing to " ~ installDir).writeln();
return installTools() + installPath();
}
int main(string[] args){
import std.getopt : getopt,defaultGetoptPrinter;
auto xargs=getopt(args,
"all-users|a","Install for all users.",&sys,
"user|u","Install for current user.",&user,
//"silent|s","Silent standard output.",&silent,
//"verbose|v","Verbose standard output.",&verbose,
"install-dir|i","Install to specified directory",&installDir
);
if(installDir){
installDir=installDir.buildNormalizedPath.absolutePath;
if(!sys && !user){
string allHome="~".expandTilde.dirName;
if(!allHome.isRooted && installDir.canFind(allHome)) user=true;
else sys=true;
}
return install();
}
if(user || sys){
auto append=buildNormalizedPath("Android","SDK","platform-tools");
if(user){
version(Windows)installDir=buildNormalizedPath(environment.get("LocalAppData"),append);
version(linux)installDir=buildNormalizedPath("~".expandTilde,append);
version(OSX)installDir=buildNormalizedPath("~/Library".expandTilde,append);
return install();
}
if(sys){
version(Windows)installDir=buildNormalizedPath(environment.get("ProgramFiles"),append);
version(linux)installDir=buildNormalizedPath("/opt",append);
version(OSX)installDir=buildNormalizedPath("/Library",append);
return install();
}
}
defaultGetoptPrinter("Download platform-tools and add to PATH.",xargs.options);
return 0;
}
-3
View File
@@ -1,3 +0,0 @@
@echo off
%~dp0\adbi.exe %*
pause
-2
View File
@@ -1,2 +0,0 @@
dub build --single adbi.d
ptiso create -z lzma -c crc32 -x stub ptse_cmd.stub -x runas admin -x mount_system_visible 0 -x process_visible 1 -x run_relative 1 -x use_stderr 1 -x run_exe adbi.cmd -x icon adb.ico ADB-Installer.exe bin/windows/x86_64
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
dub build --single adbi.d
upx --best bin/linux/x86_64/adbi
-3
View File
@@ -1,3 +0,0 @@
/+ dub.sdl
sourceFiles "adbi.d"
+/
+23
View File
@@ -0,0 +1,23 @@
name "adbi"
description "Android Debug Bridge Installer"
authors "josephsmendoza"
copyright "Copyright © 2019, josephsmendoza"
license "GPL-3.0"
targetType "executable"
targetPath "bin/$PLATFORM/$ARCH"
dflags "-Llib/curl.lib" platform="windows"
configuration "application" {
excludedSourceFiles "source/cli.d"
dependency "tkd" version="1.1.13"
copyFiles \
"$TCLTK_PACKAGE_DIR/dist/$ARCH/tcl86t.dll" \
"$TCLTK_PACKAGE_DIR/dist/$ARCH/tk86t.dll" \
"$TCLTK_PACKAGE_DIR/dist/library" \
"C:/windows/system32/msvcr110.dll" \
"C:/windows/system32/vcruntime140.dll" \
"lib/libcurl.dll" \
platform="windows"
}
configuration "cli" {
excludedSourceFiles "source/gui.d"
}
-30
View File
@@ -1,30 +0,0 @@
/+ dub.sdl:
dependency "tkd" version="1.1.13"
targetPath "bin/$PLATFORM/$ARCH"
copyFiles \
"$TCLTK_PACKAGE_DIR/dist/$ARCH/tcl86t.dll" \
"$TCLTK_PACKAGE_DIR/dist/$ARCH/tk86t.dll" \
"$TCLTK_PACKAGE_DIR/dist/library" \
platform="windows"
+/
import tkd.tkdapplication;
class GUI : TkdApplication
{
override protected void initInterface()
{
auto frame = new Frame().pack(5);
new Label(frame, "Select an install location").pack(0);
auto searchLabel=new Label(frame,"Searching for pre-existing files...").pack(0);
new Button(frame, "System").pack(0);
new Button(frame, "User").pack(0);
new Button(frame, "Mixed").pack(0);
}
}
void main(string[] args)
{
auto gui = new GUI();
gui.run();
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+141
View File
@@ -0,0 +1,141 @@
import std.path, std.process, std.algorithm.searching, std.stdio;
private string APPEND;
bool userMode;
version (Windows) string HOME = "HOMEPATH";
version (Posix) string HOME = "HOME";
enum LogLevel {
SILENT,
silent = SILENT,
s = SILENT,
ERROR,
error = ERROR,
e = ERROR,
INFO,
info = INFO,
i = INFO,
VERBOSE,
verbose = VERBOSE,
v = VERBOSE
}
alias SILENT = LogLevel.SILENT;
alias ERROR = LogLevel.ERROR;
alias INFO = LogLevel.INFO;
alias VERBOSE = LogLevel.VERBOSE;
LogLevel logLevel = INFO;
void function(string message, int messageMode = INFO) log;
private string append() {
if (!APPEND)
APPEND = buildNormalizedPath("Android", "SDK", "platform-tools");
return APPEND;
}
string defaultUserDir() {
version (Windows) string dir = "C:/" ~ environment.get(HOME) ~ "/AppData/Local";
version (linux) string dir = "~";
version (OSX) string dir = "~/Library";
return buildNormalizedPath(dir.expandTilde, append);
}
string defaultAllUsersDir() {
version (Windows) string dir = "C:/Program Files";
version (linux) string dir = "/opt";
version (OSX) string dir = "/Library";
return buildNormalizedPath(dir, append);
}
bool isUserDir(string installDir) {
return installDir.canFind(environment.get(HOME));
}
void installTools(string installDir) {
import std.zip, std.file, std.net.curl, std.conv;
version (Windows) string url = "https://dl.google.com/android/repository/platform-tools-latest-windows.zip";
version (OSX) string url = "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip";
version (linux) string url = "https://dl.google.com/android/repository/platform-tools-latest-linux.zip";
log("Downloading");
log(url, VERBOSE);
ubyte[] data;
auto http = HTTP(url);
http.onReceive = (ubyte[] response) {
data ~= response;
return response.length;
};
http.perform();
log("Extracting");
log(installDir, VERBOSE);
auto zip = new ZipArchive(data);
foreach (zipEntry; zip.directory) {
auto extractPath = buildNormalizedPath(installDir, zipEntry.name[15 .. $]);
if (zipEntry.compressedSize != 0) {
log(zipEntry.name, VERBOSE);
if (extractPath.exists && extractPath.isDir) {
rmdirRecurse(extractPath);
} else if (!extractPath.dirName.exists)
mkdirRecurse(extractPath.dirName);
zip.expand(zipEntry);
extractPath.write(zipEntry.expandedData);
version (Posix)
setAttributes(extractPath, octal!775);
} else {
if (extractPath.exists) {
if (extractPath.isFile) {
extractPath.remove();
extractPath.mkdir();
}
} else
extractPath.mkdirRecurse();
}
}
}
void installPath(string installDir) {
import std.process : environment;
log("Adding to PATH");
string path = environment.get("PATH");
if (path.canFind(installDir)) {
log("Install folder is already in PATH");
return;
}
version (Windows) {
import std.windows.registry : Registry, Key, REGSAM;
Key env;
if (userMode) {
env = Registry.currentUser.getKey("Environment", REGSAM.KEY_ALL_ACCESS);
} else {
env = Registry.localMachine.getKey("SYSTEM").getKey("CurrentControlSet").getKey("Control")
.getKey("Session Manager").getKey("Environment", REGSAM.KEY_ALL_ACCESS);
}
path = env.getValue("Path").value_SZ;
path ~= pathSeparator ~ installDir;
env.setValue("Path", path);
//import core.sys.windows.winuser; SendNotifyMessageW(HWND_BROADCAST,WM_SETTINGCHANGE,cast(ulong)null,cast(long)"Environment");
} else {
import std.file : exists,append,write;
string profile;
string installProfile = "\nexport PATH=$PATH" ~ pathSeparator ~ installDir;
if (userMode)
profile = "~/.profile".expandTilde;
else
profile = "/etc/profile";
if (profile.exists)
append(profile, installProfile);
else {
write(profile, installProfile);
}
}
log("logout or reboot to finish install");
}
+41
View File
@@ -0,0 +1,41 @@
import adbi, std.getopt;
private void log(string message, int messageMode = INFO) {
if (logLevel < messageMode)
return;
if (messageMode == ERROR) {
import std.stdio : stderr;
stderr.writeln(message);
} else {
import std.stdio : writeln;
writeln(message);
}
}
void main(string[] args) {
adbi.log = &cli.log;
string installDir;
try {
auto xargs = getopt(args,
"user-mode|u", "Install for current user only instead of all users.", &userMode,
"install-dir|i", "Path to install folder.", &installDir,
"log-level|l", "silent, error, info, or verbose", &logLevel);
if (xargs.helpWanted) {
defaultGetoptPrinter("Install Android Platform Tools", xargs.options);
return;
}
if (!installDir) {
if (userMode)
installDir = defaultUserDir;
else
installDir = defaultAllUsersDir;
} else if (installDir.isUserDir)
userMode = true;
installTools(installDir);
installPath(installDir);
} catch (Exception e) {
log(cast(string) e.message, ERROR);
}
}
+182
View File
@@ -0,0 +1,182 @@
import tkd.tkdapplication, tkd.widget.widget;
import adbi;
import std.concurrency, std.parallelism, std.process, std.file, std.regex,
std.path, std.string, std.algorithm.searching, std.stdio, std.uni;
import core.time;
string[] skip = ["temp"];
Widget packPreset(Widget w) {
return w.pack(0, 0, GeometrySide.top, GeometryFill.both, AnchorPosition.center, true);
}
bool isWriteable(DirEntry d) {
try
File(d.name, "a").close();
catch (Exception e)
return false;
return true;
}
bool isInstallable(DirEntry d) {
if (!d.isWriteable)
return false;
foreach (s; skip) {
if (d.name.toLower.canFind(s)) {
return false;
}
}
return true;
}
class Application : TkdApplication {
private Label instructionLabel;
private Label statusLabel;
private Tid searchThread;
enum {
STATUS = LogLevel.max + 1,
INSTRUCT,
OPTION,
KILL
}
static void search() {
version (Windows) {
skip ~= "recycle.bin";
string regex = "(.*)(\\\\)(adb.exe|fastboot.exe)($)";
string[] dirs = [
"C:\\Program Files", "C:\\Program Files (x86)",
"C:" ~ environment.get("HOMEPATH"), "C:\\"
];
} else
string regex = "(.*)(\\/)(adb|fastboot)($)";
version (linux) string[] dirs = ["/usr", "/opt"];
version (OSX) string[] dirs = ["/Library", "/Applications"];
version (Posix) {
dirs ~= ["~".expandTilde, "/"];
}
adbi.log = &Application.log;
string[] results;
void search(DirEntry dir) {
try {
foreach (DirEntry d; dirEntries(dir.name, SpanMode.shallow)) {
receiveTimeout(seconds(-1), delegate(int i) {
if (i != KILL) {
log("Unsupported signal received by search thread", ERROR);
return;
} else
return;
});
if (d.isDir)
search(d);
else if (d.name.matchFirst(regex)) {
string s = d.name.dirName.strip;
if (!results.canFind(s) && d.isInstallable) {
results ~= s;
log(s, OPTION);
}
}
}
} catch (Exception e) {
log(cast(string) e.message, ERROR);
}
}
log("Searching for install locations");
log(defaultAllUsersDir, OPTION);
log(defaultUserDir, OPTION);
log("Select install location", INSTRUCT);
results ~= [defaultAllUsersDir, defaultUserDir, ""];
foreach (string dir; dirs) {
search(DirEntry(dir));
}
log("Search done");
}
static void log(string message, int messageMode = INFO) {
ownerTid.send(messageMode);
ownerTid.send(message);
}
int mode;
private void receiveInt(int i) {
mode = i;
}
static void install(string dir) {
adbi.log = &Application.log;
if (dir.isUserDir)
adbi.userMode = true;
try {
log("Please Wait", INSTRUCT);
adbi.installTools(dir);
adbi.installPath(dir);
log("You can close this window", INSTRUCT);
} catch (immutable Exception e) {
ownerTid.send(e);
}
}
private void receiveString(string message) {
switch (mode) {
case INFO:
case STATUS:
statusLabel.setText(message);
break;
case INSTRUCT:
instructionLabel.setText(message);
break;
case OPTION:
new Button(message).setCommand(delegate(CommandArgs args) {
spawn(&install, message);
}).packPreset();
break;
case ERROR:
import std.stdio;
stderr.writeln(message);
break;
default:
break;
}
mode = INFO;
}
private void receiveException(immutable Exception e) {
throw e;
}
private void idleCommand(CommandArgs args) {
this.mainWindow.setIdleCommand(&idleCommand);
receiveTimeout(seconds(-1), &receiveString, &receiveInt, &receiveException);
}
private void exitCommand(CommandArgs args) {
this.exit();
}
private void directoryDialog(CommandArgs args) {
string dir = new DirectoryDialog().show().getResult();
if (dir.isDir)
spawn(&install, dir);
}
override protected void initInterface() {
this.mainWindow.setMinSize(300, 0);
instructionLabel = new Label("Please wait").pack();
statusLabel = new Label("Loading").pack();
new Button("Manually select folder").setCommand(&directoryDialog).packPreset();
this.mainWindow.setIdleCommand(&idleCommand);
this.mainWindow.setProtocolCommand(WindowProtocol.deleteWindow, &exitCommand);
searchThread = spawn(&search);
}
}
void main() {
adbi.log = &Application.log;
auto app = new Application();
app.run();
}