Why does SwiftPM use GitHub repo name and not Package.swift name?

running into this issue while testing ss-json, which is named swift-json in the Package.swift in order to follow pure-swift library naming conventions.

the SPM seems to ignore the Package.swift name and uses the GitHub repo name instead, which strikes me as odd. the workaround, which is to use package(name:url:from:), is deprecated:

Package.swift:11:10: warning: 'package(name:url:from:)' is deprecated: 
    use package(url:from:) instead
        .package(name: "swift-json", url: "https://github.com/kelvin13/ss-json", from: "0.1.0"),
         ^
4 Likes

The convention was originally intended to identify a package as belonging to Swift, not written in Swift. (But it was never communicated very well and has been widely coā€opted.)

It has been dancing in circles for the last few versions of Swift, due to an initially erroneous implementation and then sideā€effects of the work on the new package identity definition. I am now so confused I can no longer remember either what it does in which release or what it is supposed to do.

  1. Do you mean that there is a definitive bug? Such as:

    • it being impossible to write your manifest without warnings
    • it being impossible to write a single manifest that works across the various platforms and IDEs

    Or do you just not like what said warningā€free manifest looks like?

  2. How would be your preferred way of expressing your manifest (even if it does not work today)?

5 Likes

the problem is that when using the package, you have to write,

    .executableTarget(
            name: "example",
            dependencies: 
            [
                .product(name: "JSON", package: "ss-json"),
            ]),

but the actual name of the package in the Package.swift is swift-json, and this is what people expect to write in the package: field.

the url of the repository is a hosting detail, and should not affect the strings passed to product(name:package:). while moving the GitHub repository is theoretically possible, it would break all incoming links and confuse users.

7 Likes

Your expectation matches the original iteration of SEā€0226 as written. (When it was implemented in Swift 5.2, the target dependency erroneously used the last path component instead, which was fixed in some later version.)

Around the time of SEā€0292, SEā€0226 was amended to eliminate the name attribute, and now you are supposed to specify the identity, which for a URL dependency is the last path component. I do not remember at what version that change was actually made, but it think the implementation does properly distinguish each side of the tools version.

Speaking for myself, I am on the fence about which is better. On the one hand, I prefer the full freedom of the text string over the restrictions of the identifier, but on the other hand, the simplification does result in less parameters. So I ended up not really participating in that review. But with hindsight I can say that the whiplash has been as confusing as it was annoying. And so I cannot imagine myself supporting a proposal to flip it yet again.

1 Like

so, what does all this mean for ss-json? for that matter, what happens if a an established library is discovered to have a naming conflict with another library? politically this would already be a complicated situation even if renaming one of the libraries by changing the Package.swift was an option, now even that potential resolution is off the table.

iā€™ve heard package names being described as a ā€œglobal namespaceā€. if thatā€™s the case, doesnā€™t it make it more important than ever that there are ways to defuse potential conflicts that donā€™t involve forcing one of the packages to migrate to a completely new repository?

If I remember correctly, this was sort of a phase one to break the connection to what is actually in the dependency manifest. The intended eventual phase two was to enable you to christen it whatever you want at the package dependency declaration. The purpose was to solve precisely what you describe. It just has not been particularly pressing, because the module name clashes also needed a solution in order for it to actually be useful. That review just concluded.

1 Like

i just ended up moving the ss-json repository to swift-json, better to get it over with earlyā€¦

Does that all means that package name must be the same as git repository name? (last path component). This is a bit unfortunate. Does it means I can't host more than 1 package in one repo?

The package name does not have to be the same as git repository name. At this point the name argument passed to Package initializer is used only for display purposes.

You can host as many packages in a single repository as you want, but if you're adding that repository as a dependency to some other packages, IIUC you can't directly specify a specific package you depend on in that repository. In that case you'd have to create a "root" package and expose other packages as "subpackages".

Currently this would not be supported for SCM based dependencies, they can only contain a single package at the root.

1 Like

Sorry to ping this old thread, but its right inline with my problems:

Let's say I have a package with "MyFiles" in the name parameter in its Package.swift file. It happens to live in a folder called "MyFiles_2024". FWIW, The package has been git init-ed and has a brach called main, which it didn't actually need to be except to work with SPM.

To include "MyFiles" into a different package living in a neighboring directory locally there are some options:

.package(url:"../MyFiles_2024", branch:"main")
.package(path:"../MyFiles_2024")

which apparently requires the use of .product(name: "MyFiles", package: "MyFiles_2024"), in the target dependencies. Which is sort of workable but hard to discover and confusing because there is no package called "MyFiles_2024" anywhere. It's just not a real thing.

There is also the option to use either:

.package(name: "MyFiles", path: "../MyFiles2024"),
.package(name: "MyFiles", url:"../MyFiles_2024", branch:"main"),

Which means I can go ahead and use .product(name: "MyFiles", package: "MyFiles") in the target dependencies. BUT as pointed out above .package(name:url:XXX) is deprecated so:

- Is it super duper settled that it will not be possible to detach the package name from the URL's final component? can the initializer be de-deprecated?
- Also, to confirm, product(name:url:XXX)/product(url:XXX) seem to expect something like git (or other SP registry server?) at the endpoint and that external-to-swift package server is the ONLY way to specify a version?

I care about the deprecation of the product(name:url:XXX) initializer / restricting it to folders with an endpoint type requirement because packages included with (:path) dependency initializers are not allowed in packages that are they themselves depended on using versioning. I get why, good code hygiene and all, but sometimes you're just trying break up the code into pieces and try some things out. Seems like package(id:) would be the rightful place to be helpfully strict and let (:url) initializers be more permissive?

I re-raise the issue because sometimes it's not just "move the package" solvable. It's more like - "change absolutely everything about the customary workflow in order to use SPM" which is a harder sell.

Anyway, the real answer for this one project might be that git-submodules or symlinks or hand compiling would be a better fit, but those are a whole other layers of shenanigans and will make the code less straightforward to share. TBD. Thank you for reading.

4 Likes