Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c29691361 | ||
|
|
c392631339 | ||
|
|
c5de32f6dd | ||
|
|
2df8f900d6 | ||
|
|
73abfb8fa8 | ||
|
|
a62f1e998f | ||
|
|
7821de4bb4 | ||
|
|
97a89f4382 | ||
|
|
7aab701aa1 | ||
|
|
b8686d4a04 | ||
|
|
2be4c47213 | ||
|
|
d5582d17e3 | ||
|
|
ba1ba3937d | ||
|
|
fef18f8b68 | ||
|
|
d137448a7b | ||
|
|
4ce50aa635 | ||
|
|
ed5f4d7813 | ||
|
|
433330f743 | ||
|
|
e7f00bdff7 |
@@ -0,0 +1,3 @@
|
||||
bin
|
||||
res
|
||||
.dub
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
%~dp0\adbi.exe %*
|
||||
pause
|
||||
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
dub build --single adbi.d
|
||||
upx --best bin/linux/x86_64/adbi
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
+141
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user