team icon indicating copy to clipboard operation
team copied to clipboard

Packaging and distributing apps

Open killercup opened this issue 6 years ago • 45 comments

(moderated summary by @epage)

Context:

  • "Rust makes writing crossplatform, tested, modern command line applications frictionless while incorporating industry best practices and providing great documentation." (goal)
  • Focus is on CLI apps (see README for definition)

Assumptions and Implications

  • Majority of CLIs will at more than just Rust developers (for targeting rust-developers, see #20)
  • Users of CLIs will be somewhat technical considering they are using a terminal
  • Use case priorities
    1. Using the app on the command line via the path
    2. Glued together with other apps in a script
    3. Drag and drop files onto an icon for the CLI
  • Examples of content to distribute
    • one or more rust binaries
    • completion files
    • man pages (See #23)

Other solutions

Plan of attack

  1. "How to package" documentation
  1. Automation
  • Implement stager
  • Reach out to binary packaging tools to consolidate effort with stager

In-ecosystem resources

Open Issues

  • (Windows) Adding manifests, see https://github.com/rust-lang/rfcs/issues/721

Open Questions

  • Prioritized list of package formats per platform?
    • Linux: deb, rpm, flatpak, snap
      • Are flatpak / snap's apps added to PATH?
    • Windows: MSI via wix, chocolatey
    • Mac: homebrew
      • How easily are pkg's available from command line?
  • PPAs?
  • Use case, challenges, and priority of source packages?
    • See https://github.com/mmstick/cargo-deb/issues/40
  • Importance of remote administration and provisioning?

@killercup's original post

In the first meeting, we identified packaging and distributing CLI apps a something we should improve.

We need to have a best-practice solution for getting from "I have a crate with a binary" to "I can ship this app and don't have to worry about cross-platform installation stuff".

Edit 2018-03-19: This issue is about distribution of rust binaries without using cargo-install.

killercup avatar Feb 20 '18 19:02 killercup

  • cf. https://github.com/japaric/trust/
  • https://github.com/crate-ci/crate-ci.github.io by @epage
  • cargo-install doesn't respect Cargo.lock
    • help fix https://github.com/rust-lang/cargo/issues/2263

killercup avatar Feb 20 '18 19:02 killercup

Distribute documentation:

  • documentation of env vars a CLI app repsects/uses
  • there seems to be no cohesive answer for man pages yet
    • ripgrep is using aciidoc: https://github.com/BurntSushi/ripgrep/pull/776
    • issue in clap https://github.com/kbknapp/clap-rs/issues/552 (@kbknapp, awaiting clap v3-alpha)

killercup avatar Feb 20 '18 19:02 killercup

  • ref: man pages in clap v3-alpha the overall tracking issue (kbknapp/clap-rs#1037)

kbknapp avatar Feb 20 '18 19:02 kbknapp

From the etherpad:

  • Guides/How-Tos
    • Deb, RPM, AUR, Homebrew, Snap, Flatpak, AppImage, nixpkgs
  • Automation
    • cargo subcommands
    • Using CI

If cargo-install is an important use case for dev tools, how much should we look at improving it?

killercup avatar Feb 20 '18 19:02 killercup

If cargo-install is an important use case for dev tools, how much should we look at improving it?

I think this is part of a lot broader area of "crates.io's treatment of executables.". Which is something that previously has been very vague. Part of distribution should be codifying how crates.io handles and promotes executables or lack thereof.

I'm unsure how we should go about this as there isn't really a process for requesting crates.io features.

XAMPPRocky avatar Feb 22 '18 21:02 XAMPPRocky

For distributing my cli apps I made https://github.com/jaemk/self_update to support a "self update" command that pulls the latest github release built using https://github.com/japaric/trust/

jaemk avatar Mar 02 '18 03:03 jaemk

@killercup When it comes to automatically generating debian packages (and there is already cargo-deb for that) I think it's even more important to generate source packages for distributions to include (or to build a PPA with). And that is something that cargo-deb can't yet to.

See cargo-deb#40

spacekookie avatar Mar 02 '18 07:03 spacekookie

For windows specifically, it would be nice to be able to add manifest to the binary: https://github.com/rust-lang/rfcs/issues/721.

matklad avatar Mar 04 '18 20:03 matklad

A couple more thoughts after brainstorming with @killercup:

With CLI apps that are built by doing "cargo install", we have a pretty straightforward path we could go down with regards to building installers for people.

For example, what if we had a new cargo plugin, or separate tool, that could take a "cargo install"-able CLI app and then, using a bit of convention over configuration, build you an installable package for a distro or use a simple Windows installer .exe?

This seems doable because there are really only a couple steps when doing CLI work specifically: "build my binary" and "put it in my path", which distros and installers should be able to handle no problem. @killercup mentioned that we might even want to go a step further and offer some project templates that drop in whatever metadata is required for building .deb, homebrew, etc. From there maybe the cargo plugin can either be configured and/or searches for packaging tools it knows about and builds using them.

These combined with something like https://github.com/japaric/trust/ means folks could take an easy extra step to see what tweaks they'd need to make to get it to work across more platforms.

sophiajt avatar Mar 04 '18 20:03 sophiajt

This seems doable because there are really only a couple steps when doing CLI work specifically: "build my binary" and "put it in my path", which distros and installers should be able to handle no problem.

Eh, that kind of depends on the tool, and how polished an experience you want it to be. Even static binaries might want to include manpages, generic documentation, default config files, command-line completion integration, data files...

I suspect no single tool is going to be able to support many or varied platforms, because platform conventions vary so widely, and because so few tool-developers are familiar with all possible deployment platforms. However, it would be great to have a set of base conventions that platform-specific tools can extend in different ways. For example, there could be a base convention that documentation lives in a docs/ subdirectory in Markdown format, and the build-posix-package tool could have an extra convention that a file named docs/manpage.md will be installed as the manpage for the crate's main executable.

Screwtapello avatar Mar 05 '18 02:03 Screwtapello

I got pointed at this issue by @killercup on https://users.rust-lang.org/t/cargo-and-installation-of-ancilliary-files/15974

My specific problem is installing a GNOME application. So not a CLI application per se, but very similar. Whilst many of the resources needed by the application are embedded in the executable, there are some that need installing. Manual pages and user documentation certainly, but also some image files and a GNOMEShell launcher.

Whilst my need is very specific, I am sure it acts as a microcosm of the more general situation.

Meson makes it very easy to install application – my experience is with D and C++, I have not tried using Meson with Rust. It is also fairly straightforward, but not always easy, to set up installation using SCons and CMake – but again my experience is with D and C++, to date I have only used Cargo with Rust.

russel avatar Mar 05 '18 15:03 russel

@Screwtapello: I suspect no single tool is going to be able to support many or varied platforms, because platform conventions vary so widely, and because so few tool-developers are familiar with all possible deployment platforms.

This is my exact concern. I agree very much with the rest of your comment that having separate tools or conventions that people can pick/choose/extend would go a lot further than an "all in one" tool. This is with the caveat that those "separate tools" are well known, widely supported, well documented, etc. Not just one offs.

@jaemk: For distributing my cli apps I made https://github.com/jaemk/self_update to support a "self update" command that pulls the latest github release built using https://github.com/japaric/trust/

I love this! It may not work for everyone, or for complex use cases, but making it easy to have a "self update" feature of Rust CLI applications for "small utilties and binaries" would probably go a long way. Of course this doesn't solve the initial installation piece, but I still think it'd be great to include in a full blown solution. This particular piece could just be a standard guide on how to do this, such as a cookbook like recipe.

[about cargo-install in general as an install tool]

I'm on record saying I don't really like leaning on cargo-install for the general public, or general purposes. I think it's great for dev tools, or things that make sense to use during Rust development, but I personally don't want to expand it's use case to a general purpose installer.

I think there's too many nuances, and too much complexity to do everything correctly for it to all be contained in cargo. I'd like to keep cargo a Rust build tool, not a general purpose package manager. This isn't to say we shouldn't add certain features to cargo-install such as post build scripts...I'd just like to have proper guides/tools doing things the correct way first so that people don't just hit the easy button of cargo install which is what people are starting to do already.

Why?

Here's a few of the things I think would need to be sorted out (conversely why I think they shouldn't sorted out). This isn't meant to be an all encompassing list, just a quick search of some relevant issues. There may be more I can't think of off the top of my head, but here's a few:

Advanced or Post Build Steps

My primary concern with using cargo install too generally is that because of all the added complexity of correctly installing software, cargo-install takes the easy route and doesn't support complex/advanced use cases. Which is perfectly fine to me because it's not a general purpose installer. Until recently cargo-install didn't even support use of Cargo.lock files. As far as I know it still doesn't (easily) support more advanced build steps (like setting RUSTFLAGS, or like many have mentioned post build steps).

  • rust-lang/cargo#4150 (RUSTFLAGS="-C target-cpu=native" by default on cargo-install)
  • rust-lang/cargo/issues/5068 (cargo install doesn't support --target options)
  • rust-lang/cargo/issues/2386 (Request install.rs similar to build.rs)

Crate Size

Including things like docs, manpages, completion scripts, licenses, axillary files, etc. which will be required for installation of end user products will bloat the crate packages. I'd actually like to do the opposite of de-bloating crates

  • kbknapp/clap-rs#1186
  • rust-lang/cargo/issues/4988 (cargo install requires downloading and building dev-dependencies)

Binary Only Features/Deps

Until cargo supports binary only features and deps, crates that include both a lib and bin will suffer from the above points when used as a lib (compile times, crate size, etc.)

Also, being able to specify binary dependencies is huge for a general purpose package manager.

  • rust-lang/cargo#1982 (bin only features)
  • rust-lang/cargo#5120 (cargo-install binary deps, which is part of the equation, but still leaves out general binary deps)
  • rust-lang/cargo/issues/4555 (Specify deps for cargo install)
  • rust-lang/cargo/issues/3816 (General sense of allowing "external deps" in cargo)
  • rust-lang/cargo/issues/4316 (crates depending on binary crates)

Code Signing

This is another pretty big hole if we'd want to properly use cargo install as a general purpose installer.

  • rust-lang/cargo#4768

kbknapp avatar Mar 05 '18 21:03 kbknapp

Just to include packagers, nixpkgs has pretty good support for rust ATM. I managed to get the novault nixpkg created, which required custom external dependencies.

The advantage of nixpkgs is that they can run alongside other package managers on any Unix distribution (including Mac) and I believe they are trying to support windows as well. This allows for at least some installation path for almost any platform/distribution, which is very valuable.

The process is pretty straightforward, with carnix creating the package from the Cargo.lock file. I think it's a workflow worth emulating for other packaging scripts as well.

vitiral avatar Mar 07 '18 23:03 vitiral

Just to include packagers, nixpkgs has pretty good support for rust ATM.

Tell me more about this! The last time I tried to package something for nixpkgs, I failed hard. I used carnix and it created a package expression which OOM-Errored with Nix!

From what I think, Rust packaging with nixpkgs is hell!

matthiasbeyer avatar Mar 08 '18 10:03 matthiasbeyer

@matthiasbeyer this might fix your problem (just came across it): https://github.com/NixOS/nix/issues/358

Edit: link to PR

vitiral avatar Mar 08 '18 17:03 vitiral

cargo install is nice for developers who already have Rust + cargo installed and are likely to have whatever -dev packages are required to build the app, but it's a bit heavyweight otherwise. Especially since you can wind up pulling in a lot of dependent crates to build a useful tool, which means the build time for your tool creeps up...

It would be nice to have best practices for alternatives as well. For sccache we've got binary releases being built in Travis + Appveyor for Mac/Windows/Linux: https://github.com/mozilla/sccache/releases

Getting this right involved a bunch of fiddling which I'd be happy to help document somewhere: https://github.com/mozilla/sccache/blob/master/.travis.yml https://github.com/mozilla/sccache/blob/master/appveyor.yml

luser avatar Mar 16 '18 18:03 luser

@luser I'm planning on documenting creating binary releases on my crate-ci docs

See https://crate-ci.github.io/

I put it on hold for the moment because I felt like documenting the process was a bit much. Because we need to know what the target is to find the binary, we have to retrofit the CI configuration in a fairly invasive way.

My hope is soon(ish) to start a tool to make it easier to get the files needed to make it easier to document See https://github.com/crate-ci/meta/issues/1

epage avatar Mar 16 '18 18:03 epage

@kbknapp I think what you've listed as reasons cargo shouldn't be used as a build, is exactly the reasons this working group should push for solving those problems as anything that hampers general development also hampers the development of developer tools. Saying "I'd just like to have proper guides/tools doing things the correct way first so that people don't just hit the easy button of cargo install which is what people are starting to do already." is honestly a bit elitist, if people don't have an easy way they won't work on the tools. No amount of documentation or templates can compete with a single line command.

The point of this working group is provide the easy way for developers to release and distribute their apps saying "Oh well you need to integrate in with this CI template, and add this dependency to be able for users to upgrade your app." isn't an easy way to release apps, it's tedious busy work. So what if the program is only available to Rust developers? That's a great way to get feedback, you can release a 0.1 through cargo and go to r/rust or IRC and ask them to try it out.

Unless you can somehow automate the process of releasing to all package managers at once with zero configuration any other option is worse than releasing through cargo-install. Saying that because cargo lacks features so it shouldn't be a package manager is a self fulfilling prophecy as we're the CLI working group and if we choose not to try to improve cargo as a package manager that will be used as reasons to not improve cargo-install.

XAMPPRocky avatar Mar 18 '18 13:03 XAMPPRocky

@Aaronepower Well, that's all well and good and yea maybe there are some things in the cargo install pipeline that aren't very nice right now. But to target that at end-users is the wrong way to go about it.

Writing apps and CLIs specifically in Rust is so great because you're not dependent on any interpreter or runtime or toolchain. And then to say: install this toolchain to install the application is a bit…weird.

If there are any hangups with cargo-install then yea, we should of course fix them. For example a super-duper awesome feature would be that sys- package automatically install the required -dev packages on your platform so that compilation doesn't fail if they're not there.

But as an end-user experience, I don't want them touching cargo at all

spacekookie avatar Mar 19 '18 11:03 spacekookie

@spacekookie I feel like that is bit too much of generalisation on end users and the applications being made. Obviously if you're making a tool that helps write python applications it'd be a pain point to require cargo, and if you're a project that as big as ripgrep you need to provide other avenues of installation.

A lot of projects are Rust focused and even if they aren't when they start out they need a way to easily distribute their application to get feedback. I'm saying that even just as a quick way to get dev tools or small cli apps cargo-install needs to be held to a higher standard as I think improving that will have the most impact on developers releasing their applications.

XAMPPRocky avatar Mar 19 '18 12:03 XAMPPRocky

Should we split this issue into two separate issues then?

One issue could focus on making Cargo more friendly for installing CLI tools written in Rust with Rust-dev community as target userbase.

Another issue could focus on documenting distribution of CLI tools written in Rust with different package managers (+ OSes and architectures) like Homebrew, apt, etc with regular non-Rust dev audience as target userbase.

artem-zinnatullin avatar Mar 19 '18 13:03 artem-zinnatullin

This issue was never meant to cover cargo-install 😅

So, yeah, please go ahead and make that issue! Ideally with quotes from the comments here :)

killercup avatar Mar 19 '18 13:03 killercup

@killercup if it wasn't, maybe you could update issue description to specify that it tracks distribution through package managers (or other solutions) to final non-Rust-dev users?

That'll help avoid confusion we had here :)

artem-zinnatullin avatar Mar 19 '18 13:03 artem-zinnatullin

For Linux systems, it may be good to choice either Snap or Flatpak, instead of trying to support all available package managers.

ayosec avatar Mar 19 '18 14:03 ayosec

@ayosec We don't have to support all package managers.

Creating source deb files, source rpm files would be a great start. Yea sure, making snap and flatpak packages is also nice. But not everybody likes those approaches (me included :stuck_out_tongue_winking_eye:), so supporting "classic" Linux packages is also good.

Besides, deb (for bin packages) already exists :+1:

spacekookie avatar Mar 19 '18 15:03 spacekookie

I do think that it's worth separating out two separate considerations here, as a few people have suggested.

We want to support building and installing CLI tools and all the accompanying bits that people expect, including manpages, completions, etc.

We also want to support building policy-compliant source packages for Linux distributions, so that distributions can ship Rust software just as easily as they can ship anything else.

joshtriplett avatar Mar 19 '18 19:03 joshtriplett

I know I'm a bit late to this discussion, but I looked into what it would take to build a Cargo extension to package up a CLI app a while back and thought I'd add a bit of what I came up with after researching the issue.

  • It's much easier to create an installer for the platform on which you're compiling. Cross compiling is a much more complex process since you can't rely on the tools that ship with the OS.

  • Creating a very basic installer is pretty easy on most platforms, but for more complex options that make installers feel professional like adding a logo or installing files beyond the single executable, the developer will need to supply additional metadata that's currently awkward to put in Cargo.toml.

  • Homebrew should not be looked at as an acceptable Mac install solution, or at least not the only solution. It's much more analogous to cargo install in that it's targeted at developers and other more-technical users. The likely best/default answer on Mac is a .pkg file assembled with the pkgbuild tool.

  • Creating a .msi installer on Windows will probably mean requiring developers install something like Wix since the VC++ toolchain seemed to require using the GUI. Documentation on this was a bit confusing, so I could be wrong on this one, but Wix support might still be necessary to support the MinGW use case.

  • Windows .msi and Mac .pkg are particularly important because they fit in with the first-party remote administration tools that IT departments use to provision their fleets of machines and keep them up to date.

  • I'm purposefully not saying much about the Linux side of this since there are a bunch of comments here that already cover everything I found for producing debs and rpms.

It's great that this issue is getting attention and I wish I had more time to pitch in and help.

tblair avatar Mar 22 '18 05:03 tblair

@tblair

Creating a very basic installer is pretty easy on most platforms, but for more complex options that make installers feel professional like adding a logo or installing files beyond the single executable, the developer will need to supply additional metadata that's currently awkward to put in Cargo.toml.

Hm, do we need to have logos in CLI tools installers? Do we need installers for CLI tools?

Homebrew should not be looked at as an acceptable Mac install solution, or at least not the only solution. It's much more analogous to cargo install in that it's targeted at developers and other more-technical users. The likely best/default answer on Mac is a .pkg file assembled with the pkgbuild tool.

Well, CLI tools are mainly used by developers, sysadmins, devops and pro-users who tend to use some package manager and Homebrew is one of the most popular ones for macOS 😸

However definitely agree that it shouldn't be the only option 👍

Windows .msi and Mac .pkg are particularly important because they fit in with the first-party remote administration tools that IT departments use to provision their fleets of machines and keep them up to date.

Interesting perspective! // Curious though how often do CLI tools need to be provisioned on Windows and Mac by IT departments, hmmm. But still definitely agree that OS-native packaging like .msi and .pkg must be covered anyway.

artem-zinnatullin avatar Mar 22 '18 11:03 artem-zinnatullin

I've updated the issue with a summary of the conversation in context of the what we are working to achieve with this working group

I've left off man pages because generating them is more tangential to this discussion and I'll fork it off into a separate topic

@spacekookie

@killercup When it comes to automatically generating debian packages (and there is already cargo-deb for that) I think it's even more important to generate source packages for distributions to include (or to build a PPA with). And that is something that cargo-deb can't yet to.

@joshtriplett

We also want to support building policy-compliant source packages for Linux distributions, so that distributions can ship Rust software just as easily as they can ship anything else.

Is packaging for a distribution usually handled upstream or within distribution community? I worry that there are a lot of constraints and requirements in trying to cover this use case that it'll overwhelm us for what we want to accomplish this year.

@ayosec

For Linux systems, it may be good to choice either Snap or Flatpak, instead of trying to support all available package managers.

@tblair

Windows .msi and Mac .pkg are particularly importan

I've not used Mac pkgs, Snap, or Flatpak. Do they easily support running from the command line, like putting their bin in the path?

epage avatar Mar 22 '18 13:03 epage

@epage

Is packaging for a distribution usually handled upstream or within distribution community? I worry that there are a lot of constraints and requirements in trying to cover this use case that it'll overwhelm us for what we want to accomplish this year.

It's something with many common requirements across distributions, so some aspects of it need addressing upstream, in collaboration with the distribution communities. We need to take those requirements into account in our development.

joshtriplett avatar Mar 22 '18 15:03 joshtriplett