Added: Write termux shell environment to /data/data/com.termux/files/usr/etc/termux/termux.env on app startup and package changes

The `termux.env` can be sourced by shells to set termux environment normally exported. This can be useful for users starting termux shells with `adb` `run-as` or `root`. The file will not contain `SHELL_CMD__` variables since those are shell command specific.

The items in the `termux.env` file have the format `export name="value"`.
The `"`\$` characters will be escaped with `a backslash `\`, like `\"` if characters are for literal value. Note that if `$` is escaped and if its part of variable, then variable expansion will not happen if `.env` file is sourced. The `\` at the end of a value line means line continuation. Value can contain newline characters.

The `termux.env` file should be sourceable by `POSIX` compliant shells like `bash`, `zsh`, `sh`, android's `mksh`, etc. Other shells with require manual parsing of the file to export variables.

Related discussion #2565
This commit is contained in:
agnostic-apollo
2022-06-12 00:51:19 +05:00
parent f76c20d036
commit 03e1d14e1e
8 changed files with 196 additions and 5 deletions

View File

@@ -42,6 +42,60 @@ public class ShellEnvironmentUtils {
return environmentList;
}
/**
* Convert environment {@link HashMap} to {@link String} where each item equals "key=value".
*
*/
@NonNull
public static String convertEnvironmentToDotEnvFile(@NonNull HashMap<String, String> environmentMap) {
return convertEnvironmentToDotEnvFile(convertEnvironmentMapToEnvironmentVariableList(environmentMap));
}
/**
* Convert environment {@link HashMap} to `.env` file {@link String}.
*
* The items in the `.env` file have the format `export name="value"`.
*
* If the {@link ShellEnvironmentVariable#escaped} is set to {@code true}, then
* {@link ShellEnvironmentVariable#value} will be considered to be a literal value that has
* already been escaped by the caller, otherwise all the `"`\$` in the value will be escaped
* with `a backslash `\`, like `\"`. Note that if `$` is escaped and if its part of variable,
* then variable expansion will not happen if `.env` file is sourced.
*
* The `\` at the end of a value line means line continuation. Value can contain newline characters.
*
* Check {@link #isValidEnvironmentVariableName(String)} and {@link #isValidEnvironmentVariableValue(String)}
* for valid variable names and values.
*
* https://github.com/ko1nksm/shdotenv#env-file-syntax
* https://github.com/ko1nksm/shdotenv/blob/main/docs/specification.md
*/
@NonNull
public static String convertEnvironmentToDotEnvFile(@NonNull List<ShellEnvironmentVariable> environmentList) {
StringBuilder environment = new StringBuilder();
Collections.sort(environmentList);
for (ShellEnvironmentVariable variable : environmentList) {
if (isValidEnvironmentVariableNameValuePair(variable.name, variable.value, true) && variable.value != null) {
environment.append("export ").append(variable.name).append("=\"")
.append(variable.escaped ? variable.value : variable.value.replaceAll("([\"`\\\\$])", "\\\\$1"))
.append("\"\n");
}
}
return environment.toString();
}
/**
* Convert environment {@link HashMap} to {@link List< ShellEnvironmentVariable >}. Each item
* will have its {@link ShellEnvironmentVariable#escaped} set to {@code false}.
*/
@NonNull
public static List<ShellEnvironmentVariable> convertEnvironmentMapToEnvironmentVariableList(@NonNull HashMap<String, String> environmentMap) {
List<ShellEnvironmentVariable> environmentList = new ArrayList<>();
for (String name :environmentMap.keySet()) {
environmentList.add(new ShellEnvironmentVariable(name, environmentMap.get(name), false));
}
return environmentList;
}
/**
* Check if environment variable name and value pair is valid. Errors will be logged if

View File

@@ -0,0 +1,28 @@
package com.termux.shared.shell.command.environment;
public class ShellEnvironmentVariable implements Comparable<ShellEnvironmentVariable> {
/** The name for environment variable */
public String name;
/** The value for environment variable */
public String value;
/** If environment variable {@link #value} is already escaped. */
public boolean escaped;
public ShellEnvironmentVariable(String name, String value) {
this(name, value, false);
}
public ShellEnvironmentVariable(String name, String value, boolean escaped) {
this.name = name;
this.value = value;
this.escaped = escaped;
}
@Override
public int compareTo(ShellEnvironmentVariable other) {
return this.name.compareTo(other.name);
}
}