Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Federico Zanetello

May 19, 2020
Tweet

More Decks by Federico Zanetello

Other Decks in Programming

Transcript

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

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

    Sources โ”‚ โ””โ”€โ”€ hello โ”‚ โ””โ”€โ”€ main.swift โ””โ”€โ”€ Tests โ”œโ”€โ”€ helloTests โ”‚ โ”œโ”€โ”€ helloTests.swift โ”‚ โ””โ”€โ”€ XCTestManifests.swift โ””โ”€โ”€ LinuxMain.swift
  3. 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"]), ] )
  4. THE PACKAGE STRUCTURE โ”œโ”€โ”€ .gitignore โ”œโ”€โ”€ Package.swift โ”œโ”€โ”€ README.md โ”œโ”€โ”€

    Sources โ”‚ โ””โ”€โ”€ hello โ”‚ โ””โ”€โ”€ main.swift โ””โ”€โ”€ Tests โ”œโ”€โ”€ helloTests โ”‚ โ”œโ”€โ”€ helloTests.swift โ”‚ โ””โ”€โ”€ XCTestManifests.swift โ””โ”€โ”€ LinuxMain.swift
  5. BUILD RUN TEST $ swift build hello $ swift run

    hello $ swift test ..OR USE XCODE
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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"]), ] )
  11. 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.
  12. 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"]), ] )
  13. 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! ! ")
  14. USE THE SCRIPT ANYWHERE $ swift build -c release $

    cp .build/release/hello /usr/local/bin/hello $ hello