Fixed: Fix `termux.properties` reload not working if the properties file didn't exist at app startup

Closes #2836
This commit is contained in:
agnostic-apollo 2022-06-15 18:30:21 +05:00
parent e92a6db06b
commit 82b1580312
4 changed files with 59 additions and 64 deletions

View File

@ -9,6 +9,8 @@ import androidx.annotation.Nullable;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.primitives.Primitives;
import com.termux.shared.file.FileUtils;
import com.termux.shared.file.filesystem.FileType;
import com.termux.shared.logger.Logger;
import java.io.File;
@ -16,6 +18,7 @@ import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@ -253,6 +256,38 @@ public class SharedProperties {
return properties;
}
/** Returns the first {@link File} found in
* {@code propertiesFilePaths} from which app properties can be loaded. If the {@link File} found
* is not a regular file or is not readable, then {@code null} is returned. Symlinks **will not**
* be followed for potential security reasons.
*
* @param propertiesFilePaths The {@link List<String>} containing properties file paths.
* @param logTag If log tag to use for logging errors.
* @return Returns the {@link File} object for Termux:Float app properties.
*/
public static File getPropertiesFileFromList(List<String> propertiesFilePaths, @NonNull String logTag) {
if (propertiesFilePaths == null || propertiesFilePaths.size() == 0)
return null;
for(String propertiesFilePath : propertiesFilePaths) {
File propertiesFile = new File(propertiesFilePath);
// Symlinks **will not** be followed.
FileType fileType = FileUtils.getFileType(propertiesFilePath, false);
if (fileType == FileType.REGULAR) {
if (propertiesFile.canRead())
return propertiesFile;
else
Logger.logWarn(logTag, "Ignoring properties file at \"" + propertiesFilePath + "\" since it is not readable");
} else if (fileType != FileType.NO_EXIST) {
Logger.logWarn(logTag, "Ignoring properties file at \"" + propertiesFilePath + "\" of type: \"" + fileType.getName() + "\"");
}
}
Logger.logDebug(logTag, "No readable properties file found at: " + propertiesFilePaths);
return null;
}
public static String getProperty(Context context, File propertiesFile, String key, String def) {

View File

@ -13,7 +13,7 @@ public class TermuxAppSharedProperties extends TermuxSharedProperties {
private TermuxAppSharedProperties(@NonNull Context context) {
super(context, TermuxConstants.TERMUX_APP_NAME,
TermuxPropertyConstants.getTermuxPropertiesFile(), TermuxPropertyConstants.TERMUX_APP_PROPERTIES_LIST,
TermuxConstants.TERMUX_PROPERTIES_FILE_PATHS_LIST, TermuxPropertyConstants.TERMUX_APP_PROPERTIES_LIST,
new TermuxSharedProperties.SharedPropertiesParserClient());
}

View File

@ -478,58 +478,4 @@ public final class TermuxPropertyConstants {
public static final Set<String> TERMUX_DEFAULT_INVERETED_TRUE_BOOLEAN_BEHAVIOUR_PROPERTIES_LIST = new HashSet<>(Arrays.asList(
));
/** Returns the first {@link File} found in
* {@link TermuxConstants#TERMUX_PROPERTIES_FILE_PATHS_LIST} via a call to
* {@link #getPropertiesFile(List)}.
*
* @return Returns the {@link File} object for Termux app properties.
*/
public static File getTermuxPropertiesFile() {
return getPropertiesFile(TermuxConstants.TERMUX_PROPERTIES_FILE_PATHS_LIST);
}
/** Returns the first {@link File} found in
* {@link TermuxConstants#TERMUX_FLOAT_PROPERTIES_FILE_PATHS_LIST} via a call to
* {@link #getPropertiesFile(List)}.
*
* @return Returns the {@link File} object for Termux:Float app properties.
*/
public static File getTermuxFloatPropertiesFile() {
return getPropertiesFile(TermuxConstants.TERMUX_FLOAT_PROPERTIES_FILE_PATHS_LIST);
}
/** Returns the first {@link File} found in
* {@code propertiesFilePaths} from which app properties can be loaded. If the {@link File} found
* is not a regular file or is not readable, then {@code null} is returned. Symlinks **will not**
* be followed for potential security reasons.
*
* @return Returns the {@link File} object for Termux:Float app properties.
*/
public static File getPropertiesFile(List<String> propertiesFilePaths) {
if (propertiesFilePaths == null || propertiesFilePaths.size() == 0)
return null;
for(String propertiesFilePath : propertiesFilePaths) {
File propertiesFile = new File(propertiesFilePath);
// Symlinks **will not** be followed.
FileType fileType = FileUtils.getFileType(propertiesFilePath, false);
if (fileType == FileType.REGULAR) {
if (propertiesFile.canRead())
return propertiesFile;
else
Logger.logWarn(LOG_TAG, "Ignoring properties file at \"" + propertiesFilePath + "\" since it is not readable");
} else if (fileType != FileType.NO_EXIST) {
Logger.logWarn(LOG_TAG, "Ignoring properties file at \"" + propertiesFilePath + "\" of type: \"" + fileType.getName() + "\"");
}
}
Logger.logDebug(LOG_TAG, "No readable properties file found at: " + propertiesFilePaths);
return null;
}
}

View File

@ -12,6 +12,7 @@ import com.termux.shared.termux.TermuxConstants;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@ -20,24 +21,35 @@ public abstract class TermuxSharedProperties {
protected final Context mContext;
protected final String mLabel;
protected final File mPropertiesFile;
protected final SharedProperties mSharedProperties;
protected final List<String> mPropertiesFilePaths;
protected final Set<String> mPropertiesList;
protected final SharedPropertiesParser mSharedPropertiesParser;
protected File mPropertiesFile;
protected SharedProperties mSharedProperties;
public static final String LOG_TAG = "TermuxSharedProperties";
public TermuxSharedProperties(@NonNull Context context, @NonNull String label, File propertiesFile,
public TermuxSharedProperties(@NonNull Context context, @NonNull String label, List<String> propertiesFilePaths,
@NonNull Set<String> propertiesList, @NonNull SharedPropertiesParser sharedPropertiesParser) {
mContext = context.getApplicationContext();
mLabel = label;
mPropertiesFile = propertiesFile;
mSharedProperties = new SharedProperties(context, mPropertiesFile, propertiesList, sharedPropertiesParser);
mPropertiesFilePaths = propertiesFilePaths;
mPropertiesList = propertiesList;
mSharedPropertiesParser = sharedPropertiesParser;
loadTermuxPropertiesFromDisk();
}
/**
* Reload the termux properties from disk into an in-memory cache.
*/
public void loadTermuxPropertiesFromDisk() {
public synchronized void loadTermuxPropertiesFromDisk() {
// Properties files must be searched everytime since no file may exist when constructor is
// called or a higher priority file may have been created afterward. Otherwise, if no file
// was found, then default props would keep loading, since mSharedProperties would be null. #2836
mPropertiesFile = SharedProperties.getPropertiesFileFromList(mPropertiesFilePaths, LOG_TAG);
mSharedProperties = null;
mSharedProperties = new SharedProperties(mContext, mPropertiesFile, mPropertiesList, mSharedPropertiesParser);
mSharedProperties.loadPropertiesFromDisk();
dumpPropertiesToLog();
dumpInternalPropertiesToLog();
@ -167,8 +179,8 @@ public abstract class TermuxSharedProperties {
/**
* Get the internal {@link Object} value for the key passed from the file returned by
* {@link TermuxPropertyConstants#getTermuxPropertiesFile()}. The {@link Properties} object is
* Get the internal {@link Object} value for the key passed from the first file found in
* {@link TermuxConstants#TERMUX_PROPERTIES_FILE_PATHS_LIST}. The {@link Properties} object is
* read directly from the file and internal value is returned for the property value against the key.
*
* @param context The context for operations.
@ -177,7 +189,9 @@ public abstract class TermuxSharedProperties {
* the object stored against the key is {@code null}.
*/
public static Object getTermuxInternalPropertyValue(Context context, String key) {
return SharedProperties.getInternalProperty(context, TermuxPropertyConstants.getTermuxPropertiesFile(), key, new SharedPropertiesParserClient());
return SharedProperties.getInternalProperty(context,
SharedProperties.getPropertiesFileFromList(TermuxConstants.TERMUX_PROPERTIES_FILE_PATHS_LIST, LOG_TAG),
key, new SharedPropertiesParserClient());
}
/**