Add Files Resource Synthesizer (#3584)

* Add Add Files Resource Synthesizer

* Update Dependencies.swift and CHANGELOG

Co-authored-by: Pedro Piñera Buendía <pedro@ppinera.es>
This commit is contained in:
Daniel Jankowski 2021-10-22 18:47:59 +02:00 committed by GitHub
parent ffe78a2423
commit 277f1aaee3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 233 additions and 40 deletions

View File

@ -17,8 +17,13 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
- Add support for configuring the `LastUpgradeCheck` of the `Xcode` project [#3561](https://github.com/tuist/tuist/pull/3561) by [@mollyIV](https://github.com/mollyIV)
- Add arbitrarily high `LastUpgradeCheck` to SwiftPackageManager generated projects to disable warnings [#3569](https://github.com/tuist/tuist/pull/3569) by [@danyf90](https://github.com/danyf90)
- Add `isCI` parameter to analytics events [#3568](https://github.com/tuist/tuist/pull/3568) by [@mollyIV](https://github.com/mollyIV)
- Add Add Files Resource Synthesizer [#3584](https://github.com/tuist/tuist/pull/3584) by [@mollyIV](https://github.com/mollyIV)
- Add support for additional files at the target level [#3579](https://github.com/tuist/tuist/pull/3579) by [@danyf90](https://github.com/danyf90)
### Changed
- Perform remote cache download and upload concurrently [#3549](https://github.com/tuist/tuist/pull/3549) by [@danyf90](https://github.com/danyf90)
### Fixed
- Fix target caching resources linking for extensions. They are now considered `runnable` targrts (which they are) [#3570](https://github.com/tuist/tuist/pull/3570) by [@fila95](https://github.com/fila95)

View File

@ -28,13 +28,22 @@
"version": "1.0.2"
}
},
{
"package": "combine-schedulers",
"repositoryURL": "https://github.com/pointfreeco/combine-schedulers",
"state": {
"branch": null,
"revision": "f1250faa1c1436ca83950ce676a4fe97a309a457",
"version": "0.4.1"
}
},
{
"package": "CombineExt",
"repositoryURL": "https://github.com/CombineCommunity/CombineExt.git",
"state": {
"branch": null,
"revision": "0880829102152185190064fd17847a7c681d2127",
"version": "1.5.1"
"revision": "5b8a0c0f178527f9204200505c5fefa6847e528f",
"version": "1.3.0"
}
},
{
@ -51,8 +60,8 @@
"repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git",
"state": {
"branch": null,
"revision": "4b0565384d3c4c588af09e660535b2c7c9bf5b39",
"version": "1.4.2"
"revision": "8d4f6384e0a8cc41f2005247241dd553963a492a",
"version": "1.4.1"
}
},
{
@ -87,8 +96,8 @@
"repositoryURL": "https://github.com/shibapm/Komondor.git",
"state": {
"branch": null,
"revision": "7c3c6040c01c99b83afc7eaa8f2a8a69337f659a",
"version": "1.1.1"
"revision": "855c74f395a4dc9e02828f58d931be6920bcbf6f",
"version": "1.0.6"
}
},
{
@ -96,8 +105,8 @@
"repositoryURL": "https://github.com/shibapm/PackageConfig.git",
"state": {
"branch": null,
"revision": "84d4d70de31a797ca54abee47816cdafba36d290",
"version": "1.0.2"
"revision": "bf90dc69fa0792894b08a0b74cf34029694ae486",
"version": "0.13.0"
}
},
{
@ -123,8 +132,8 @@
"repositoryURL": "https://github.com/ReactiveX/RxSwift.git",
"state": {
"branch": null,
"revision": "cec68169a048a079f461ba203fe85636548d7a89",
"version": "5.1.3"
"revision": "254617dd7fae0c45319ba5fbea435bf4d0e15b5d",
"version": "5.1.2"
}
},
{
@ -168,8 +177,8 @@
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
"state": {
"branch": null,
"revision": "6b2aa2748a7881eebb9f84fb10c01293e15b52ca",
"version": "0.5.0"
"revision": "986d191f94cec88f6350056da59c2e59e83d1229",
"version": "0.4.3"
}
},
{
@ -186,8 +195,8 @@
"repositoryURL": "https://github.com/apple/swift-tools-support-core.git",
"state": {
"branch": null,
"revision": "f9bbd6b80d67408021576adf6247e17c2e957d92",
"version": "0.2.4"
"revision": "ab6339b6a33b69886b3cf2254d3326eddfe58eb0",
"version": "0.2.2"
}
},
{
@ -201,11 +210,11 @@
},
{
"package": "SwiftGen",
"repositoryURL": "https://github.com/fortmarek/SwiftGen",
"repositoryURL": "https://github.com/SwiftGen/SwiftGen",
"state": {
"branch": "stable",
"revision": "4b365316b079c2aeb38396f3294739e7deeee3a5",
"version": null
"branch": null,
"revision": "d498d285867f42ef0c74c5ebd9ddced747831372",
"version": "6.5.1"
}
},
{
@ -217,6 +226,15 @@
"version": "8.5.0"
}
},
{
"package": "xctest-dynamic-overlay",
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state": {
"branch": null,
"revision": "603974e3909ad4b48ba04aad7e0ceee4f077a518",
"version": "0.1.0"
}
},
{
"package": "Yams",
"repositoryURL": "https://github.com/jpsim/Yams.git",

View File

@ -64,7 +64,7 @@ let package = Package(
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMajor(from: "0.4.3")),
.package(url: "https://github.com/maparoni/Zip.git", .revision("059e7346082d02de16220cd79df7db18ddeba8c3")),
.package(url: "https://github.com/tuist/GraphViz.git", .branch("tuist")),
.package(url: "https://github.com/fortmarek/SwiftGen", .branch("stable")),
.package(url: "https://github.com/SwiftGen/SwiftGen", .upToNextMajor(from: "6.5.1")),
.package(url: "https://github.com/SwiftGen/StencilSwiftKit.git", .upToNextMajor(from: "2.8.0")),
.package(url: "https://github.com/FabrizioBrancati/Queuer.git", .upToNextMajor(from: "2.1.1")),
.package(url: "https://github.com/CombineCommunity/CombineExt.git", .upToNextMajor(from: "1.3.0")),

View File

@ -73,6 +73,7 @@ public struct ResourceSynthesizer: Codable, Equatable {
case interfaceBuilder
case json
case yaml
case files
}
/// Default strings synthesizer defined in `Tuist/{ProjectName}` or tuist itself
@ -259,6 +260,30 @@ public struct ResourceSynthesizer: Codable, Equatable {
)
}
/// Files synthesizer defined in a plugin
public static func files(plugin: String, extensions: Set<String>) -> Self {
.files(
templateType: .plugin(
name: plugin,
resourceName: "Files"
),
extensions: extensions
)
}
/// Files synthesizer with a template defined in `Tuist/{ProjectName}`
public static func files(extensions: Set<String>) -> Self {
.files(templateType: .defaultTemplate(resourceName: "Files"), extensions: extensions)
}
private static func files(templateType: TemplateType, extensions: Set<String>) -> Self {
.init(
templateType: templateType,
parser: .files,
extensions: extensions
)
}
/// Custom synthesizer from a plugin
/// - Parameters:
/// - plugin: Name of a plugin where resource synthesizer template is located

View File

@ -195,7 +195,7 @@ public final class SynthesizedResourceInterfaceProjectMapper: ProjectMapping { /
paths = prioritizedPaths + unprioritizedPaths
case .assets, .coreData, .fonts, .interfaceBuilder, .json, .plists, .yaml:
case .assets, .coreData, .fonts, .interfaceBuilder, .json, .plists, .yaml, .files:
break
}
@ -228,6 +228,8 @@ public final class SynthesizedResourceInterfaceProjectMapper: ProjectMapping { /
return SynthesizedResourceInterfaceTemplates.fontsTemplate
case .coreData, .interfaceBuilder, .json, .yaml:
throw SynthesizedResourceInterfaceProjectMapperError.defaultTemplateNotAvailable(parser)
case .files:
return SynthesizedResourceInterfaceTemplates.filesTemplate
}
}
}

View File

@ -0,0 +1,117 @@
// swiftlint:disable line_length
extension SynthesizedResourceInterfaceTemplates {
static let filesTemplate = """
// swiftlint:disable all
// swift-format-ignore-file
// swiftformat:disable all
// Generated using tuist https://github.com/tuist/tuist
{% if groups.count > 0 %}
{% set enumName %}{{param.enumName|default:"Files"}}{% endset %}
{% set useExt %}{% if param.useExtension|default:"true" %}true{% endif %}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set resourceType %}{{param.resourceTypeName|default:"File"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length line_length implicit_return
// MARK: - Files
{% macro groupBlock group %}
{% for file in group.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in group.directories %}
{% call dirBlock dir "" %}
{% endfor %}
{% endmacro %}
{% macro fileBlock file %}
/// {% if file.path and param.preservePath %}{{file.path}}/{% endif %}{{file.name}}{% if file.ext %}.{{file.ext}}{% endif %}
{% set identifier %}{{ file.name }}{% if useExt %}.{{ file.ext }}{% endif %}{% endset %}
{{accessModifier}} static let {{identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{resourceType}}(name: "{{file.name}}", ext: {% if file.ext %}"{{file.ext}}"{% else %}nil{% endif %}, relativePath: "{{file.path if param.preservePath}}", mimeType: "{{file.mimeType}}")
{% endmacro %}
{% macro dirBlock directory parent %}
{% set fullDir %}{{parent}}{{directory.name}}/{% endset %}
/// {{ fullDir }}
{{accessModifier}} enum {{directory.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% for file in directory.files %}
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
{% endfor %}
{% for dir in directory.directories %}
{% filter indent:2 %}{% call dirBlock dir fullDir %}{% endfilter %}
{% endfor %}
}
{% endmacro %}
// swiftlint:disable explicit_type_interface identifier_name
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{{accessModifier}} enum {{enumName}} {
{% if groups.count > 1 or param.forceFileNameEnum %}
{% for group in groups %}
{{accessModifier}} enum {{group.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call groupBlock group %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call groupBlock groups.first %}
{% endif %}
}
// swiftlint:enable explicit_type_interface identifier_name
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
{{accessModifier}} struct {{resourceType}} {
{{accessModifier}} let name: String
{{accessModifier}} let ext: String?
{{accessModifier}} let relativePath: String
{{accessModifier}} let mimeType: String
{{accessModifier}} var url: URL {
return url(locale: nil)
}
{{accessModifier}} func url(locale: Locale?) -> URL {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
let url = bundle.url(
forResource: name,
withExtension: ext,
subdirectory: relativePath,
localization: locale?.identifier
)
guard let result = url else {
let file = name + (ext.flatMap { "." + $0 } ?? "")
fatalError("Could not locate file named" + file)
}
return result
}
{{accessModifier}} var path: String {
return path(locale: nil)
}
{{accessModifier}} func path(locale: Locale?) -> String {
return url(locale: locale).path
}
}
{% if not param.bundle %}
// swiftlint:disable convenience_type explicit_type_interface
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type explicit_type_interface
{% endif %}
{% else %}
// No files found
{% endif %}
// swiftlint:enable all
// swiftformat:enable all
"""
}

View File

@ -60,6 +60,8 @@ final class SynthesizedResourceInterfacesGenerator: SynthesizedResourceInterface
return try JSON.Parser()
case .yaml:
return try Yaml.Parser()
case .files:
return try Files.Parser()
}
}
}

View File

@ -20,6 +20,7 @@ public struct ResourceSynthesizer: Equatable, Hashable, Codable {
case interfaceBuilder
case json
case yaml
case files
}
public init(

View File

@ -57,6 +57,8 @@ extension TuistGraph.ResourceSynthesizer.Parser {
return .json
case .yaml:
return .yaml
case .files:
return .files
}
}
}

View File

@ -19,7 +19,7 @@ let dependencies = Dependencies(
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.4.1")),
.package(url: "https://github.com/tuist/GraphViz.git", .branch("tuist")),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMajor(from: "0.4.3")),
.package(url: "https://github.com/fortmarek/SwiftGen", .branch("stable")),
.package(url: "https://github.com/SwiftGen/SwiftGen", .upToNextMajor(from: "6.5.1")),
.package(url: "https://github.com/kylef/PathKit.git", .upToNextMajor(from: "1.0.0")),
],
deploymentTargets: [.macOS(targetVersion: "10.15")]

View File

@ -28,13 +28,22 @@
"version": "1.0.2"
}
},
{
"package": "combine-schedulers",
"repositoryURL": "https://github.com/pointfreeco/combine-schedulers",
"state": {
"branch": null,
"revision": "f1250faa1c1436ca83950ce676a4fe97a309a457",
"version": "0.4.1"
}
},
{
"package": "CombineExt",
"repositoryURL": "https://github.com/CombineCommunity/CombineExt.git",
"state": {
"branch": null,
"revision": "0880829102152185190064fd17847a7c681d2127",
"version": "1.5.1"
"revision": "5b8a0c0f178527f9204200505c5fefa6847e528f",
"version": "1.3.0"
}
},
{
@ -51,8 +60,8 @@
"repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git",
"state": {
"branch": null,
"revision": "4b0565384d3c4c588af09e660535b2c7c9bf5b39",
"version": "1.4.2"
"revision": "8d4f6384e0a8cc41f2005247241dd553963a492a",
"version": "1.4.1"
}
},
{
@ -87,8 +96,8 @@
"repositoryURL": "https://github.com/shibapm/Komondor.git",
"state": {
"branch": null,
"revision": "7c3c6040c01c99b83afc7eaa8f2a8a69337f659a",
"version": "1.1.1"
"revision": "855c74f395a4dc9e02828f58d931be6920bcbf6f",
"version": "1.0.6"
}
},
{
@ -96,8 +105,8 @@
"repositoryURL": "https://github.com/shibapm/PackageConfig.git",
"state": {
"branch": null,
"revision": "84d4d70de31a797ca54abee47816cdafba36d290",
"version": "1.0.2"
"revision": "bf90dc69fa0792894b08a0b74cf34029694ae486",
"version": "0.13.0"
}
},
{
@ -123,8 +132,8 @@
"repositoryURL": "https://github.com/ReactiveX/RxSwift.git",
"state": {
"branch": null,
"revision": "cec68169a048a079f461ba203fe85636548d7a89",
"version": "5.1.3"
"revision": "254617dd7fae0c45319ba5fbea435bf4d0e15b5d",
"version": "5.1.2"
}
},
{
@ -168,8 +177,8 @@
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
"state": {
"branch": null,
"revision": "6b2aa2748a7881eebb9f84fb10c01293e15b52ca",
"version": "0.5.0"
"revision": "986d191f94cec88f6350056da59c2e59e83d1229",
"version": "0.4.3"
}
},
{
@ -186,8 +195,8 @@
"repositoryURL": "https://github.com/apple/swift-tools-support-core.git",
"state": {
"branch": null,
"revision": "f9bbd6b80d67408021576adf6247e17c2e957d92",
"version": "0.2.4"
"revision": "ab6339b6a33b69886b3cf2254d3326eddfe58eb0",
"version": "0.2.2"
}
},
{
@ -201,11 +210,11 @@
},
{
"package": "SwiftGen",
"repositoryURL": "https://github.com/fortmarek/SwiftGen",
"repositoryURL": "https://github.com/SwiftGen/SwiftGen",
"state": {
"branch": "stable",
"revision": "4b365316b079c2aeb38396f3294739e7deeee3a5",
"version": null
"branch": null,
"revision": "d498d285867f42ef0c74c5ebd9ddced747831372",
"version": "6.5.1"
}
},
{
@ -217,6 +226,15 @@
"version": "8.5.0"
}
},
{
"package": "xctest-dynamic-overlay",
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state": {
"branch": null,
"revision": "603974e3909ad4b48ba04aad7e0ceee4f077a518",
"version": "0.1.0"
}
},
{
"package": "Yams",
"repositoryURL": "https://github.com/jpsim/Yams.git",

View File

@ -61,6 +61,7 @@ Currently, tuist has templates for these types of resources with the following i
- Strings {TargetName}Assets `Strings+{TargetName}.swift`
- Plists {NameOfPlist} `{NameOfPlist}.swift`
- Fonts `Fonts+{TargetName}.swift`
- Files `Files+{TargetName}.swift`
So, for example if you have a target `MyFramework` with the following resources:
@ -102,8 +103,9 @@ That means:
- `interfaceBuilder`
- `json`
- `yaml`
- `files`
For `strings`, `plists`, `fonts`, and `assets` there are templates offered by tuist, to initialize eg. strings resource synthesizer (as described above):
For `strings`, `plists`, `fonts`, `assets` and `files` there are templates offered by tuist, to initialize eg. strings resource synthesizer (as described above):
```swift
.strings()
@ -123,6 +125,7 @@ You can also use a local template. Just add it to `Tuist/ResourceSynthesizers/{n
- `interfaceBuilder` => `InterfaceBuilder.stencil`
- `json` => `JSON.stencil`
- `yaml` => `YAML.stencil`
- `files` => `Files.stencil`
If a plugin offers a resource synthesizer template, you can also do: