Skip to content
Merged

Next #23

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ anyhow = "1.0.92"
regex = "1.11.1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.140"

[dependencies.adw]
package = "libadwaita"
Expand Down
8 changes: 8 additions & 0 deletions data/com.ranfdev.DistroShelf.metainfo.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@
</screenshots>

<releases>
<release version="1.0.7" date="2025-05-23">
<description translate="no">
<ul>
<li>Added support for custom terminal commands</li>
<li>Refactored code to improve support of flatpak and non-flatpak versions</li>
</ul>
</description>
</release>
<release version="1.0.6" date="2025-05-12">
<description translate="no">
<ul>
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project('distroshelf', 'rust',
version: '1.0.6',
version: '1.0.7',
meson_version: '>= 1.0.0',
default_options: [ 'warning_level=2', 'werror=false', ],
)
Expand Down
64 changes: 39 additions & 25 deletions src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/

use std::path::Path;
use std::rc::Rc;

use adw::prelude::*;
use adw::subclass::prelude::*;
use gettextrs::gettext;
use gtk::{gio, glib};

use crate::config::VERSION;
use crate::distrobox::{Distrobox, DistroboxCommandRunnerResponse};
use crate::distrobox::{
CommandRunner, Distrobox, DistroboxCommandRunnerResponse, FlatpakCommandRunner,
RealCommandRunner,
};
use crate::root_store::RootStore;
use crate::DistroShelfWindow;

Expand Down Expand Up @@ -191,33 +197,41 @@ impl DistroShelfApplication {
.build()
}

fn get_is_in_flatpak() -> bool {
let fp_env = std::env::var("FLATPAK_ID").is_ok();
if fp_env {
return true;
}

Path::new("/.flatpak-info").exists()
}

fn recreate_window(&self) -> adw::ApplicationWindow {
let distrobox = match { self.imp().distrobox_store_ty.borrow().to_owned() } {
DistroboxStoreTy::NullWorking => Distrobox::new_null_with_responses(
&[
DistroboxCommandRunnerResponse::Version,
DistroboxCommandRunnerResponse::new_list_common_distros(),
DistroboxCommandRunnerResponse::new_common_images(),
DistroboxCommandRunnerResponse::new_common_exported_apps(),
],
false,
),
DistroboxStoreTy::NullEmpty => Distrobox::new_null_with_responses(
&[
DistroboxCommandRunnerResponse::Version,
DistroboxCommandRunnerResponse::List(vec![]),
DistroboxCommandRunnerResponse::new_common_images(),
],
false,
),
DistroboxStoreTy::NullNoVersion => Distrobox::new_null_with_responses(
&[DistroboxCommandRunnerResponse::NoVersion],
false,
),
_ => Distrobox::new(),
let command_runner = match { self.imp().distrobox_store_ty.borrow().to_owned() } {
DistroboxStoreTy::NullWorking => Distrobox::null_command_runner(&[
DistroboxCommandRunnerResponse::Version,
DistroboxCommandRunnerResponse::new_list_common_distros(),
DistroboxCommandRunnerResponse::new_common_images(),
DistroboxCommandRunnerResponse::new_common_exported_apps(),
]),
DistroboxStoreTy::NullEmpty => Distrobox::null_command_runner(&[
DistroboxCommandRunnerResponse::Version,
DistroboxCommandRunnerResponse::List(vec![]),
DistroboxCommandRunnerResponse::new_common_images(),
]),
DistroboxStoreTy::NullNoVersion => {
Distrobox::null_command_runner(&[DistroboxCommandRunnerResponse::NoVersion])
}
_ => {
if Self::get_is_in_flatpak() {
Rc::new(FlatpakCommandRunner::new(Rc::new(RealCommandRunner {}))) as Rc<dyn CommandRunner>
} else {
Rc::new(RealCommandRunner {}) as Rc<dyn CommandRunner>
}
}
};

self.set_root_store(RootStore::new(distrobox));
self.set_root_store(RootStore::new(command_runner));
let window =
DistroShelfWindow::new(self.upcast_ref::<adw::Application>(), self.root_store());
window.upcast()
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub static VERSION: &str = "1.0.6";
pub static VERSION: &str = "1.0.7";
pub static GETTEXT_PACKAGE: &str = "distroshelf";
pub static LOCALEDIR: &str = "/app/share/locale";
pub static PKGDATADIR: &str = "/app/share/distroshelf";
25 changes: 25 additions & 0 deletions src/distrobox/command_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use futures::{
FutureExt,
};

use super::wrap_flatpak_cmd;

pub trait CommandRunner {
fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>>;
fn output(
Expand All @@ -43,6 +45,29 @@ impl CommandRunner for RealCommandRunner {
}
}

#[derive(Clone)]
pub struct FlatpakCommandRunner {
pub command_runner: Rc<dyn CommandRunner>,
}
impl FlatpakCommandRunner {
pub fn new(command_runner: Rc<dyn CommandRunner>) -> Self {
FlatpakCommandRunner { command_runner }
}
}

impl CommandRunner for FlatpakCommandRunner {
fn spawn(&self, command: Command) -> io::Result<Box<dyn Child + Send>> {
self.command_runner.spawn(wrap_flatpak_cmd(command))
}
fn output(
&self,
command: Command,
) -> Pin<Box<dyn Future<Output = io::Result<std::process::Output>>>> {
self.command_runner.output(wrap_flatpak_cmd(command))
}
}


#[derive(Default, Clone)]
pub struct NullCommandRunnerBuilder {
responses: HashMap<Vec<String>, Rc<dyn Fn() -> Result<String, io::Error>>>,
Expand Down
59 changes: 15 additions & 44 deletions src/distrobox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,13 @@ impl<T: Clone + std::fmt::Debug> OutputTracker<T> {
}

pub struct Distrobox {
cmd_runner: Box<dyn CommandRunner>,
cmd_runner: Rc<dyn CommandRunner>,
output_tracker: OutputTracker<String>,
is_in_flatpak: bool,
}

impl std::fmt::Debug for Distrobox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Distrobox")
.field("is_in_flatpak", &self.is_in_flatpak)
.field("output_tracker", &self.output_tracker)
.finish()
}
Expand Down Expand Up @@ -412,25 +410,22 @@ impl DistroboxCommandRunnerResponse {
}

impl Distrobox {
pub fn new() -> Self {
pub fn new(cmd_runner:Rc<dyn CommandRunner + 'static> ) -> Self {
Self {
cmd_runner: Box::new(RealCommandRunner {}),
is_in_flatpak: Self::get_is_in_flatpak(),
cmd_runner,
output_tracker: Default::default(),
}
}
pub fn new_null(runner: NullCommandRunner, is_in_flatpak: bool) -> Self {
pub fn new_null(runner: NullCommandRunner) -> Self {
Self {
cmd_runner: Box::new(runner),
cmd_runner: Rc::new(runner),
output_tracker: OutputTracker::default(),
is_in_flatpak,
}
}

pub fn new_null_with_responses(
pub fn null_command_runner(
responses: &[DistroboxCommandRunnerResponse],
is_in_flatpak: bool,
) -> Self {
) -> Rc<dyn CommandRunner> {
let cmd_runner = {
let mut builder = NullCommandRunnerBuilder::new();
for res in responses {
Expand All @@ -440,33 +435,17 @@ impl Distrobox {
}
builder.build()
};
Self {
cmd_runner: Box::new(cmd_runner),
output_tracker: OutputTracker::default(),
is_in_flatpak,
}
Rc::new(cmd_runner) as Rc<dyn CommandRunner>
}

pub fn output_tracker(&self) -> OutputTracker<String> {
self.output_tracker.enable();
self.output_tracker.clone()
}

fn get_is_in_flatpak() -> bool {
let fp_env = std::env::var("FLATPAK_ID").is_ok();
if fp_env {
return true;
}

Path::new("/.flatpak-info").exists()
}


pub fn cmd_spawn(&self, cmd: Command) -> Result<Box<dyn Child + Send>, Error> {
let mut cmd = if self.is_in_flatpak {
wrap_flatpak_cmd(cmd)
} else {
cmd
};
pub fn cmd_spawn(&self, mut cmd: Command) -> Result<Box<dyn Child + Send>, Error> {
wrap_capture_cmd(&mut cmd);

let program = cmd.program.to_string_lossy().to_string();
Expand All @@ -491,12 +470,7 @@ impl Distrobox {
Ok(child)
}

async fn cmd_output(&self, cmd: Command) -> Result<Output, Error> {
let mut cmd = if self.is_in_flatpak {
wrap_flatpak_cmd(cmd)
} else {
cmd
};
async fn cmd_output(&self, mut cmd: Command) -> Result<Output, Error> {
wrap_capture_cmd(&mut cmd);

let program = cmd.program.to_string_lossy().to_string();
Expand Down Expand Up @@ -838,7 +812,7 @@ impl Distrobox {

impl Default for Distrobox {
fn default() -> Self {
Self::new()
Self::new(Rc::new(NullCommandRunner::default()))
}
}

Expand All @@ -856,7 +830,6 @@ d24405b14180 | ubuntu | Created | ghcr.io/ublue-os/ubun
NullCommandRunnerBuilder::new()
.cmd(&["distrobox", "ls", "--no-color"], output)
.build(),
false,
);
assert_eq!(
db.list().await?,
Expand All @@ -879,7 +852,6 @@ d24405b14180 | ubuntu | Created | ghcr.io/ublue-os/ubun
NullCommandRunnerBuilder::new()
.cmd(&["distrobox", "version"], output)
.build(),
false,
);
assert_eq!(db.version().await?, "1.7.2.1".to_string(),);
Ok(())
Expand Down Expand Up @@ -935,7 +907,6 @@ Comment=A brief description of my application
Categories=Utility;Network;
",)
.build(),
false
);

let apps = block_on(db.list_apps("ubuntu"))?;
Expand All @@ -950,7 +921,7 @@ Categories=Utility;Network;
#[test]
fn create() -> Result<(), Error> {
let _ = tracing_subscriber::fmt().with_test_writer().try_init();
let db = Distrobox::new_null(NullCommandRunner::default(), false);
let db = Distrobox::new_null(NullCommandRunner::default());
let output_tracker = db.output_tracker();
debug!("Testing container creation");
let args = CreateArgs {
Expand All @@ -969,7 +940,7 @@ Categories=Utility;Network;
}
#[test]
fn assemble() -> Result<(), Error> {
let db = Distrobox::new_null(NullCommandRunner::default(), false);
let db = Distrobox::new_null(NullCommandRunner::default());
let output_tracker = db.output_tracker();
db.assemble("/path/to/assemble.yml")?;
assert_eq!(
Expand All @@ -981,7 +952,7 @@ Categories=Utility;Network;

#[test]
fn remove() -> Result<(), Error> {
let db = Distrobox::new_null(NullCommandRunner::default(), false);
let db = Distrobox::new_null(NullCommandRunner::default());
let output_tracker = db.output_tracker();
block_on(db.remove("ubuntu"))?;
assert_eq!(
Expand Down
Loading
Loading