Skip to content

Commit a3781a7

Browse files
fix: don't deadlock on setup
Signed-off-by: Oskar Manhart <[email protected]>
1 parent bc49e92 commit a3781a7

File tree

9 files changed

+73
-85
lines changed

9 files changed

+73
-85
lines changed

winapps-cli/src/main.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,27 @@ fn main() -> Result<()> {
3434
.init();
3535

3636
let config_lock = Config::try_get_lock()?;
37-
let config = config_lock.read();
38-
39-
let client = Freerdp::new();
40-
let backend = config.get_backend();
41-
42-
client.check_depends()?;
43-
backend.check_depends()?;
37+
config_lock.read().get_backend().check_depends()?;
4438

4539
let cli = cli();
4640

4741
match cli.clone().get_matches().subcommand() {
4842
Some(("setup", _)) => {
4943
info!("Running setup");
5044

51-
match inquire::MultiSelect::new("Select apps to link", config.get_available_apps()?)
45+
let apps = config_lock.read().get_available_apps()?;
46+
47+
// TODO: Allow deleting apps, maybe pass installed apps
48+
// so they can be deselected?
49+
match inquire::MultiSelect::new("Select apps to link", apps)
5250
.prompt_skippable()
5351
.map_err(|e| winapps::Error::Command {
5452
message: "Failed to display selection dialog".into(),
5553
source: e.into(),
5654
})? {
5755
Some(apps) => apps
5856
.into_iter()
59-
.try_for_each(|app| app.link(&mut config_lock.write(), "".into()))?,
57+
.try_for_each(|app| app.link(&mut config_lock.write()))?,
6058
None => info!("No apps selected, skipping setup..."),
6159
};
6260

@@ -66,18 +64,25 @@ fn main() -> Result<()> {
6664
Some(("connect", _)) => {
6765
info!("Connecting to remote");
6866

67+
let client = Freerdp::new();
68+
69+
client.check_depends()?;
6970
client.run_full_session()?;
7071
Ok(())
7172
}
7273

7374
Some(("run", sub_matches)) => {
7475
info!("Connecting to app on remote");
7576

77+
let client = Freerdp::new();
78+
79+
client.check_depends()?;
80+
7681
let args = sub_matches
77-
.get_many::<String>("args")
82+
.get_many::<String>("ARGS")
7883
.map_or(Vec::new(), |args| args.map(|v| v.to_owned()).collect());
7984

80-
match sub_matches.get_one::<String>("name") {
85+
match sub_matches.get_one::<String>("NAME") {
8186
None => panic!("App is required and should never be None here"),
8287
Some(app) => client.run_app(app.to_owned(), args),
8388
}?;

winapps-image/oem/install.ps1

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ function Install-NetworkProfileCleanup
5050
}
5151
}
5252

53-
Set-ExecutionPolicy Unrestricted
54-
5553
# Run functions
5654
Copy-Item -Path "$PSScriptRoot\ExtractPrograms.ps1" -Destination "$env:windir" -Force
5755

winapps/src/backend/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use enum_dispatch::enum_dispatch;
55
use crate::{
66
backend::{container::Container, manual::Manual},
77
command::Command,
8-
config::{App, AppKind::Detected},
8+
config::{App, AppKind},
99
Config, Result,
1010
};
1111

@@ -59,7 +59,7 @@ impl Config {
5959
id: id.to_string(),
6060
name: name.to_string(),
6161
win_exec: path.to_string(),
62-
kind: Detected(icon.to_string()),
62+
kind: AppKind::FromBase64(icon.to_string()),
6363
}),
6464
_ => None,
6565
}

winapps/src/command.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ impl Command {
7373
config.auth.username,
7474
config.get_backend().get_host()
7575
),
76+
"-oStrictHostKeyChecking=accept-new",
7677
"-p",
7778
&*config.auth.ssh_port.to_string(),
7879
])

winapps/src/config/apps.rs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ use crate::{
44
Config, Result,
55
};
66
use base64::{prelude::BASE64_STANDARD, Engine};
7-
use std::{fmt::Display, fs::write};
7+
use std::{
8+
fmt::Display,
9+
fs::{set_permissions, write, Permissions},
10+
os::unix::fs::PermissionsExt,
11+
};
12+
use tracing::debug;
813

914
impl PartialEq for App {
1015
fn eq(&self, other: &Self) -> bool {
@@ -21,51 +26,57 @@ impl Display for App {
2126
impl App {
2227
fn try_as_existing(&mut self) -> Result<&mut Self> {
2328
match self.kind.clone() {
24-
AppKind::Detected(base64) => {
29+
AppKind::FromBase64(base64) => {
2530
let path = icons_dir()?.join(format!("{}.png", self.id));
2631
write(path.clone(), BASE64_STANDARD.decode(base64)?)?;
2732

28-
self.kind = AppKind::Existing(path);
33+
self.kind = AppKind::Existing;
2934

3035
Ok(self)
3136
}
32-
AppKind::Existing(_) => Ok(self),
37+
AppKind::Existing => Ok(self),
3338
}
3439
}
3540

36-
fn try_as_desktop_file(&mut self, exec: String) -> Result<String> {
41+
fn try_as_desktop_file(&mut self) -> Result<String> {
42+
debug!("Writing desktop icon for {}", self.id);
43+
3744
match &self.kind {
38-
AppKind::Detected(_) => self.try_as_existing()?.try_as_desktop_file(exec),
39-
AppKind::Existing(path) => Ok(format!(
45+
AppKind::FromBase64(_) => self.try_as_existing()?.try_as_desktop_file(),
46+
AppKind::Existing => Ok(format!(
4047
"[Desktop Entry]
4148
Name={}
42-
Exec={exec}
49+
Exec=winapps run {}
4350
Terminal=false
4451
Type=Application
4552
Icon={}
4653
StartupWMClass={}
47-
Comment={}",
54+
Comment={} (WinApps)",
4855
self.name,
49-
path.to_string_lossy(),
56+
self.id,
57+
icons_dir()?
58+
.join(format!("{}.png", self.id))
59+
.to_string_lossy(),
5060
self.id,
5161
self.name
5262
)),
5363
}
5464
}
5565

56-
pub fn link(mut self, config: &mut Config, exec: String) -> Result<()> {
66+
pub fn link(mut self, config: &mut Config) -> Result<()> {
5767
self.try_as_existing()?;
5868

59-
write(
60-
desktop_dir()?.join(format!("{}.desktop", self.id)),
61-
self.try_as_desktop_file(exec)?,
62-
)?;
69+
let path = desktop_dir()?.join(format!("{}.desktop", self.id));
70+
71+
write(&path, self.try_as_desktop_file()?)?;
72+
set_permissions(&path, Permissions::from_mode(0o750))?;
6373

6474
if !config.linked_apps.contains(&self) {
65-
config.linked_apps.push(self)
66-
}
75+
debug!("Writing app {} to config", self.id);
6776

68-
config.save()?;
77+
config.linked_apps.push(self);
78+
config.save()?;
79+
}
6980

7081
Ok(())
7182
}

winapps/src/config/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::Backends;
22
use derive_new::new;
33
use serde::{Deserialize, Serialize};
4-
use std::{path::PathBuf, sync::OnceLock};
4+
use std::sync::OnceLock;
55

66
mod apps;
77
mod operations;
@@ -79,16 +79,18 @@ pub struct FreerdpConfig {
7979
pub executable: String,
8080
}
8181

82-
#[derive(Debug, Deserialize, Serialize, Clone)]
82+
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
8383
pub enum AppKind {
84-
Detected(String),
85-
Existing(PathBuf),
84+
FromBase64(String),
85+
#[default]
86+
Existing,
8687
}
8788

8889
#[derive(Debug, Deserialize, Serialize, Clone)]
8990
pub struct App {
9091
pub id: String,
9192
pub name: String,
9293
pub win_exec: String,
94+
#[serde(skip)]
9395
pub kind: AppKind,
9496
}

winapps/src/config/operations.rs

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
use parking_lot::RwLock;
22
use std::{
3-
fs::{self, File},
4-
io::Write,
3+
fs::{self, write},
54
net::IpAddr,
6-
path::PathBuf,
75
str::FromStr,
86
sync::OnceLock,
97
};
108
use tracing::warn;
119

12-
use crate::{bail, dirs::path_ok, Config, Error, IntoResult, Result};
10+
use crate::{bail, dirs::config_dir, Config, Error, IntoResult, Result};
1311

1412
static CONFIG: OnceLock<RwLock<Config>> = OnceLock::new();
1513

@@ -28,7 +26,7 @@ impl Config {
2826
/// Reads the config from disk.
2927
fn try_new() -> Result<Self> {
3028
let config = Self::new();
31-
let config_path = Self::get_path()?;
29+
let config_path = config_dir()?.join("config.toml");
3230

3331
let Ok(true) = config_path.try_exists() else {
3432
warn!("Config does not exist, writing default...");
@@ -53,48 +51,11 @@ impl Config {
5351
Ok(config)
5452
}
5553

56-
fn get_path() -> Result<PathBuf> {
57-
let path = match dirs::config_dir() {
58-
Some(path) => Ok(path),
59-
None => "Could not find $XDG_CONFIG_HOME and no config path specified".into_result(),
60-
}
61-
.map(|path| path.join("winapps").join("config.toml"))?;
62-
63-
// SAFETY: We just set the parent, so there will always be one
64-
let parent = path.parent().unwrap();
65-
path_ok(parent)?;
66-
67-
Ok(path)
68-
}
69-
7054
pub fn save(&self) -> Result<()> {
71-
let config_path = Self::get_path()?;
72-
let serialized_config = toml::to_string_pretty(&self).into_result()?;
73-
74-
let mut config_file = match config_path.try_exists() {
75-
Ok(true) => File::open(&config_path).into_result(),
76-
Ok(false) => File::create(&config_path).into_result(),
77-
Err(e) => Error::Io(e).into(),
78-
}?;
79-
80-
if let Err(e) = write!(config_file, "{serialized_config}") {
81-
bail!(e);
82-
}
83-
84-
Ok(())
85-
}
86-
87-
pub fn get_data_path() -> Result<PathBuf> {
88-
let path = match dirs::data_dir() {
89-
Some(path) => Ok(path),
90-
None => "Could not find $XDG_DATA_HOME and no data path specified".into_result(),
91-
}
92-
.map(|path| path.join("winapps"))?;
93-
94-
// SAFETY: We just set the parent, so there will always be one
95-
let parent = path.parent().unwrap();
96-
path_ok(parent)?;
97-
98-
Ok(path)
55+
write(
56+
config_dir()?.join("config.toml"),
57+
toml::to_string_pretty(&self).into_result()?,
58+
)
59+
.into_result()
9960
}
10061
}

winapps/src/dirs.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ pub fn data_dir() -> Result<PathBuf> {
3030
Ok(data_dir)
3131
}
3232

33+
/// Get the data dir and validates it exists
34+
pub fn config_dir() -> Result<PathBuf> {
35+
let Some(config_dir) = dirs::config_dir().map(|path| path.join("winapps")) else {
36+
bail!("Could not determine $XDG_CONFIG_HOME")
37+
};
38+
39+
path_ok(config_dir.as_path())?;
40+
Ok(config_dir)
41+
}
42+
3343
/// Get the icons dir and validates it exists
3444
pub fn icons_dir() -> Result<PathBuf> {
3545
let Some(data_dir) = dirs::data_dir().map(|path| path.join("icons")) else {

winapps/src/remote_client/freerdp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl RemoteClient for Freerdp {
7979
};
8080

8181
self.get_command()
82-
.arg(format!("/app:program:{path}"))
82+
.arg(format!("/app:program:{path},hidef:on"))
8383
.args(args.iter().map(|arg| {
8484
if arg.contains("/") && home_regex.is_match(arg) {
8585
home_regex

0 commit comments

Comments
 (0)