8000 feat: add `rattler_menuinst` crate by wolfv · Pull Request #840 · conda/rattler · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
8000

feat: add rattler_menuinst crate #840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 132 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
ff23eed
improve and clean linux implementation
wolfv Nov 11, 2024
100f977
write the rest of the items to linux desktop file
wolfv Nov 11, 2024
30e7842
remove comment
wolfv Nov 11, 2024
b402d1b
re-add missing function
wolfv Nov 11, 2024
3002b56
Improve Linux support
Hofer-Julian Nov 11, 2024
0f09559
Fix clippy warnings
Hofer-Julian Nov 11, 2024
5f081b5
Another clippy warning
Hofer-Julian Nov 11, 2024
26150ea
Run commands with bash
Hofer-Julian Nov 11, 2024
08654d8
continue xml writing for mimetypes
wolfv Nov 11, 2024
2972e17
some clippy
wolfv Nov 11, 2024
e53e561
Run update-desktop-database
Hofer-Julian Nov 11, 2024
02c8b0b
write xml file
wolfv Nov 11, 2024
61326ff
properly implement the `paths` function
wolfv Nov 11, 2024
d6fce2a
implement more macOS
wolfv Nov 11, 2024
f830f2d
register mime types on linux
wolfv Nov 11, 2024
4a8d70d
write out the entire plist file
wolfv Nov 11, 2024
d2e16d2
fix tests
wolfv Nov 11, 2024
7e88b6b
fix some clippy warnings
wolfv Nov 11, 2024
bfdd26d
add pre-create
wolfv Nov 12, 2024
bb18d71
improve linux code some more
wolfv Nov 12, 2024
dcf1011
add directory entry functions
wolfv Nov 12, 2024
9592a89
some improvements
wolfv Nov 24, 2024
9b214c9
work on mr. windows
wolfv Nov 25, 2024
3eb2cc2
continue windows implementation
wolfv Nov 26, 2024
5835828
make compile on unix
wolfv Dec 10, 2024
1239522
pre-process transaction and remove menu items
wolfv Dec 10, 2024
1e9447c
add simple menu test recipe
wolfv Dec 10, 2024
639874c
add example menu
wolfv Dec 10, 2024
6b3f88e
update linux menu xml modifications
wolfv Dec 11, 2024
ead7c27
make the test recipe noarch: generic
wolfv Dec 11, 2024
e2e136f
correct test and add create_shortcut functions
wolfv Dec 11, 2024
22f130a
fmt clippy
wolfv Dec 11, 2024
582b1cd
add tests for registry
wolfv Dec 11, 2024
b18ccc7
fmt
wolfv Dec 11, 2024
0169a41
create a first shortcut on Windows
wolfv Dec 11, 2024
d48686b
improve
wolfv Dec 11, 2024
8de5021
add SingleMainWindow
wolfv Dec 12, 2024
8b298dd
add macos testing of the whole menu installation
wolfv Dec 12, 2024
c446acb
add snapshot test for linux desktop file
wolfv Dec 12, 2024
141b1e8
a little clean up
wolfv Dec 12, 2024
f9e59e0
clean
wolfv Dec 12, 2024
3cd2c19
use correct defaults
wolfv Dec 12, 2024
e73d516
remove $id, add nsautomaticgraphicsswitching, update snapshots
wolfv Dec 13, 2024
390a7b7
clippy
wolfv Dec 13, 2024
c565f54
small improvement
wolfv Dec 13, 2024
b51b59e
..
wolfv Dec 16, 2024
4a708a4
fix things up
wolfv Dec 16, 2024
6004fc7
add handler for mime config
wolfv Dec 16, 2024
a14792e
..
wolfv Dec 16, 2024
cfcb718
some clippy
wolfv Dec 16, 2024
5cd9bb4
more placeholders
wolfv Dec 17, 2024
b7a34bd
[skip ci] ..
wolfv Dec 17, 2024
374807e
run pre-create
wolfv Dec 16, 2024
1271afc
implement more
wolfv Dec 16, 2024
9afee15
wire up more on Windows
wolfv Dec 18, 2024
a458d96
fix location
wolfv Dec 18, 2024
40d2be4
use the mime config things
wolfv Dec 18, 2024
6df5eb8
remove warnings, fix test
wolfv Dec 18, 2024
aaaa567
make things work
wolfv Dec 18, 2024
ecbbe8d
more menuinst changes
wolfv Dec 20, 2024
144abb1
add missing files
wolfv Dec 20, 2024
99cefa4
fix tests, add a new error
wolfv Dec 20, 2024
116e505
rebase
wolfv Feb 19, 2025
d8e5cf6
fix tests and clippy
wolfv Feb 19, 2025
c7b69c1
start to implement the `MenuinstTracker` to make removal simple
wolfv Feb 19, 2025
6f7cedd
implement tracker
wolfv Feb 19, 2025
8d3e66a
continue tracker implementation
wolfv Feb 19, 2025
61fefc5
make things kinda work on linux
wolfv Feb 19, 2025
46f2f0f
fix stuff on macOS
wolfv Feb 19, 2025
b5b121e
refactor windows code
wolfv Feb 19, 2025
3aabb34
implement tracker on Windows and fix a number of clippy things
wolfv Feb 19, 2025
4318724
cleanup
wolfv Feb 19, 2025
1bc887f
fix clippy
wolfv Feb 19, 2025
1f5713c
fix win build
wolfv Feb 20, 2025
3d94672
use latest windows bindings and windows-registry crate
wolfv Feb 20, 2025
38906b8
add terminal profile stuff
wolfv Feb 20, 2025
b6e190b
more docs
wolfv Feb 20, 2025
2645838
add more docs
wolfv Feb 20, 2025
0310c46
add menuinst types to rattler_conda_types
wolfv Feb 20, 2025
ccaf57b
fix everything up on linux
wolfv Feb 20, 2025
8f6702a
fix up windows
wolfv Feb 20, 2025
5fc3195
clippy
wolfv Feb 20, 2025
800d642
fix docs
wolfv Feb 20, 2025
075e242
fmt
wolfv Feb 21, 2025
ee82081
add in `installed_system_menus` to python bindings
wolfv Feb 21, 2025
55f9b31
make things a bit nicer perhaps
wolfv Feb 21, 2025
806faa6
stricter typing for macos version and other macos types
wolfv Feb 21, 2025
f0555d7
fix clippy and tests
wolfv Feb 21, 2025
fba4833
move macos specific stuff
wolfv Feb 21, 2025
56c8171
fmt
wolfv Feb 21, 2025
1e78cde
simplify
wolfv Feb 23, 2025
ba4e8f4
remove index map
ruben-arts Feb 24, 2025
eafca67
clean up cargo.toml
wolfv Feb 24, 2025
1f0185e
update single lib
wolfv Feb 24, 2025
9c4f43a
move things around
wolfv Feb 24, 2025
ac855fd
enable indexmap for tests
wolfv Feb 24, 2025
86515a3
more clean up for linux
wolfv Feb 24, 2025
636c71a
clippy
wolfv Feb 24, 2025
08683b3
update defaults.json
wolfv Feb 24, 2025
7a38f0e
fix casing of error messages
wolfv Feb 24, 2025
223bba0
fix typo
wolfv Feb 24, 2025
b303b3d
only warn when removal doesnt work
wolfv Feb 24, 2025
7df5c6f
add install-menu and remove-menu to rattler
wolfv Feb 24, 2025
edbdd22
improve logging on macos
wolfv Feb 24, 2025
faa76d9
clippy
wolfv Feb 24, 2025
9babf90
Improve `install_menuitems_for_record`
Hofer-Julian Feb 24, 2025
8d84e8c
Remove unneeded file
Hofer-Julian Feb 24, 2025
4ee5a34
Clean up code
Hofer-Julian Feb 24, 2025
1ad46b3
Remove unneeded test data
Hofer-Julian Feb 24, 2025
2dfed77
Revert pixi toml to main
Hofer-Julian Feb 24, 2025
4716453
Fix doctest
Hofer-Julian Feb 25, 2025
c6e7b7a
Add resolve again
Hofer-Julian Feb 25, 2025
3e436ee
Allow dead code
Hofer-Julian Feb 25, 2025
4557f24
Fix macos
Hofer-Julian Feb 25, 2025
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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ tracing-test = { version = "0.2.5" }
trybuild = { version = "1.0.103" }
typed-path = { version = "0.10.0" }
url = { version = "2.5.4" }
unicode-normalization = "0.1.24"
uuid = { version = "1.13.1", default-features = false }
walkdir = "2.5.0"
which = "7.0.2"
windows-sys = { version = "0.59.0", default-features = false }
winver = { version = "1.0.0" }
zip = { version = "2.2.2", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions crates/rattler-bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ rattler_repodata_gateway = { path="../rattler_repodata_gateway", version = "0.21
rattler_solve = { path="../rattler_solve", version = "1.3.8", default-features = false, features = ["resolvo", "libsolv_c"] }
rattler_virtual_packages = { path="../rattler_virtual_packages", version = "2.0.3", default-features = false }
rattler_cache = { path="../rattler_cache", version = "0.3.9", default-features = false }
rattler_menuinst = { path="../rattler_menuinst", version = "0.1.0", default-features = false }
reqwest = { workspace = true }
reqwest-middleware = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
Expand Down
59 changes: 59 additions & 0 deletions crates/rattler-bin/src/commands/menu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use anyhow::{Context, Result};
use clap::Parser;
use rattler_conda_types::{menuinst::MenuMode, PackageName, Platform, PrefixRecord};
use std::{fs, path::PathBuf};

#[derive(Debug, Parser)]
pub s 10000 truct InstallOpt {
/// Target prefix to look for the package (defaults to `.prefix`)
#[clap(long, short, default_value = ".prefix")]
target_prefix: PathBuf,

/// Name of the package for which to install menu items
package_name: PackageName,
}

pub async fn install_menu(opts: InstallOpt) -> Result<()> {
// Find the prefix record in the target_prefix and call `install_menu` on it
let records: Vec<PrefixRecord> = PrefixRecord::collect_from_prefix(&opts.target_prefix)?;

let record = records
.iter()
.find(|r| r.repodata_record.package_record.name == opts.package_name)
.with_context(|| {
format!(
"Package {} not found in prefix {:?}",
opts.package_name.as_normalized(),
opts.target_prefix
)
})?;
let prefix = fs::canonicalize(&opts.target_prefix)?;
rattler_menuinst::install_menuitems_for_record(
&prefix,
record,
Platform::current(),
MenuMode::User,
)?;

Ok(())
}

pub async fn remove_menu(opts: InstallOpt) -> Result<()> {
// Find the prefix record in the target_prefix and call `remove_menu` on it
let records: Vec<PrefixRecord> = PrefixRecord::collect_from_prefix(&opts.target_prefix)?;

let record = records
.iter()
.find(|r| r.repodata_record.package_record.name == opts.package_name)
.with_context(|| {
format!(
"Package {} not found in prefix {:?}",
opts.package_name.as_normalized(),
opts.target_prefix
)
})?;

rattler_menuinst::remove_menu_items(&record.installed_system_menus)?;

Ok(())
}
1 change: 1 addition & 0 deletions crates/rattler-bin/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod create;
pub mod menu;
pub mod virtual_packages;
4 changes: 4 additions & 0 deletions crates/rattler-bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ struct Opt {
enum Command {
Create(commands::create::Opt),
VirtualPackages(commands::virtual_packages::Opt),
InstallMenu(commands::menu::InstallOpt),
RemoveMenu(commands::menu::InstallOpt),
}

/// Entry point of the `rattler` cli.
Expand Down Expand Up @@ -72,5 +74,7 @@ async fn main() -> anyhow::Result<()> {
match opt.command {
Command::Create(opts) => commands::create::create(opts).await,
Command::VirtualPackages(opts) => commands::virtual_packages::virtual_packages(opts),
Command::InstallMenu(opts) => commands::menu::install_menu(opts).await,
Command::RemoveMenu(opts) => commands::menu::remove_menu(opts).await,
}
}
2 changes: 2 additions & 0 deletions crates/rattler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ rattler_digest = { path = "../rattler_digest", version = "1.0.6", default-featur
rattler_networking = { path = "../rattler_networking", version = "0.22.4", default-features = false }
rattler_shell = { path = "../rattler_shell", version = "0.22.19", default-features = false }
rattler_package_streaming = { path = "../rattler_package_streaming", version = "0.22.28", default-features = false, features = ["reqwest"] }
rattler_menuinst = { path = "../rattler_menuinst", version = "0.1.0", default-features = false }
rayon = { workspace = true }
reflink-copy = { workspace = true }
regex = { workspace = true }
Expand All @@ -52,6 +53,7 @@ tracing = { workspace = true }
url = { workspace = true, features = ["serde"] }
uuid = { workspace = true, features = ["v4", "fast-rng"] }
console = { workspace = true, optional = true }
serde_json.workspace = true

[dev-dependencies]
assert_matches = { workspace = true }
Expand Down
18 changes: 16 additions & 2 deletions crates/rattler/src/install/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,32 @@ impl InstallDriver {
transaction: &Transaction<Old, New>,
target_prefix: &Path,
) -> Result<Option<PrePostLinkResult>, PrePostLinkError> {
let mut result = None;
if self.execute_link_scripts {
match self.run_pre_unlink_scripts(transaction, target_prefix) {< 3D11 /span>
Ok(res) => {
return Ok(Some(res));
result = Some(res);
}
Err(e) => {
tracing::error!("Error running pre-unlink scripts: {:?}", e);
}
}
}

Ok(None)
// For all packages that are removed, we need to remove menuinst entries as well
for record in transaction.removed_packages() {
let prefix_record = record.borrow();
if !prefix_record.installed_system_menus.is_empty() {
match rattler_menuinst::remove_menu_items(&prefix_record.installed_system_menus) {
Ok(_) => {}
Err(e) => {
tracing::warn!("Failed to remove menu item: {}", e);
}
}
}
}

Ok(result)
}

/// Runs a blocking task that will execute on a separate thread. The task is
Expand Down
1 change: 1 addition & 0 deletions crates/rattler/src/install/installer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ async fn link_package(
// ...
link_type: Some(LinkType::HardLink),
}),
installed_system_menus: Vec::new(),
};

let conda_meta_path = target_prefix.join("conda-meta");
Expand Down
1 change: 1 addition & 0 deletions crates/rattler/src/install/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub async fn install_package_to_environment(
paths_data: paths.into(),
requested_spec: None,
link: None,
installed_system_menus: Vec::new(),
};

// Create the conda-meta directory if it doesnt exist yet.
Expand Down
1 change: 1 addition & 0 deletions crates/rattler_conda_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod channel;
mod channel_data;
mod explicit_environment_spec;
mod match_spec;
pub mod menuinst;
mod no_arch_type;
mod parse_mode;
mod platform;
Expand Down
132 changes: 132 additions & 0 deletions crates/rattler_conda_types/src/menuinst/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! Define types that can be serialized into a `PrefixRecord` to track
//! menu entries installed into the system.
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Menu mode that was used to install the menu entries
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum MenuMode {
/// System-wide installation
System,

/// User installation
#[default]
User,
}

/// Tracker for menu entries installed into the system
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Tracker {
/// Linux tracker
Linux(LinuxTracker),
/// Windows tracker
Windows(WindowsTracker),
/// macOS tracker
MacOs(MacOsTracker),
}

/// Registered MIME file on the system
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct LinuxRegisteredMimeFile {
/// The application that was registered
pub application: String,
/// Path to use when calling `update-mime-database`
pub database_path: PathBuf,
/// The location of the config file that was edited
pub config_file: PathBuf,
/// The MIME types that were associated to the application
pub mime_types: Vec<String>,
}

/// Tracker for Linux installations
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct LinuxTracker {
/// The menu mode that was used to install the menu entries
pub install_mode: MenuMode,

/// List of desktop files that were installed
pub paths: Vec<PathBuf>,

/// MIME types that were installed
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mime_types: Option<LinuxRegisteredMimeFile>,

/// MIME type glob files that were registered on the system
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub registered_mime_files: Vec<PathBuf>,
}

/// File extension that was installed
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowsFileExtension {
/// The file extension that was installed
pub extension: String,
/// The identifier of the file extension
pub identifier: String,
}

/// URL protocol that was installed
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowsUrlProtocol {
/// The URL protocol that was installed
pub protocol: String,
/// The identifier of the URL protocol
pub identifier: String,
}

/// Terminal profile that was installed
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowsTerminalProfile {
/// The name of the terminal profile
pub configuration_file: PathBuf,
/// The identifier of the terminal profile
pub identifier: String,
}

/// Tracker for Windows installations
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowsTracker {
/// The menu mode that was used to install the menu entries
pub menu_mode: MenuMode,

/// List of shortcuts that were installed
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub shortcuts: Vec<PathBuf>,

/// List of file extensions that were installed
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub file_extensions: Vec<WindowsFileExtension>,

/// List of URL protocols that were installed
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub url_protocols: Vec<WindowsUrlProtocol>,

/// List of terminal profiles that were installed
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub terminal_profiles: Vec<WindowsTerminalProfile>,
}

impl WindowsTracker {
/// Create a new Windows tracker
pub fn new(menu_mode: MenuMode) -> Self {
Self {
menu_mode,
shortcuts: Vec::new(),
file_extensions: Vec::new(),
url_protocols: Vec::new(),
terminal_profiles: Vec::new(),
}
}
}

/// Tracker for macOS installations
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct MacOsTracker {
/// The app folder that was installed, e.g. ~/Applications/foobar.app
pub app_folder: PathBuf,
/// Argument that was used to call `lsregister` and that we need to
/// call to unregister the app
#[serde(default, skip_serializing_if = "Option::is_none")]
pub lsregister: Option<PathBuf>,
}
8 changes: 7 additions & 1 deletion crates/rattler_conda_types/src/prefix_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::package::FileMode;
use crate::repo_data::RecordFromPath;
use crate::repo_data_record::RepoDataRecord;
use crate::PackageRecord;
use crate::{menuinst, PackageRecord};
use rattler_digest::serde::SerializableHash;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
Expand Down Expand Up @@ -179,6 +179,11 @@ pub struct PrefixRecord {
/// currently another spec was used. Note: conda seems to serialize a "None" string value instead of `null`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requested_spec: Option<String>,

/// If menuinst is enabled and added menu items, this field contains the menuinst tracker data.
/// This data is used to remove the menu items when the package is uninstalled.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub installed_system_menus: Vec<menuinst::Tracker>,
}

impl PrefixRecord {
Expand Down Expand Up @@ -209,6 +214,7 @@ impl PrefixRecord {
paths_data: paths.into(),
link,
requested_spec,
installed_system_menus: Vec::new(),
}
}

Expand Down
50 changes: 50 additions & 0 deletions crates/rattler_menuinst/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[package]
name = "rattler_menuinst"
version = "0.1.0"
edition.workspace = true
authors = ["Wolf Vollprecht <w.vollprecht@gmail.com>"]
description = "Install menu entries for a Conda package"
categories.workspace = true
homepage.workspace = true
repository.workspace = true
license.workspace = true
readme.workspace = true

[dependencies]
dirs = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tracing = { workspace = true }
rattler_conda_types = { path = "../rattler_conda_types", default-features = false }
rattler_shell = { path = "../rattler_shell", default-features = false }
thiserror = { workspace = true }
unicode-normalization = { workspace = true }
regex = { workspace = true }
tempfile = { workspace = true }
fs-err = { workspace = true }
which = { workspace = true }
chrono = { workspace = true, features = ["clock"] }
once_cell = {workspace = true}

[target.'cfg(target_os = "macos")'.dependencies]
plist = { workspace = true }
sha2 = { workspace = true }

[target.'cfg(target_os = "linux")'.dependencies]
quick-xml = "0.37.2"
configparser = { version = "3.1.0" }
shlex = { workspace = true }

[target.'cfg(target_os = "windows")'.dependencies]
known-folders = "1.2.0"
windows = { version = "0.60.0", features = [
"Win32_System_Com_StructuredStorage",
"Win32_UI_Shell_PropertiesSystem",
"Win32_Storage_EnhancedStorage",
"Win32_System_Variant",
]}
windows-registry = "0.5.0"

[dev-dependencies]
insta = { workspace = true, features = ["json"] }
configparser = { version = "3.1.0", features = ["indexmap"] }
Binary file not shown.
Binary file not shown.
Binary file added crates/rattler_menuinst/data/osx_launcher_arm64
Binary file not shown.
Binary file added crates/rattler_menuinst/data/osx_launcher_x86_64
Binary file not shown.
Loading
Loading
8D
0