Swift Scripts: Zero to Hero ๐Ÿฆธ๐Ÿผโ€โ™€๏ธ

Swift Scripts: Zero to Heroย ๐Ÿฆธ๐Ÿผโ€โ™€๏ธ

Every iOS/macOS developer uses (scripting) tools such as fastlane and SwiftLint to automate tasks as much as possible: in this talk we will dive into how we can build our own Swift scripts.

This is a technical talk, and presents code to the audience:
many slides will contain code that can be copy-pasted to existing projects, or that can be used as a start for new (scripting) tools.

E35f18d9e5584b48a7cf5550f905522f?s=128

Federico Zanetello

May 19, 2020
Tweet

Transcript

  1. SWIFT SCRIPTS: ZERO TO HERO FEDERICO ZANETELLO ฬฃฬฃฬฃฬฃฬฃ fivestars.blog โ€ข

    @zntfdr
  2. WHY?

  3. GETTING STARTED

  4. hello

  5. CREATING AN EXECUTABLE $ mkdir hello $ cd hello $

    swift package init --type executable
  6. THE PACKAGE STRUCTURE โ”œโ”€โ”€ .gitignore โ”œโ”€โ”€ Package.swift โ”œโ”€โ”€ README.md โ”œโ”€โ”€

    Sources โ”‚ โ””โ”€โ”€ hello โ”‚ โ””โ”€โ”€ main.swift โ””โ”€โ”€ Tests โ”œโ”€โ”€ helloTests โ”‚ โ”œโ”€โ”€ helloTests.swift โ”‚ โ””โ”€โ”€ XCTestManifests.swift โ””โ”€โ”€ LinuxMain.swift
  7. PACKAGE.SWIFT // swift-tools-version:5.2 import PackageDescription let package = Package( name:

    "hello", dependencies: [ ], targets: [ .target( name: "hello", dependencies: []), .testTarget( name: "helloTests", dependencies: ["hello"]), ] )
  8. THE PACKAGE STRUCTURE โ”œโ”€โ”€ .gitignore โ”œโ”€โ”€ Package.swift โ”œโ”€โ”€ README.md โ”œโ”€โ”€

    Sources โ”‚ โ””โ”€โ”€ hello โ”‚ โ””โ”€โ”€ main.swift โ””โ”€โ”€ Tests โ”œโ”€โ”€ helloTests โ”‚ โ”œโ”€โ”€ helloTests.swift โ”‚ โ””โ”€โ”€ XCTestManifests.swift โ””โ”€โ”€ LinuxMain.swift
  9. MAIN.SWIFT print("Hello, world!")

  10. BUILD RUN TEST $ swift build hello $ swift run

    hello $ swift test
  11. BUILD RUN TEST $ swift build hello $ swift run

    hello $ swift test ..OR USE XCODE
  12. WE'RE DONE! !

  13. GUI -> TUI

  14. LAUNCH ARGUMENTS import Foundation // The first argument is the

    script execution path. let arguments = CommandLine.arguments.dropFirst() if let name = arguments.first { print("Hello \(name)") } else { exit(EXIT_FAILURE) } $ swift run hello Federico > Hello Federico
  15. INTERACTIVE import Foundation print("What's your name?") guard let name =

    readLine(), !name.isEmpty else { exit(EXIT_FAILURE) } print("Hello \(name)") $ swift run hello > What's your name? > Federico > Hello Federico
  16. ENVIRONMENT VARIABLES import Foundation let processInfo = ProcessInfo.processInfo let environment

    = processInfo.environment if let name = environment["MYNAME"] { print("Hello \(name)") } else { exit(EXIT_FAILURE) } $ MYNAME=Federico swift run > Hello Federico
  17. PIPELINE MESSAGES import Foundation let standardInput: FileHandle = .standardInput let

    data = standardInput.availableData if let inputString = String( data: data, encoding: .utf8 ) { print("Hello \(inputString)") } else { exit(EXIT_FAILURE) } $ printf Federico | swift run hello > Hello Federico
  18. ARGUMENT PARSER

  19. ADDING A DEPENDENCY let package = Package( name: "hello", dependencies:

    [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.0.1"), ], targets: [ .target( name: "hello", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser") ] ), .testTarget( name: "helloTests", dependencies: ["hello"]), ] )
  20. ARGUMENTPARSER import ArgumentParser struct Hello: ParsableCommand { @Argument(help: "Specify your

    name.") var name: String func run() throws { print("Hello \(name)") } } Hello.main() $ swift run hello Federico > Hello Federico $ swift run hello > Error: Missing expected argument '<name>' > Usage: hello <name> $ swift run hello --help > USAGE: hello <name> > > OPTIONS: > <name> Specify your name. > -h, --help Show help information.
  21. SwiftToolsSupport's TSCUTILITY & TSCBASIC

  22. ADDING A DEPENDENCY 2 let package = Package( name: "hello",

    dependencies: [ .package(url: "https://github.com/apple/swift-tools-support-core.git", from: "0.0.1"), ], targets: [ .target( name: "hello", dependencies: [ .product(name: "SwiftToolsSupport", package: "swift-tools-support-core") ] ), .testTarget( name: "helloTests", dependencies: ["hello"]), ] )
  23. PROGRESS STATE import Foundation import TSCBasic import TSCUtility let animation

    = PercentProgressAnimation( stream: stdoutStream, header: "Loading Greeting") for i in 0..<100 { let second: Double = 1_000_000 usleep(UInt32(second * 0.05)) animation.update(step: i, total: 100, text: "Almost there...") } animation.complete(success: true) print("Hello UIKonf! ! ")
  24. RELEASE

  25. USE THE SCRIPT ANYWHERE $ swift build -c release $

    cp .build/release/hello /usr/local/bin/hello $ hello
  26. WE'RE DONE! *REALLY

  27. LINKS github.com/apple/swift-package-manager github.com/apple/swift-argument-parser github.com/apple/swift-tools-support-core fivestars.blog/ultimate-guide-swift-executables.html github.com/zntfdr/talks

  28. SWIFT SCRIPTS: ZERO TO HERO FEDERICO ZANETELLO ฬฃฬฃฬฃฬฃฬฃ fivestars.blog โ€ข

    @zntfdr