mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-06 02:35:19 +08:00
Implement Errno system
This commit adds onto 679e0de0
If an exception is thrown, the exception message might not contain the full errors. Individual failures may get added to suppressed throwables. FileUtils functions previously just returned the exception message as errmsg which did not contain full error info.
Now `Error` class has been implemented which will used to return errors, including suppressed throwables. Each `Error` object will have an error type, code, message and a list of throwables in case multiple throwables need to returned, in addition to the suppressed throwables list in each throwable.
A supportive `Errno` base class has been implemented as well which other errno classes can inherit of which some have been added. Each `Errno` object will have an error type, code and message and can be converted to an `Error` object if needed.
Requirement for `Context` object has been removed from FileUtils so that they can be called from anywhere in code instead of having to pass around `Context` objects. Previously, `string.xml` was used to store error messages in case multi language support had to be added in future since error messages are displayed to users and not just for dev usage. However, now this will have to handled in java code if needed, based on locale.
The termux related file utils have also been moved from FileUtils to TermuxFileUtils
This commit is contained in:
@@ -14,6 +14,7 @@ import com.termux.R;
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.interact.DialogUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.models.errors.Error;
|
||||
import com.termux.shared.termux.TermuxConstants;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -88,21 +89,21 @@ final class TermuxInstaller {
|
||||
try {
|
||||
Logger.logInfo(LOG_TAG, "Installing " + TermuxConstants.TERMUX_APP_NAME + " bootstrap packages.");
|
||||
|
||||
String errmsg;
|
||||
Error error;
|
||||
|
||||
final String STAGING_PREFIX_PATH = TermuxConstants.TERMUX_STAGING_PREFIX_DIR_PATH;
|
||||
final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH);
|
||||
|
||||
// Delete prefix staging directory or any file at its destination
|
||||
errmsg = FileUtils.deleteFile(activity, "prefix staging directory", STAGING_PREFIX_PATH, true);
|
||||
if (errmsg != null) {
|
||||
throw new RuntimeException(errmsg);
|
||||
error = FileUtils.deleteFile("prefix staging directory", STAGING_PREFIX_PATH, true);
|
||||
if (error != null) {
|
||||
throw new RuntimeException(error.toString());
|
||||
}
|
||||
|
||||
// Delete prefix directory or any file at its destination
|
||||
errmsg = FileUtils.deleteFile(activity, "prefix directory", PREFIX_FILE_PATH, true);
|
||||
if (errmsg != null) {
|
||||
throw new RuntimeException(errmsg);
|
||||
error = FileUtils.deleteFile("prefix directory", PREFIX_FILE_PATH, true);
|
||||
if (error != null) {
|
||||
throw new RuntimeException(error.toString());
|
||||
}
|
||||
|
||||
Logger.logInfo(LOG_TAG, "Extracting bootstrap zip to prefix staging directory \"" + STAGING_PREFIX_PATH + "\".");
|
||||
@@ -125,14 +126,14 @@ final class TermuxInstaller {
|
||||
String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
|
||||
symlinks.add(Pair.create(oldPath, newPath));
|
||||
|
||||
ensureDirectoryExists(activity, new File(newPath).getParentFile());
|
||||
ensureDirectoryExists(new File(newPath).getParentFile());
|
||||
}
|
||||
} else {
|
||||
String zipEntryName = zipEntry.getName();
|
||||
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName);
|
||||
boolean isDirectory = zipEntry.isDirectory();
|
||||
|
||||
ensureDirectoryExists(activity, isDirectory ? targetFile : targetFile.getParentFile());
|
||||
ensureDirectoryExists(isDirectory ? targetFile : targetFile.getParentFile());
|
||||
|
||||
if (!isDirectory) {
|
||||
try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
|
||||
@@ -173,7 +174,7 @@ final class TermuxInstaller {
|
||||
activity.finish();
|
||||
}).setPositiveButton(R.string.bootstrap_error_try_again, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
FileUtils.deleteFile(activity, "prefix directory", PREFIX_FILE_PATH, true);
|
||||
FileUtils.deleteFile("prefix directory", PREFIX_FILE_PATH, true);
|
||||
TermuxInstaller.setupBootstrapIfNeeded(activity, whenDone);
|
||||
}).show();
|
||||
} catch (WindowManager.BadTokenException e1) {
|
||||
@@ -201,12 +202,13 @@ final class TermuxInstaller {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
String errmsg;
|
||||
Error error;
|
||||
File storageDir = TermuxConstants.TERMUX_STORAGE_HOME_DIR;
|
||||
|
||||
errmsg = FileUtils.clearDirectory(context, "~/storage", storageDir.getAbsolutePath());
|
||||
if (errmsg != null) {
|
||||
Logger.logErrorAndShowToast(context, LOG_TAG, errmsg);
|
||||
error = FileUtils.clearDirectory("~/storage", storageDir.getAbsolutePath());
|
||||
if (error != null) {
|
||||
Logger.logErrorAndShowToast(context, LOG_TAG, error.getMessage());
|
||||
Logger.logErrorExtended(LOG_TAG, error.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -249,12 +251,12 @@ final class TermuxInstaller {
|
||||
}.start();
|
||||
}
|
||||
|
||||
private static void ensureDirectoryExists(Context context, File directory) {
|
||||
String errmsg;
|
||||
private static void ensureDirectoryExists(File directory) {
|
||||
Error error;
|
||||
|
||||
errmsg = FileUtils.createDirectoryFile(context, directory.getAbsolutePath());
|
||||
if (errmsg != null) {
|
||||
throw new RuntimeException(errmsg);
|
||||
error = FileUtils.createDirectoryFile(directory.getAbsolutePath());
|
||||
if (error != null) {
|
||||
throw new RuntimeException(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.termux.R;
|
||||
import com.termux.shared.activities.ReportActivity;
|
||||
import com.termux.shared.models.errors.Error;
|
||||
import com.termux.shared.notification.NotificationUtils;
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.models.ReportInfo;
|
||||
@@ -62,25 +63,25 @@ public class CrashUtils {
|
||||
if (!FileUtils.regularFileExists(TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, false))
|
||||
return;
|
||||
|
||||
String errmsg;
|
||||
Error error;
|
||||
StringBuilder reportStringBuilder = new StringBuilder();
|
||||
|
||||
// Read report string from crash log file
|
||||
errmsg = FileUtils.readStringFromFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportStringBuilder, false);
|
||||
if (errmsg != null) {
|
||||
Logger.logError(logTag, errmsg);
|
||||
error = FileUtils.readStringFromFile("crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportStringBuilder, false);
|
||||
if (error != null) {
|
||||
Logger.logErrorExtended(logTag, error.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Move crash log file to backup location if it exists
|
||||
FileUtils.moveRegularFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, TermuxConstants.TERMUX_CRASH_LOG_BACKUP_FILE_PATH, true);
|
||||
if (errmsg != null) {
|
||||
Logger.logError(logTag, errmsg);
|
||||
error = FileUtils.moveRegularFile("crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, TermuxConstants.TERMUX_CRASH_LOG_BACKUP_FILE_PATH, true);
|
||||
if (error != null) {
|
||||
Logger.logErrorExtended(logTag, error.toString());
|
||||
}
|
||||
|
||||
String reportString = reportStringBuilder.toString();
|
||||
|
||||
if (reportString == null || reportString.isEmpty())
|
||||
if (reportString.isEmpty())
|
||||
return;
|
||||
|
||||
// Send a notification to show the crash log which when clicked will open the {@link ReportActivity}
|
||||
|
@@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.markdown.MarkdownUtils;
|
||||
import com.termux.shared.models.errors.Error;
|
||||
import com.termux.shared.termux.TermuxConstants;
|
||||
import com.termux.shared.termux.TermuxUtils;
|
||||
|
||||
@@ -57,7 +58,7 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler {
|
||||
reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Thread", thread.toString(), "-"));
|
||||
reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Timestamp", TermuxUtils.getCurrentTimeStamp(), "-"));
|
||||
|
||||
reportString.append("\n\n").append(Logger.getStackTracesMarkdownString("Stacktrace", Logger.getStackTraceStringArray(throwable)));
|
||||
reportString.append("\n\n").append(Logger.getStackTracesMarkdownString("Stacktrace", Logger.getStackTracesStringArray(throwable)));
|
||||
reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(context, true));
|
||||
reportString.append("\n\n").append(TermuxUtils.getDeviceInfoMarkdownString(context));
|
||||
|
||||
@@ -65,9 +66,9 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler {
|
||||
Logger.logError(reportString.toString());
|
||||
|
||||
// Write report string to crash log file
|
||||
String errmsg = FileUtils.writeStringToFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportString.toString(), false);
|
||||
if (errmsg != null) {
|
||||
Logger.logError(LOG_TAG, errmsg);
|
||||
Error error = FileUtils.writeStringToFile("crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportString.toString(), false);
|
||||
if (error != null) {
|
||||
Logger.logErrorExtended(LOG_TAG, error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,123 @@
|
||||
package com.termux.shared.file;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import com.termux.shared.models.errors.Error;
|
||||
import com.termux.shared.termux.TermuxConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TermuxFileUtils {
|
||||
/**
|
||||
* Replace "$PREFIX/" or "~/" prefix with termux absolute paths.
|
||||
*
|
||||
* @param path The {@code path} to expand.
|
||||
* @return Returns the {@code expand path}.
|
||||
*/
|
||||
public static String getExpandedTermuxPath(String path) {
|
||||
if (path != null && !path.isEmpty()) {
|
||||
path = path.replaceAll("^\\$PREFIX$", TermuxConstants.TERMUX_PREFIX_DIR_PATH);
|
||||
path = path.replaceAll("^\\$PREFIX/", TermuxConstants.TERMUX_PREFIX_DIR_PATH + "/");
|
||||
path = path.replaceAll("^~/$", TermuxConstants.TERMUX_HOME_DIR_PATH);
|
||||
path = path.replaceAll("^~/", TermuxConstants.TERMUX_HOME_DIR_PATH + "/");
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace termux absolute paths with "$PREFIX/" or "~/" prefix.
|
||||
*
|
||||
* @param path The {@code path} to unexpand.
|
||||
* @return Returns the {@code unexpand path}.
|
||||
*/
|
||||
public static String getUnExpandedTermuxPath(String path) {
|
||||
if (path != null && !path.isEmpty()) {
|
||||
path = path.replaceAll("^" + Pattern.quote(TermuxConstants.TERMUX_PREFIX_DIR_PATH) + "/", "\\$PREFIX/");
|
||||
path = path.replaceAll("^" + Pattern.quote(TermuxConstants.TERMUX_HOME_DIR_PATH) + "/", "~/");
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get canonical path.
|
||||
*
|
||||
* @param path The {@code path} to convert.
|
||||
* @param prefixForNonAbsolutePath Optional prefix path to prefix before non-absolute paths. This
|
||||
* can be set to {@code null} if non-absolute paths should
|
||||
* be prefixed with "/". The call to {@link File#getCanonicalPath()}
|
||||
* will automatically do this anyways.
|
||||
* @param expandPath The {@code boolean} that decides if input path is first attempted to be expanded by calling
|
||||
* {@link TermuxFileUtils#getExpandedTermuxPath(String)} before its passed to
|
||||
* {@link FileUtils#getCanonicalPath(String, String)}.
|
||||
|
||||
* @return Returns the {@code canonical path}.
|
||||
*/
|
||||
public static String getCanonicalPath(String path, final String prefixForNonAbsolutePath, final boolean expandPath) {
|
||||
if (path == null) path = "";
|
||||
|
||||
if (expandPath)
|
||||
path = getExpandedTermuxPath(path);
|
||||
|
||||
return FileUtils.getCanonicalPath(path, prefixForNonAbsolutePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if {@code path} is under the allowed termux working directory paths. If it is, then
|
||||
* allowed parent path is returned.
|
||||
*
|
||||
* @param path The {@code path} to check.
|
||||
* @return Returns the allowed path if it {@code path} is under it, otherwise {@link TermuxConstants#TERMUX_FILES_DIR_PATH}.
|
||||
*/
|
||||
public static String getMatchedAllowedTermuxWorkingDirectoryParentPathForPath(String path) {
|
||||
if (path == null || path.isEmpty()) return TermuxConstants.TERMUX_FILES_DIR_PATH;
|
||||
|
||||
if (path.startsWith(TermuxConstants.TERMUX_STORAGE_HOME_DIR_PATH + "/")) {
|
||||
return TermuxConstants.TERMUX_STORAGE_HOME_DIR_PATH;
|
||||
} if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath() + "/")) {
|
||||
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
} else if (path.startsWith("/sdcard/")) {
|
||||
return "/sdcard";
|
||||
} else {
|
||||
return TermuxConstants.TERMUX_FILES_DIR_PATH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the existence and permissions of directory file at path as a working directory for
|
||||
* termux app.
|
||||
*
|
||||
* The creation of missing directory and setting of missing permissions will only be done if
|
||||
* {@code path} is under paths returned by {@link #getMatchedAllowedTermuxWorkingDirectoryParentPathForPath(String)}.
|
||||
*
|
||||
* The permissions set to directory will be {@link FileUtils#APP_WORKING_DIRECTORY_PERMISSIONS}.
|
||||
*
|
||||
* @param label The optional label for the directory file. This can optionally be {@code null}.
|
||||
* @param filePath The {@code path} for file to validate or create. Symlinks will not be followed.
|
||||
* @param createDirectoryIfMissing The {@code boolean} that decides if directory file
|
||||
* should be created if its missing.
|
||||
* @param setPermissions The {@code boolean} that decides if permissions are to be
|
||||
* automatically set defined by {@code permissionsToCheck}.
|
||||
* @param setMissingPermissionsOnly The {@code boolean} that decides if only missing permissions
|
||||
* are to be set or if they should be overridden.
|
||||
* @param ignoreErrorsIfPathIsInParentDirPath The {@code boolean} that decides if existence
|
||||
* and permission errors are to be ignored if path is
|
||||
* in {@code parentDirPath}.
|
||||
* @param ignoreIfNotExecutable The {@code boolean} that decides if missing executable permission
|
||||
* error is to be ignored. This allows making an attempt to set
|
||||
* executable permissions, but ignoring if it fails.
|
||||
* @return Returns the {@code error} if path is not a directory file, failed to create it,
|
||||
* or validating permissions failed, otherwise {@code null}.
|
||||
*/
|
||||
public static Error validateDirectoryFileExistenceAndPermissions(String label, final String filePath, final boolean createDirectoryIfMissing,
|
||||
final boolean setPermissions, final boolean setMissingPermissionsOnly,
|
||||
final boolean ignoreErrorsIfPathIsInParentDirPath, final boolean ignoreIfNotExecutable) {
|
||||
return FileUtils.validateDirectoryFileExistenceAndPermissions(label, filePath,
|
||||
TermuxFileUtils.getMatchedAllowedTermuxWorkingDirectoryParentPathForPath(filePath), createDirectoryIfMissing,
|
||||
FileUtils.APP_WORKING_DIRECTORY_PERMISSIONS, setPermissions, setMissingPermissionsOnly,
|
||||
ignoreErrorsIfPathIsInParentDirPath, ignoreIfNotExecutable);
|
||||
}
|
||||
|
||||
}
|
@@ -90,7 +90,7 @@ public class FileTypes {
|
||||
return getFileType(fileAttributes);
|
||||
} catch (Exception e) {
|
||||
// If not a ENOENT (No such file or directory) exception
|
||||
if (!e.getMessage().contains("ENOENT"))
|
||||
if (e.getMessage() != null && !e.getMessage().contains("ENOENT"))
|
||||
Logger.logError("Failed to get file type for file at path \"" + filePath + "\": " + e.getMessage());
|
||||
return FileType.NO_EXIST;
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.models.errors.Error;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -31,18 +32,19 @@ public class FileUtilsTests {
|
||||
Logger.logInfo(LOG_TAG, "Running tests");
|
||||
Logger.logInfo(LOG_TAG, "testRootDirectoryPath: \"" + testRootDirectoryPath + "\"");
|
||||
|
||||
String fileUtilsTestsDirectoryCanonicalPath = FileUtils.getCanonicalPath(testRootDirectoryPath, null, false);
|
||||
String fileUtilsTestsDirectoryCanonicalPath = FileUtils.getCanonicalPath(testRootDirectoryPath, null);
|
||||
assertEqual("FileUtilsTests directory path is not a canonical path", testRootDirectoryPath, fileUtilsTestsDirectoryCanonicalPath);
|
||||
|
||||
runTestsInner(context, testRootDirectoryPath);
|
||||
runTestsInner(testRootDirectoryPath);
|
||||
Logger.logInfo(LOG_TAG, "All tests successful");
|
||||
} catch (Exception e) {
|
||||
Logger.logErrorAndShowToast(context, LOG_TAG, e.getMessage());
|
||||
Logger.logErrorExtended(LOG_TAG, e.getMessage());
|
||||
Logger.showToast(context, e.getMessage() != null ? e.getMessage().replaceAll("(?s)\nFull Error:\n.*", "") : null, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTestsInner(@NonNull final Context context, @NonNull final String testRootDirectoryPath) throws Exception {
|
||||
String errmsg;
|
||||
private static void runTestsInner(@NonNull final String testRootDirectoryPath) throws Exception {
|
||||
Error error;
|
||||
String label;
|
||||
String path;
|
||||
|
||||
@@ -101,20 +103,20 @@ public class FileUtilsTests {
|
||||
|
||||
// Create or clear test root directory file
|
||||
label = "testRootDirectoryPath";
|
||||
errmsg = FileUtils.clearDirectory(context, label, testRootDirectoryPath);
|
||||
assertEqual("Failed to create " + label + " directory file", null, errmsg);
|
||||
error = FileUtils.clearDirectory(label, testRootDirectoryPath);
|
||||
assertEqual("Failed to create " + label + " directory file", null, error);
|
||||
|
||||
if (!FileUtils.directoryFileExists(testRootDirectoryPath, false))
|
||||
throwException("The " + label + " directory file does not exist as expected after creation");
|
||||
|
||||
|
||||
// Create dir1 directory file
|
||||
errmsg = FileUtils.createDirectoryFile(context, dir1_label, dir1_path);
|
||||
assertEqual("Failed to create " + dir1_label + " directory file", null, errmsg);
|
||||
error = FileUtils.createDirectoryFile(dir1_label, dir1_path);
|
||||
assertEqual("Failed to create " + dir1_label + " directory file", null, error);
|
||||
|
||||
// Create dir2 directory file
|
||||
errmsg = FileUtils.createDirectoryFile(context, dir2_label, dir2_path);
|
||||
assertEqual("Failed to create " + dir2_label + " directory file", null, errmsg);
|
||||
error = FileUtils.createDirectoryFile(dir2_label, dir2_path);
|
||||
assertEqual("Failed to create " + dir2_label + " directory file", null, error);
|
||||
|
||||
|
||||
|
||||
@@ -122,29 +124,29 @@ public class FileUtilsTests {
|
||||
|
||||
// Create dir1/sub_dir1 directory file
|
||||
label = dir1__sub_dir1_label; path = dir1__sub_dir1_path;
|
||||
errmsg = FileUtils.createDirectoryFile(context, label, path);
|
||||
assertEqual("Failed to create " + label + " directory file", null, errmsg);
|
||||
error = FileUtils.createDirectoryFile(label, path);
|
||||
assertEqual("Failed to create " + label + " directory file", null, error);
|
||||
if (!FileUtils.directoryFileExists(path, false))
|
||||
throwException("The " + label + " directory file does not exist as expected after creation");
|
||||
|
||||
// Create dir1/sub_reg1 regular file
|
||||
label = dir1__sub_reg1_label; path = dir1__sub_reg1_path;
|
||||
errmsg = FileUtils.createRegularFile(context, label, path);
|
||||
assertEqual("Failed to create " + label + " regular file", null, errmsg);
|
||||
error = FileUtils.createRegularFile(label, path);
|
||||
assertEqual("Failed to create " + label + " regular file", null, error);
|
||||
if (!FileUtils.regularFileExists(path, false))
|
||||
throwException("The " + label + " regular file does not exist as expected after creation");
|
||||
|
||||
// Create dir1/sub_sym1 -> dir2 absolute symlink file
|
||||
label = dir1__sub_sym1_label; path = dir1__sub_sym1_path;
|
||||
errmsg = FileUtils.createSymlinkFile(context, label, dir2_path, path);
|
||||
assertEqual("Failed to create " + label + " symlink file", null, errmsg);
|
||||
error = FileUtils.createSymlinkFile(label, dir2_path, path);
|
||||
assertEqual("Failed to create " + label + " symlink file", null, error);
|
||||
if (!FileUtils.symlinkFileExists(path))
|
||||
throwException("The " + label + " symlink file does not exist as expected after creation");
|
||||
|
||||
// Copy dir1/sub_sym1 symlink file to dir1/sub_sym2
|
||||
label = dir1__sub_sym2_label; path = dir1__sub_sym2_path;
|
||||
errmsg = FileUtils.copySymlinkFile(context, label, dir1__sub_sym1_path, path, false);
|
||||
assertEqual("Failed to copy " + dir1__sub_sym1_label + " symlink file to " + label, null, errmsg);
|
||||
error = FileUtils.copySymlinkFile(label, dir1__sub_sym1_path, path, false);
|
||||
assertEqual("Failed to copy " + dir1__sub_sym1_label + " symlink file to " + label, null, error);
|
||||
if (!FileUtils.symlinkFileExists(path))
|
||||
throwException("The " + label + " symlink file does not exist as expected after copying it from " + dir1__sub_sym1_label);
|
||||
if (!new File(path).getCanonicalPath().equals(dir2_path))
|
||||
@@ -156,25 +158,25 @@ public class FileUtilsTests {
|
||||
|
||||
// Write "line1" to dir2/sub_reg1 regular file
|
||||
label = dir2__sub_reg1_label; path = dir2__sub_reg1_path;
|
||||
errmsg = FileUtils.writeStringToFile(context, label, path, Charset.defaultCharset(), "line1", false);
|
||||
assertEqual("Failed to write string to " + label + " file with append mode false", null, errmsg);
|
||||
error = FileUtils.writeStringToFile(label, path, Charset.defaultCharset(), "line1", false);
|
||||
assertEqual("Failed to write string to " + label + " file with append mode false", null, error);
|
||||
if (!FileUtils.regularFileExists(path, false))
|
||||
throwException("The " + label + " file does not exist as expected after writing to it with append mode false");
|
||||
|
||||
// Write "line2" to dir2/sub_reg1 regular file
|
||||
errmsg = FileUtils.writeStringToFile(context, label, path, Charset.defaultCharset(), "\nline2", true);
|
||||
assertEqual("Failed to write string to " + label + " file with append mode true", null, errmsg);
|
||||
error = FileUtils.writeStringToFile(label, path, Charset.defaultCharset(), "\nline2", true);
|
||||
assertEqual("Failed to write string to " + label + " file with append mode true", null, error);
|
||||
|
||||
// Read dir2/sub_reg1 regular file
|
||||
StringBuilder dataStringBuilder = new StringBuilder();
|
||||
errmsg = FileUtils.readStringFromFile(context, label, path, Charset.defaultCharset(), dataStringBuilder, false);
|
||||
assertEqual("Failed to read from " + label + " file", null, errmsg);
|
||||
error = FileUtils.readStringFromFile(label, path, Charset.defaultCharset(), dataStringBuilder, false);
|
||||
assertEqual("Failed to read from " + label + " file", null, error);
|
||||
assertEqual("The data read from " + label + " file in not as expected", "line1\nline2", dataStringBuilder.toString());
|
||||
|
||||
// Copy dir2/sub_reg1 regular file to dir2/sub_reg2 file
|
||||
label = dir2__sub_reg2_label; path = dir2__sub_reg2_path;
|
||||
errmsg = FileUtils.copyRegularFile(context, label, dir2__sub_reg1_path, path, false);
|
||||
assertEqual("Failed to copy " + dir2__sub_reg1_label + " regular file to " + label, null, errmsg);
|
||||
error = FileUtils.copyRegularFile(label, dir2__sub_reg1_path, path, false);
|
||||
assertEqual("Failed to copy " + dir2__sub_reg1_label + " regular file to " + label, null, error);
|
||||
if (!FileUtils.regularFileExists(path, false))
|
||||
throwException("The " + label + " regular file does not exist as expected after copying it from " + dir2__sub_reg1_label);
|
||||
|
||||
@@ -184,22 +186,22 @@ public class FileUtilsTests {
|
||||
|
||||
// Copy dir1 directory file to dir3
|
||||
label = dir3_label; path = dir3_path;
|
||||
errmsg = FileUtils.copyDirectoryFile(context, label, dir2_path, path, false);
|
||||
assertEqual("Failed to copy " + dir2_label + " directory file to " + label, null, errmsg);
|
||||
error = FileUtils.copyDirectoryFile(label, dir2_path, path, false);
|
||||
assertEqual("Failed to copy " + dir2_label + " directory file to " + label, null, error);
|
||||
if (!FileUtils.directoryFileExists(path, false))
|
||||
throwException("The " + label + " directory file does not exist as expected after copying it from " + dir2_label);
|
||||
|
||||
// Copy dir1 directory file to dir3 again to test overwrite
|
||||
label = dir3_label; path = dir3_path;
|
||||
errmsg = FileUtils.copyDirectoryFile(context, label, dir2_path, path, false);
|
||||
assertEqual("Failed to copy " + dir2_label + " directory file to " + label, null, errmsg);
|
||||
error = FileUtils.copyDirectoryFile(label, dir2_path, path, false);
|
||||
assertEqual("Failed to copy " + dir2_label + " directory file to " + label, null, error);
|
||||
if (!FileUtils.directoryFileExists(path, false))
|
||||
throwException("The " + label + " directory file does not exist as expected after copying it from " + dir2_label);
|
||||
|
||||
// Move dir3 directory file to dir4
|
||||
label = dir4_label; path = dir4_path;
|
||||
errmsg = FileUtils.moveDirectoryFile(context, label, dir3_path, path, false);
|
||||
assertEqual("Failed to move " + dir3_label + " directory file to " + label, null, errmsg);
|
||||
error = FileUtils.moveDirectoryFile(label, dir3_path, path, false);
|
||||
assertEqual("Failed to move " + dir3_label + " directory file to " + label, null, error);
|
||||
if (!FileUtils.directoryFileExists(path, false))
|
||||
throwException("The " + label + " directory file does not exist as expected after copying it from " + dir3_label);
|
||||
|
||||
@@ -209,16 +211,16 @@ public class FileUtilsTests {
|
||||
|
||||
// Create dir1/sub_sym3 -> dir4 relative symlink file
|
||||
label = dir1__sub_sym3_label; path = dir1__sub_sym3_path;
|
||||
errmsg = FileUtils.createSymlinkFile(context, label, "../dir4", path);
|
||||
assertEqual("Failed to create " + label + " symlink file", null, errmsg);
|
||||
error = FileUtils.createSymlinkFile(label, "../dir4", path);
|
||||
assertEqual("Failed to create " + label + " symlink file", null, error);
|
||||
if (!FileUtils.symlinkFileExists(path))
|
||||
throwException("The " + label + " symlink file does not exist as expected after creation");
|
||||
|
||||
// Create dir1/sub_sym3 -> dirX relative dangling symlink file
|
||||
// This is to ensure that symlinkFileExists returns true if a symlink file exists but is dangling
|
||||
label = dir1__sub_sym3_label; path = dir1__sub_sym3_path;
|
||||
errmsg = FileUtils.createSymlinkFile(context, label, "../dirX", path);
|
||||
assertEqual("Failed to create " + label + " symlink file", null, errmsg);
|
||||
error = FileUtils.createSymlinkFile(label, "../dirX", path);
|
||||
assertEqual("Failed to create " + label + " symlink file", null, error);
|
||||
if (!FileUtils.symlinkFileExists(path))
|
||||
throwException("The " + label + " dangling symlink file does not exist as expected after creation");
|
||||
|
||||
@@ -228,8 +230,8 @@ public class FileUtilsTests {
|
||||
|
||||
// Delete dir1/sub_sym2 symlink file
|
||||
label = dir1__sub_sym2_label; path = dir1__sub_sym2_path;
|
||||
errmsg = FileUtils.deleteSymlinkFile(context, label, path, false);
|
||||
assertEqual("Failed to delete " + label + " symlink file", null, errmsg);
|
||||
error = FileUtils.deleteSymlinkFile(label, path, false);
|
||||
assertEqual("Failed to delete " + label + " symlink file", null, error);
|
||||
if (FileUtils.fileExists(path, false))
|
||||
throwException("The " + label + " symlink file still exist after deletion");
|
||||
|
||||
@@ -245,8 +247,8 @@ public class FileUtilsTests {
|
||||
|
||||
// Delete dir1 directory file
|
||||
label = dir1_label; path = dir1_path;
|
||||
errmsg = FileUtils.deleteDirectoryFile(context, label, path, false);
|
||||
assertEqual("Failed to delete " + label + " directory file", null, errmsg);
|
||||
error = FileUtils.deleteDirectoryFile(label, path, false);
|
||||
assertEqual("Failed to delete " + label + " directory file", null, error);
|
||||
if (FileUtils.fileExists(path, false))
|
||||
throwException("The " + label + " directory file still exist after deletion");
|
||||
|
||||
@@ -267,8 +269,8 @@ public class FileUtilsTests {
|
||||
|
||||
// Delete dir2/sub_reg1 regular file
|
||||
label = dir2__sub_reg1_label; path = dir2__sub_reg1_path;
|
||||
errmsg = FileUtils.deleteRegularFile(context, label, path, false);
|
||||
assertEqual("Failed to delete " + label + " regular file", null, errmsg);
|
||||
error = FileUtils.deleteRegularFile(label, path, false);
|
||||
assertEqual("Failed to delete " + label + " regular file", null, error);
|
||||
if (FileUtils.fileExists(path, false))
|
||||
throwException("The " + label + " regular file still exist after deletion");
|
||||
|
||||
@@ -276,6 +278,14 @@ public class FileUtilsTests {
|
||||
FileUtils.getFileType("/dev/null", false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void assertEqual(@NonNull final String message, final String expected, final Error actual) throws Exception {
|
||||
String actualString = actual != null ? actual.getMessage() : null;
|
||||
if (!equalsRegardingNull(expected, actualString))
|
||||
throwException(message + "\nexpected: \"" + expected + "\"\nactual: \"" + actualString + "\"\nFull Error:\n" + (actual != null ? actual.toString() : ""));
|
||||
}
|
||||
|
||||
public static void assertEqual(@NonNull final String message, final String expected, final String actual) throws Exception {
|
||||
if (!equalsRegardingNull(expected, actual))
|
||||
throwException(message + "\nexpected: \"" + expected + "\"\nactual: \"" + actual + "\"");
|
||||
|
@@ -0,0 +1,89 @@
|
||||
package com.termux.shared.models.errors;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.termux.shared.logger.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** The {@link Class} that defines error messages and codes. */
|
||||
public class Errno {
|
||||
|
||||
public static final String TYPE = "Error";
|
||||
|
||||
|
||||
public static final Errno ERRNO_SUCCESS = new Errno(TYPE, Activity.RESULT_OK, "Success");
|
||||
public static final Errno ERRNO_MINOR_FAILURES = new Errno(TYPE, Activity.RESULT_FIRST_USER, "Minor failure");
|
||||
public static final Errno ERRNO_FAILED = new Errno(TYPE, Activity.RESULT_FIRST_USER + 1, "Failed");
|
||||
public static final Errno ERRNO_CANCELED = new Errno(TYPE, Activity.RESULT_FIRST_USER + 2, "Cancelled");
|
||||
|
||||
/** The errno type. */
|
||||
protected String type;
|
||||
/** The errno code. */
|
||||
protected final int code;
|
||||
/** The errno message. */
|
||||
protected final String message;
|
||||
|
||||
private static final String LOG_TAG = "Errno";
|
||||
|
||||
|
||||
public Errno(final String type, final int code, final String message) {
|
||||
this.type = type;
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "type=" + type + ", code=" + code + ", message=\"" + message + "\"";
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Error getError() {
|
||||
return new Error(getType(), getCode(), getMessage());
|
||||
}
|
||||
|
||||
public Error getError(Object... args) {
|
||||
try {
|
||||
return new Error(getType(), getCode(), String.format(getMessage(), args));
|
||||
} catch (Exception e) {
|
||||
Logger.logWarn(LOG_TAG, "Exception raised while calling String.format() for error message of errno " + this + " with args" + Arrays.toString(args) + "\n" + e.getMessage());
|
||||
// Return unformatted message as a backup
|
||||
return new Error(getType(), getCode(), getMessage() + ": " + Arrays.toString(args));
|
||||
}
|
||||
}
|
||||
|
||||
public Error getError(Throwable throwable, Object... args) {
|
||||
return getError(Collections.singletonList(throwable), args);
|
||||
}
|
||||
|
||||
public Error getError(List<Throwable> throwablesList, Object... args) {
|
||||
try {
|
||||
return new Error(getType(), getCode(), String.format(getMessage(), args), throwablesList);
|
||||
} catch (Exception e) {
|
||||
Logger.logWarn(LOG_TAG, "Exception raised while calling String.format() for error message of errno " + this + " with args" + Arrays.toString(args) + "\n" + e.getMessage());
|
||||
// Return unformatted message as a backup
|
||||
return new Error(getType(), getCode(), getMessage() + ": " + Arrays.toString(args), throwablesList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,249 @@
|
||||
package com.termux.shared.models.errors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.markdown.MarkdownUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Error implements Serializable {
|
||||
|
||||
/** The error type. */
|
||||
private String type;
|
||||
/** The error code. */
|
||||
private int code;
|
||||
/** The error message. */
|
||||
private String message;
|
||||
/** The error exceptions. */
|
||||
private List<Throwable> throwablesList = new ArrayList<>();
|
||||
|
||||
private static final String LOG_TAG = "Error";
|
||||
|
||||
|
||||
public Error() {
|
||||
InitError(null, null, null, null);
|
||||
}
|
||||
|
||||
public Error(String type, Integer code, String message, List<Throwable> throwablesList) {
|
||||
InitError(type, code, message, throwablesList);
|
||||
}
|
||||
|
||||
public Error(String type, Integer code, String message, Throwable throwable) {
|
||||
InitError(type, code, message, Collections.singletonList(throwable));
|
||||
}
|
||||
|
||||
public Error(String type, Integer code, String message) {
|
||||
InitError(type, code, message, null);
|
||||
}
|
||||
|
||||
public Error(Integer code, String message, List<Throwable> throwablesList) {
|
||||
InitError(null, code, message, throwablesList);
|
||||
}
|
||||
|
||||
public Error(Integer code, String message, Throwable throwable) {
|
||||
InitError(null, code, message, Collections.singletonList(throwable));
|
||||
}
|
||||
|
||||
public Error(Integer code, String message) {
|
||||
InitError(null, code, message, null);
|
||||
}
|
||||
|
||||
public Error(String message, Throwable throwable) {
|
||||
InitError(null, null, message, Collections.singletonList(throwable));
|
||||
}
|
||||
|
||||
public Error(String message, List<Throwable> throwablesList) {
|
||||
InitError(null, null, message, throwablesList);
|
||||
}
|
||||
|
||||
public Error(String message) {
|
||||
InitError(null, null, message, null);
|
||||
}
|
||||
|
||||
private void InitError(String type, Integer code, String message, List<Throwable> throwablesList) {
|
||||
if (type != null && !type.isEmpty())
|
||||
this.type = type;
|
||||
else
|
||||
this.type = Errno.TYPE;
|
||||
|
||||
if (code != null && code > Errno.ERRNO_SUCCESS.getCode())
|
||||
this.code = code;
|
||||
else
|
||||
this.code = Errno.ERRNO_SUCCESS.getCode();
|
||||
|
||||
this.message = message;
|
||||
this.throwablesList = throwablesList;
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void prependMessage(String message) {
|
||||
if (message != null && isStateFailed())
|
||||
this.message = message + this.message;
|
||||
}
|
||||
|
||||
public void appendMessage(String message) {
|
||||
if (message != null && isStateFailed())
|
||||
this.message = this.message + message;
|
||||
}
|
||||
|
||||
public List<Throwable> getThrowablesList() {
|
||||
return Collections.unmodifiableList(throwablesList);
|
||||
}
|
||||
|
||||
|
||||
public synchronized boolean setStateFailed(@NonNull Error error) {
|
||||
return setStateFailed(error.getType(), error.getCode(), error.getMessage(), null);
|
||||
}
|
||||
|
||||
public synchronized boolean setStateFailed(@NonNull Error error, Throwable throwable) {
|
||||
return setStateFailed(error.getType(), error.getCode(), error.getMessage(), Collections.singletonList(throwable));
|
||||
}
|
||||
public synchronized boolean setStateFailed(@NonNull Error error, List<Throwable> throwablesList) {
|
||||
return setStateFailed(error.getType(), error.getCode(), error.getMessage(), throwablesList);
|
||||
}
|
||||
|
||||
public synchronized boolean setStateFailed(int code, String message) {
|
||||
return setStateFailed(this.type, code, message, null);
|
||||
}
|
||||
|
||||
public synchronized boolean setStateFailed(int code, String message, Throwable throwable) {
|
||||
return setStateFailed(this.type, code, message, Collections.singletonList(throwable));
|
||||
}
|
||||
|
||||
public synchronized boolean setStateFailed(int code, String message, List<Throwable> throwablesList) {
|
||||
return setStateFailed(this.type, code, message, throwablesList);
|
||||
}
|
||||
|
||||
public synchronized boolean setStateFailed(String type, int code, String message, List<Throwable> throwablesList) {
|
||||
this.message = message;
|
||||
this.throwablesList = throwablesList;
|
||||
|
||||
if (type != null && !type.isEmpty())
|
||||
this.type = type;
|
||||
|
||||
if (code > Errno.ERRNO_SUCCESS.getCode()) {
|
||||
this.code = code;
|
||||
return true;
|
||||
} else {
|
||||
Logger.logWarn(LOG_TAG, "Ignoring invalid error code value \"" + code + "\". Force setting it to RESULT_CODE_FAILED \"" + Errno.ERRNO_FAILED.getCode() + "\"");
|
||||
this.code = Errno.ERRNO_FAILED.getCode();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStateFailed() {
|
||||
return code > Errno.ERRNO_SUCCESS.getCode();
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return getErrorLogString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log friendly {@link String} for {@link Error} error parameters.
|
||||
*
|
||||
* @param error The {@link Error} to convert.
|
||||
* @return Returns the log friendly {@link String}.
|
||||
*/
|
||||
public static String getErrorLogString(final Error error) {
|
||||
if (error == null) return "null";
|
||||
|
||||
StringBuilder logString = new StringBuilder();
|
||||
|
||||
logString.append(error.getCodeString());
|
||||
logString.append("\n").append(error.getTypeAndMessageLogString());
|
||||
if (error.throwablesList != null)
|
||||
logString.append("\n").append(error.geStackTracesLogString());
|
||||
|
||||
return logString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a minimal log friendly {@link String} for {@link Error} error parameters.
|
||||
*
|
||||
* @param error The {@link Error} to convert.
|
||||
* @return Returns the log friendly {@link String}.
|
||||
*/
|
||||
public static String getMinimalErrorLogString(final Error error) {
|
||||
if (error == null) return "null";
|
||||
|
||||
StringBuilder logString = new StringBuilder();
|
||||
|
||||
logString.append(error.getCodeString());
|
||||
logString.append(error.getTypeAndMessageLogString());
|
||||
|
||||
return logString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a minimal {@link String} for {@link Error} error parameters.
|
||||
*
|
||||
* @param error The {@link Error} to convert.
|
||||
* @return Returns the {@link String}.
|
||||
*/
|
||||
public static String getMinimalErrorString(final Error error) {
|
||||
if (error == null) return "null";
|
||||
|
||||
StringBuilder logString = new StringBuilder();
|
||||
|
||||
logString.append("(").append(error.getCode()).append(") ");
|
||||
logString.append(error.getType()).append(": ").append(error.getMessage());
|
||||
|
||||
return logString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a markdown {@link String} for {@link Error}.
|
||||
*
|
||||
* @param error The {@link Error} to convert.
|
||||
* @return Returns the markdown {@link String}.
|
||||
*/
|
||||
public static String getErrorMarkdownString(final Error error) {
|
||||
if (error == null) return "null";
|
||||
|
||||
StringBuilder markdownString = new StringBuilder();
|
||||
|
||||
markdownString.append(MarkdownUtils.getSingleLineMarkdownStringEntry("Error Code", error.getCode(), "-"));
|
||||
markdownString.append("\n").append(MarkdownUtils.getMultiLineMarkdownStringEntry((Errno.TYPE.equals(error.getType()) ? "Error Message" : "Error Message (" + error.getType() + ")"), error.message, "-"));
|
||||
markdownString.append("\n\n").append(error.geStackTracesMarkdownString());
|
||||
|
||||
return markdownString.toString();
|
||||
}
|
||||
|
||||
|
||||
public String getCodeString() {
|
||||
return Logger.getSingleLineLogStringEntry("Error Code", code, "-");
|
||||
}
|
||||
|
||||
public String getTypeAndMessageLogString() {
|
||||
return Logger.getMultiLineLogStringEntry(Errno.TYPE.equals(type) ? "Error Message" : "Error Message (" + type + ")", message, "-");
|
||||
}
|
||||
|
||||
public String geStackTracesLogString() {
|
||||
return Logger.getStackTracesString("StackTraces:", Logger.getStackTracesStringArray(throwablesList));
|
||||
}
|
||||
|
||||
public String geStackTracesMarkdownString() {
|
||||
return Logger.getStackTracesMarkdownString("StackTraces", Logger.getStackTracesStringArray(throwablesList));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
package com.termux.shared.models.errors;
|
||||
|
||||
/** The {@link Class} that defines FileUtils error messages and codes. */
|
||||
public class FileUtilsErrno extends Errno {
|
||||
|
||||
public static final String TYPE = "FileUtils Error";
|
||||
|
||||
|
||||
/* Errors for null or empty paths (100-150) */
|
||||
public static final Errno ERRNO_EXECUTABLE_REQUIRED = new Errno(TYPE, 100, "Executable required.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_REGULAR_FILE_PATH = new Errno(TYPE, 101, "The regular file path is null or empty.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_REGULAR_FILE = new Errno(TYPE, 102, "The regular file is null or empty.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_EXECUTABLE_FILE_PATH = new Errno(TYPE, 103, "The executable file path is null or empty.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_EXECUTABLE_FILE = new Errno(TYPE, 104, "The executable file is null or empty.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_DIRECTORY_FILE_PATH = new Errno(TYPE, 105, "The directory file path is null or empty.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_DIRECTORY_FILE = new Errno(TYPE, 106, "The directory file is null or empty.");
|
||||
|
||||
|
||||
|
||||
/* Errors for invalid or not found files at path (150-200) */
|
||||
public static final Errno ERRNO_FILE_NOT_FOUND_AT_PATH = new Errno(TYPE, 150, "The %1$s is not found at path \"%2$s\".");
|
||||
|
||||
public static final Errno ERRNO_NO_REGULAR_FILE_FOUND = new Errno(TYPE, 151, "Regular file not found at %1$s path.");
|
||||
public static final Errno ERRNO_NOT_A_REGULAR_FILE = new Errno(TYPE, 152, "The %1$s at path \"%2$s\" is not a regular file.");
|
||||
|
||||
public static final Errno ERRNO_NON_REGULAR_FILE_FOUND = new Errno(TYPE, 153, "Non-regular file found at %1$s path.");
|
||||
public static final Errno ERRNO_NON_DIRECTORY_FILE_FOUND = new Errno(TYPE, 154, "Non-directory file found at %1$s path.");
|
||||
public static final Errno ERRNO_NON_SYMLINK_FILE_FOUND = new Errno(TYPE, 155, "Non-symlink file found at %1$s path.");
|
||||
|
||||
public static final Errno ERRNO_FILE_NOT_AN_ALLOWED_FILE_TYPE = new Errno(TYPE, 156, "The %1$s found at path \"%2$s\" is not one of allowed file types \"%3$s\".");
|
||||
|
||||
public static final Errno ERRNO_VALIDATE_FILE_EXISTENCE_AND_PERMISSIONS_FAILED_WITH_EXCEPTION = new Errno(TYPE, 157, "Validating file existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
public static final Errno ERRNO_VALIDATE_DIRECTORY_EXISTENCE_AND_PERMISSIONS_FAILED_WITH_EXCEPTION = new Errno(TYPE, 158, "Validating directory existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
|
||||
|
||||
|
||||
/* Errors for file creation (200-250) */
|
||||
public static final Errno ERRNO_CREATING_FILE_FAILED = new Errno(TYPE, 200, "Creating %1$s at path \"%2$s\" failed.");
|
||||
public static final Errno ERRNO_CREATING_FILE_FAILED_WITH_EXCEPTION = new Errno(TYPE, 201, "Creating %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
|
||||
public static final Errno ERRNO_CANNOT_OVERWRITE_A_NON_SYMLINK_FILE_TYPE = new Errno(TYPE, 202, "Cannot overwrite %1$s while creating symlink at \"%2$s\" to \"%3$s\" since destination file type \"%4$s\" is not a symlink.");
|
||||
public static final Errno ERRNO_CREATING_SYMLINK_FILE_FAILED_WITH_EXCEPTION = new Errno(TYPE, 203, "Creating %1$s at path \"%2$s\" to \"%3$s\" failed.\nException: %4$s");
|
||||
|
||||
|
||||
|
||||
/* Errors for file copying and moving (250-300) */
|
||||
public static final Errno ERRNO_COPYING_OR_MOVING_FILE_FAILED_WITH_EXCEPTION = new Errno(TYPE, 250, "%1$s from \"%2$s\" to \"%3$s\" failed.\nException: %4$s");
|
||||
public static final Errno ERRNO_COPYING_OR_MOVING_FILE_TO_SAME_PATH = new Errno(TYPE, 251, "%1$s from \"%2$s\" to \"%3$s\" cannot be done since they point to the same path.");
|
||||
public static final Errno ERRNO_CANNOT_OVERWRITE_A_DIFFERENT_FILE_TYPE = new Errno(TYPE, 252, "Cannot overwrite %1$s while %2$s it from \"%3$s\" to \"%4$s\" since destination file type \"%5$s\" is different from source file type \"%6$s\".");
|
||||
public static final Errno ERRNO_CANNOT_MOVE_DIRECTORY_TO_SUB_DIRECTORY_OF_ITSELF = new Errno(TYPE, 253, "Cannot move %1$s from \"%2$s\" to \"%3$s\" since destination is a subdirectory of the source.");
|
||||
|
||||
|
||||
|
||||
/* Errors for file deletion (300-350) */
|
||||
public static final Errno ERRNO_DELETING_FILE_FAILED = new Errno(TYPE, 300, "Deleting %1$s at path \"%2$s\" failed.");
|
||||
public static final Errno ERRNO_DELETING_FILE_FAILED_WITH_EXCEPTION = new Errno(TYPE, 301, "Deleting %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
public static final Errno ERRNO_CLEARING_DIRECTORY_FAILED_WITH_EXCEPTION = new Errno(TYPE, 302, "Clearing %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
public static final Errno ERRNO_FILE_STILL_EXISTS_AFTER_DELETING = new Errno(TYPE, 303, "The %1$s still exists after deleting it from \"%2$s\".");
|
||||
|
||||
|
||||
|
||||
/* Errors for file reading and writing (350-400) */
|
||||
public static final Errno ERRNO_READING_STRING_TO_FILE_FAILED_WITH_EXCEPTION = new Errno(TYPE, 350, "Reading string from %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
public static final Errno ERRNO_WRITING_STRING_TO_FILE_FAILED_WITH_EXCEPTION = new Errno(TYPE, 351, "Writing string to %1$s at path \"%2$s\" failed.\nException: %3$s");
|
||||
public static final Errno ERRNO_UNSUPPORTED_CHARSET = new Errno(TYPE, 352, "Unsupported charset \"%1$s\"");
|
||||
public static final Errno ERRNO_CHECKING_IF_CHARSET_SUPPORTED_FAILED = new Errno(TYPE, 353, "Checking if charset \"%1$s\" is supported failed.\nException: %2$s");
|
||||
|
||||
|
||||
|
||||
/* Errors for invalid file permissions (400-450) */
|
||||
public static final Errno ERRNO_INVALID_FILE_PERMISSIONS_STRING_TO_CHECK = new Errno(TYPE, 400, "The file permission string to check is invalid.");
|
||||
public static final Errno ERRNO_FILE_NOT_READABLE = new Errno(TYPE, 401, "The %1$s at path is not readable. Permission Denied.");
|
||||
public static final Errno ERRNO_FILE_NOT_WRITABLE = new Errno(TYPE, 402, "The %1$s at path is not writable. Permission Denied.");
|
||||
public static final Errno ERRNO_FILE_NOT_EXECUTABLE = new Errno(TYPE, 403, "The %1$s at path is not executable. Permission Denied.");
|
||||
|
||||
|
||||
FileUtilsErrno(final String type, final int code, final String message) {
|
||||
super(type, code, message);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package com.termux.shared.models.errors;
|
||||
|
||||
/** The {@link Class} that defines function error messages and codes. */
|
||||
public class FunctionErrno extends Errno {
|
||||
|
||||
public static final String TYPE = "Function Error";
|
||||
|
||||
|
||||
/* Errors for null or empty parameters (100-150) */
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_PARAMETER = new Errno(TYPE, 100, "The %1$s parameter passed to \"%2$s\" is null or empty.");
|
||||
public static final Errno ERRNO_NULL_OR_EMPTY_PARAMETERS = new Errno(TYPE, 101, "The %1$s parameters passed to \"%2$s\" are null or empty.");
|
||||
public static final Errno ERRNO_UNSET_PARAMETER = new Errno(TYPE, 102, "The %1$s parameter passed to \"%2$s\" must be set.");
|
||||
public static final Errno ERRNO_UNSET_PARAMETERS = new Errno(TYPE, 103, "The %1$s parameters passed to \"%2$s\" must be set.");
|
||||
|
||||
|
||||
FunctionErrno(final String type, final int code, final String message) {
|
||||
super(type, code, message);
|
||||
}
|
||||
|
||||
}
|
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.termux.shared.models.errors.Error;
|
||||
import com.termux.shared.termux.TermuxConstants;
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
@@ -150,14 +151,14 @@ public class ShellUtils {
|
||||
return (lastSlash == -1) ? executable : executable.substring(lastSlash + 1);
|
||||
}
|
||||
|
||||
public static void clearTermuxTMPDIR(Context context, boolean onlyIfExists) {
|
||||
public static void clearTermuxTMPDIR(boolean onlyIfExists) {
|
||||
if(onlyIfExists && !FileUtils.directoryFileExists(TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH, false))
|
||||
return;
|
||||
|
||||
String errmsg;
|
||||
errmsg = FileUtils.clearDirectory(context, "$TMPDIR", FileUtils.getCanonicalPath(TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH, null, false));
|
||||
if (errmsg != null) {
|
||||
Logger.logError(errmsg);
|
||||
Error error;
|
||||
error = FileUtils.clearDirectory("$TMPDIR", FileUtils.getCanonicalPath(TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH, null));
|
||||
if (error != null) {
|
||||
Logger.logErrorExtended(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -13,52 +13,7 @@
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- FileUtils -->
|
||||
<string name="error_executable_required">Executable required.</string>
|
||||
<string name="error_null_or_empty_parameter">The %1$s is to \"%2$s\" null or empty.</string>
|
||||
<string name="error_null_or_empty_regular_file_path">The regular file path is null or empty.</string>
|
||||
<string name="error_null_or_empty_regular_file">The regular file is null or empty.</string>
|
||||
<string name="error_null_or_empty_executable_file_path">The executable file path is null or empty.</string>
|
||||
<string name="error_null_or_empty_executable_file">The executable file is null or empty.</string>
|
||||
<string name="error_null_or_empty_directory_file_path">The directory file path is null or empty.</string>
|
||||
<string name="error_null_or_empty_directory_file">The directory file is null or empty.</string>
|
||||
|
||||
<string name="error_file_not_found_at_path">The %1$s is not found at path \"%2$s\".</string>
|
||||
<string name="error_no_regular_file_found">Regular file not found at %1$s path.</string>
|
||||
<string name="error_not_a_regular_file">The %1$s at path \"%2$s\" is not a regular file.</string>
|
||||
<string name="error_non_regular_file_found">Non-regular file found at %1$s path.</string>
|
||||
<string name="error_non_directory_file_found">Non-directory file found at %1$s path.</string>
|
||||
<string name="error_non_symlink_file_found">Non-symlink file found at %1$s path.</string>
|
||||
<string name="error_file_not_an_allowed_file_type">The %1$s found at path \"%2$s\" is not one of allowed file types \"%3$s\".</string>
|
||||
|
||||
<string name="error_validate_file_existence_and_permissions_failed_with_exception">Validating file existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
<string name="error_validate_directory_existence_and_permissions_failed_with_exception">Validating directory existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
|
||||
<string name="error_creating_file_failed">Creating %1$s at path \"%2$s\" failed.</string>
|
||||
<string name="error_creating_file_failed_with_exception">Creating %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
|
||||
<string name="error_cannot_overwrite_a_non_symlink_file_type">Cannot overwrite %1$s while creating symlink at \"%2$s\" to \"%3$s\" since destination file type \"%4$s\" is not a symlink.</string>
|
||||
<string name="error_creating_symlink_file_failed_with_exception">Creating %1$s at path \"%2$s\" to \"%3$s\" failed.\nException: %4$s</string>
|
||||
|
||||
<string name="error_copying_or_moving_file_failed_with_exception">%1$s from \"%2$s\" to \"%3$s\" failed.\nException: %4$s</string>
|
||||
<string name="error_copying_or_moving_file_to_same_path">%1$s from \"%2$s\" to \"%3$s\" cannot be done since they point to the same path.</string>
|
||||
<string name="error_cannot_overwrite_a_different_file_type">Cannot overwrite %1$s while %2$s it from \"%3$s\" to \"%4$s\" since destination file type \"%5$s\" is different from source file type \"%6$s\".</string>
|
||||
<string name="error_cannot_move_directory_to_sub_directory_of_itself">Cannot move %1$s from \"%2$s\" to \"%3$s\" since destination is a subdirectory of the source.</string>
|
||||
|
||||
<string name="error_file_still_exists_after_deleting">The %1$s still exists after deleting it from \"%2$s\".</string>
|
||||
<string name="error_deleting_file_failed">Deleting %1$s at path \"%2$s\" failed.</string>
|
||||
<string name="error_deleting_file_failed_with_exception">Deleting %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
<string name="error_clearing_directory_failed_with_exception">Clearing %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
|
||||
<string name="error_reading_string_to_file_failed_with_exception">Reading string from %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
<string name="error_writing_string_to_file_failed_with_exception">Writing string to %1$s at path \"%2$s\" failed.\nException: %3$s</string>
|
||||
<string name="error_unsupported_charset">Unsupported charset \"%1$s\"</string>
|
||||
<string name="error_checking_if_charset_supported_failed">Checking if charset \"%1$s\" is suppoted failed.\nException: %2$s</string>
|
||||
|
||||
<string name="error_invalid_file_permissions_string_to_check">The file permission string to check is invalid.</string>
|
||||
<string name="error_file_not_readable">The %1$s at path is not readable. Permission Denied.</string>
|
||||
<string name="error_file_not_writable">The %1$s at path is not writable. Permission Denied.</string>
|
||||
<string name="error_file_not_executable">The %1$s at path is not executable. Permission Denied.</string>
|
||||
<string name="msg_directory_absolute_path">%1$s Directory Absolute Path: \"%2$s\"</string>
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user