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: add support for Swift package registries #1318

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

luispadron
Copy link
Collaborator

@luispadron luispadron commented Oct 30, 2024

Fixes #1016

This adds initial support for consuming packages using a Swift Package Registry.

The majority of the changes are in the new registry_swift_package rule which creates a repository to build the targets from a package downloaded via a registry.

Notably, because the identity of the package is used to derive the repository name, packages used via a registry have the following label: @swiftpkg_[org].[name], so for example @swiftpkg_swift_collections becomes @swiftpkg_apple.swift_collections if using the swift-collections package from the apple organization (as registries support multiple orgs).

The registry_swift_package rule is mostly just an updated version of #1043 (thanks @watt)

Open questions

  • Should the label replace . with _ in identity? E.g. @swiftpkg_apple.swift_collections vs. @swiftpkg_apple_swift_collections: NO

Follow-up

  • rule_swift_package_manager already has a bootstrapping issue, if there is no Package.resolved defined already then the Bazel repositories fail to generate. The addition of registry support adds another bootstrapping issue with the registries.json file (users will need to run swift package-registry commands to create it currently). We should address both of these by making bootstrapping a new project easier.

Caveats


Example

The following shows an example of a swift_binary target depending on an SPM dependency downloaded from a registry defined in registries.json.

Package.swift

let package = Package(
    name: "swift_package_registry_example",
    dependencies: [
        .package(id: "apple.swift-collections", exact: "1.1.3"),
    ]
)

Package.resolved

{
  "pins" : [
    {
      "identity" : "apple.swift-collections",
      "kind" : "registry",
      "location" : "",
      "state" : {
        "version" : "1.1.3"
      }
    }
  ],
  "version" : 2
}

registries.json

{
  "authentication" : {

  },
  "registries" : {
    "[default]" : {
      "supportsAvailability" : false,
      "url" : "https://fake-spm-registry.deno.dev/"
    }
  },
  "version" : 1
}

MODULE.bazel

swift_deps = use_extension(
    "@rules_swift_package_manager//:extensions.bzl",
    "swift_deps",
)
swift_deps.from_package(
    registries = "//:registries.json",
    resolved = "//:Package.resolved",
    swift = "//:Package.swift",
)
swift_deps.configure_swift_package(
    replace_scm_with_registry = True,
)
use_repo(
    swift_deps,
    "swift_package",
    "swiftpkg_apple.swift_collections",
)

BUILD.bazel

swift_binary(
    name = "swift_package_registry_example",
    srcs = ["main.swift"],
    module_name = "swift_package_registry_example",
    visibility = ["//visibility:public"],
    deps = ["@swiftpkg_apple.swift_collections//:Collections"],
)

@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 2 times, most recently from a5adfda to 6739de1 Compare October 30, 2024 17:08
@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 4 times, most recently from 452f05d to ad96158 Compare November 5, 2024 07:15
@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 2 times, most recently from 671c25d to f921aba Compare November 12, 2024 02:41
@luispadron luispadron marked this pull request as ready for review November 12, 2024 02:49
@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 3 times, most recently from a541b18 to 9838fcd Compare November 12, 2024 04:50
@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 4 times, most recently from 3d7452d to 01abd62 Compare November 12, 2024 16:45
@luispadron
Copy link
Collaborator Author

luispadron commented Nov 12, 2024

Im testing in a real registry implementation now and realizing some issues, going to make some updates but the majority of the design is ready for review

@brentleyjones
Copy link
Collaborator

We should address both of these by making bootstrapping a new project easier.

💯 (as a follow-up).

@brentleyjones
Copy link
Collaborator

I can maintain the fake, read-only registry until we have an alternative or it somehow starts costing me too much money

Can we spin up a local webserver as part of CI instead?

@cgrindel
Copy link
Owner

Should the label replace . with _ in identity? E.g. @swiftpkg_apple.swift_collections vs. @swiftpkg_apple_swift_collections

I like the underscores version. However, it is not a strong preference.

@cgrindel
Copy link
Owner

I can maintain the fake, read-only registry until we have an alternative or it somehow starts costing me too much money
Can we spin up a local webserver as part of CI instead?

+1 to @brentleyjones suggestion. Again, I am not too familiar with Swift registry hosting. If it is static, can we use GitHub to host it? I presume the functionality just needs a URL.

@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch from 01abd62 to 2a46f9e Compare November 12, 2024 18:17
@luispadron
Copy link
Collaborator Author

I can maintain the fake, read-only registry until we have an alternative or it somehow starts costing me too much money

Can we spin up a local webserver as part of CI instead?

I tried this originally but local host doesn't support https and so the bazel download stuff fails because of insecure connection.

@luispadron
Copy link
Collaborator Author

I can maintain the fake, read-only registry until we have an alternative or it somehow starts costing me too much money

Can we spin up a local webserver as part of CI instead?

+1 to @brentleyjones suggestion. Again, I am not too familiar with Swift registry hosting. If it is static, can we use GitHub to host it? I presume the functionality just needs a URL.

It is not static, it needs to be a web server which follows the registry spec.

@luispadron
Copy link
Collaborator Author

Im testing in a real registry implementation now and realizing some issues, going to make some updates but the majority of the design is ready for review

Done! I fixed my fake registry implementation, the .zip needed to contain a single directory named scope.name where i had name-version

@cgrindel
Copy link
Owner

@luispadron When you are ready to merge, if you don't want to babysit the merge, you can specify @mergifyio queue in a comment. This will add it to the merge queue that we are using.

@luispadron
Copy link
Collaborator Author

Should the label replace . with _ in identity? E.g. @swiftpkg_apple.swift_collections vs. @swiftpkg_apple_swift_collections

I think the answer is here is: no? Thoughts? Doing the replacement would require manipulating the identity in a fair amount of the rules and im not sure it gives us much (plus the label is still different than non registry so we don't gain anything from doing the replacement)

Copy link
Contributor

@watt watt left a comment

Choose a reason for hiding this comment

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

🎉

swiftpkg/internal/registry_swift_package.bzl Outdated Show resolved Hide resolved
swiftpkg/internal/registry_swift_package.bzl Show resolved Hide resolved
swiftpkg/internal/registry_swift_package.bzl Outdated Show resolved Hide resolved
swiftpkg/internal/swift_package_tool_attrs.bzl Outdated Show resolved Hide resolved
swiftpkg/internal/swift_package_tool_attrs.bzl Outdated Show resolved Hide resolved
swiftpkg/internal/swift_package_tool_runner_template.sh Outdated Show resolved Hide resolved
@brentleyjones
Copy link
Collaborator

I think the answer is here is: no?

Yeah, let's not do the replacement.

@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 3 times, most recently from 24c49a6 to 7ef0ec4 Compare November 24, 2024 23:35
@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch 4 times, most recently from 0aebb42 to 00897e2 Compare December 9, 2024 16:03
@luispadron
Copy link
Collaborator Author

@cgrindel @watt @brentleyjones The PR has been updated, I believe I have addressed all comments here if folks want to give it another review. The biggest change was proper support for replace_scm_with_registry.

I also added a doc on using Swift package registries over here

@luispadron luispadron force-pushed the luis/add-swift-package-registry-support branch from 00897e2 to bc773b3 Compare December 11, 2024 05:55
@brentleyjones
Copy link
Collaborator

Firebase failure is unrelated to this change (cc: @cgrindel).

@cgrindel
Copy link
Owner

Firebase failure is unrelated to this change (cc: @cgrindel).

@brentleyjones That is a weird error. Is this an issue in rules_xcodeproj?

@brentleyjones
Copy link
Collaborator

Yes. Seems that rules_xcodeproj doesn't support Bazel 8 yet, in particular it looks like the change from ~ to + in Bzlmod labels.

Copy link
Owner

@cgrindel cgrindel left a comment

Choose a reason for hiding this comment

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

Overall, LGTM. Most of my comments are related to formatting (e.g., line length).

@@ -196,10 +206,23 @@ def _declare_pkg_from_dependency(dep, config_pkg):
dependencies_index = None,
)

elif dep.registry:
resolved = from_package.resolved if from_package else None
replace_scm_with_registry = config_swift_package.replace_scm_with_registry if config_swift_package else False
Copy link
Owner

Choose a reason for hiding this comment

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

Can we format for line length?

config_swift_package = config_swift_package
for config_swift_package_tag in mod.tags.configure_swift_package:
if config_swift_package:
fail("Expected only one `configure_swift_package` tag, but found multiple.")
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
fail("Expected only one `configure_swift_package` tag, but found multiple.")
fail("""\
Expected only one `configure_swift_package` tag, but found multiple.\
""")

@@ -499,7 +519,7 @@ def _new_dependency_identity_to_name_map(dump_deps):
result = {}
for dep in dump_deps:
identity_provider_list = (
dep.get("sourceControl") or dep.get("fileSystem")
dep.get("sourceControl") or dep.get("fileSystem") or dep.get("registry")
Copy link
Owner

Choose a reason for hiding this comment

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

Line length.

@@ -703,7 +723,7 @@ def _new_platform(name, version):

# MARK: - External Dependency

def _new_dependency(identity, name, source_control = None, file_system = None):
def _new_dependency(identity, name, source_control = None, file_system = None, registry = None):
Copy link
Owner

Choose a reason for hiding this comment

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

Line length.

Comment on lines +90 to +92
# NOTE: because the Swift Package Registry spec does not define the allowable prefixes within the archive,
# we cannot rely on Bazel's `stripPrefix` feature to strip the parent directory reliably.
# Instead, we'll download and extract to a temporary location and then move the contents to the output.
Copy link
Owner

Choose a reason for hiding this comment

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

Line length

# Instead, we'll download and extract to a temporary location and then move the contents to the output.
download_output = "{output}/download".format(output = output)

# NOTE: this requires Bazel 7.1 or later to use `headers` which must be set to reach this endpoint.
Copy link
Owner

Choose a reason for hiding this comment

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

Please check the line length for this entire file.

template_dict.add("%(enable_build_manifest_caching)s", "true" if ctx.attr.manifest_caching else "false")
template_dict.add("%(enable_dependency_cache)s", "true" if ctx.attr.dependency_caching else "false")
template_dict.add("%(manifest_cache)s", ctx.attr.manifest_cache)
template_dict.add("%(registries_json)s", registries.short_path if registries else "")
template_dict.add("%(replace_scm_with_registry)s", "true" if ctx.attr.replace_scm_with_registry else "false")
Copy link
Owner

Choose a reason for hiding this comment

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

Line length.


_swift_package_tool_config_attrs = {
"build_path": attr.string(
doc = "The relative path within the runfiles tree for the Swift Package Manager build directory.",
Copy link
Owner

Choose a reason for hiding this comment

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

Please check the line length for this file.

@cgrindel
Copy link
Owner

Yes. Seems that rules_xcodeproj doesn't support Bazel 8 yet, in particular it looks like the change from ~ to + in Bzlmod labels.

Something is wrong. The .bazelversion for the repo is set to 7.4.1. 🤔 This seems to suggest that rules_bazel_integration_test is not using the correct version information.

Copy link
Contributor

@watt watt left a comment

Choose a reason for hiding this comment

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

I attempted to test this locally with a Package.swift that has a dependency graph requiring the SCM replacement, and it didn't seem to work for me unfortunately. Haven't dug into exactly where it failed yet.


return source_archive.get("checksum")

def _get_resolved_pin_for_url(*, registry_url, repository_ctx, resolved_pkg_map, url):
Copy link
Contributor

Choose a reason for hiding this comment

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

Could there be a layer of caching in here somewhere, to avoid hitting the registry multiple times for the same URL?

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you want to mention the Bazel 7 requirement in this file?

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.

Swift registry support
4 participants