Locate app bundle based on location of CLI binary

The app bundle can also be specified via `-b` or `--bundle-path`.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-04-20 16:34:22 +02:00
parent f77239bd96
commit 07562c2ccd
3 changed files with 20 additions and 40 deletions

2
Cargo.lock generated
View File

@ -998,12 +998,10 @@ version = "0.1.0"
dependencies = [
"anyhow",
"clap 3.1.8",
"cocoa",
"core-foundation",
"core-services",
"dirs 3.0.1",
"ipc-channel",
"objc",
"plist",
"serde",
]

View File

@ -19,8 +19,6 @@ ipc-channel = "0.16"
serde = { version = "1.0", features = ["derive"] }
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24"
core-foundation = "0.9"
core-services = "0.2"
objc = "0.2"
plist = "1.3"

View File

@ -8,9 +8,8 @@ use core_foundation::{
};
use core_services::{kLSLaunchDefaults, LSLaunchURLSpec, LSOpenFromURLSpec, TCFType};
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
use objc::{class, msg_send, sel, sel_impl};
use serde::Deserialize;
use std::{ffi::CStr, fs, path::PathBuf, ptr};
use std::{ffi::OsStr, fs, path::PathBuf, ptr};
#[derive(Parser)]
#[clap(name = "zed", global_setting(clap::AppSettings::NoAutoVersion))]
@ -24,6 +23,9 @@ struct Args {
/// Print Zed's version and the app path.
#[clap(short, long)]
version: bool,
/// Custom Zed.app path
#[clap(short, long)]
bundle_path: Option<PathBuf>,
}
#[derive(Debug, Deserialize)]
@ -35,19 +37,24 @@ struct InfoPlist {
fn main() -> Result<()> {
let args = Args::parse();
let app_path = locate_app()?;
let bundle_path = if let Some(bundle_path) = args.bundle_path {
bundle_path.canonicalize()?
} else {
locate_bundle()?
};
if args.version {
let plist_path = app_path.join("Contents/Info.plist");
let plist_path = bundle_path.join("Contents/Info.plist");
let plist = plist::from_file::<_, InfoPlist>(plist_path)?;
println!(
"Zed {} {}",
plist.bundle_short_version_string,
app_path.to_string_lossy()
bundle_path.to_string_lossy()
);
return Ok(());
}
let (tx, rx) = launch_app(app_path)?;
let (tx, rx) = launch_app(bundle_path)?;
tx.send(CliRequest::Open {
paths: args
@ -70,38 +77,15 @@ fn main() -> Result<()> {
Ok(())
}
fn locate_app() -> Result<PathBuf> {
if cfg!(debug_assertions) {
Ok(std::env::current_exe()?
.parent()
.unwrap()
.join("bundle/osx/Zed.app"))
} else {
Ok(path_to_app_with_bundle_identifier("dev.zed.Zed")
.unwrap_or_else(|| "/Applications/Zed.dev".into()))
}
}
fn path_to_app_with_bundle_identifier(bundle_id: &str) -> Option<PathBuf> {
use cocoa::{
base::{id, nil},
foundation::{NSString, NSURL as _},
};
unsafe {
let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace];
let bundle_id = NSString::alloc(nil).init_str(bundle_id);
let app_url: id = msg_send![workspace, URLForApplicationWithBundleIdentifier: bundle_id];
if !app_url.is_null() {
Some(PathBuf::from(
CStr::from_ptr(app_url.path().UTF8String())
.to_string_lossy()
.to_string(),
))
} else {
None
fn locate_bundle() -> Result<PathBuf> {
let cli_path = std::env::current_exe()?.canonicalize()?;
let mut app_path = cli_path.clone();
while app_path.extension() != Some(OsStr::new("app")) {
if !app_path.pop() {
return Err(anyhow!("cannot find app bundle containing {:?}", cli_path));
}
}
Ok(app_path)
}
fn launch_app(app_path: PathBuf) -> Result<(IpcSender<CliRequest>, IpcReceiver<CliResponse>)> {