Skip to content

Commit e42de5e

Browse files
committed
feat: include applications found in the user's .local if the HOME in the distrobox differs
1 parent b41ffbf commit e42de5e

File tree

3 files changed

+197
-29
lines changed

3 files changed

+197
-29
lines changed

Cargo.lock

Lines changed: 79 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ async-process = "2.3.0"
1212
futures = "0.3.31"
1313
anyhow = "1.0.92"
1414
regex = "1.11.1"
15+
toml = "0.9.8"
1516
tracing = "0.1"
1617
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
1718
serde = { version = "1.0", features = ["derive"] }

src/distrobox/mod.rs

Lines changed: 117 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
use crate::fakers::{
22
Child, Command, CommandRunner, FdMode, InnerCommandRunner, NullCommandRunnerBuilder,
33
};
4+
use serde::{Deserialize, Deserializer};
45
use std::{
56
cell::LazyCell,
67
collections::BTreeMap,
8+
env,
9+
ffi::OsString,
710
future::Future,
811
io,
12+
os::unix::ffi::OsStringExt,
913
path::{Path, PathBuf},
1014
pin::Pin,
1115
process::Output,
@@ -18,7 +22,110 @@ mod desktop_file;
1822

1923
pub use desktop_file::*;
2024

21-
const POSIX_FIND_AND_CONCAT_DESKTOP_FILES: &str = "grep -L '^[[:space:]]*NoDisplay[[:space:]]*=[[:space:]]*true[[:space:]]*$' /usr/share/applications/*.desktop 2>/dev/null | while IFS= read -r file; do printf '# START FILE %s\n' \"$file\"; cat \"$file\"; done";
25+
const POSIX_FIND_AND_CONCAT_DESKTOP_FILES: &str = r#"
26+
set -o pipefail >/dev/null 2>&1 # TODO: Join with the following (without piping), as it is part of POSIX 2022, but Debian 13 Trixie and Ubuntu 24.10 Oracular Oriole are the first releases with a `dash` version (>=0.5.12-7) supporting this flag. See also https://github.com/koalaman/shellcheck/issues/2555 and https://metadata.ftp-master.debian.org/changelogs/main/d/dash/stable_changelog
27+
set -eu
28+
29+
base16FunctionDefinition="$(cat <<'EOF'
30+
base16() {
31+
if [ "$#" -eq 0 ]; then
32+
cat
33+
else
34+
printf '%s' "$1"
35+
fi | od -vt x1 -A n | tr -d '[[:space:]]'
36+
}
37+
EOF
38+
)"
39+
40+
eval "$base16FunctionDefinition"
41+
42+
dumpDesktopFiles() {
43+
if ! [ -d "$1" ]; then
44+
return
45+
fi
46+
47+
find "$1" -name '*.desktop' -not -exec grep -q '^[[:space:]]*NoDisplay[[:space:]]*=[[:space:]]*true[[:space:]]*$' '{}' \; -exec sh -c "$(set +o);$base16FunctionDefinition;"'printf '\''"%s"="%s"\n'\'' "$(base16 "$1")" "$(base16 <"$1")"' - '{}' \;
48+
}
49+
50+
printf 'home_dir="%s"\n' "$(base16 "$HOME")"
51+
52+
printf '[system]\n'
53+
dumpDesktopFiles /usr/share/applications
54+
55+
printf '[user]\n'
56+
dumpDesktopFiles "$HOME/.local/share/applications"
57+
"#;
58+
59+
#[derive(Deserialize, Debug)]
60+
struct DesktopFiles {
61+
#[serde(deserialize_with = "DesktopFiles::deserialize_path")]
62+
home_dir: PathBuf,
63+
#[serde(deserialize_with = "DesktopFiles::deserialize_desktop_files")]
64+
system: BTreeMap<PathBuf, String>,
65+
#[serde(deserialize_with = "DesktopFiles::deserialize_desktop_files")]
66+
user: BTreeMap<PathBuf, String>,
67+
}
68+
69+
impl DesktopFiles {
70+
fn decode_hex<E: serde::de::Error>(hex_str: &str) -> Result<Vec<u8>, E> {
71+
if hex_str.len() % 2 != 0 {
72+
return Err(E::invalid_length(
73+
hex_str.len(),
74+
&"hex string to have an even lenght",
75+
));
76+
}
77+
78+
(0..hex_str.len())
79+
.step_by(2)
80+
.map(|i| u8::from_str_radix(&hex_str[i..=i + 1], 16))
81+
.collect::<Result<_, _>>()
82+
.map_err(|e| {
83+
E::custom(format_args!(
84+
"hex string contains non hex characters: {e:?}"
85+
))
86+
})
87+
}
88+
89+
fn decode_utf8_from_hex<E: serde::de::Error>(hex_str: &str) -> Result<String, E> {
90+
String::from_utf8(Self::decode_hex(hex_str)?).map_err(|e| {
91+
E::custom(format_args!(
92+
"decoded hex string does not represent valid UTF-8: {e:?}"
93+
))
94+
})
95+
}
96+
97+
fn decode_path_from_hex<E: serde::de::Error>(hex_str: &str) -> Result<PathBuf, E> {
98+
Ok(PathBuf::from(OsString::from_vec(Self::decode_hex(
99+
hex_str,
100+
)?)))
101+
}
102+
103+
fn deserialize_path<'de, D: Deserializer<'de>>(deserializer: D) -> Result<PathBuf, D::Error> {
104+
Self::decode_path_from_hex(&String::deserialize(deserializer)?)
105+
}
106+
107+
fn deserialize_desktop_files<'de, D: Deserializer<'de>>(
108+
deserializer: D,
109+
) -> Result<BTreeMap<PathBuf, String>, D::Error> {
110+
BTreeMap::<String, String>::deserialize(deserializer)?
111+
.into_iter()
112+
.map(|(path, content)| {
113+
Ok((
114+
Self::decode_path_from_hex(&path)?,
115+
Self::decode_utf8_from_hex(&content)?,
116+
))
117+
})
118+
.collect()
119+
}
120+
121+
fn into_map(self) -> BTreeMap<PathBuf, String> {
122+
let mut desktop_files = self.system;
123+
if env::home_dir() != Some(self.home_dir) {
124+
desktop_files.extend(self.user)
125+
}
126+
desktop_files
127+
}
128+
}
22129

23130
#[derive(Clone)]
24131
pub struct FlatpakCommandRunner {
@@ -624,20 +731,15 @@ impl Distrobox {
624731
"-c",
625732
POSIX_FIND_AND_CONCAT_DESKTOP_FILES,
626733
]);
627-
let concatenated_files = self.cmd_output_string(cmd).await?;
628-
debug!(concatenated_files = concatenated_files);
629-
let res = concatenated_files
630-
.split("# START FILE ")
631-
.skip(1)
632-
.map(|file_content| {
633-
let file_path = file_content.lines().next().map(|name| name.trim_start());
634-
(
635-
file_path.unwrap_or_default().to_string(),
636-
file_content.to_string(),
637-
)
638-
})
639-
.collect();
640-
Ok(res)
734+
let desktop_files: DesktopFiles = toml::from_str(&self.cmd_output_string(cmd).await?)
735+
.map_err(|e| Error::ParseOutput(format!("{e:?}")))?;
736+
debug!(desktop_files = format_args!("{desktop_files:#?}"));
737+
738+
Ok(desktop_files
739+
.into_map()
740+
.into_iter()
741+
.map(|(path, content)| (path.to_string_lossy().into_owned(), content))
742+
.collect::<Vec<_>>())
641743
}
642744

643745
pub async fn list_apps(&self, box_name: &str) -> Result<Vec<ExportableApp>, Error> {

0 commit comments

Comments
 (0)