Skip to content
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

Add initial support for link flag #403

Merged
merged 11 commits into from
Apr 27, 2024
20 changes: 20 additions & 0 deletions native/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 native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ lto = true
portable = ["dep:phf"]
static = ["reqwest/native-tls-vendored", "bzip2/static"]
immutable-runtime = []
linked-runtime = ["dep:blake3"]

[dependencies]
ab_glyph = "0.2.23"
Expand Down Expand Up @@ -75,6 +76,7 @@ features = [
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
glob = "0.3.1"
phf = { version = "0.11.2", features = ["macros"] }
blake3 = { version = "1.5.0", optional = true }

[target.'cfg(target_os = "linux")'.dependencies]
bzip2 = "0.4.4"
Expand Down
79 changes: 74 additions & 5 deletions native/src/components/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ use tempfile::{NamedTempFile, TempDir};
use crate::components::site::Site;
use crate::directories::ProjectDirs;

// TODO: Remove this constant and implement variable firefox path into user documentation
pub const FFOX: &str = "/usr/lib/firefox/";

cfg_if! {
if #[cfg(any(platform_linux, platform_bsd))] {

Expand Down Expand Up @@ -107,9 +110,9 @@ fn get_download_url() -> &'static str {
pub struct Runtime {
pub version: Option<String>,

directory: PathBuf,
executable: PathBuf,
config: PathBuf,
pub directory: PathBuf,
pub executable: PathBuf,
pub config: PathBuf,
}

impl Runtime {
Expand Down Expand Up @@ -195,6 +198,21 @@ impl Runtime {
const COPY_ERROR: &str = "Failed to copy the runtime";
const CLEANUP_ERROR: &str = "Failed to clean up the runtime";

#[cfg(feature = "linked-runtime")]
{
use crate::storage::Storage;

let dirs = ProjectDirs::new()?;
let mut storage = Storage::load(&dirs)?;

if storage.config.use_linked_runtime {
self.uninstall()?;
}

storage.config.use_linked_runtime = false;
storage.write(&dirs)?;
}

warn!("This will download the unmodified Mozilla Firefox and locally modify it");
warn!("Firefox is licensed under the Mozilla Public License 2.0");
warn!("Firefox is a trademark of the Mozilla Foundation in the U.S. and other countries");
Expand Down Expand Up @@ -267,13 +285,64 @@ impl Runtime {
remove_dir_all(extracted).context(CLEANUP_ERROR)?;

info!("Runtime installed!");

Ok(())
}

#[cfg(feature = "linked-runtime")]
pub fn link(&self) -> Result<()> {
use std::fs::{copy, create_dir_all};
use std::os::unix::fs::symlink;

use crate::storage::Storage;

let dirs = ProjectDirs::new()?;
let mut storage = Storage::load(&dirs)?;

self.uninstall()?;

storage.config.use_linked_runtime = true;

info!("Linking the runtime");

if Path::new(FFOX).exists() {
for entry in read_dir(FFOX)?.flatten() {
let entry = entry.path();
match entry.file_name().expect("Couldn't retrieve a file name").to_str() {
// Use a different branch for the "defaults" folder due to the patches to apply afterwhile
Some("defaults") => {
create_dir_all(self.directory.join("defaults/pref"))?;
symlink(
entry.join("defaults/pref/channel-prefs.js"),
self.directory.join("defaults/pref/channel-prefs.js"),
)?;
}
Some("firefox-bin") => {
copy(entry, self.directory.join("firefox-bin"))?;
}
Some("firefox") => {
copy(entry, self.directory.join("firefox"))?;
}
Some(&_) => {
let link = self.directory.join(entry.file_name().unwrap());
symlink(entry, link)?;
}
None => todo!(),
}
}
}

storage.write(&dirs)?;

info!("Runtime linked!");

Ok(())
}

#[cfg(not(feature = "immutable-runtime"))]
pub fn uninstall(self) -> Result<()> {
pub fn uninstall(&self) -> Result<()> {
info!("Uninstalling the runtime");
remove_dir_contents(self.directory).context("Failed to remove runtime directory")?;
remove_dir_contents(&self.directory).context("Failed to remove runtime directory")?;

info!("Runtime uninstalled!");
Ok(())
Expand Down
5 changes: 4 additions & 1 deletion native/src/connector/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ impl Process for SetConfig {

impl Process for InstallRuntime {
fn process(&self, _connection: &Connection) -> Result<ConnectorResponse> {
let command = RuntimeInstallCommand {};
let command = RuntimeInstallCommand {
#[cfg(feature = "linked-runtime")]
link: self.link,
};
command.run()?;

Ok(ConnectorResponse::RuntimeInstalled)
Expand Down
10 changes: 10 additions & 0 deletions native/src/connector/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ pub struct SetConfig(pub Config);
///
/// [`ConnectorResponse::RuntimeInstalled`] - No data.
///

#[cfg(feature = "linked-runtime")]
#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct InstallRuntime {
/// Experimental: Use a linked runtime instead of downloading from Mozilla.
pub link: bool,
}

#[cfg(not(feature = "linked-runtime"))]
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct InstallRuntime;

Expand Down Expand Up @@ -603,6 +612,7 @@ impl Into<crate::console::app::HTTPClientConfig> for HTTPClientConfig {

deserialize_unit_struct!(GetSystemVersions);
deserialize_unit_struct!(GetConfig);
#[cfg(not(feature = "linked-runtime"))]
deserialize_unit_struct!(InstallRuntime);
deserialize_unit_struct!(UninstallRuntime);
deserialize_unit_struct!(GetSiteList);
Expand Down
7 changes: 6 additions & 1 deletion native/src/console/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,12 @@ pub enum RuntimeCommand {
}

#[derive(Parser, Debug, Eq, PartialEq, Clone)]
pub struct RuntimeInstallCommand {}
pub struct RuntimeInstallCommand {
/// Experimental: Use a linked runtime instead of downloading from Mozilla
#[cfg(feature = "linked-runtime")]
#[clap(long)]
pub link: bool,
}

#[derive(Parser, Debug, Eq, PartialEq, Clone)]
pub struct RuntimeUninstallCommand {}
Expand Down
9 changes: 9 additions & 0 deletions native/src/console/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ impl Run for RuntimeInstallCommand {

let dirs = ProjectDirs::new()?;
let runtime = Runtime::new(&dirs)?;

#[cfg(feature = "linked-runtime")]
if self.link {
runtime.link().context("Failed to link runtime")?
} else {
runtime.install().context("Failed to install runtime")?;
}

#[cfg(not(feature = "linked-runtime"))]
runtime.install().context("Failed to install runtime")?;

let runtime = Runtime::new(&dirs)?;
Expand Down
36 changes: 28 additions & 8 deletions native/src/console/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,11 @@ impl Run for SiteLaunchCommand {
let site = storage.sites.get(&self.id).context("Web app does not exist")?;
let args = if !&self.arguments.is_empty() { &self.arguments } else { &storage.arguments };

cfg_if! {
if #[cfg(platform_macos)] {
use crate::integrations;

if !self.direct_launch {
integrations::launch(site, &self.url, args)?;
return Ok(())
}
#[cfg(platform_macos)]
{
if !self.direct_launch {
integrations::launch(site, &self.url, args)?;
return Ok(());
}
}

Expand All @@ -50,6 +47,29 @@ impl Run for SiteLaunchCommand {
bail!("Runtime not installed");
}

#[cfg(feature = "linked-runtime")]
{
use std::fs::File;
use std::io::Read;
use std::path::Path;

use blake3::{hash, Hash};

fn hasher<P: AsRef<Path>>(path: P) -> Hash {
let mut file = File::open(path.as_ref().join("firefox")).unwrap();
let mut buf = Vec::new();
let _ = file.read_to_end(&mut buf);

hash(&buf)
}

if storage.config.use_linked_runtime
&& hasher(crate::components::runtime::FFOX) != hasher(&runtime.directory)
{
runtime.link()?;
}
}

// Patching on macOS is always needed to correctly show the web app name
// Otherwise, patch runtime and profile only if needed
let should_patch = if cfg!(platform_macos) || storage.config.always_patch {
Expand Down
5 changes: 5 additions & 0 deletions native/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ pub struct Config {
/// Only affects Linux, on supported desktop environments.
/// May be overwritten with a system environment variable.
pub runtime_use_portals: bool,

#[cfg(feature = "linked-runtime")]
/// Experimental: Using the system runtime to save some disk space.
/// This might not work on your system.
pub use_linked_runtime: bool,
}

#[non_exhaustive]
Expand Down
Loading