Skip to content

Alpine Linux Backend #1401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@
"globals": ["Global1"]
},
"files": {
"include": ["src/**/*", "utils/**/*.js", "www/**/*.js", "www/res/**/*.css"],
"include": [
"src/**/*",
"utils/**/*.js",
"www/**/*.js",
"www/res/**/*.css",
"src/plugins/terminal"
],
"ignore": [
"ace-builds",
"www/js/**/*.js",
Expand Down
30 changes: 30 additions & 0 deletions hooks/post-process.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-console */
const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');

const buildFilePath = path.resolve(__dirname, '../build.json');
const copyToPath = path.resolve(__dirname, '../platforms/android/build.json');
Expand Down Expand Up @@ -28,6 +29,35 @@ deleteDirRecursively(resPath, [
'xml',
]);
copyDirRecursively(localResPath, resPath);
enableLegacyJni()


function enableLegacyJni() {
const prefix = execSync('npm prefix').toString().trim();
const gradleFile = path.join(prefix, 'platforms/android/app/build.gradle');

if (!fs.existsSync(gradleFile)) return;

let content = fs.readFileSync(gradleFile, 'utf-8');
// Check for correct block to avoid duplicate insertion
if (content.includes('useLegacyPackaging = true')) return;

// Inject under android block with correct Groovy syntax
content = content.replace(/android\s*{/, match => {
return (
match +
`
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}`
);
});

fs.writeFileSync(gradleFile, content, 'utf-8');
console.log('[Cordova Hook] ✅ Enabled legacy JNI packaging');
}

/**
* Copy directory recursively
Expand Down
28 changes: 26 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
"cordova-plugin-sdcard": {},
"cordova-plugin-browser": {},
"cordova-plugin-iap": {},
"cordova-plugin-system": {},
"cordova-plugin-advanced-http": {
"ANDROIDBLACKLISTSECURESOCKETPROTOCOLS": "SSLv3,TLSv1"
},
"cordova-plugin-websocket": {},
"com.foxdebug.acode.rk.exec.terminal": {},
"cordova-plugin-buildinfo": {}
"cordova-plugin-buildinfo": {},
"cordova-plugin-system": {},
"com.foxdebug.acode.rk.exec.terminal": {}
},
"platforms": [
"android"
Expand Down Expand Up @@ -88,6 +88,7 @@
"sass": "^1.77.2",
"sass-loader": "^14.2.1",
"style-loader": "^4.0.0",
"terminal": "^0.1.4",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4"
},
Expand Down
3 changes: 2 additions & 1 deletion src/lib/checkFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ export default async function checkFiles() {
* @returns {Promise<void>}
*/
async function checkFile(file) {
if (file.isUnsaved || !file.loaded || file.loading) return;
if (file === undefined || file.isUnsaved || !file.loaded || file.loading)
return;

if (file.uri) {
const fs = fsOperation(file.uri);
Expand Down
1 change: 0 additions & 1 deletion src/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import NotificationManager from "lib/notificationManager";
import { addedFolder } from "lib/openFolder";
import { getEncoding, initEncodings } from "utils/encodings";
import auth, { loginEvents } from "./auth";
import constants from "./constants";

const previousVersionCode = Number.parseInt(localStorage.versionCode, 10);

Expand Down
27 changes: 27 additions & 0 deletions src/pages/fileBrowser/fileBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,33 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) {
);
}

// Check for Terminal Home Directory storage
try {
const isTerminalInstalled = await Terminal.isInstalled();
if (typeof Terminal !== "undefined" && isTerminalInstalled) {
const isTerminalSupported = await Terminal.isSupported();

if (isTerminalSupported && isTerminalInstalled) {
const terminalHomeUrl = cordova.file.dataDirectory + "alpine/home";

// Check if this storage is not already in the list
const terminalStorageExists = allStorages.find(
(storage) =>
storage.uuid === "terminal-home" ||
storage.url === terminalHomeUrl,
);

if (!terminalStorageExists) {
util.pushFolder(allStorages, "Terminal Home", terminalHomeUrl, {
uuid: "terminal-home",
});
}
}
}
} catch (error) {
console.error("Error checking Terminal installation:", error);
}

try {
const res = await externalFs.listStorages();
res.forEach((storage) => {
Expand Down
122 changes: 122 additions & 0 deletions src/plugins/system/android/com/foxdebug/system/System.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package com.foxdebug.system;


import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.io.IOException;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ClipData;
Expand Down Expand Up @@ -47,6 +52,10 @@
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;


public class System extends CordovaPlugin {

Expand Down Expand Up @@ -156,6 +165,66 @@ public void run() {
}
);
return true;
case "fileExists":
callbackContext.success(fileExists(args.getString(0),args.getString(1)) ? 1 : 0);
return true;

case "createSymlink":
boolean success = createSymlink(args.getString(0), args.getString(1));
callbackContext.success(success ? 1 : 0);
return true;

case "getNativeLibraryPath":
callbackContext.success(getNativeLibraryPath());
return true;

case "getFilesDir":
callbackContext.success(getFilesDir());
return true;

case "getParentPath":
callbackContext.success(getParentPath(args.getString(0)));
return true;

case "listChildren":
callbackContext.success(listChildren(args.getString(0)));
return true;
case "writeText": {
try {
String filePath = args.getString(0);
String content = args.getString(1);

Files.write(Paths.get(filePath),
Collections.singleton(content),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);

callbackContext.success("File written successfully");
} catch (Exception e) {
callbackContext.error("Failed to write file: " + e.getMessage());
}
return true;
}

case "getArch":
String arch;

if (android.os.Build.VERSION.SDK_INT >= 21) {
arch = android.os.Build.SUPPORTED_ABIS[0];
} else {
arch = android.os.Build.CPU_ABI;
}

callbackContext.success(arch);
return true;
case "mkdirs":
File file = new File(args.getString(0));
if(file.mkdirs()){
callbackContext.success();
}else{
callbackContext.error("mkdirs failed");
}
return true;
default:
return false;
}
Expand Down Expand Up @@ -399,6 +468,59 @@ private void hasPermission(String permission, CallbackContext callback) {
callback.error("No permission passed to check.");
}

public boolean fileExists(String path, String countSymlinks) {
Path p = new File(path).toPath();
try {
if (Boolean.parseBoolean(countSymlinks)) {
// This will return true even for broken symlinks
return Files.exists(p, LinkOption.NOFOLLOW_LINKS);
} else {
// Check target file, not symlink itself
return Files.exists(p) && !Files.isSymbolicLink(p);
}
} catch (Exception e) {
return false;
}
}

public boolean createSymlink(String target, String linkPath) {
try {
Process process = Runtime.getRuntime().exec(new String[]{"ln", "-s", target, linkPath});
return process.waitFor() == 0;
} catch (Exception e) {
return false;
}
}

public String getNativeLibraryPath() {
ApplicationInfo appInfo = context.getApplicationInfo();
return appInfo.nativeLibraryDir;
}

public String getFilesDir() {
return context.getFilesDir().getAbsolutePath();
}

public String getParentPath(String path) {
File file = new File(path);
File parent = file.getParentFile();
return parent != null ? parent.getAbsolutePath() : null;
}

public JSONArray listChildren(String path) throws JSONException {
File dir = new File(path);
JSONArray result = new JSONArray();
if (dir.exists() && dir.isDirectory()) {
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
result.put(file.getAbsolutePath());
}
}
}
return result;
}

public void onRequestPermissionResult(
int code,
String[] permissions,
Expand Down
33 changes: 33 additions & 0 deletions src/plugins/system/www/plugin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,37 @@
module.exports = {
fileExists: function (path,countSymlinks, success, error) {
cordova.exec(success, error, 'System', 'fileExists', [path,String(countSymlinks)]);
},

createSymlink: function (target, linkPath, success, error) {
cordova.exec(success, error, 'System', 'createSymlink', [target, linkPath]);
},
writeText: function (path, content, success, error) {
cordova.exec(success, error, 'System', 'writeText', [path, content]);
},

getNativeLibraryPath: function (success, error) {
cordova.exec(success, error, 'System', 'getNativeLibraryPath', []);
},

getFilesDir: function (success, error) {
cordova.exec(success, error, 'System', 'getFilesDir', []);
},

getParentPath: function (path, success, error) {
cordova.exec(success, error, 'System', 'getParentPath', [path]);
},

listChildren: function (path, success, error) {
cordova.exec(success, error, 'System', 'listChildren', [path]);
},
mkdirs: function (path, success, error) {
cordova.exec(success, error, 'System', 'mkdirs', [path]);
},
getArch: function (success, error) {
cordova.exec(success, error, 'System', 'getArch', []);
},

clearCache: function (success, fail) {
return cordova.exec(success, fail, "System", "clearCache", []);
},
Expand Down
Binary file added src/plugins/terminal/libs/arm32/libproot-xed.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/arm32/libtalloc.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/arm64/libproot-xed.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/arm64/libproot32.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/arm64/libtalloc.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/x64/libproot-xed.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/x64/libproot.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/x64/libproot32.so
Binary file not shown.
Binary file added src/plugins/terminal/libs/x64/libtalloc.so
Binary file not shown.
Loading