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

feat: Mac .pkg installer #1312

Merged
merged 3 commits into from
Sep 3, 2024
Merged

feat: Mac .pkg installer #1312

merged 3 commits into from
Sep 3, 2024

Conversation

mistydemeo
Copy link
Contributor

@mistydemeo mistydemeo commented Aug 12, 2024

This adds support for building Mac .pkg installers. This current implementation is intentionally a bit simplistic: it produces one .pkg per package in the user's workspace, without any special branding applied. We currently only allow the app identifier and install location to be configured, but we can consider adding further customization in the future.

Although I added support for configuring this in init, I ran into a bit of trouble serializing that value since the new config is set up as a struct rather than two separate fields.

Here's sample config from one app:

[workspace.metadata.dist.mac-pkg-config]
identifier = "dev.axo.cargo-dist"
install-location = "/usr/local"

And here's the No Name / Sans nom installer it produces:

image

Comment on lines 45 to 50
let build_dir_target = TempDir::new()?;
let build_dir = build_dir_target.path();
let bindir = build_dir.join("bin");
fs::create_dir_all(&bindir)?;
let libdir = build_dir.join("lib");
fs::create_dir_all(&libdir)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no raw io errors, I really want to remove that error variant from DistError, because it's awful to slam a user with that.

We have several places where we do tempdirs we should be reusing, and axoasset APIs for others. Also camino.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promoted the tempdir thing to a public method; making me wonder if we just want this to be in axoasset.

Converted the rest into axoasset calls except the symlinks, which axoasset doesn't know about yet. I can add that though, feels in scope.

cargo-dist/src/backend/installer/macpkg.rs Outdated Show resolved Hide resolved
cargo-dist/src/backend/installer/macpkg.rs Outdated Show resolved Hide resolved
Comment on lines +439 to +446
/// Configuration specific to Mac .pkg installers
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub mac_pkg_config: Option<MacPkgConfig>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

glossing over this as something we can freely rejig in config 1.0...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, like I mentioned elsewhere this is something I wanted to check in with you about wrt handling before/after config 1.0.

cargo-dist/src/init.rs Outdated Show resolved Hide resolved
return Err(DistError::MacPkgBundleIdentifierMissing {});
}

let prompt = r#"Please enter the installation prefix this .pkg should use."#;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably specify the default, or we shouldn't even ask? Not sure how typical it is to overload this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overloading it is pretty common. Many people are going to want the default /usr/local, which is in the PATH but shared with other software. Other people are going to prefer, say, /opt/mypkg, which is out of the default PATH but a prefix fully owned by them, etc.

I was going for an "accept NULL, unwrap to /usr/local later" approach. But I guess that means the default could shift under the user, which maybe isn't ideal - I guess "inline a default if not specified" is probably better.

cargo-dist/src/init.rs Outdated Show resolved Hide resolved
let binaries = variant.binaries.clone();
let target = &variant.target;
if !target.contains("darwin") {
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally we warn here, I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following the pattern from the MSI, which doesn't warn here.

Comment on lines +2517 to +2535
// Compute which package we're actually building, based on the binaries
let mut package_info: Option<(String, PackageIdx)> = None;
for &binary_idx in &binaries {
let binary = self.binary(binary_idx);
if let Some((existing_spec, _)) = &package_info {
// we haven't set ourselves up to bundle multiple packages yet
if existing_spec != &binary.pkg_spec {
return Err(DistError::MultiPackage {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...wild why was this logic exclusive to msi

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right I think it's because I needed to enforce this for the sake of calling into cargo-wix, but I don't think the pkg stuff has that limitation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so the goal wasn't to create a single MSI containing every package but rather just that cargo-wix can't understand what to do when given multiple packages? I think I misunderstood the purpose of this guard then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I see now why we've got a separate conflict here. We're fetching some package-level metadata to pass to the package build - specifically, the identifier field is package-level metadata. We don't have the package directly accessible to us - just on the binaries - and if we did end up with a conflict of which package they resolve to, I don't know if I could get a better answer than the MSI path does.

Copy link
Contributor

@Gankra Gankra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(also we need to disable the init code temporarily to land this)

Comment on lines 1515 to 1473
let mut new_table = toml_edit::table();
if let Some(new_table) = new_table.as_table_mut() {
new_table.insert("identifier", toml_edit::value(&mac_pkg_config.identifier));
if let Some(location) = &mac_pkg_config.install_location {
new_table.insert("install-location", toml_edit::value(location));
}
new_table.decor_mut().set_prefix(desc);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason these can't call into apply_optional and friends?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, right, I guess I didn't really consider that this is also a table we could just apply_optional_* into.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like me to break this init commit out into a separate PR? Then we can land the rest with the init stuff missing.

cargo-dist/src/init.rs Outdated Show resolved Hide resolved
This adds support for building Mac .pkg installers. This current
implementation is intentionally a bit simplistic: it produces one
.pkg per package in the user's workspace, without any special
branding applied. We currently only allow the app identifier and
install location to be configured, but we can consider adding further
customization in the future.
@Gankra Gankra merged commit 3f58b8e into main Sep 3, 2024
16 checks passed
@Gankra Gankra deleted the pkg branch September 3, 2024 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants