Swift Package Pluginワークショップ

Swift Package Pluginワークショップ

More Decks by giginet

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • @giginet • LINEגࣜձࣾ σΟϕϩούʔΤΫεϖ ϦΤϯε։ൃνʔϜ • Core Contributor

    of Carthage/fastlane/ XcodeGen etc... • h=ps:/ /github.com/giginet • h=ps:/ /twi=er.com/giginet • ؾܰʹmenBon͍ͯͩ͘͠͞ʂ 2/45
  2. Swi$ Packageͷ࡞੒ $ mkdir MyUsefulTools $ cd MyUsefulTools $ swift

    package init Creating library package: MyUsefulTools Creating Package.swift Creating README.md Creating .gitignore Creating Sources/ Creating Sources/MyUsefulTools/MyUsefulTools.swift Creating Tests/ Creating Tests/MyUsefulToolsTests/ Creating Tests/MyUsefulToolsTests/MyUsefulToolsTests.swift 8/45
  3. Package.swi+ // swift-tools-version: 5.7 // The swift-tools-version declares the minimum

    version of Swift required to build this package. import PackageDescription let package = Package( name: "MyUsefulTools", products: [ .executable(name: "greeting", targets: ["greeting"]), ], dependencies: [], targets: [ .executableTarget(name: "greeting"), ] ) 10/45
  4. σΟϨΫτϦߏ੒ . ├── Package.swift ├── README.md ├── Sources │ └──

    greeting │ └── main.swift └── Tests └── greetingTests └── CommandTests.swift 11/45
  5. σΟϨΫτϦߏ੒ . ├── Package.swift ├── README.md ├── Sources │ └──

    greeting │ └── main.swift └── Tests └── greetingTests └── CommandTests.swift 11/45
  6. import Foundation let arguments = ProcessInfo.processInfo.arguments guard let name =

    arguments.last, arguments.count >= 2 else { fatalError("name is required") } print("Hello \(name)!") 12/45
  7. Package Pluginͷ෼ྨ • Command Plugin (SE-0332) • Build Tool Plugin

    (SE-0303) • Prebuild Command • Build Command 15/45
  8. ࡞ྫɿgiginet/Milepost • h#ps:/ /github.com/giginet/Milepost • GitͷϦϏδϣϯΛ؆୯ʹΞϓϦʹຒΊ ࠐΉBuild Tool Plugin •

    Ϗϧυ࣌ʹgitίϚϯυΛ࣮ߦͯ͠ revisionͳͲΛऔಘ • BundleʹϦϏδϣϯΛؚΜͩplistΛ ੜ੒ɺσίʔυͯ͠දࣔ 21/45
  9. Milepost import PackageDescription let package = Package( name: "Milepost", targets:

    [ .target( name: "Milepost" ), .plugin( name: "PrepareMilepost", capability: .buildTool(), dependencies: ["bundle-generator"] ), .executableTarget( name: "bundle-generator", dependencies: [ .target(name: "Milepost"), ] ), ] ) 22/45
  10. Milepost import PackageDescription let package = Package( name: "Milepost", targets:

    [ .target( name: "Milepost" ), .plugin( name: "PrepareMilepost", capability: .buildTool(), dependencies: ["bundle-generator"] ), .executableTarget( name: "bundle-generator", dependencies: [ .target(name: "Milepost"), ] ), ] ) 22/45
  11. Milepost import PackageDescription let package = Package( name: "Milepost", targets:

    [ .target( name: "Milepost" ), .plugin( name: "PrepareMilepost", capability: .buildTool(), dependencies: ["bundle-generator"] ), .executableTarget( name: "bundle-generator", dependencies: [ .target(name: "Milepost"), ] ), ] ) 22/45
  12. ࢀߟ • Meet Swi) Package Plugins • h4ps:/ /developer.apple.com/videos/play/wwdc2022/110359/ •

    Create Swi) Package Plugins • h4ps:/ /developer.apple.com/videos/play/wwdc2022/110401 23/45
  13. Package.swi+ // swift-tools-version: 5.7 // The swift-tools-version declares the minimum

    version of Swift required to build this package. import PackageDescription let package = Package( name: "MyUsefulTools", products: [], dependencies: [], targets: [ .plugin( name: "CommandPlugin", capability: .command( intent: .custom(verb: "Run Something", description: "This is a sample command!"), permissions: [.writeToPackageDirectory(reason: "testing")] ) ) ] ) 25/45
  14. σΟϨΫτϦߏ੒ . ├── Package.swift ├── Plugins │ └── MyCommand │

    └── Command.swift ├── README.md ├── Sources │ └── greeting │ └── main.swift └── Tests └── greetingTests └── CommandTests.swift 26/45
  15. ࡞ͬͨϓϥάΠϯΛϓϩδΣΫτʹೖΕΔ 1. ௨ৗ௨ΓXcode ProjectΛ࡞੒ iOS > Swi2UI AppͳͲ 2. General

    > Package Dependencies > Add Local... 3. PackageͷϑΥϧμΛ௥Ճ ͜ΕͰ௚઀ΞϓϦଆͷXcodeϓϩδΣΫτ͔ΒϓϥάΠϯ΋ฤू͠ ͯσόοάͰ͖Δ 27/45
  16. Command PluginͷॲཧΛ࣮૷ import PackagePlugin import Foundation @main struct MyCommand: CommandPlugin

    { func performCommand(context: PluginContext, arguments: [String]) async throws { // (ry } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension MyCommand: XcodeCommandPlugin { func performCommand(context: XcodePluginContext, arguments: [String]) throws { let path = context.xcodeProject.directory.appending("hello.txt") let data = "hello".data(using: .utf8) FileManager.default.createFile(atPath: path.string, contents: data) } } #endif 28/45
  17. import ArgumentParser @main struct Repeat: ParsableCommand { @Flag(help: "Include a

    counter with each repetition.") var includeCounter = false @Option(name: .shortAndLong, help: "The number of times to repeat 'phrase'.") var count: Int? @Argument(help: "The phrase to repeat.") var phrase: String mutating func run() throws { let repeatCount = count ?? 2 for i in 1...repeatCount { if includeCounter { print("\(i): \(phrase)") } else { print(phrase) } } } } 33/45