SE-0301: Package Editor Commands

After reading the proposal a second time, and reviewing parts of the implementation, I have some more suggestions for this proposal.

Command pattern/structure

In the "Alternatives Considered" section:

Support for Deleting Products/Targets/Dependencies and Renaming Products/Targets

This functionality was considered, but ultimately removed from the scope of the initial proposal. Most of these editing operations appear to be fairly uncommon, so it seems better to wait and see how the new commands are used in practice before rolling out more.

One common operation not covered by either the detailed design or the alternatives considered is adding new dependencies/targets to existing targets/products. I think it's fine if all additional commands are left for the future, but they should still be considered for the "scalability" of the proposed commands' pattern/structure.

The proposed commands use verb-noun for each operation:

swift package add-dependency <name> ...
swift package add-product <name> ...
swift package add-target <name> ...

If additional commands are to follow this pattern, they will probably be like:

swift package remove-dependency <name> ...
swift package remove-product <name> ...
swift package remove-target <name> ...
swift package rename-dependency <oldName> <newName> ...
swift package rename-product <oldName> <newName> ...
swift package rename-target <oldName> <newName> ...
swift package upgrade-dependency <name> ...
...

One concern I have here is that all the commands can get crowded at the swift package level, and it can make them more difficult to discover in documentation.

Mock output of the `--help` manual
$ swift package --help
OVERVIEW: Perform operations on Swift packages

USAGE: swift package [options] subcommand

OPTIONS:
  ... 21 existing options omitted ...

SUBCOMMANDS:
  ... 15 existing options omitted ...
  add-dependency          Add a dependency to the current package.
  add-product             Add a product to the current package.
  add-target              Add a target to the current package.
  remove-dependency       Remove a dependency from the current package.
  remove-product          Remove a product from the current package.
  remove-target           Remove a target from the current package.
  rename-dependency       Rename a dependency in the current package.
  rename-product          Rename a product in the current package.
  rename-target           Rename a target in the current package.
  upgrade-dependency      Upgrade a dependency in the current package.
  ... 

SEE ALSO: swift build, swift run, swift test

I suggest changing the commands to the noun verb pattern, so all of them can be grouped under the dependency, product, and target subcommands:

swift package dependency add <name> ...
swift package dependency remove <name> ...
swift package dependency rename <oldName> <newName> ...
swift package dependency upgrade <name> ...

swift package product add <name> ...
swift package product remove <name> ...
swift package product rename <oldName> <newName> ...

swift package target add <name> ...
swift package target remove <name> ...
swift package target rename <oldName> <newName> ...

...
Mock output of the `--help` manuals
$ swift package --help
OVERVIEW: Perform operations on Swift packages

USAGE: swift package [options] subcommand

OPTIONS:
  ... 21 existing options omitted ...

SUBCOMMANDS:
  ... 15 existing options omitted ...
  dependency              Perform dependency-related operations on Swift packages.
  product                 Perform product-related operations on Swift packages.
  target                  Perform target-related operations on Swift packages.

SEE ALSO: swift build, swift run, swift test
$ swift package dependency --help
OVERVIEW: Perform dependency-related operations on Swift packages.

USAGE: swift package dependency subcommand

SUBCOMMANDS:
  add                    Add a dependency to the current package.
  remove                 Remove a dependency from the current package.
  rename                 Rename a dependency in the current package.
  upgrade                Upgrade a dependency in the current package.
  ... 
$ swift package target --help
OVERVIEW: Perform target-related operations on Swift packages.

USAGE: swift package target subcommand

SUBCOMMANDS:
  add                    Add a target to the current package.
  remove                 Remove a target from the current package.
  rename                 Rename a target in the current package.
  ... 
$ swift package product --help
OVERVIEW: Perform product-related operations on Swift packages.

USAGE: swift package product subcommand

SUBCOMMANDS:
  add                    Add a product to the current package.
  remove                 Remove a product from the current package.
  rename                 Rename a product in the current package.
  ... 

There are also precedents of this noun verb subcommand pattern in other programs. For example in Git:

git remote add myRemote https://path.to.my/remote
git remote remove origin
git remote rename oldName newName

git submodule add
git submodule status
git submodule init

URL and path

swift package add-target <name> [--type <type>] [--no-test-target] [--dependencies <dependencies>] [--url <url>] [--path <path>] [--checksum <checksum>]

[...]

  • url/path : The URL for a remote binary target or path for a local one.
  • checksum : The checksum for a remote binary target.

[...]

swift package add-dependency <dependency> [--exact <version>] [--revision <revision>] [--branch <branch>] [--from <version>] [--up-to-next-minor-from <version>]

  • dependency : This may be the URL of a remote package, the path to a local package, or the name of a package in one of the user's package collections.

add-target uses separate --url and --path options, while add-dependency combines both into the dependency argument.

If SwiftPM is able to tell whether a dependency's path is local or remote, can one of the --url and --path options be dropped and have the remaining one take both local and remote paths?


From...to and from...through versions

Package.Dependency has these 2 static functions:

static func package(name: String? = nil, url: String, _ range: Range<Version>) -> Package.Dependency

static func package(name: String? = nil, url: String, _ range: ClosedRange<Version>) -> Package.Dependency

Can this proposal add --to <version> and --through <version> to pair with --from <version>, so the add-dependency command can accept all supported version requirements?

8 Likes

This is a fair criticism, but I'm starting to think the set of commands accessible via the CLI might remain fairly small. For example, I think renaming is an operation that people are unlikely to want to do on the command line, so maybe instead off adding a new subcommand we'd just expose libSwiftPM APIs for IDEs to use. 4 levels of nesting for something like swift package product add feels also like a lot, and if at all possible I'd like all the help info for the editing commands at the top level of swift package.

It's possible, but the error messaging around checksum issues might not be quite as good so I decided to match the argument labels exactly here.

There's no technical restriction here, but I was under the impression using these was discouraged, and I'm somewhat concerned spellings like --to or --through might encourage people to use them more.
Edit: After thinking about this more, I think this suggestion makes sense, so every type of requirement is fully supported.

Glad to hear that good error messaging is a priority. I'm curious, what exactly is preventing the same quality of messages for a unified url+path flag?

I like the suggested commands, but I think if we provide add commands, we should also add a way of reverting these commands. So I personally would "accept with modifications".

More specifically, the proposal explains the rationale for not adding more commands like this:

I disagree with this. From my experience, typos in product, target or dependency names are "fairly common". Thus I'm pretty sure users will be more confident/relaxed with using these new commands (directly or via another tool they are used by) if we also provide a way to revert the last command. I could imagine 2 ways to handle this:

  1. We provide remove-product, remove-target and remove-dependency commands
  2. For all add command we provide a --revert option so I can just re-run the same command with this added to revert the changes

Yes.

Yes.

I personally never use such commands directly as I learned over time that I don't have control over what they exactly edit, thus I'm editing manually and don't remember what commands other languages/libraries provide.

I read the full proposal and all comments above my answer in this thread.

Because only binary targets have a url or path, the split flags make it a little easier to determine the user's intent when dealing with checksums (Did they provide a checksum when it wasn't required, or forget one that was), or if they forget to specify --type binary, since other types of targets don't have URLs. Dependencies aren't affected by this as much because they all have a URL or path. The error message improvements are small, but worth it IMO

late here but +1 if it helps. I do support the inclusion of remove commands or something similar even if it just somehow 'suggested' what to remove instead of actually doing it

1 Like

Just hopping in here that'd I'd strongly support this spelling of commands :+1:

It is much better to evolve in the future and easier to type and remember from "more general to more specific" as on goes through the commands. Other build tools (sbt), cluster env (k8s) command lines and various other big data tools also used these patterns if I remember properly from my "previous life" :wink: This form of nesting is also great for learning a tool -- tab driven "i have no idea how to achieve what I want, but I know something with package [tab tab] aha, seems I want dependency [tab tab] yeah I want to upgrade, I see!" :slight_smile:

Really looking forward to this feature as I think it'll be invaluable in collaboration with package collections/indexes to automatically add missing dependencies etc :slight_smile:

10 Likes

I'm also in the noun first, verb second team, even if that requires 4 nested levels of commands. I can imagine that this pattern indeed improves discoverability of those commands, especially because of it's similarities to the widely known git command.

Otherwise I'm very +1 for adding these commands to swift package.

2 Likes

SE-0301 has been accepted with modification. If you'd like to continue discussing this, please do so in that thread.

Terms of Service

Privacy Policy

Cookie Policy