diff --git a/app/src/main/java/com/termux/app/RunCommandService.java b/app/src/main/java/com/termux/app/RunCommandService.java index bc4d6451..f54f1693 100644 --- a/app/src/main/java/com/termux/app/RunCommandService.java +++ b/app/src/main/java/com/termux/app/RunCommandService.java @@ -148,7 +148,6 @@ public class RunCommandService extends Service { FileUtils.APP_EXECUTABLE_FILE_PERMISSIONS, true, true, false); if (error != null) { - error.appendMessage("\n" + this.getString(R.string.msg_executable_absolute_path, executionCommand.executable)); executionCommand.setStateFailed(error); PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false); return stopService(); @@ -170,7 +169,6 @@ public class RunCommandService extends Service { true, true, true, false, true); if (error != null) { - error.appendMessage("\n" + this.getString(R.string.msg_working_directory_absolute_path, executionCommand.workingDirectory)); executionCommand.setStateFailed(error); PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false); return stopService(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6b37c06b..192eddd5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -111,12 +111,6 @@ - - Executable Absolute Path: \"%1$s\" - Working Directory Absolute Path: \"%1$s\" - - - Save file in ~/downloads/ Edit diff --git a/termux-shared/src/main/java/com/termux/shared/file/FileUtils.java b/termux-shared/src/main/java/com/termux/shared/file/FileUtils.java index dd057e4c..c1b5b6fd 100644 --- a/termux-shared/src/main/java/com/termux/shared/file/FileUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/file/FileUtils.java @@ -10,6 +10,7 @@ import com.termux.shared.file.filesystem.FileType; import com.termux.shared.file.filesystem.FileTypes; import com.termux.shared.data.DataUtils; import com.termux.shared.logger.Logger; +import com.termux.shared.models.errors.Errno; import com.termux.shared.models.errors.Error; import com.termux.shared.models.errors.FileUtilsErrno; import com.termux.shared.models.errors.FunctionErrno; @@ -34,6 +35,7 @@ import java.nio.file.LinkOption; import java.nio.file.StandardCopyOption; import java.util.Calendar; import java.util.Iterator; +import java.util.List; import java.util.regex.Pattern; public class FileUtils { @@ -260,7 +262,7 @@ public class FileUtils { // If file exists but not a regular file if (fileType != FileType.NO_EXIST && fileType != FileType.REGULAR) { - return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file"); + return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file", filePath).setLabel(label + "file"); } boolean isPathUnderParentDirPath = false; @@ -283,7 +285,8 @@ public class FileUtils { // If path is not a regular file // Regular files cannot be automatically created so we do not ignore if missing if (fileType != FileType.REGULAR) { - return FileUtilsErrno.ERRNO_NO_REGULAR_FILE_FOUND.getError(label + "file"); + label += "regular file"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, filePath).setLabel(label); } // If there is not parentDirPath restriction or path is not under parentDirPath or @@ -341,7 +344,7 @@ public class FileUtils { // If file exists but not a directory file if (fileType != FileType.NO_EXIST && fileType != FileType.DIRECTORY) { - return FileUtilsErrno.ERRNO_NON_DIRECTORY_FILE_FOUND.getError(label + "directory"); + return FileUtilsErrno.ERRNO_NON_DIRECTORY_FILE_FOUND.getError(label + "directory", filePath).setLabel(label + "directory"); } boolean isPathInParentDirPath = false; @@ -380,7 +383,8 @@ public class FileUtils { // If path is not a directory // Directories can be automatically created so we can ignore if missing with above check if (fileType != FileType.DIRECTORY) { - return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "directory", filePath); + label += "directory"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, filePath).setLabel(label); } if (permissionsToCheck != null) { @@ -455,7 +459,7 @@ public class FileUtils { // If file exists but not a regular file if (fileType != FileType.NO_EXIST && fileType != FileType.REGULAR) { - return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file"); + return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file", filePath).setLabel(label + "file"); } // If regular file already exists @@ -645,8 +649,10 @@ public class FileUtils { // If target file does not exist if (targetFileType == FileType.NO_EXIST) { // If dangling symlink should not be allowed, then return with error - if (!allowDangling) - return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "symlink target file", targetFileAbsolutePath); + if (!allowDangling) { + label += "symlink target file"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, targetFileAbsolutePath).setLabel(label); + } } // If destination exists @@ -920,8 +926,10 @@ public class FileUtils { if (ignoreNonExistentSrcFile) return null; // Else return with error - else - return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "source file", srcFilePath); + else { + label += "source file"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, srcFilePath).setLabel(label); + } } // If the file type of the source file does not exist in the allowedFileTypeFlags, then return with error @@ -1121,8 +1129,10 @@ public class FileUtils { if (ignoreNonExistentFile) return null; // Else return with error - else - return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "file meant to be deleted", filePath); + else { + label += "file meant to be deleted"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, filePath).setLabel(label); + } } // If the file type of the file does not exist in the allowedFileTypeFlags @@ -1224,7 +1234,7 @@ public class FileUtils { // If file exists but not a directory file if (fileType != FileType.NO_EXIST && fileType != FileType.DIRECTORY) { - return FileUtilsErrno.ERRNO_NON_DIRECTORY_FILE_FOUND.getError(label + "directory"); + return FileUtilsErrno.ERRNO_NON_DIRECTORY_FILE_FOUND.getError(label + "directory", filePath).setLabel(label + "directory"); } // If directory exists, clear its contents @@ -1288,7 +1298,7 @@ public class FileUtils { // If file exists but not a directory file if (fileType != FileType.NO_EXIST && fileType != FileType.DIRECTORY) { - return FileUtilsErrno.ERRNO_NON_DIRECTORY_FILE_FOUND.getError(label + "directory"); + return FileUtilsErrno.ERRNO_NON_DIRECTORY_FILE_FOUND.getError(label + "directory", filePath).setLabel(label + "directory"); } // If file does not exist @@ -1297,8 +1307,10 @@ public class FileUtils { if (ignoreNonExistentFile) return null; // Else return with error - else - return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "directory under which files had to be deleted", filePath); + else { + label += "directory under which files had to be deleted"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, filePath).setLabel(label); + } } // If directory exists, delete its contents @@ -1349,7 +1361,7 @@ public class FileUtils { // If file exists but not a regular file if (fileType != FileType.NO_EXIST && fileType != FileType.REGULAR) { - return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file"); + return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file", filePath).setLabel(label + "file"); } // If file does not exist @@ -1358,8 +1370,10 @@ public class FileUtils { if (ignoreNonExistentFile) return null; // Else return with error - else - return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "file meant to be read", filePath); + else { + label += "file meant to be read"; + return FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, filePath).setLabel(label); + } } if (charset == null) charset = Charset.defaultCharset(); @@ -1428,7 +1442,7 @@ public class FileUtils { // If file exists but not a regular file if (fileType != FileType.NO_EXIST && fileType != FileType.REGULAR) { - return new ReadSerializableObjectResult(FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file"), null); + return new ReadSerializableObjectResult(FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file", filePath).setLabel(label + "file"), null); } // If file does not exist @@ -1437,8 +1451,10 @@ public class FileUtils { if (ignoreNonExistentFile) return new ReadSerializableObjectResult(null, null); // Else return with error - else - return new ReadSerializableObjectResult(FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label + "file meant to be read", filePath), null); + else { + label += "file meant to be read"; + return new ReadSerializableObjectResult(FileUtilsErrno.ERRNO_FILE_NOT_FOUND_AT_PATH.getError(label, filePath).setLabel(label), null); + } } FileInputStream fileInputStream = null; @@ -1556,7 +1572,7 @@ public class FileUtils { // If file exists but not a regular file if (fileType != FileType.NO_EXIST && fileType != FileType.REGULAR) { - return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file"); + return FileUtilsErrno.ERRNO_NON_REGULAR_FILE_FOUND.getError(label + "file", filePath).setLabel(label + "file"); } // Create the file parent directory @@ -1764,17 +1780,17 @@ public class FileUtils { // If file is not readable if (permissionsToCheck.contains("r") && !file.canRead()) { - return FileUtilsErrno.ERRNO_FILE_NOT_READABLE.getError(label + "file"); + return FileUtilsErrno.ERRNO_FILE_NOT_READABLE.getError(label + "file", filePath).setLabel(label + "file"); } // If file is not writable if (permissionsToCheck.contains("w") && !file.canWrite()) { - return FileUtilsErrno.ERRNO_FILE_NOT_WRITABLE.getError(label + "file"); + return FileUtilsErrno.ERRNO_FILE_NOT_WRITABLE.getError(label + "file", filePath).setLabel(label + "file"); } // If file is not executable // This canExecute() will give "avc: granted { execute }" warnings for target sdk 29 else if (permissionsToCheck.contains("x") && !file.canExecute() && !ignoreIfNotExecutable) { - return FileUtilsErrno.ERRNO_FILE_NOT_EXECUTABLE.getError(label + "file"); + return FileUtilsErrno.ERRNO_FILE_NOT_EXECUTABLE.getError(label + "file", filePath).setLabel(label + "file"); } return null; @@ -1794,4 +1810,26 @@ public class FileUtils { return Pattern.compile("^([r-])[w-][x-]$", 0).matcher(string).matches(); } + + + /** + * Get a {@link Error} that contains a shorter version of {@link Errno} message. + * + * @param error The original {@link Error} returned by one of the {@link FileUtils} functions. + * @return Returns the shorter {@link Error} if one exists, otherwise original {@code error}. + */ + public static Error getShortFileUtilsError(final Error error) { + String type = error.getType(); + if (!FileUtilsErrno.TYPE.equals(type)) return error; + + Errno shortErrno = FileUtilsErrno.ERRNO_SHORT_MAPPING.get(Errno.valueOf(type, error.getCode())); + if (shortErrno == null) return error; + + List throwables = error.getThrowablesList(); + if (throwables.isEmpty()) + return shortErrno.getError(DataUtils.getDefaultIfNull(error.getLabel(), "file")); + else + return shortErrno.getError(throwables, error.getLabel(), "file"); + } + } diff --git a/termux-shared/src/main/java/com/termux/shared/models/errors/Errno.java b/termux-shared/src/main/java/com/termux/shared/models/errors/Errno.java index ce4c702d..d330787c 100644 --- a/termux-shared/src/main/java/com/termux/shared/models/errors/Errno.java +++ b/termux-shared/src/main/java/com/termux/shared/models/errors/Errno.java @@ -8,11 +8,14 @@ import com.termux.shared.logger.Logger; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; /** The {@link Class} that defines error messages and codes. */ public class Errno { + private static final HashMap map = new HashMap<>(); + public static final String TYPE = "Error"; @@ -35,6 +38,7 @@ public class Errno { this.type = type; this.code = code; this.message = message; + map.put(type + ":" + code, this); } @NonNull @@ -56,6 +60,17 @@ public class Errno { return code; } + /** + * Get the {@link Errno} of a specific type and code. + * + * @param type The unique type of the {@link Errno}. + * @param code The unique code of the {@link Errno}. + */ + public static Errno valueOf(String type, Integer code) { + if (type == null || type.isEmpty() || code == null) return null; + return map.get(type + ":" + code); + } + public Error getError() { @@ -73,12 +88,18 @@ public class Errno { } public Error getError(Throwable throwable, Object... args) { - return getError(Collections.singletonList(throwable), args); + if (throwable == null) + return getError(args); + else + return getError(Collections.singletonList(throwable), args); } public Error getError(List throwablesList, Object... args) { try { - return new Error(getType(), getCode(), String.format(getMessage(), args), throwablesList); + if (throwablesList == null) + return new Error(getType(), getCode(), String.format(getMessage(), args)); + else + 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 diff --git a/termux-shared/src/main/java/com/termux/shared/models/errors/Error.java b/termux-shared/src/main/java/com/termux/shared/models/errors/Error.java index b9dba33f..f74f4485 100644 --- a/termux-shared/src/main/java/com/termux/shared/models/errors/Error.java +++ b/termux-shared/src/main/java/com/termux/shared/models/errors/Error.java @@ -12,6 +12,8 @@ import java.util.List; public class Error implements Serializable { + /** The optional error label. */ + private String label; /** The error type. */ private String type; /** The error code. */ @@ -76,7 +78,18 @@ public class Error implements Serializable { this.code = Errno.ERRNO_SUCCESS.getCode(); this.message = message; - this.throwablesList = throwablesList; + + if (throwablesList != null) + this.throwablesList = throwablesList; + } + + public Error setLabel(String label) { + this.label = label; + return this; + } + + public String getLabel() { + return label; } diff --git a/termux-shared/src/main/java/com/termux/shared/models/errors/FileUtilsErrno.java b/termux-shared/src/main/java/com/termux/shared/models/errors/FileUtilsErrno.java index 48b4b096..f8c701d8 100644 --- a/termux-shared/src/main/java/com/termux/shared/models/errors/FileUtilsErrno.java +++ b/termux-shared/src/main/java/com/termux/shared/models/errors/FileUtilsErrno.java @@ -1,5 +1,8 @@ package com.termux.shared.models.errors; +import java.util.HashMap; +import java.util.Map; + /** The {@link Class} that defines FileUtils error messages and codes. */ public class FileUtilsErrno extends Errno { @@ -18,19 +21,20 @@ public class FileUtilsErrno extends Errno { /* 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_FILE_NOT_FOUND_AT_PATH = new Errno(TYPE, 150, "The %1$s not found at path \"%2$s\"."); + public static final Errno ERRNO_FILE_NOT_FOUND_AT_PATH_SHORT = new Errno(TYPE, 151, "The %1$s not found at path."); - 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, 152, "Non-regular file found at %1$s path \"%2$s\"."); + public static final Errno ERRNO_NON_REGULAR_FILE_FOUND_SHORT = 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 \"%2$s\"."); + public static final Errno ERRNO_NON_DIRECTORY_FILE_FOUND_SHORT = new Errno(TYPE, 155, "Non-directory file found at %1$s path."); + public static final Errno ERRNO_NON_SYMLINK_FILE_FOUND = new Errno(TYPE, 156, "Non-symlink file found at %1$s path \"%2$s\"."); + public static final Errno ERRNO_NON_SYMLINK_FILE_FOUND_SHORT = new Errno(TYPE, 157, "Non-symlink file found at %1$s path."); - 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, 158, "The %1$s found at path \"%2$s\" is not one of allowed file types \"%3$s\"."); - 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"); + public static final Errno ERRNO_VALIDATE_FILE_EXISTENCE_AND_PERMISSIONS_FAILED_WITH_EXCEPTION = new Errno(TYPE, 159, "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, 160, "Validating directory existence and permissions of %1$s at path \"%2$s\" failed.\nException: %3$s"); @@ -72,13 +76,31 @@ public class FileUtilsErrno extends Errno { /* 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."); + public static final Errno ERRNO_FILE_NOT_READABLE = new Errno(TYPE, 401, "The %1$s at path \"%2$s\" is not readable. Permission Denied."); + public static final Errno ERRNO_FILE_NOT_READABLE_SHORT = new Errno(TYPE, 402, "The %1$s at path is not readable. Permission Denied."); + public static final Errno ERRNO_FILE_NOT_WRITABLE = new Errno(TYPE, 403, "The %1$s at path \"%2$s\" is not writable. Permission Denied."); + public static final Errno ERRNO_FILE_NOT_WRITABLE_SHORT = new Errno(TYPE, 404, "The %1$s at path is not writable. Permission Denied."); + public static final Errno ERRNO_FILE_NOT_EXECUTABLE = new Errno(TYPE, 405, "The %1$s at path \"%2$s\" is not executable. Permission Denied."); + public static final Errno ERRNO_FILE_NOT_EXECUTABLE_SHORT = new Errno(TYPE, 406, "The %1$s at path is not executable. Permission Denied."); FileUtilsErrno(final String type, final int code, final String message) { super(type, code, message); } + + + /** Defines the {@link Errno} mapping to get a shorter version of {@link FileUtilsErrno}. */ + public static Map ERRNO_SHORT_MAPPING = new HashMap() {{ + put(ERRNO_FILE_NOT_FOUND_AT_PATH, ERRNO_FILE_NOT_FOUND_AT_PATH_SHORT); + + put(ERRNO_NON_REGULAR_FILE_FOUND, ERRNO_NON_REGULAR_FILE_FOUND_SHORT); + put(ERRNO_NON_DIRECTORY_FILE_FOUND, ERRNO_NON_DIRECTORY_FILE_FOUND_SHORT); + put(ERRNO_NON_SYMLINK_FILE_FOUND, ERRNO_NON_SYMLINK_FILE_FOUND_SHORT); + + put(ERRNO_FILE_NOT_READABLE, ERRNO_FILE_NOT_READABLE_SHORT); + put(ERRNO_FILE_NOT_WRITABLE, ERRNO_FILE_NOT_WRITABLE_SHORT); + put(ERRNO_FILE_NOT_EXECUTABLE, ERRNO_FILE_NOT_EXECUTABLE_SHORT); + }}; + }