diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index e6914d1333..9a2f0ede7f 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -2,7 +2,7 @@ Acode is an open-source code editor and web IDE for Android. Edit projects, mana LINUX TERMINAL -Acode includes an Alpine Linux terminal powered by proot, with no root required. Use apk to install supported command-line packages, keep multiple terminal tabs, customize your shell, and back up or restore your terminal setup. +Acode includes an Ubuntu Linux terminal powered by proot, with no root required. Use apt to install supported command-line packages, keep multiple terminal tabs, customize your shell, and back up or restore your terminal setup. AI CODING SUPPORT diff --git a/src/cm/lsp/index.ts b/src/cm/lsp/index.ts index e165f91b17..36dce09636 100644 --- a/src/cm/lsp/index.ts +++ b/src/cm/lsp/index.ts @@ -110,11 +110,11 @@ export { stopManagedServer, } from "./serverLauncher"; export { - BUILTIN_ALPINE_RUNTIME_ID, + BUILTIN_UBUNTU_RUNTIME_ID, EXTERNAL_WEBSOCKET_RUNTIME_ID, getRuntimeProvider, inferWorkspaceKind, - isBuiltinAlpineAccessible, + isBuiltinUbuntuAccessible, listRuntimeProviders, registerRuntimeProvider, selectRuntimeProvider, diff --git a/src/cm/lsp/providerUtils.ts b/src/cm/lsp/providerUtils.ts index 61ef189f65..a28291b182 100644 --- a/src/cm/lsp/providerUtils.ts +++ b/src/cm/lsp/providerUtils.ts @@ -135,15 +135,15 @@ export function defineServer(options: ManagedServerOptions): LspServerManifest { } export const installers = { - apk(options: { + apt(options: { packages: string[]; executable: string; label?: string; source?: string; }): LauncherInstallConfig { return { - kind: "apk", - source: options.source || "apk", + kind: "apt", + source: options.source || "apt", label: options.label, executable: options.executable, packages: options.packages, diff --git a/src/cm/lsp/runtimeProviders.ts b/src/cm/lsp/runtimeProviders.ts index 61e9323533..db06795fbb 100644 --- a/src/cm/lsp/runtimeProviders.ts +++ b/src/cm/lsp/runtimeProviders.ts @@ -6,7 +6,7 @@ import type { } from "./types"; import { getConfiguredRuntimeId } from "./runtimeSettings"; -export const BUILTIN_ALPINE_RUNTIME_ID = "builtin-alpine"; +export const BUILTIN_UBUNTU_RUNTIME_ID = "builtin-ubuntu"; export const EXTERNAL_WEBSOCKET_RUNTIME_ID = "external-websocket"; export const WEB_WORKER_RUNTIME_ID = "web-worker"; @@ -188,13 +188,13 @@ export function inferWorkspaceKind( if (scheme !== "content") return "unknown"; if (/^content:\/\/com\.foxdebug\.acode(?:free)?\.documents\//i.test(uri)) { - return "builtin-alpine"; + return "builtin-ubuntu"; } if (/termux/i.test(uri)) return "termux-saf"; return "saf"; } -export function isBuiltinAlpineAccessible( +export function isBuiltinUbuntuAccessible( context: Pick, ): boolean { const uri = String(context.rootUri || context.file?.uri || context.uri || ""); @@ -211,11 +211,11 @@ export function isBuiltinAlpineAccessible( } export default { - BUILTIN_ALPINE_RUNTIME_ID, + BUILTIN_UBUNTU_RUNTIME_ID, WEB_WORKER_RUNTIME_ID, getRuntimeProvider, inferWorkspaceKind, - isBuiltinAlpineAccessible, + isBuiltinUbuntuAccessible, listRuntimeProviders, registerRuntimeProvider, selectRuntimeProvider, diff --git a/src/cm/lsp/runtimes/builtinAlpine.ts b/src/cm/lsp/runtimes/builtinUbuntu.ts similarity index 85% rename from src/cm/lsp/runtimes/builtinAlpine.ts rename to src/cm/lsp/runtimes/builtinUbuntu.ts index 499ba15454..9dc3605396 100644 --- a/src/cm/lsp/runtimes/builtinAlpine.ts +++ b/src/cm/lsp/runtimes/builtinUbuntu.ts @@ -4,12 +4,12 @@ import { createTransport } from "../transport"; import { checkServerInstallation, ensureServerRunning, - getInstallCommand as getAlpineInstallCommand, - getUninstallCommand as getAlpineUninstallCommand, + getInstallCommand as getUbuntuInstallCommand, + getUninstallCommand as getUbuntuUninstallCommand, installServer, uninstallServer, } from "../serverLauncher"; -import { isBuiltinAlpineAccessible } from "../runtimeProviders"; +import { isBuiltinUbuntuAccessible } from "../runtimeProviders"; import type { LspRuntimeContext, LspRuntimeProvider, @@ -17,7 +17,7 @@ import type { LspRuntimeUriResolutionContext, } from "../types"; -export const BUILTIN_ALPINE_RUNTIME_ID = "builtin-alpine"; +export const BUILTIN_UBUNTU_RUNTIME_ID = "builtin-ubuntu"; function isUntitled(context: LspRuntimeContext): boolean { return /^untitled:/i.test( @@ -40,16 +40,16 @@ function cacheDocumentUri(context: LspRuntimeContext): string | null { } function canUseRealPath(context: LspRuntimeContext): boolean { - return isBuiltinAlpineAccessible({ + return isBuiltinUbuntuAccessible({ ...context, rootUri: context.originalRootUri || context.rootUri, uri: context.originalDocumentUri || context.uri, }); } -export const builtinAlpineRuntimeProvider: LspRuntimeProvider = { - id: BUILTIN_ALPINE_RUNTIME_ID, - label: "Built-in Alpine", +export const builtinUbuntuRuntimeProvider: LspRuntimeProvider = { + id: BUILTIN_UBUNTU_RUNTIME_ID, + label: "Built-in Ubuntu", priority: -100, canHandle( @@ -78,7 +78,7 @@ export const builtinAlpineRuntimeProvider: LspRuntimeProvider = { const documentUri = cacheDocumentUri(context); if (!documentUri) { throw new Error( - `Built-in Alpine cannot resolve a cache URI for ${context.originalDocumentUri}`, + `Built-in Ubuntu cannot resolve a cache URI for ${context.originalDocumentUri}`, ); } return { @@ -133,11 +133,11 @@ export const builtinAlpineRuntimeProvider: LspRuntimeProvider = { }, getInstallCommand(server, context, mode) { - return getAlpineInstallCommand(server, mode); + return getUbuntuInstallCommand(server, mode); }, getUninstallCommand(server) { - return getAlpineUninstallCommand(server); + return getUbuntuUninstallCommand(server); }, async start(server, context) { @@ -149,10 +149,10 @@ export const builtinAlpineRuntimeProvider: LspRuntimeProvider = { }); return { kind: "transport", - providerId: BUILTIN_ALPINE_RUNTIME_ID, + providerId: BUILTIN_UBUNTU_RUNTIME_ID, transport, }; }, }; -export default builtinAlpineRuntimeProvider; +export default builtinUbuntuRuntimeProvider; diff --git a/src/cm/lsp/runtimes/registerBuiltins.ts b/src/cm/lsp/runtimes/registerBuiltins.ts index 5e49c5c9fc..907c5c548f 100644 --- a/src/cm/lsp/runtimes/registerBuiltins.ts +++ b/src/cm/lsp/runtimes/registerBuiltins.ts @@ -1,8 +1,8 @@ import { registerRuntimeProvider } from "../runtimeProviders"; -import builtinAlpineRuntimeProvider from "./builtinAlpine"; +import builtinUbuntuRuntimeProvider from "./builtinUbuntu"; import externalWebSocketRuntimeProvider from "./externalWebSocket"; import webWorkerRuntimeProvider from "./webWorker"; -registerRuntimeProvider(builtinAlpineRuntimeProvider, { replace: true }); +registerRuntimeProvider(builtinUbuntuRuntimeProvider, { replace: true }); registerRuntimeProvider(externalWebSocketRuntimeProvider, { replace: true }); registerRuntimeProvider(webWorkerRuntimeProvider, { replace: true }); diff --git a/src/cm/lsp/serverLauncher.ts b/src/cm/lsp/serverLauncher.ts index ea39576d5a..ec479f20e2 100644 --- a/src/cm/lsp/serverLauncher.ts +++ b/src/cm/lsp/serverLauncher.ts @@ -86,11 +86,11 @@ let cachedFilesDir: string | null = null; /** * Get candidate Terminal data directories from system.getFilesDir(). * Newer Terminal builds keep shared runtime state in public. Older builds used - * alpine/home, and some installs keep it as a symlink for shell compatibility. + * ubuntu/home, and some installs keep it as a symlink for shell compatibility. */ async function getTerminalDataDirs(): Promise { if (cachedFilesDir) { - return [`${cachedFilesDir}/public`, `${cachedFilesDir}/alpine/home`]; + return [`${cachedFilesDir}/public`, `${cachedFilesDir}/ubuntu/home`]; } const system = ( @@ -112,7 +112,7 @@ async function getTerminalDataDirs(): Promise { system.getFilesDir( (filesDir: string) => { cachedFilesDir = filesDir; - resolve([`${filesDir}/public`, `${filesDir}/alpine/home`]); + resolve([`${filesDir}/public`, `${filesDir}/ubuntu/home`]); }, (error: string) => reject(new Error(error)), ); @@ -336,7 +336,7 @@ function normalizeInstallSpec(server: LspServerDefinition) { const kind = install.kind || (install.binaryPath ? "manual" : null) || - (install.source === "apk" ? "apk" : null) || + (install.source === "apt" ? "apt" : null) || (install.source === "npm" ? "npm" : null) || (install.source === "pip" ? "pip" : null) || (install.source === "cargo" ? "cargo" : null) || @@ -448,9 +448,9 @@ function buildUninstallCommand(server: LspServerDefinition): string | null { } switch (spec.kind) { - case "apk": + case "apt": return spec.packages.length - ? `apk del ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` + ? `apt-get remove -y ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` : null; case "npm": { if (!spec.packages.length) return null; @@ -489,15 +489,15 @@ function buildInstallCommand( } switch (spec.kind) { - case "apk": + case "apt": return spec.packages.length - ? `apk add --no-cache ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` + ? `apt-get install -y ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` : null; case "npm": { if (!spec.packages.length) return null; const npmCommand = spec.npmCommand || "npm"; const installFlags = spec.global !== false ? "install -g" : "install"; - return `apk add --no-cache nodejs npm && ${npmCommand} ${installFlags} ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}`; + return `apt-get install -y nodejs npm && ${npmCommand} ${installFlags} ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}`; } case "pip": { if (!spec.packages.length) return null; @@ -506,11 +506,11 @@ function buildInstallCommand( spec.breakSystemPackages !== false ? "PIP_BREAK_SYSTEM_PACKAGES=1 " : ""; - return `apk add --no-cache python3 py3-pip && ${breakPackages}${pipCommand} install ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}`; + return `apt-get install -y python3 python3-pip && ${breakPackages}${pipCommand} install ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}`; } case "cargo": return spec.packages.length - ? `apk add --no-cache rust cargo && cargo install ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` + ? `apt-get install -y cargo && cargo install ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` : null; case "github-release": { if (!spec.repo || !spec.binaryPath) return null; @@ -522,10 +522,10 @@ function buildInstallCommand( const downloadUrl = `https://github.com/${spec.repo}/releases/latest/download/$ASSET`; if (spec.archiveType === "binary") { - return `apk add --no-cache curl && ARCH="$(uname -m)" && case "$ARCH" in\n${caseLines}\n\t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;\nesac && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o ${archivePath} && install -Dm755 ${archivePath} ${installTarget}`; + return `apt-get install -y curl && ARCH="$(uname -m)" && case "$ARCH" in\n${caseLines}\n\t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;\nesac && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o ${archivePath} && install -Dm755 ${archivePath} ${installTarget}`; } - return `apk add --no-cache curl unzip && ARCH="$(uname -m)" && case "$ARCH" in\n${caseLines}\n\t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;\nesac && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o ${archivePath} && unzip -oq ${archivePath} -d "$TMP_DIR" && install -Dm755 "$TMP_DIR"/${extractedFile} ${installTarget}`; + return `apt-get install -y curl unzip && ARCH="$(uname -m)" && case "$ARCH" in\n${caseLines}\n\t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;\nesac && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o ${archivePath} && unzip -oq ${archivePath} -d "$TMP_DIR" && install -Dm755 "$TMP_DIR"/${extractedFile} ${installTarget}`; } case "manual": return null; diff --git a/src/cm/lsp/serverRegistry.ts b/src/cm/lsp/serverRegistry.ts index faaeaa9494..51cdd81f69 100644 --- a/src/cm/lsp/serverRegistry.ts +++ b/src/cm/lsp/serverRegistry.ts @@ -81,7 +81,7 @@ interface RawBridgeConfig { function sanitizeInstallKind( value: unknown, ): - | "apk" + | "apt" | "npm" | "pip" | "cargo" @@ -90,7 +90,7 @@ function sanitizeInstallKind( | "shell" | undefined { switch (value) { - case "apk": + case "apt": case "npm": case "pip": case "cargo": diff --git a/src/cm/lsp/servers/javascript.ts b/src/cm/lsp/servers/javascript.ts index e87480d89a..494ead799c 100644 --- a/src/cm/lsp/servers/javascript.ts +++ b/src/cm/lsp/servers/javascript.ts @@ -33,7 +33,7 @@ export const javascriptServers: LspServerManifest[] = [ "tsx", "jsx", ], - runtimes: ["builtin-alpine"], + runtimes: ["builtin-ubuntu"], transport: { kind: "websocket", }, @@ -74,7 +74,7 @@ export const javascriptServers: LspServerManifest[] = [ "tsx", "jsx", ], - runtimes: ["builtin-alpine"], + runtimes: ["builtin-ubuntu"], transport: { kind: "websocket", }, diff --git a/src/cm/lsp/servers/luau.ts b/src/cm/lsp/servers/luau.ts index 4d401ff4dc..244a9844a4 100644 --- a/src/cm/lsp/servers/luau.ts +++ b/src/cm/lsp/servers/luau.ts @@ -29,7 +29,7 @@ function isGlibcRuntimeError(output: string): boolean { function getLuauRuntimeFailureMessage(output: string): string { if (isGlibcRuntimeError(output)) { - return "Luau release binary requires glibc and is not runnable in this Alpine/musl environment."; + return "Luau release binary requires glibc and is not runnable in this Ubuntu/musl environment."; } const firstLine = String(output || "") @@ -157,10 +157,10 @@ export const luauBundle: LspServerBundle = defineBundle({ } const downloadUrl = `https://github.com/${repo}/releases/latest/download/$ASSET`; - const command = `apk add --no-cache curl unzip && ARCH="$(uname -m)" && case "$ARCH" in + const command = `apt-get install -y curl unzip && ARCH="$(uname -m)" && case "$ARCH" in ${assetCases} \t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; -esac && apk add --no-cache gcompat libstdc++ && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o "$TMP_DIR/$ASSET" && unzip -oq "$TMP_DIR/$ASSET" -d "$TMP_DIR" && chmod +x "$TMP_DIR/luau-lsp" && if ! "$TMP_DIR/luau-lsp" --help >/dev/null 2>&1 && ! "$TMP_DIR/luau-lsp" lsp --help >/dev/null 2>&1; then command -v ldd >/dev/null 2>&1 && ldd "$TMP_DIR/luau-lsp" >&2 || true; echo "Luau release binary is not runnable in this environment." >&2; exit 1; fi && install -Dm755 "$TMP_DIR/luau-lsp" ${quoteArg(binaryPath)}`; +esac && apt-get install -y libstdc++6 && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o "$TMP_DIR/$ASSET" && unzip -oq "$TMP_DIR/$ASSET" -d "$TMP_DIR" && chmod +x "$TMP_DIR/luau-lsp" && if ! "$TMP_DIR/luau-lsp" --help >/dev/null 2>&1 && ! "$TMP_DIR/luau-lsp" lsp --help >/dev/null 2>&1; then command -v ldd >/dev/null 2>&1 && ldd "$TMP_DIR/luau-lsp" >&2 || true; echo "Luau release binary is not runnable in this environment." >&2; exit 1; fi && install -Dm755 "$TMP_DIR/luau-lsp" ${quoteArg(binaryPath)}`; const loadingDialog = loader.create( label, diff --git a/src/cm/lsp/servers/systems.ts b/src/cm/lsp/servers/systems.ts index 1e0dc84ae4..ceed2e014f 100644 --- a/src/cm/lsp/servers/systems.ts +++ b/src/cm/lsp/servers/systems.ts @@ -13,9 +13,9 @@ export const systemsServers: LspServerManifest[] = [ "--header-insertion=never", ], checkCommand: "which clangd", - installer: installers.apk({ + installer: installers.apt({ executable: "clangd", - packages: ["clang-extra-tools"], + packages: ["clangd"], }), enabled: false, }), @@ -26,9 +26,9 @@ export const systemsServers: LspServerManifest[] = [ command: "gopls", args: ["serve"], checkCommand: "which gopls", - installer: installers.apk({ + installer: installers.apt({ executable: "gopls", - packages: ["go", "gopls"], + packages: ["golang-go", "gopls"], }), initializationOptions: { usePlaceholders: false, @@ -83,9 +83,9 @@ export const systemsServers: LspServerManifest[] = [ languages: ["rust"], command: "rust-analyzer", checkCommand: "which rust-analyzer", - installer: installers.apk({ + installer: installers.apt({ executable: "rust-analyzer", - packages: ["rust", "cargo", "rust-analyzer"], + packages: ["rustc", "cargo", "rust-analyzer"], }), initializationOptions: { cargo: { diff --git a/src/cm/lsp/servers/web.ts b/src/cm/lsp/servers/web.ts index 4b811312ad..04f89bb811 100644 --- a/src/cm/lsp/servers/web.ts +++ b/src/cm/lsp/servers/web.ts @@ -48,7 +48,7 @@ export const webServers: LspServerManifest[] = [ id: "html-stdio", label: "HTML (STDIO)", languages: ["html", "vue", "svelte"], - runtimes: ["builtin-alpine"], + runtimes: ["builtin-ubuntu"], command: "vscode-html-language-server", args: ["--stdio"], checkCommand: "which vscode-html-language-server", @@ -68,7 +68,7 @@ export const webServers: LspServerManifest[] = [ id: "css-stdio", label: "CSS (STDIO)", languages: ["css", "scss", "less"], - runtimes: ["builtin-alpine"], + runtimes: ["builtin-ubuntu"], command: "vscode-css-language-server", args: ["--stdio"], checkCommand: "which vscode-css-language-server", @@ -88,7 +88,7 @@ export const webServers: LspServerManifest[] = [ id: "json-stdio", label: "JSON (STDIO)", languages: ["json", "jsonc"], - runtimes: ["builtin-alpine"], + runtimes: ["builtin-ubuntu"], command: "vscode-json-language-server", args: ["--stdio"], checkCommand: "which vscode-json-language-server", diff --git a/src/cm/lsp/types.ts b/src/cm/lsp/types.ts index 6f39038a42..c860dfc0ec 100644 --- a/src/cm/lsp/types.ts +++ b/src/cm/lsp/types.ts @@ -89,7 +89,7 @@ export interface TransportContext { export type WorkspaceKind = | "app-private" - | "builtin-alpine" + | "builtin-ubuntu" | "termux-saf" | "saf" | "remote" @@ -199,7 +199,7 @@ export interface BridgeConfig { } export type InstallerKind = - | "apk" + | "apt" | "npm" | "pip" | "cargo" diff --git a/src/components/terminal/terminalManager.js b/src/components/terminal/terminalManager.js index 63f05d44a0..d893a5a3a5 100644 --- a/src/components/terminal/terminalManager.js +++ b/src/components/terminal/terminalManager.js @@ -1228,7 +1228,7 @@ class TerminalManager { const packageName = window.BuildInfo?.packageName || "com.foxdebug.acode"; const dataDir = `/data/user/0/${packageName}`; - const alpineRoot = `${dataDir}/files/alpine`; + const ubuntuRoot = `${dataDir}/files/ubuntu`; let convertedPath; @@ -1242,8 +1242,8 @@ class TerminalManager { ) { convertedPath = `file://${prootPath}`; } else if (prootPath.startsWith("/")) { - // Everything else is relative to alpine root - convertedPath = `file://${alpineRoot}${prootPath}`; + // Everything else is relative to ubuntu root + convertedPath = `file://${ubuntuRoot}${prootPath}`; } else { convertedPath = prootPath; } diff --git a/src/index.d.ts b/src/index.d.ts index 12e76f127f..f0df6130fb 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -41,11 +41,11 @@ type ExecutorCallback = ( ) => void; interface Executor { - execute: (command: string, alpine: boolean) => Promise; + execute: (command: string, ubuntu: boolean) => Promise; start: ( command: string, callback: ExecutorCallback, - alpine: boolean, + ubuntu: boolean, ) => Promise; write: (uuid: string, input: string) => Promise; stop: (uuid: string) => Promise; @@ -67,7 +67,7 @@ interface ExecutorProcess { id: string; pid: number; command: string; - alpine: boolean; + ubuntu: boolean; startedAt: number; background: boolean; } diff --git a/src/lang/ar-ye.json b/src/lang/ar-ye.json index 9149ce9f1b..8735573195 100644 --- a/src/lang/ar-ye.json +++ b/src/lang/ar-ye.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "تعذر التحقق من حالة التثبيت تلقائياً.", "lsp-install-info-version-available": "الإصدار {version} متاح.", "lsp-install-notification": "{server} غير مثبت. اضغط للتثبيت.", - "lsp-install-method-apk": "حزمة APK", + "lsp-install-method-apt": "حزمة APT", "lsp-install-method-cargo": "حزمة Cargo", "lsp-install-method-manual": "ملف ثنائي يدوي", "lsp-install-method-npm": "حزمة npm", diff --git a/src/lang/be-by.json b/src/lang/be-by.json index 240f92549a..d43fef6775 100644 --- a/src/lang/be-by.json +++ b/src/lang/be-by.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} не ўсталяваны. Націсніце, каб усталяваць.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/bn-bd.json b/src/lang/bn-bd.json index 3dad218691..7f5b8722e5 100644 --- a/src/lang/bn-bd.json +++ b/src/lang/bn-bd.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} ইনস্টল করা নেই। ইনস্টল করতে ট্যাপ করুন।", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/cs-cz.json b/src/lang/cs-cz.json index 6e3070fffb..4b9ff3d064 100644 --- a/src/lang/cs-cz.json +++ b/src/lang/cs-cz.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} není nainstalován. Klepnutím nainstalujete.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/de-de.json b/src/lang/de-de.json index 157c1e985d..76ca2fbc0d 100644 --- a/src/lang/de-de.json +++ b/src/lang/de-de.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} ist nicht installiert. Zum Installieren tippen.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/en-us.json b/src/lang/en-us.json index 23ae1c2679..09a3cfe0b2 100644 --- a/src/lang/en-us.json +++ b/src/lang/en-us.json @@ -585,7 +585,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} language server is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/es-sv.json b/src/lang/es-sv.json index 18ee5d6146..1aa395d418 100644 --- a/src/lang/es-sv.json +++ b/src/lang/es-sv.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} no está instalado. Toque para instalar.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/fr-fr.json b/src/lang/fr-fr.json index 4f7b96c83e..f776824187 100644 --- a/src/lang/fr-fr.json +++ b/src/lang/fr-fr.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} n'est pas installé. Appuyez pour installer.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/he-il.json b/src/lang/he-il.json index 5e65d36f14..9de7f3551e 100644 --- a/src/lang/he-il.json +++ b/src/lang/he-il.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} לא מותקן. הקש כדי להתקין.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/hi-in.json b/src/lang/hi-in.json index f1ff016551..5d148c9f4e 100644 --- a/src/lang/hi-in.json +++ b/src/lang/hi-in.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "इंस्टॉलेशन स्थिति स्वतः जाँची नहीं जा सकी।", "lsp-install-info-version-available": "वर्ज़न {version} उपलब्ध है।", "lsp-install-notification": "{server} स्थापित नहीं है। स्थापित करने के लिए टैप करें।", - "lsp-install-method-apk": "APK पैकेज", + "lsp-install-method-apt": "APT पैकेज", "lsp-install-method-cargo": "कार्गो क्रेट", "lsp-install-method-manual": "मैनुअल बाइनरी", "lsp-install-method-npm": "npm पैकेज", diff --git a/src/lang/hu-hu.json b/src/lang/hu-hu.json index f8e76f3ac0..f436242d97 100644 --- a/src/lang/hu-hu.json +++ b/src/lang/hu-hu.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "A telepítési állapot automatikus ellenőrzése nem lehetséges.", "lsp-install-info-version-available": "A {version} verzió elérhető.", "lsp-install-notification": "A(z) {server} nincs telepítve. Koppintson a telepítéshez.", - "lsp-install-method-apk": "APK-csomag", + "lsp-install-method-apt": "APT-csomag", "lsp-install-method-cargo": "Cargo-crate", "lsp-install-method-manual": "Kézi bináris", "lsp-install-method-npm": "npm-csomag", diff --git a/src/lang/id-id.json b/src/lang/id-id.json index f2560fd6d8..676218f4e2 100644 --- a/src/lang/id-id.json +++ b/src/lang/id-id.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Status pemasangan tidak dapat diperiksa secara otomatis.", "lsp-install-info-version-available": "Versi {version} tersedia.", "lsp-install-notification": "{server} belum terpasang. Ketuk untuk memasang.", - "lsp-install-method-apk": "Paket APK", + "lsp-install-method-apt": "Paket APT", "lsp-install-method-cargo": "Crate Cargo", "lsp-install-method-manual": "Biner manual", "lsp-install-method-npm": "Paket npm", diff --git a/src/lang/index.d.ts b/src/lang/index.d.ts index 5777e10477..053634c674 100644 --- a/src/lang/index.d.ts +++ b/src/lang/index.d.ts @@ -588,7 +588,7 @@ declare type LangStrings = { "lsp-install-info-unknown": string; "lsp-install-info-version-available": string; "lsp-install-notification": string; - "lsp-install-method-apk": string; + "lsp-install-method-apt": string; "lsp-install-method-cargo": string; "lsp-install-method-manual": string; "lsp-install-method-npm": string; diff --git a/src/lang/ir-fa.json b/src/lang/ir-fa.json index 7d9cbedea2..b872ca217c 100644 --- a/src/lang/ir-fa.json +++ b/src/lang/ir-fa.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/it-it.json b/src/lang/it-it.json index 28c6ba3bd0..0665ec11c3 100644 --- a/src/lang/it-it.json +++ b/src/lang/it-it.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/ja-jp.json b/src/lang/ja-jp.json index 2329d81b84..f579ae2669 100644 --- a/src/lang/ja-jp.json +++ b/src/lang/ja-jp.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} はインストールされていません。タップしてインストール。", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/ko-kr.json b/src/lang/ko-kr.json index d8d1daec75..db812321a0 100644 --- a/src/lang/ko-kr.json +++ b/src/lang/ko-kr.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server}이(가) 설치되지 않았습니다. 설치하려면 탭하세요.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/ml-in.json b/src/lang/ml-in.json index 137e1311d2..b481a321dd 100644 --- a/src/lang/ml-in.json +++ b/src/lang/ml-in.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല. ഇൻസ്റ്റാൾ ചെയ്യാൻ ടാപ്പ് ചെയ്യുക.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/mm-unicode.json b/src/lang/mm-unicode.json index 2a504340ee..da4e3910c9 100644 --- a/src/lang/mm-unicode.json +++ b/src/lang/mm-unicode.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/mm-zawgyi.json b/src/lang/mm-zawgyi.json index 2962e24868..9594634136 100644 --- a/src/lang/mm-zawgyi.json +++ b/src/lang/mm-zawgyi.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/pl-pl.json b/src/lang/pl-pl.json index 9f9aa52498..5f51878790 100644 --- a/src/lang/pl-pl.json +++ b/src/lang/pl-pl.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} nie jest zainstalowany. Dotknij, aby zainstalować.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/pt-br.json b/src/lang/pt-br.json index 1affbea199..77307d067c 100644 --- a/src/lang/pt-br.json +++ b/src/lang/pt-br.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} não está instalado. Toque para instalar.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/pu-in.json b/src/lang/pu-in.json index 22734a25c9..19ed23ee63 100644 --- a/src/lang/pu-in.json +++ b/src/lang/pu-in.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/ru-ru.json b/src/lang/ru-ru.json index 1d28242fce..8ddeb50151 100644 --- a/src/lang/ru-ru.json +++ b/src/lang/ru-ru.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} не установлен. Нажмите, чтобы установить.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/tl-ph.json b/src/lang/tl-ph.json index 811030d742..2848d4b9f1 100644 --- a/src/lang/tl-ph.json +++ b/src/lang/tl-ph.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "Hindi naka-install ang {server}. I-tap para i-install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/tr-tr.json b/src/lang/tr-tr.json index 742f48ad5f..a0fa46ccef 100644 --- a/src/lang/tr-tr.json +++ b/src/lang/tr-tr.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/uk-ua.json b/src/lang/uk-ua.json index b6522b1d60..70eb8e18de 100644 --- a/src/lang/uk-ua.json +++ b/src/lang/uk-ua.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/uz-uz.json b/src/lang/uz-uz.json index 1f4272b967..9c29e57b29 100644 --- a/src/lang/uz-uz.json +++ b/src/lang/uz-uz.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} is not installed. Tap to install.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/vi-vn.json b/src/lang/vi-vn.json index fd4eee2626..b004951a79 100644 --- a/src/lang/vi-vn.json +++ b/src/lang/vi-vn.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} chưa được cài đặt. Nhấn để cài đặt.", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lang/zh-cn.json b/src/lang/zh-cn.json index d8067ddb03..602418ab3f 100644 --- a/src/lang/zh-cn.json +++ b/src/lang/zh-cn.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "无法自动检查安装状态。", "lsp-install-info-version-available": "可用版本:{version}", "lsp-install-notification": "{server} 未安装。点击安装。", - "lsp-install-method-apk": "APK 包", + "lsp-install-method-apt": "APT 包", "lsp-install-method-cargo": "Cargo 包", "lsp-install-method-manual": "手动二进制", "lsp-install-method-npm": "npm 包", diff --git a/src/lang/zh-hant.json b/src/lang/zh-hant.json index 2bbe289d28..5601a46c5a 100644 --- a/src/lang/zh-hant.json +++ b/src/lang/zh-hant.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "無法自動檢查安裝狀態。", "lsp-install-info-version-available": "可用版本:{version}", "lsp-install-notification": "{server} 未安裝。點擊安裝。", - "lsp-install-method-apk": "APK 包", + "lsp-install-method-apt": "APT 包", "lsp-install-method-cargo": "Cargo 包", "lsp-install-method-manual": "手動二進制", "lsp-install-method-npm": "npm 包", diff --git a/src/lang/zh-tw.json b/src/lang/zh-tw.json index add0b58a04..b60c651c51 100644 --- a/src/lang/zh-tw.json +++ b/src/lang/zh-tw.json @@ -563,7 +563,7 @@ "lsp-install-info-unknown": "Installation status could not be checked automatically.", "lsp-install-info-version-available": "Version {version} is available.", "lsp-install-notification": "{server} 未安裝。點擊安裝。", - "lsp-install-method-apk": "APK package", + "lsp-install-method-apt": "APT package", "lsp-install-method-cargo": "Cargo crate", "lsp-install-method-manual": "Manual binary", "lsp-install-method-npm": "npm package", diff --git a/src/lib/openFolder.js b/src/lib/openFolder.js index 927606a926..959e6be852 100644 --- a/src/lib/openFolder.js +++ b/src/lib/openFolder.js @@ -32,23 +32,23 @@ const isTerminalSafUri = (value = "") => const getTerminalPaths = () => { const packageName = window.BuildInfo?.packageName || "com.foxdebug.acode"; const dataDir = `/data/user/0/${packageName}`; - const alpineRoot = `${dataDir}/files/alpine`; + const ubuntuRoot = `${dataDir}/files/ubuntu`; const publicDir = `${dataDir}/files/public`; - return { alpineRoot, publicDir, dataDir }; + return { ubuntuRoot, publicDir, dataDir }; }; const isTerminalAccessiblePath = (url = "") => { if (isAcodeTerminalPublicSafUri(url)) return true; - const { alpineRoot, publicDir } = getTerminalPaths(); + const { ubuntuRoot, publicDir } = getTerminalPaths(); const cleanUrl = url.replace(/^file:\/\//, ""); - if (cleanUrl.startsWith(alpineRoot) || cleanUrl.startsWith(publicDir)) { + if (cleanUrl.startsWith(ubuntuRoot) || cleanUrl.startsWith(publicDir)) { return true; } return false; }; const convertToProotPath = (url = "") => { - const { alpineRoot, publicDir } = getTerminalPaths(); + const { ubuntuRoot, publicDir } = getTerminalPaths(); if (isAcodeTerminalPublicSafUri(url)) { try { const { docId } = Uri.parse(url); @@ -81,8 +81,8 @@ const convertToProotPath = (url = "") => { if (cleanUrl.startsWith(publicDir)) { return cleanUrl.replace(publicDir, "/public"); } - if (cleanUrl.startsWith(alpineRoot)) { - return cleanUrl.replace(alpineRoot, "") || "/"; + if (cleanUrl.startsWith(ubuntuRoot)) { + return cleanUrl.replace(ubuntuRoot, "") || "/"; } console.warn(`Unrecognized path for terminal conversion: ${url}`); return cleanUrl; diff --git a/src/pages/runningProcesses/runningProcesses.js b/src/pages/runningProcesses/runningProcesses.js index 47a6720971..834eb57b79 100644 --- a/src/pages/runningProcesses/runningProcesses.js +++ b/src/pages/runningProcesses/runningProcesses.js @@ -124,7 +124,7 @@ export default function RunningProcesses() { managedMap.set(p.pid, { type: "Terminal service", id: p.id, - alpine: p.alpine, + ubuntu: p.ubuntu, startedAt: p.startedAt, background: false, }); @@ -134,7 +134,7 @@ export default function RunningProcesses() { managedMap.set(p.pid, { type: "Background executor", id: p.id, - alpine: p.alpine, + ubuntu: p.ubuntu, startedAt: p.startedAt, background: true, }); @@ -146,7 +146,7 @@ export default function RunningProcesses() { p.managed = true; p.managedType = managed.type; p.managedId = managed.id; - p.alpine = managed.alpine; + p.ubuntu = managed.ubuntu; if (managed.startedAt) p.startedAt = managed.startedAt; } } @@ -274,7 +274,7 @@ export default function RunningProcesses() { {text("acode service", "Acode Service")} - {proc.managedType} ({proc.alpine ? "Alpine" : "Android"}) + {proc.managedType} ({proc.ubuntu ? "Ubuntu" : "Android"}) )} diff --git a/src/plugins/browser/utils/updatePackage.js b/src/plugins/browser/utils/updatePackage.js index eb2ade1644..744df603e4 100644 --- a/src/plugins/browser/utils/updatePackage.js +++ b/src/plugins/browser/utils/updatePackage.js @@ -8,7 +8,7 @@ const menuJava = path.resolve( ); const docProvider = path.resolve( __dirname, - "../../../platforms/android/app/src/main/java/com/foxdebug/acode/rk/exec/terminal/AlpineDocumentProvider.java" + "../../../platforms/android/app/src/main/java/com/foxdebug/acode/rk/exec/terminal/UbuntuDocumentProvider.java" ); const repeatChar = (char, times) => char.repeat(times); diff --git a/src/plugins/proot/assets/alpine_assets/arm32/alpine.rootfs b/src/plugins/proot/assets/alpine_assets/arm32/alpine.rootfs deleted file mode 100755 index 1ad5e69f9f..0000000000 Binary files a/src/plugins/proot/assets/alpine_assets/arm32/alpine.rootfs and /dev/null differ diff --git a/src/plugins/proot/assets/alpine_assets/arm64/alpine.rootfs b/src/plugins/proot/assets/alpine_assets/arm64/alpine.rootfs deleted file mode 100755 index 0adc1737ca..0000000000 Binary files a/src/plugins/proot/assets/alpine_assets/arm64/alpine.rootfs and /dev/null differ diff --git a/src/plugins/proot/assets/alpine_assets/x64/alpine.rootfs b/src/plugins/proot/assets/alpine_assets/x64/alpine.rootfs deleted file mode 100755 index 9c524717b8..0000000000 Binary files a/src/plugins/proot/assets/alpine_assets/x64/alpine.rootfs and /dev/null differ diff --git a/src/plugins/proot/assets/arm32/ubuntu.rootfs b/src/plugins/proot/assets/arm32/ubuntu.rootfs new file mode 100644 index 0000000000..b196ab7c4f Binary files /dev/null and b/src/plugins/proot/assets/arm32/ubuntu.rootfs differ diff --git a/src/plugins/proot/assets/arm64/ubuntu.rootfs b/src/plugins/proot/assets/arm64/ubuntu.rootfs new file mode 100644 index 0000000000..6347e59867 Binary files /dev/null and b/src/plugins/proot/assets/arm64/ubuntu.rootfs differ diff --git a/src/plugins/proot/assets/x64/ubuntu.rootfs b/src/plugins/proot/assets/x64/ubuntu.rootfs new file mode 100644 index 0000000000..98828f89dc Binary files /dev/null and b/src/plugins/proot/assets/x64/ubuntu.rootfs differ diff --git a/src/plugins/proot/plugin.xml b/src/plugins/proot/plugin.xml index 01cfc35cbc..7d79f12f84 100644 --- a/src/plugins/proot/plugin.xml +++ b/src/plugins/proot/plugin.xml @@ -13,7 +13,7 @@ - + @@ -22,7 +22,7 @@ - + @@ -31,7 +31,7 @@ - + diff --git a/src/plugins/system/android/com/foxdebug/system/System.java b/src/plugins/system/android/com/foxdebug/system/System.java index c97ef0c77d..4c6028c6e0 100644 --- a/src/plugins/system/android/com/foxdebug/system/System.java +++ b/src/plugins/system/android/com/foxdebug/system/System.java @@ -41,6 +41,7 @@ import androidx.documentfile.provider.DocumentFile; import com.foxdebug.system.Ui.Theme; import java.io.BufferedReader; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -62,6 +63,11 @@ import java.nio.file.StandardOpenOption; import java.security.MessageDigest; import java.util.*; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.compressors.CompressorInputStream; +import org.apache.commons.compress.compressors.CompressorStreamFactory; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; @@ -139,6 +145,7 @@ public boolean execute( case "compare-file-text": case "compare-texts": case "extractAsset": + case "extractTarXz": case "pin-file-shortcut": break; case "get-configuration": @@ -367,6 +374,17 @@ public void run() { ); } return; + case "extractTarXz": + try { + String sourcePath = args.getString(0); + String destinationPath = args.getString(1); + extractTarXz(sourcePath, destinationPath, callbackContext); + } catch (Exception e) { + callbackContext.error( + "Failed to extract tar.xz: " + e.getMessage() + ); + } + return; case "getInstaller": try { PackageManager pm = context.getPackageManager(); @@ -2185,6 +2203,95 @@ private void setNativeContextMenuDisabled(boolean disabled) { webView.setNativeContextMenuDisabled(disabled); } + private CompressorInputStream openCompressor(File source) throws Exception { + String name = source.getName().toLowerCase(); + if (name.endsWith(".tar.gz") || name.endsWith(".tgz")) { + return new GzipCompressorInputStream(new BufferedInputStream(new FileInputStream(source))); + } else if (name.endsWith(".tar.xz") || name.endsWith(".txz")) { + return new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.XZ, + new FileInputStream(source)); + } + return new CompressorStreamFactory().createCompressorInputStream( + new BufferedInputStream(new FileInputStream(source))); + } + + private void setRwx(File file) { + file.setReadable(true, false); + file.setWritable(true, false); + file.setExecutable(true, false); + } + + private void extractTarXz( + String sourcePath, + String destinationPath, + CallbackContext callback + ) { + try { + File sourceFile = new File(sourcePath); + File destDir = new File(destinationPath); + if (!destDir.exists()) { + destDir.mkdirs(); + } + setRwx(destDir); + + try ( + CompressorInputStream compIn = openCompressor(sourceFile); + TarArchiveInputStream tarIn = new TarArchiveInputStream(compIn) + ) { + String canonicalDest = destDir.getCanonicalPath(); + TarArchiveEntry entry; + while ((entry = tarIn.getNextEntry()) != null) { + File entryFile = new File(canonicalDest, entry.getName()); + String canonicalEntry = entryFile.getCanonicalPath(); + if (!canonicalEntry.startsWith(canonicalDest + File.separator) + && !canonicalEntry.equals(canonicalDest)) { + callback.error("Path traversal detected in tar entry: " + entry.getName()); + return; + } + + if (entry.isDirectory()) { + entryFile.mkdirs(); + setRwx(entryFile); + } else if ((entry.isSymbolicLink() || entry.isLink()) && entry.getLinkName() != null && !entry.getLinkName().isEmpty()) { + File parent = entryFile.getParentFile(); + if (!parent.exists()) { + parent.mkdirs(); + setRwx(parent); + } + if (entryFile.exists()) { + entryFile.delete(); + } + Files.createSymbolicLink( + entryFile.toPath(), + Paths.get(entry.getLinkName()) + ); + } else { + File parent = entryFile.getParentFile(); + if (!parent.exists()) { + parent.mkdirs(); + setRwx(parent); + } + + try (OutputStream out = new FileOutputStream(entryFile)) { + byte[] buffer = new byte[8192]; + int length; + while ((length = tarIn.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + out.flush(); + } + setRwx(entryFile); + } + } + callback.success(); + } + } catch (Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + callback.error(sw.toString()); + } + } + private void extractAsset( String assetName, String destinationPath, diff --git a/src/plugins/system/plugin.xml b/src/plugins/system/plugin.xml index ed80bf0cb4..79536b148b 100644 --- a/src/plugins/system/plugin.xml +++ b/src/plugins/system/plugin.xml @@ -35,12 +35,14 @@ - - - - + + + + + + diff --git a/src/plugins/system/system.d.ts b/src/plugins/system/system.d.ts index aa2ef8bf7f..3228145c08 100644 --- a/src/plugins/system/system.d.ts +++ b/src/plugins/system/system.d.ts @@ -283,6 +283,20 @@ interface System { onSuccess: (status: RewardStatus | string) => void, onFail: OnFail, ): void; + /** + * Extract a .tar.xz archive to a destination directory + * @param sourcePath + * @param destinationPath + * @param onSuccess + * @param onFail + */ + extractTarXz( + sourcePath: string, + destinationPath: string, + onSuccess: () => void, + onFail: OnFail, + ): void; + /** * Enable/disable native WebView long-press context behavior. * Use this when rendering a custom editor context menu. diff --git a/src/plugins/system/www/plugin.js b/src/plugins/system/www/plugin.js index 8bebd47efd..039e73bd2f 100644 --- a/src/plugins/system/www/plugin.js +++ b/src/plugins/system/www/plugin.js @@ -55,6 +55,10 @@ module.exports = { cordova.exec(success, error, 'System', 'extractAsset', [assetName, destinationPath]); }, + extractTarXz: function (sourcePath, destinationPath, success, error) { + cordova.exec(success, error, 'System', 'extractTarXz', [sourcePath, destinationPath]); + }, + getParentPath: function (path, success, error) { cordova.exec(success, error, 'System', 'getParentPath', [path]); }, diff --git a/src/plugins/terminal/plugin.xml b/src/plugins/terminal/plugin.xml index 35cc968ebf..79bd0fd078 100644 --- a/src/plugins/terminal/plugin.xml +++ b/src/plugins/terminal/plugin.xml @@ -15,6 +15,7 @@ + @@ -35,16 +36,16 @@ - + - - + + /dev/null 2>&1; then - missing_packages="$missing_packages $pkg" - fi -done - -if [ -n "$missing_packages" ]; then - echo -e "\e[34;1m[*] \e[0mInstalling important packages\e[0m" - apk update && apk upgrade - apk add $missing_packages - if [ $? -eq 0 ]; then - echo -e "\e[32;1m[+] \e[0mSuccessfully installed\e[0m" - fi - echo -e "\e[34m[*] \e[0mUse \e[32mapk\e[0m to install new packages\e[0m" -fi - - -if [ ! -f /linkerconfig/ld.config.txt ]; then - mkdir -p /linkerconfig - touch /linkerconfig/ld.config.txt -fi - - -if [ "$INSTALLING" = true ]; then - echo "Configuring timezone..." - - if [ -n "$ANDROID_TZ" ] && [ -f "/usr/share/zoneinfo/$ANDROID_TZ" ]; then - ln -sf "/usr/share/zoneinfo/$ANDROID_TZ" /etc/localtime - echo "$ANDROID_TZ" > /etc/timezone - echo "Timezone set to: $ANDROID_TZ" - else - echo "Failed to detect timezone" - fi - - mkdir -p "$PREFIX/.configured" - - if [ ! -f "$HOME/.bashrc" ]; then - touch "$HOME/.bashrc" && chmod 644 "$HOME/.bashrc" - fi - - echo "Installation completed." - exit 0 -fi - - - - echo "$$" > "$PREFIX/pid" - chmod +x "$PREFIX/axs" - - if [ ! -e "$PREFIX/alpine/etc/acode_motd" ]; then - cat < "$PREFIX/alpine/etc/acode_motd" -Welcome to Alpine Linux in Acode! - -Working with packages: - - - Search: apk search - - Install: apk add - - Uninstall: apk del - - Upgrade: apk update && apk upgrade - -EOF - fi - - # Create acode CLI tool - if [ ! -e "$PREFIX/alpine/usr/local/bin/acode" ]; then - mkdir -p "$PREFIX/alpine/usr/local/bin" - cat <<'ACODE_CLI' > "$PREFIX/alpine/usr/local/bin/acode" -#!/bin/bash -# acode - Open files/folders in Acode editor -# Uses OSC escape sequences to communicate with the Acode terminal - -usage() { - echo "Usage: acode [file/folder...]" - echo "" - echo "Open files or folders in Acode editor." - echo "" - echo "Examples:" - echo " acode file.txt # Open a file" - echo " acode . # Open current folder" - echo " acode ~/project # Open a folder" - echo " acode -h, --help # Show this help" -} - -get_abs_path() { - local path="$1" - local abs_path="" - - if command -v realpath >/dev/null 2>&1; then - abs_path=$(realpath -- "$path" 2>/dev/null) - fi - - if [[ -z "$abs_path" ]]; then - if [[ -d "$path" ]]; then - abs_path=$(cd -- "$path" 2>/dev/null && pwd -P) - elif [[ -e "$path" ]]; then - local dir_name file_name - dir_name=$(dirname -- "$path") - file_name=$(basename -- "$path") - abs_path="$(cd -- "$dir_name" 2>/dev/null && pwd -P)/$file_name" - elif [[ "$path" == /* ]]; then - abs_path="$path" - else - abs_path="$PWD/$path" - fi - fi - - echo "$abs_path" -} - -open_in_acode() { - local path=$(get_abs_path "$1") - local type="file" - [[ -d "$path" ]] && type="folder" - - # Send OSC 7777 escape sequence: \e]7777;cmd;type;path\a - # The terminal component will intercept and handle this - printf '\e]7777;open;%s;%s\a' "$type" "$path" -} - -if [[ $# -eq 0 ]]; then - open_in_acode "." - exit 0 -fi - -for arg in "$@"; do - case "$arg" in - -h|--help) - usage - exit 0 - ;; - *) - if [[ -e "$arg" ]]; then - open_in_acode "$arg" - else - echo "Error: '$arg' does not exist" >&2 - exit 1 - fi - ;; - esac -done -ACODE_CLI - chmod +x "$PREFIX/alpine/usr/local/bin/acode" - fi - - # Create initrc if it doesn't exist - #initrc runs in bash so we can use bash features -if [ ! -e "$PREFIX/alpine/initrc" ]; then - cat <<'EOF' > "$PREFIX/alpine/initrc" -# Source rc files if they exist - -if [ -f "/etc/profile" ]; then - source "/etc/profile" -fi - -# Environment setup -export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/share/bin:/usr/share/sbin:/usr/local/bin:/usr/local/sbin - -export HOME=/public -export TERM=xterm-256color -SHELL=/bin/bash -export PIP_BREAK_SYSTEM_PACKAGES=1 - -# Default prompt with fish-style path shortening (~/p/s/components) -# To use custom prompts (Starship, Oh My Posh, etc.), just init them in ~/.bashrc: -# eval "$(starship init bash)" -_shorten_path() { - local path="$PWD" - - if [[ "$HOME" != "/" && "$path" == "$HOME" ]]; then - echo "~" - return - elif [[ "$HOME" != "/" && "$path" == "$HOME/"* ]]; then - path="~${path#$HOME}" - fi - - [[ "$path" == "~" ]] && echo "~" && return - - local parts result="" - IFS='/' read -ra parts <<< "$path" - local len=${#parts[@]} - - for ((i=0; i/dev/null)" - else - cmd_path="$(command -v "$cmd" 2>/dev/null)" - - # Resolve symlinks/relative paths - if [[ -n "$cmd_path" ]]; then - cmd_path="$(realpath "$cmd_path" 2>/dev/null)" - fi - fi - - [[ -z "$cmd_path" ]] && return - [[ ! -f "$cmd_path" ]] && return - - if [[ "$cmd_path" == /storage/* ]] || \ - [[ "$cmd_path" == /sdcard/* ]]; then - echo -e "\e[1;31m[!] ATTENTION REQUIRED\e[0m - -\e[1;31mThe binary is located in:\e[0m - \e[36m$cmd_path\e[0m - -\e[1;31mBinaries cannot be executed reliably from /sdcard or /storage.\e[0m -These locations are backed by Android's external storage layer and do not support normal Linux executable permissions. - -Move your project or binary to a directory under: - \e[1;32m/home/\e[0m - -Example: - \e[1;32mmv myproject ~/myproject\e[0m - \e[1;32mcd ~/myproject\e[0m - -Then run the binary again. -" >&2 - fi -} - -_acode_preexec() { - # Skip commands executed by the trap itself - [[ "$BASH_COMMAND" == trap* ]] && return - - local cmd="${BASH_COMMAND%% *}" - check_binary_execution "$cmd" -} - -# Preserve any existing DEBUG trap and append our handler instead of overwriting it. -# This avoids clobbering user-installed preexec hooks (starship, fzf, bash-preexec, etc.). -__acode_existing_debug_trap="$(trap -p DEBUG 2>/dev/null)" -if [[ -n "${__acode_existing_debug_trap}" ]]; then - __acode_existing_cmd="$(printf "%s" "${__acode_existing_debug_trap}" | sed -E "s/.*'((.*)?)'.*/\1/")" -else - __acode_existing_cmd="" -fi - -# Only add our handler if it's not already present -if [[ "${__acode_existing_cmd}" != *"_acode_preexec"* ]]; then - if [[ -n "${__acode_existing_cmd}" ]]; then - trap "${__acode_existing_cmd}; _acode_preexec" DEBUG - else - trap '_acode_preexec' DEBUG - fi -fi -unset __acode_existing_debug_trap __acode_existing_cmd - -# Command-not-found handler -command_not_found_handle() { - cmd="$1" - pkg="" - green="\e[1;32m" - reset="\e[0m" - - pkg=$(apk search -x "cmd:$cmd" 2>/dev/null | awk -F'-[0-9]' '{print $1}' | head -n 1) - - if [ -n "$pkg" ]; then - echo -e "The program '$cmd' is not installed.\nInstall it by executing:\n ${green}apk add $pkg${reset}" >&2 - else - echo "The program '$cmd' is not installed and no package provides it." >&2 - fi - - return 127 -} - -# Replicate behaviour of termux (non standard) -alias clear='reset' - -# Source user configs AFTER defaults (so user can override everything) -if [ -f /etc/bash/bashrc ]; then - source /etc/bash/bashrc -fi - -if [ -f "$HOME/.bashrc" ]; then - source "$HOME/.bashrc" -fi - -EOF -fi - -# Add PS1 only if not already present -if ! grep -q 'PS1=' "$PREFIX/alpine/initrc"; then - # Smart path shortening (fish-style: ~/p/s/components) - echo 'PS1="\[\033[1;32m\]\u\[\033[0m\]@localhost \[\033[1;34m\]\$_PS1_PATH\[\033[0m\] \[\$([ \$_PS1_EXIT -ne 0 ] && echo \"\033[31m\")\]\$\[\033[0m\] "' >> "$PREFIX/alpine/initrc" - # Simple prompt (uncomment below and comment above if you prefer full paths) - # echo 'PS1="\[\033[1;32m\]\u\[\033[0m\]@localhost \[\033[1;34m\]\w\[\033[0m\] \$ "' >> "$PREFIX/alpine/initrc" -fi - - -chmod +x "$PREFIX/alpine/initrc" - -if [ "$FAILSAFE" != true ]; then - #everytime a terminal is started initrc will run - "$PREFIX/axs" -c "bash --rcfile /initrc -i" -fi diff --git a/src/plugins/terminal/scripts/init-sandbox.sh b/src/plugins/terminal/scripts/init-sandbox.sh index 5e100ef9e4..a0b0dec92b 100644 --- a/src/plugins/terminal/scripts/init-sandbox.sh +++ b/src/plugins/terminal/scripts/init-sandbox.sh @@ -1,7 +1,7 @@ export LD_LIBRARY_PATH=$PREFIX mkdir -p "$PREFIX/tmp" -mkdir -p "$PREFIX/alpine/tmp" +mkdir -p "$PREFIX/ubuntu/tmp" mkdir -p "$PREFIX/public" export PROOT_TMP_DIR=$PREFIX/tmp @@ -66,7 +66,7 @@ ARGS="$ARGS -b $NATIVE_DIR" ARGS="$ARGS -b $PREFIX/public:/public" ARGS="$ARGS -b $PREFIX/public:/home" ARGS="$ARGS -b $PREFIX/public:/root" -ARGS="$ARGS -b $PREFIX/alpine/tmp:/dev/shm" +ARGS="$ARGS -b $PREFIX/ubuntu/tmp:/dev/shm" if [ -e "/proc/self/fd" ]; then @@ -86,7 +86,7 @@ if [ -e "/proc/self/fd/2" ]; then fi -ARGS="$ARGS -r $PREFIX/alpine" +ARGS="$ARGS -r $PREFIX/ubuntu" ARGS="$ARGS -0" ARGS="$ARGS --link2symlink" ARGS="$ARGS --sysvipc" @@ -118,5 +118,5 @@ if [ "$FAILSAFE" = true ] && [ "$INSTALLING" != true ]; then exec "$LINKER" "$PREFIX/axs" -c "sh" else - exec "$PROOT" $ARGS /bin/sh "$PREFIX/init-alpine.sh" "$@" + exec "$PROOT" $ARGS /bin/sh "$PREFIX/init-ubuntu.sh" "$@" fi \ No newline at end of file diff --git a/src/plugins/terminal/scripts/init-ubuntu.sh b/src/plugins/terminal/scripts/init-ubuntu.sh new file mode 100644 index 0000000000..bdae221fc9 --- /dev/null +++ b/src/plugins/terminal/scripts/init-ubuntu.sh @@ -0,0 +1,437 @@ +#!/bin/bash + +# ============================================================ +# Acode Ubuntu Rootfs launcher +# ============================================================ + +export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/share/bin:/usr/share/sbin:/usr/local/bin:/usr/local/sbin:/system/bin:/system/xbin:$PREFIX/local/bin" +export HOME="/public" +export TERM="xterm-256color" +export PS1='\[\e[38;5;46m\]\u\[\e[39m\]@localhost \[\e[39m\]\w \[\e[0m\]\$ ' + +INSTALLING=false +FAILSAFE=false + +# ============================================================ +# Parse arguments +# ============================================================ + +while [ "$#" -gt 0 ]; do + case "$1" in + --installing) + INSTALLING=true + shift + ;; + --failsafe) + FAILSAFE=true + shift + ;; + --) + shift + break + ;; + *) + break + ;; + esac +done + +# ============================================================ +# Execute supplied command directly (VERY IMPORTANT) +# ============================================================ + +if [ "$INSTALLING" != true ] && [ "$#" -gt 0 ]; then + exec "$@" +fi + +# ============================================================ +# One-time rootfs installation +# +# IMPORTANT: +# Normal launches should NEVER run apt. +# ============================================================ + +if [ "$INSTALLING" = true ]; then + export DEBIAN_FRONTEND=noninteractive + + echo "[*] Configuring rootfs..." + + # -------------------------------------------------------- + # Configure timezone before tzdata is installed. + # -------------------------------------------------------- + + if [ -n "$ANDROID_TZ" ] && + [ -f "/usr/share/zoneinfo/$ANDROID_TZ" ]; then + + mkdir -p /etc + + ln -sf \ + "/usr/share/zoneinfo/$ANDROID_TZ" \ + /etc/localtime + + echo "$ANDROID_TZ" > /etc/timezone + + echo "[+] Timezone: $ANDROID_TZ" + else + ln -sf /usr/share/zoneinfo/UTC /etc/localtime + echo "Etc/UTC" > /etc/timezone + + echo "[+] Timezone: UTC" + fi + + # -------------------------------------------------------- + # Rootfs filesystem setup + # -------------------------------------------------------- + + mkdir -p /linkerconfig + + if [ ! -f /linkerconfig/ld.config.txt ]; then + touch /linkerconfig/ld.config.txt + fi + + mkdir -p "$HOME" + mkdir -p "$PREFIX/ubuntu/usr/local/bin" + + # -------------------------------------------------------- + # Acode MOTD + # -------------------------------------------------------- + + if [ ! -e "$PREFIX/ubuntu/etc/acode_motd" ]; then + cat > "$PREFIX/ubuntu/etc/acode_motd" <<'EOF' +Welcome to Ubuntu Linux in Acode! + +Working with packages: + + - Search: apt search + - Install: apt install + - Uninstall: apt remove + - Upgrade: apt update && apt upgrade +EOF + fi + + # -------------------------------------------------------- + # Acode CLI + # -------------------------------------------------------- + + if [ ! -e "$PREFIX/ubuntu/usr/local/bin/acode" ]; then + cat > "$PREFIX/ubuntu/usr/local/bin/acode" <<'ACODE_CLI' +#!/bin/bash + +usage() { + echo "Usage: acode [file/folder...]" + echo + echo "Open files or folders in Acode editor." + echo + echo "Examples:" + echo " acode file.txt" + echo " acode ." + echo " acode ~/project" + echo " acode -h, --help" +} + +get_abs_path() { + local path="$1" + local abs_path="" + + if command -v realpath >/dev/null 2>&1; then + abs_path=$(realpath -- "$path" 2>/dev/null) + fi + + if [ -z "$abs_path" ]; then + if [ -d "$path" ]; then + abs_path=$(cd -- "$path" 2>/dev/null && pwd -P) + + elif [ -e "$path" ]; then + local dir_name + local file_name + + dir_name=$(dirname -- "$path") + file_name=$(basename -- "$path") + + abs_path="$( + cd -- "$dir_name" 2>/dev/null && + pwd -P + )/$file_name" + + elif [[ "$path" == /* ]]; then + abs_path="$path" + + else + abs_path="$PWD/$path" + fi + fi + + echo "$abs_path" +} + +open_in_acode() { + local path + local type="file" + + path=$(get_abs_path "$1") + + if [ -d "$path" ]; then + type="folder" + fi + + printf '\e]7777;open;%s;%s\a' "$type" "$path" +} + +if [ "$#" -eq 0 ]; then + open_in_acode "." + exit 0 +fi + +for arg in "$@"; do + case "$arg" in + -h|--help) + usage + exit 0 + ;; + + *) + if [ -e "$arg" ]; then + open_in_acode "$arg" + else + echo "Error: '$arg' does not exist" >&2 + exit 1 + fi + ;; + esac +done +ACODE_CLI + + chmod +x "$PREFIX/ubuntu/usr/local/bin/acode" + fi + + # -------------------------------------------------------- + # Create initrc + # -------------------------------------------------------- + + if [ ! -e "$PREFIX/ubuntu/initrc" ]; then + cat > "$PREFIX/ubuntu/initrc" <<'EOF' +# ============================================================ +# Acode Ubuntu shell initialization +# ============================================================ + +# Load system profile +if [ -f /etc/profile ]; then + source /etc/profile +fi + +export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/share/bin:/usr/share/sbin:/usr/local/bin:/usr/local/sbin" +export HOME="/public" +export TERM="xterm-256color" +export SHELL="/bin/bash" + +# Allow pip to install packages into the system environment. +export PIP_BREAK_SYSTEM_PACKAGES=1 + +# ============================================================ +# Shorten current path +# ~/project/src/components +# becomes: +# ~/p/s/components +# ============================================================ + +_shorten_path() { + local path="$PWD" + + if [[ "$HOME" != "/" && "$path" == "$HOME" ]]; then + echo "~" + return + fi + + if [[ "$HOME" != "/" && "$path" == "$HOME/"* ]]; then + path="~${path#$HOME}" + fi + + [[ "$path" == "~" ]] && echo "~" && return + + local parts + local result="" + local len + + IFS='/' read -ra parts <<< "$path" + + len=${#parts[@]} + + for ((i=0; i/dev/null)" + else + cmd_path="$(command -v "$cmd" 2>/dev/null)" + + if [[ -n "$cmd_path" ]]; then + cmd_path="$(realpath "$cmd_path" 2>/dev/null)" + fi + fi + + [[ -z "$cmd_path" ]] && return + [[ ! -f "$cmd_path" ]] && return + + if [[ "$cmd_path" == /storage/* ]] || + [[ "$cmd_path" == /sdcard/* ]]; then + + echo -e "\e[1;31m[!] ATTENTION REQUIRED\e[0m + +\e[1;31mThe binary is located in:\e[0m + \e[36m$cmd_path\e[0m + +\e[1;31mBinaries cannot be executed reliably from /sdcard or /storage.\e[0m + +These locations are backed by Android's external storage layer +and do not support normal Linux executable permissions. + +Move your project or binary to a directory under: + + \e[1;32m/home/\e[0m + +Example: + + \e[1;32mmv myproject ~/myproject\e[0m + \e[1;32mcd ~/myproject\e[0m + +Then run the binary again. +" >&2 + fi +} + +_acode_preexec() { + [[ "$BASH_COMMAND" == trap* ]] && return + + local cmd="${BASH_COMMAND%% *}" + + check_binary_execution "$cmd" +} + +# Preserve an existing DEBUG trap. +__acode_existing_debug_trap="$(trap -p DEBUG 2>/dev/null)" + +if [[ -n "$__acode_existing_debug_trap" ]]; then + __acode_existing_cmd="$( + printf '%s' "$__acode_existing_debug_trap" | + sed -E "s/.*'((.*))'.*/\1/" + )" +else + __acode_existing_cmd="" +fi + +if [[ "$__acode_existing_cmd" != *"_acode_preexec"* ]]; then + if [[ -n "$__acode_existing_cmd" ]]; then + trap "$__acode_existing_cmd; _acode_preexec" DEBUG + else + trap '_acode_preexec' DEBUG + fi +fi + +unset __acode_existing_debug_trap +unset __acode_existing_cmd + +# ============================================================ +# Command-not-found handler +# ============================================================ + +command_not_found_handle() { + local cmd="$1" + local pkg="" + + pkg="$( + apt-cache search "^${cmd}$" 2>/dev/null | + awk '{print $1}' | + head -n 1 + )" + + if [ -n "$pkg" ]; then + echo -e "The program '$cmd' is not installed.\nInstall it with:\n \e[1;32mapt install $pkg\e[0m" >&2 + else + echo "The program '$cmd' is not installed and no package provides it." >&2 + fi + + return 127 +} + +# Termux-compatible behaviour +alias clear='reset' + +# ============================================================ +# User configuration +# ============================================================ + +if [ -f /etc/bash/bashrc ]; then + source /etc/bash/bashrc +fi + +if [ -f "$HOME/.bashrc" ]; then + source "$HOME/.bashrc" +fi +EOF + fi + + chmod +x "$PREFIX/ubuntu/initrc" + + # -------------------------------------------------------- + # Mark rootfs as configured + # -------------------------------------------------------- + + mkdir -p "$PREFIX/.configured" + + touch "$PREFIX/.configured/rootfs" + + echo "[+] Rootfs configuration complete." + exit 0 +fi + +# ============================================================ + +echo "$$" > "$PREFIX/pid" + +chmod +x "$PREFIX/axs" + +if [ "$FAILSAFE" = true ]; then + exit 0 +fi + +exec "$PREFIX/axs" -c "exec bash --rcfile /initrc -i" diff --git a/src/plugins/terminal/scripts/rm-wrapper.sh b/src/plugins/terminal/scripts/rm-wrapper.sh deleted file mode 100644 index 07d195fdc7..0000000000 --- a/src/plugins/terminal/scripts/rm-wrapper.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -unlink_recursive() { - path="$1" - - # Try to recurse into it as a directory first - for entry in "$path"/* "$path"/.[!.]* "$path"/..?*; do - case "$entry" in - *'*'*|*'?'*) continue ;; - esac - unlink_recursive "$entry" - done 2>/dev/null - - unlink "$path" 2>/dev/null || : -} - -for target in "$@"; do - unlink_recursive "$target" -done - -# Run busybox rm, capture stderr, and filter out the "No such file or directory" message -err="$(busybox rm "$@" 2>&1 >/dev/null)" - -# Print only real errors -printf "%s\n" "$err" | grep -v "No such file or directory" \ No newline at end of file diff --git a/src/plugins/terminal/src/android/BackgroundExecutor.java b/src/plugins/terminal/src/android/BackgroundExecutor.java index 3230473af2..fc4e506b64 100644 --- a/src/plugins/terminal/src/android/BackgroundExecutor.java +++ b/src/plugins/terminal/src/android/BackgroundExecutor.java @@ -62,10 +62,10 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo } } - private void exec(String cmd, boolean useAlpine, CallbackContext callbackContext) { + private void exec(String cmd, boolean useUbuntu, CallbackContext callbackContext) { cordova.getThreadPool().execute(() -> { try { - ProcessManager.ExecResult result = processManager.executeCommand(cmd, useAlpine); + ProcessManager.ExecResult result = processManager.executeCommand(cmd, useUbuntu); if (result.isSuccess()) { callbackContext.success(result.stdout); @@ -78,17 +78,17 @@ private void exec(String cmd, boolean useAlpine, CallbackContext callbackContext }); } - private void startProcess(String pid, String cmd, boolean useAlpine, CallbackContext callbackContext) { + private void startProcess(String pid, String cmd, boolean useUbuntu, CallbackContext callbackContext) { cordova.getThreadPool().execute(() -> { try { - ProcessBuilder builder = processManager.createProcessBuilder(cmd, useAlpine); + ProcessBuilder builder = processManager.createProcessBuilder(cmd, useUbuntu); Process process = builder.start(); long pidVal = ProcessUtils.getPid(process); processes.put(pid, process); processInputs.put(pid, process.getOutputStream()); processCallbacks.put(pid, callbackContext); - processDetails.put(pid, new ProcessDetails(cmd, useAlpine, pidVal)); + processDetails.put(pid, new ProcessDetails(cmd, useUbuntu, pidVal)); sendPluginResult(callbackContext, pid, true); @@ -165,7 +165,7 @@ private void listProcesses(CallbackContext callbackContext) { JSONObject item = new JSONObject(); item.put("id", id); item.put("command", details.command); - item.put("alpine", details.alpine); + item.put("ubuntu", details.ubuntu); item.put("startedAt", details.startedAt); item.put("pid", details.pid); result.put(item); @@ -226,13 +226,13 @@ private void killProcess(int pid, CallbackContext callbackContext) { private static class ProcessDetails { final String command; - final boolean alpine; + final boolean ubuntu; final long startedAt; final long pid; - ProcessDetails(String command, boolean alpine, long pid) { + ProcessDetails(String command, boolean ubuntu, long pid) { this.command = command; - this.alpine = alpine; + this.ubuntu = ubuntu; this.startedAt = System.currentTimeMillis(); this.pid = pid; } diff --git a/src/plugins/terminal/src/android/Executor.java b/src/plugins/terminal/src/android/Executor.java index 0fd14cee8b..8de21ea83a 100644 --- a/src/plugins/terminal/src/android/Executor.java +++ b/src/plugins/terminal/src/android/Executor.java @@ -394,7 +394,7 @@ private void stopServiceNow() { } } - private void startProcess(String pid, String cmd, String alpine) { + private void startProcess(String pid, String cmd, String ubuntu) { CallbackContext callbackContext = getCallbackContext(pid); if (callbackContext != null) { PluginResult result = new PluginResult(PluginResult.Status.OK, pid); @@ -407,7 +407,7 @@ private void startProcess(String pid, String cmd, String alpine) { Bundle bundle = new Bundle(); bundle.putString("id", pid); bundle.putString("cmd", cmd); - bundle.putString("alpine", alpine); + bundle.putString("ubuntu", ubuntu); msg.setData(bundle); try { serviceMessenger.send(msg); @@ -420,13 +420,13 @@ private void startProcess(String pid, String cmd, String alpine) { } } - private void exec(String execId, String cmd, String alpine) { + private void exec(String execId, String cmd, String ubuntu) { Message msg = Message.obtain(null, TerminalService.MSG_EXEC); msg.replyTo = handlerMessenger; Bundle bundle = new Bundle(); bundle.putString("id", execId); bundle.putString("cmd", cmd); - bundle.putString("alpine", alpine); + bundle.putString("ubuntu", ubuntu); msg.setData(bundle); try { serviceMessenger.send(msg); diff --git a/src/plugins/terminal/src/android/ProcessManager.java b/src/plugins/terminal/src/android/ProcessManager.java index 51c94d25f7..e08c91940a 100644 --- a/src/plugins/terminal/src/android/ProcessManager.java +++ b/src/plugins/terminal/src/android/ProcessManager.java @@ -23,11 +23,11 @@ public ProcessManager(Context context) { /** * Creates a ProcessBuilder with common environment setup */ - public ProcessBuilder createProcessBuilder(String cmd, boolean useAlpine) { - if (useAlpine) { + public ProcessBuilder createProcessBuilder(String cmd, boolean useUbuntu) { + if (useUbuntu) { refreshAxsSymlink(); } - String xcmd = useAlpine ? "source $PREFIX/init-sandbox.sh " + cmd : cmd; + String xcmd = useUbuntu ? "source $PREFIX/init-sandbox.sh " + cmd : cmd; ProcessBuilder builder = new ProcessBuilder("sh", "-c", xcmd); setupEnvironment(builder.environment()); return builder; @@ -113,8 +113,8 @@ public static String readStream(InputStream stream) throws IOException { /** * Executes a command and returns the result */ - public ExecResult executeCommand(String cmd, boolean useAlpine) throws Exception { - ProcessBuilder builder = createProcessBuilder(cmd, useAlpine); + public ExecResult executeCommand(String cmd, boolean useUbuntu) throws Exception { + ProcessBuilder builder = createProcessBuilder(cmd, useUbuntu); Process process = builder.start(); String stdout = readStream(process.getInputStream()); diff --git a/src/plugins/terminal/src/android/TerminalService.java b/src/plugins/terminal/src/android/TerminalService.java index f662664ce1..64d98eb97d 100644 --- a/src/plugins/terminal/src/android/TerminalService.java +++ b/src/plugins/terminal/src/android/TerminalService.java @@ -103,9 +103,9 @@ public void handleMessage(Message msg) { switch (msg.what) { case MSG_START_PROCESS: String cmd = bundle.getString("cmd"); - String alpine = bundle.getString("alpine"); + String ubuntu = bundle.getString("ubuntu"); clientMessengers.put(id, clientMessenger); - startProcess(id, cmd, "true".equals(alpine)); + startProcess(id, cmd, "true".equals(ubuntu)); break; case MSG_WRITE_TO_PROCESS: String input = bundle.getString("input"); @@ -119,9 +119,9 @@ public void handleMessage(Message msg) { break; case MSG_EXEC: String execCmd = bundle.getString("cmd"); - String execAlpine = bundle.getString("alpine"); + String execUbuntu = bundle.getString("ubuntu"); clientMessengers.put(id, clientMessenger); - exec(id, execCmd, "true".equals(execAlpine)); + exec(id, execCmd, "true".equals(execUbuntu)); break; case MSG_LIST_PROCESSES: listProcesses(id, clientMessenger); @@ -158,16 +158,16 @@ private void releaseWakeLock() { } } - private void startProcess(String pid, String cmd, boolean useAlpine) { + private void startProcess(String pid, String cmd, boolean useUbuntu) { threadPool.execute(() -> { try { - ProcessBuilder builder = processManager.createProcessBuilder(cmd, useAlpine); + ProcessBuilder builder = processManager.createProcessBuilder(cmd, useUbuntu); Process process = builder.start(); long pidVal = ProcessUtils.getPid(process); processes.put(pid, process); processInputs.put(pid, process.getOutputStream()); - processDetails.put(pid, new ProcessDetails(cmd, useAlpine, pidVal)); + processDetails.put(pid, new ProcessDetails(cmd, useUbuntu, pidVal)); // Stream stdout threadPool.execute(() -> @@ -200,10 +200,10 @@ private void startProcess(String pid, String cmd, boolean useAlpine) { }); } - private void exec(String execId, String cmd, boolean useAlpine) { + private void exec(String execId, String cmd, boolean useUbuntu) { threadPool.execute(() -> { try { - ProcessManager.ExecResult result = processManager.executeCommand(cmd, useAlpine); + ProcessManager.ExecResult result = processManager.executeCommand(cmd, useUbuntu); if (result.isSuccess()) { sendExecResultToClient(execId, true, result.stdout); @@ -288,7 +288,7 @@ private void listProcesses(String requestId, Messenger clientMessenger) { JSONObject item = new JSONObject(); item.put("id", id); item.put("command", details.command); - item.put("alpine", details.alpine); + item.put("ubuntu", details.ubuntu); item.put("startedAt", details.startedAt); item.put("pid", details.pid); result.put(item); @@ -338,13 +338,13 @@ private void cleanup(String id) { private static class ProcessDetails { final String command; - final boolean alpine; + final boolean ubuntu; final long startedAt; final long pid; - ProcessDetails(String command, boolean alpine, long pid) { + ProcessDetails(String command, boolean ubuntu, long pid) { this.command = command; - this.alpine = alpine; + this.ubuntu = ubuntu; this.startedAt = System.currentTimeMillis(); this.pid = pid; } diff --git a/src/plugins/terminal/src/android/AlpineDocumentProvider.java b/src/plugins/terminal/src/android/UbuntuDocumentProvider.java similarity index 99% rename from src/plugins/terminal/src/android/AlpineDocumentProvider.java rename to src/plugins/terminal/src/android/UbuntuDocumentProvider.java index 97a4dd50ab..7b4f55309c 100644 --- a/src/plugins/terminal/src/android/AlpineDocumentProvider.java +++ b/src/plugins/terminal/src/android/UbuntuDocumentProvider.java @@ -22,7 +22,7 @@ import com.foxdebug.acode.R; import com.foxdebug.acode.rk.exec.terminal.*; -public class AlpineDocumentProvider extends DocumentsProvider { +public class UbuntuDocumentProvider extends DocumentsProvider { private static final String ALL_MIME_TYPES = "*/*"; @@ -306,7 +306,7 @@ private void includeFile(MatrixCursor result, String docId, File file) throws Fi } public static boolean isDocumentProviderEnabled(Context context) { - ComponentName componentName = new ComponentName(context, AlpineDocumentProvider.class); + ComponentName componentName = new ComponentName(context, UbuntuDocumentProvider.class); int state = context.getPackageManager().getComponentEnabledSetting(componentName); return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; @@ -316,7 +316,7 @@ public static void setDocumentProviderEnabled(Context context, boolean enabled) if (isDocumentProviderEnabled(context) == enabled) { return; } - ComponentName componentName = new ComponentName(context, AlpineDocumentProvider.class); + ComponentName componentName = new ComponentName(context, UbuntuDocumentProvider.class); int newState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; diff --git a/src/plugins/terminal/www/Executor.js b/src/plugins/terminal/www/Executor.js index 541dcbdadc..d1ad49a4de 100644 --- a/src/plugins/terminal/www/Executor.js +++ b/src/plugins/terminal/www/Executor.js @@ -45,7 +45,7 @@ class Executor { * - `"stdout"`: Standard output line. * - `"stderr"`: Standard error line. * - `"exit"`: Exit code of the process. - * @param {boolean} [alpine=false] - Whether to run the command inside the Alpine sandbox environment (`true`) or on Android directly (`false`). + * @param {boolean} [ubuntu=false] - Whether to run the command inside the Ubuntu sandbox environment (`true`) or on Android directly (`false`). * @returns {Promise} Resolves with a unique process ID (UUID) used for future references like `write()` or `stop()`. * * @example @@ -57,7 +57,7 @@ class Executor { * executor.stop(uuid); * }); */ - start(command, onData, alpine = false) { + start(command, onData, ubuntu = false) { return new Promise((resolve, reject) => { let first = true; exec( @@ -82,7 +82,7 @@ class Executor { reject, this.ExecutorType, "start", - [command, String(alpine)] + [command, String(ubuntu)] ); }); } @@ -173,7 +173,7 @@ class Executor { /** * Lists the processes currently managed by this executor. * - * @returns {Promise>} + * @returns {Promise>} */ listProcesses() { return new Promise((resolve, reject) => { @@ -234,7 +234,7 @@ class Executor { * Unlike {@link Executor#start}, this does not stream output. * * @param {string} command - The shell command to execute. - * @param {boolean} [alpine=false] - Whether to run the command in the Alpine sandbox (`true`) or Android environment (`false`). + * @param {boolean} [ubuntu=false] - Whether to run the command in the Ubuntu sandbox (`true`) or Android environment (`false`). * @returns {Promise} Resolves with standard output on success, rejects with an error or standard error on failure. * * @example @@ -242,9 +242,9 @@ class Executor { * .then(//console.log) * .catch(console.error); */ - execute(command, alpine = false) { + execute(command, ubuntu = false) { return new Promise((resolve, reject) => { - exec(resolve, reject, this.ExecutorType, "exec", [command, String(alpine)]); + exec(resolve, reject, this.ExecutorType, "exec", [command, String(ubuntu)]); }); } diff --git a/src/plugins/terminal/www/Terminal.js b/src/plugins/terminal/www/Terminal.js index 21ffde3755..1933d5e4d8 100644 --- a/src/plugins/terminal/www/Terminal.js +++ b/src/plugins/terminal/www/Terminal.js @@ -15,9 +15,8 @@ const Terminal = { const failsafeArg = failsafe ? "--failsafe" : ""; - const [initAlpine, rmWrapper, initSandbox] = await Promise.all([ - readAsset("init-alpine.sh"), - readAsset("rm-wrapper.sh"), + const [initUbuntu, initSandbox] = await Promise.all([ + readAsset("init-ubuntu.sh"), readAsset("init-sandbox.sh"), ]); @@ -31,13 +30,9 @@ const Terminal = { } - await writeText(`${filesDir}/init-alpine.sh`, initAlpine); + await writeText(`${filesDir}/init-ubuntu.sh`, initUbuntu); await writeText(`${filesDir}/init-sandbox.sh`, initSandbox); - await deleteFile(`${filesDir}/alpine/bin/rm`).catch(() => {}); - await writeText(`${filesDir}/alpine/bin/rm`, rmWrapper); - await setExec(`${filesDir}/alpine/bin/rm`, true); - if (installing) { return new Promise((resolve, reject) => { let lastError = ""; @@ -114,7 +109,7 @@ const Terminal = { }, /** - * Installs Alpine by downloading binaries and extracting the root filesystem. + * Installs Ubuntu by downloading binaries and extracting the root filesystem. * Also sets up additional dependencies for F-Droid variant. * @param {Function} [logger=console.log] - Function to log standard output. * @param {Function} [err_logger=console.error] - Function to log errors. @@ -148,24 +143,24 @@ const Terminal = { "arm64-v8a": { libraryDirectory: "arm64", axsArchitecture: "arm64", - alpineDirectory: "aarch64", - alpineFilename: "alpine-minirootfs-3.21.0-aarch64.tar.gz", + githubArch: "arm64", + ubuntuFilename: "ubuntu-base-24.04.3-base-arm64.tar.gz", hasLibproot32: true }, "armeabi-v7a": { libraryDirectory: "arm32", axsArchitecture: "armv7", - alpineDirectory: "armhf", - alpineFilename: "alpine-minirootfs-3.21.0-armhf.tar.gz", + githubArch: "armhf", + ubuntuFilename: "ubuntu-base-24.04.3-base-armhf.tar.gz", hasLibproot32: false }, "x86_64": { libraryDirectory: "x64", axsArchitecture: "x86_64", - alpineDirectory: "x86_64", - alpineFilename: "alpine-minirootfs-3.21.0-x86_64.tar.gz", + githubArch: "amd64", + ubuntuFilename: "ubuntu-base-24.04.3-base-amd64.tar.gz", hasLibproot32: true } }; @@ -199,15 +194,21 @@ const Terminal = { "com" ], - alpineDomain: [ - "dl", + ubuntuDomain: [ + "Xed", "-", - "cdn", - ".", - "alpine", - "linux", - ".", - "org" + "Editor", + "/", + "Karbon", + "-", + "PackagesX", + "/", + "releases", + "/", + "download", + "/", + "ubuntu", + "/" ], acodeFoundation: [ @@ -260,12 +261,6 @@ const Terminal = { "/releases/latest/download/" ); - const alpineBase = buildUrl( - ...strings.protocol, - ...strings.alpineDomain, - "/alpine/v3.21/releases/" - ); - const libraryBaseUrl = buildUrl( rawGithubBase, architecture.libraryDirectory, @@ -300,15 +295,16 @@ const Terminal = { architecture.axsArchitecture ); - const alpineUrl = buildUrl( - alpineBase, - architecture.alpineDirectory, + const ubuntuUrl = buildUrl( + ...strings.protocol, + ...strings.githubDomain, "/", - architecture.alpineFilename + ...strings.ubuntuDomain, + architecture.ubuntuFilename ); logger("⬇️ Downloading sandbox filesystem..."); - await downloadFile(alpineUrl, cordova.file.dataDirectory + "alpine.tar.gz", "Sandbox filesystem"); + await downloadFile(ubuntuUrl, cordova.file.dataDirectory + "ubuntu.tar.gz", "Sandbox filesystem"); logger("⬇️ Downloading axs..."); await downloadFile(axsUrl, cordova.file.dataDirectory + "axs", "AXS"); @@ -331,8 +327,8 @@ const Terminal = { }else{ logger("📦 Extracting assets..."); await new Promise((resolve, reject) => { - system.extractAsset(`alpine_assets/${architecture.libraryDirectory}/alpine.rootfs`, `${filesDir}/alpine.tar.gz`, resolve, (e)=>{ - console.error(`Failed to extract alpine.tar.gz: ${formatError(e)}`); + system.extractAsset(`${architecture.libraryDirectory}/ubuntu.rootfs`, `${filesDir}/ubuntu.tar.gz`, resolve, (e)=>{ + console.error(`Failed to extract ubuntu.tar.gz: ${formatError(e)}`); reject(e); }); }); @@ -349,21 +345,20 @@ const Terminal = { await ensureDir(`${filesDir}/.downloaded`); - const alpineDir = `${filesDir}/alpine`; + const ubuntuDir = `${filesDir}/ubuntu`; - await ensureDir(alpineDir); + await ensureDir(ubuntuDir); logger("📦 Extracting sandbox filesystem..."); - await Executor.execute(`tar --no-same-owner -xf ${filesDir}/alpine.tar.gz -C ${alpineDir}`); + await new Promise((resolve, reject) => { + system.extractTarXz(`${filesDir}/ubuntu.tar.gz`, ubuntuDir, resolve, (e) => { + reject(e); + }); + }); logger("⚙️ Applying basic configuration..."); - await writeText(`${alpineDir}/etc/resolv.conf`, `nameserver 8.8.4.4 \nnameserver 8.8.8.8`); - - const rmWrapper = await readAsset("rm-wrapper.sh"); - await deleteFile(`${alpineDir}/bin/rm`).catch(() => {}); - await writeText(`${alpineDir}/bin/rm`, rmWrapper); - await setExec(`${alpineDir}/bin/rm`, true); + await writeText(`${ubuntuDir}/etc/resolv.conf`, `nameserver 8.8.4.4 \nnameserver 8.8.8.8`); logger("✅ Extraction complete"); await ensureDir(`${filesDir}/.extracted`); @@ -385,7 +380,7 @@ const Terminal = { }, /** - * Checks if alpine is already installed. + * Checks if ubuntu is already installed. * @returns {Promise} - Returns true if all required files and directories exist. */ isInstalled() { @@ -394,31 +389,31 @@ const Terminal = { system.getFilesDir(resolve, reject); }); - const alpineExists = await new Promise((resolve, reject) => { - system.fileExists(`${filesDir}/alpine`, false, (result) => { + const ubuntuExists = await new Promise((resolve, reject) => { + system.fileExists(`${filesDir}/ubuntu`, false, (result) => { resolve(result == 1); }, reject); }); - const downloaded = alpineExists && await new Promise((resolve, reject) => { + const downloaded = ubuntuExists && await new Promise((resolve, reject) => { system.fileExists(`${filesDir}/.downloaded`, false, (result) => { resolve(result == 1); }, reject); }); - const extracted = alpineExists && await new Promise((resolve, reject) => { + const extracted = ubuntuExists && await new Promise((resolve, reject) => { system.fileExists(`${filesDir}/.extracted`, false, (result) => { resolve(result == 1); }, reject); }); - const configured = alpineExists && await new Promise((resolve, reject) => { + const configured = ubuntuExists && await new Promise((resolve, reject) => { system.fileExists(`${filesDir}/.configured`, false, (result) => { resolve(result == 1); }, reject); }); - resolve(alpineExists && downloaded && extracted && configured); + resolve(ubuntuExists && downloaded && extracted && configured); }); }, @@ -434,12 +429,12 @@ const Terminal = { }); }, /** - * Creates a backup of the Alpine Linux installation + * Creates a backup of the Ubuntu Linux installation * @async * @function backup - * @description Creates a compressed tar archive of the Alpine installation + * @description Creates a compressed tar archive of the Ubuntu installation * @returns {Promise} Promise that resolves to the file URI of the created backup file (aterm_backup.tar) - * @throws {string} Rejects with "Alpine is not installed." if Alpine is not currently installed + * @throws {string} Rejects with "Ubuntu is not installed." if Ubuntu is not currently installed * @throws {string} Rejects with command output if backup creation fails * @example * try { @@ -452,16 +447,16 @@ const Terminal = { backup() { return new Promise(async (resolve, reject) => { if (!await this.isInstalled()) { - reject("Alpine is not installed."); + reject("Ubuntu is not installed."); return; } const cmd = ` set -e - INCLUDE_FILES="alpine .downloaded .extracted .configured axs" + INCLUDE_FILES="ubuntu .downloaded .extracted .configured axs" if [ "$FDROID" = "true" ]; then INCLUDE_FILES="$INCLUDE_FILES libtalloc.so.2 libproot-xed.so" fi - EXCLUDE="--exclude=alpine/data --exclude=alpine/system --exclude=alpine/vendor --exclude=alpine/sdcard --exclude=alpine/storage --exclude=alpine/public --exclude=alpine/apex --exclude=alpine/odm --exclude=alpine/product --exclude=alpine/system_ext --exclude=alpine/linkerconfig --exclude=alpine/proc --exclude=alpine/sys --exclude=alpine/dev --exclude=alpine/run --exclude=alpine/tmp" + EXCLUDE="--exclude=ubuntu/data --exclude=ubuntu/system --exclude=ubuntu/vendor --exclude=ubuntu/sdcard --exclude=ubuntu/storage --exclude=ubuntu/public --exclude=ubuntu/apex --exclude=ubuntu/odm --exclude=ubuntu/product --exclude=ubuntu/system_ext --exclude=ubuntu/linkerconfig --exclude=ubuntu/proc --exclude=ubuntu/sys --exclude=ubuntu/dev --exclude=ubuntu/run --exclude=ubuntu/tmp" tar -cf "$PREFIX/aterm_backup.tar" -C "$PREFIX" $EXCLUDE $INCLUDE_FILES echo "ok" `; @@ -474,11 +469,11 @@ const Terminal = { }); }, /** - * Restores Alpine Linux installation from a backup file + * Restores Ubuntu Linux installation from a backup file * @async * @function restore - * @description Restores the Alpine installation from a previously created backup file (aterm_backup.tar). - * This function stops any running Alpine processes, removes existing installation files, and extracts + * @description Restores the Ubuntu installation from a previously created backup file (aterm_backup.tar). + * This function stops any running Ubuntu processes, removes existing installation files, and extracts * the backup to restore the previous state. The backup file must exist in the expected location. * @returns {Promise} Promise that resolves to "ok" when restoration completes successfully * @throws {string} Rejects with "Backup File does not exist" if aterm_backup.tar is not found @@ -486,13 +481,17 @@ const Terminal = { * @example * try { * await restore(); - * console.log("Alpine installation restored successfully"); + * console.log("Ubuntu installation restored successfully"); * } catch (error) { * console.error(`Restore failed: ${error}`); * } */ restore() { return new Promise(async (resolve, reject) => { + if (!await this.isBackup()) { + reject("Backup File does not exist"); + return; + } if (await this.isAxsRunning()) { await this.stopAxs(); } @@ -500,7 +499,7 @@ const Terminal = { const cmd = ` set -e - INCLUDE_FILES="$PREFIX/alpine $PREFIX/.downloaded $PREFIX/.extracted $PREFIX/.configured $PREFIX/axs" + INCLUDE_FILES="$PREFIX/ubuntu $PREFIX/.downloaded $PREFIX/.extracted $PREFIX/.configured $PREFIX/axs" if [ "$FDROID" = "true" ]; then INCLUDE_FILES="$INCLUDE_FILES $PREFIX/libtalloc.so.2 $PREFIX/libproot-xed.so" @@ -509,32 +508,35 @@ const Terminal = { for item in $INCLUDE_FILES; do rm -rf -- "$item" done - - tar -xf $PREFIX/aterm_backup.* -C "$PREFIX" echo "ok" `; const result = await Executor.BackgroundExecutor.execute(cmd); - if (result === "ok") { - resolve(result); - } else { + if (result !== "ok") { reject(result); + return; } + + const backupPath = `${cordova.file.dataDirectory}aterm_backup.tar`; + await new Promise((res, rej) => { + system.extractTarXz(backupPath, cordova.file.dataDirectory, res, rej); + }); + resolve("ok"); }); }, /** - * Uninstalls the Alpine Linux installation + * Uninstalls the Ubuntu Linux installation * @async * @function uninstall - * @description Completely removes the Alpine Linux installation from the device by deleting all - * Alpine-related files and directories. This function stops any running Alpine processes before + * @description Completely removes the Ubuntu Linux installation from the device by deleting all + * Ubuntu-related files and directories. This function stops any running Ubuntu processes before * removal. NOTE: This does not perform cleanup of $PREFIX * @returns {Promise} Promise that resolves to "ok" when uninstallation completes successfully * @throws {string} Rejects with command output if uninstallation fails * @example * try { * await uninstall(); - * console.log("Alpine installation removed successfully"); + * console.log("Ubuntu installation removed successfully"); * } catch (error) { * console.error(`Uninstall failed: ${error}`); * } @@ -548,7 +550,7 @@ const Terminal = { const cmd = ` set -e - INCLUDE_FILES="$PREFIX/alpine $PREFIX/.downloaded $PREFIX/.extracted $PREFIX/.configured $PREFIX/axs" + INCLUDE_FILES="$PREFIX/ubuntu $PREFIX/.downloaded $PREFIX/.extracted $PREFIX/.configured $PREFIX/axs" if [ "$FDROID" = "true" ]; then INCLUDE_FILES="$INCLUDE_FILES $PREFIX/libtalloc.so.2 $PREFIX/libproot-xed.so" diff --git a/src/settings/lspSettings.js b/src/settings/lspSettings.js index 6a9b418034..8ef1ca0108 100644 --- a/src/settings/lspSettings.js +++ b/src/settings/lspSettings.js @@ -36,7 +36,7 @@ function normalizePackages(value) { function getInstallMethods() { return [ { value: "manual", text: strings["lsp-install-method-manual"] }, - { value: "apk", text: strings["lsp-install-method-apk"] }, + { value: "apt", text: strings["lsp-install-method-apt"] }, { value: "npm", text: strings["lsp-install-method-npm"] }, { value: "pip", text: strings["lsp-install-method-pip"] }, { value: "cargo", text: strings["lsp-install-method-cargo"] }, @@ -114,7 +114,7 @@ async function promptInstaller(binaryCommand) { binaryPath: String(binaryPath || "").trim() || undefined, }; } - case "apk": + case "apt": case "npm": case "pip": case "cargo": {