-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Basics: support multiple formats with a single archiver #6369
Conversation
`swift experimental-destination install` subcommand fails when pointed to a destination bundle compressed with `.tar.gz` extension, compressed with tar and gzip. This archival format is vastly superior to zip in the context of cross-compilation destination bundles. In our typical scenario we see that `.tar.gz` archives are at least 4x better than `.zip`.
|
||
var description: String { | ||
switch self { | ||
case .unknownFormat(let ext, let path): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not consider using magic? https://github.com/file/file/tree/ec41083645689a787cdd00cb3b5bf578aa79e46c should be possible to use on Windows even.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we assume it's installed on Windows? It doesn't seem to be installed on swift
Docker images for Ubuntu, so adding a dependency on it will require updating Dockerfile
s in the swift-docker
repository. This isn't supposed to be an incredibly resilient algorithm, but something that we can still land in 5.9 I hope. So distinguishing by extension should be good enough for now, and we can consider adding support for magic format detection later.
Sources/Basics/Archiver+Zip.swift
Outdated
@@ -14,7 +14,7 @@ import TSCBasic | |||
import Dispatch | |||
|
|||
/// An `Archiver` that handles ZIP archives using the command-line `zip` and `unzip` tools. | |||
public struct ZipArchiver: Archiver, Cancellable { | |||
public final class ZipArchiver: Archiver, Cancellable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ideally this remains a struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in the base TarArchiver
PR, both FileSystem
and Cancellator
are reference types, and Cancellator
in particular holds mutable state, which transitively makes ZipArchiver
stateful.
|
||
private let formatMapping: [String: any Archiver] | ||
|
||
public init(_ archivers: [any Archiver]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not convinced about this API. the client should not care to initialize the "multiplexing" archiver with concrete archivers. Instead, an API that takes the desired "extensions" or "archiveTypes" (enum) and then creates the concrete instances seems a more intent based API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the archivers used by this new archiver are an implementation detail, wouldn't an enum for archive types be a premature generalization? I've changed it to take only any FileSystem
and Cancellator
to initialize instances of ZipArchiver
and TarArchiver
, like you suggested. Would that be ok for this initial implementation?
throw Error.noFileNameExtension(archivePath) | ||
} | ||
|
||
var extensions = String(filename[firstDot ..< filename.endIndex]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dont we have an API to extract the extension from a path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in a comment above on the line 53, that AbsolutePath
API doesn't support stacked extensions, it returns just gz
for .tar.gz
archives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll expand the comment to mention the behavior explicitly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add an API that can return multiple extensions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exactly ^^ we can add that to basics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense, added in the latest commit
0592ba4
to
cc88808
Compare
|
||
/// An `Archiver` that handles multiple formats by delegating to other existing archivers each dedicated to its own | ||
/// format. | ||
public final class UniversalArchiver: Archiver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be a value type
self.supportedExtensions = supportedExtensions | ||
} | ||
|
||
private func archiver(for archivePath: AbsolutePath) throws -> any Archiver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
@@ -14,7 +14,7 @@ import TSCBasic | |||
import Dispatch | |||
|
|||
/// An `Archiver` that handles ZIP archives using the command-line `zip` and `unzip` tools. | |||
public struct ZipArchiver: Archiver, Cancellable { | |||
public final class ZipArchiver: Archiver, Cancellable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think this change is necessary
844994c
to
d34bb91
Compare
Added `MultiFormatArchiver` that can handle multiple formats by delegating to other archivers it was initialized with. Since most uses of `Archiver` are either generic or take an existential, this allows us to pass `MultiFormatArchiver` that previously supported only a single archive format. rdar://107485048 # Conflicts: # Sources/Basics/MultiFormatArchiver.swift
d34bb91
to
00fb477
Compare
…xd/multi-format-archiver # Conflicts: # Sources/Basics/CMakeLists.txt # Tests/BasicsTests/Archiver/Inputs/archive.tar.gz # Tests/BasicsTests/Archiver/Inputs/invalid_archive.tar.gz
@swift-ci smoke test |
@swift-ci smoke test |
@swift-ci test windows |
@swift-ci smoke test macos |
@swift-ci test windows |
@swift-ci smoke test macos |
In certain function signatures only a single archiver instance can be taken as an argument. We need to support multiple archive formats, such as `.zip` and `.tar.gz`, for example in cross-compilation destination bundles. Instead of updating those functions to take multiple archivers, creating a single type that can support multiple formats would be a better solution. Added `MultiFormatArchiver` that can handle multiple formats by delegating to other archivers it was initialized with. Since most uses of `Archiver` are either generic or take an existential, this allows us to pass `MultiFormatArchiver` to functions that previously supported only a single archive format. This is technically NFC as `MultiFormatArchiver` is not used anywhere yet. rdar://107485048
Motivation:
In certain function signatures only a single archiver instance can be taken as an argument. We need to support multiple archive formats, such as
.zip
and.tar.gz
, for example in cross-compilation destination bundles. Instead of updating those functions to take multiple archivers, creating a single type that can support multiple formats would be a better solution.Modifications:
Added
MultiFormatArchiver
that can handle multiple formats by delegating to other archivers it was initialized with. Since most uses ofArchiver
are either generic or take an existential, this allows us to passMultiFormatArchiver
to functions that previously supported only a single archive format.rdar://107485048
Results
This is technically NFC as
MultiFormatArchiver
is not used anywhere yet.