Convert Figma logo to code with AI

mxcl logoswift-sh

Easily script with third-party Swift dependencies.

1,799
59
1,799
21

Top Related Projects

[DEPRECATED] Marathon makes it easy to write, run and manage your Swift scripts 🏃

2,313

A package manager that installs and runs executable Swift packages

14,957

A simple, decentralized dependency manager for Cocoa

The Package Manager for the Swift Programming Language

Quick Overview

swift-sh is a tool that allows you to run Swift scripts with third-party dependencies. It provides a simple way to execute Swift code with external libraries without the need for a full Xcode project or package manager setup. This makes it ideal for quick prototyping, scripting, and small-scale development tasks.

Pros

  • Easy to use: Quickly run Swift scripts with dependencies using a simple shebang line
  • No project setup required: Eliminates the need for creating a full Swift package or Xcode project
  • Supports various package managers: Works with Swift Package Manager, CocoaPods, and Carthage
  • Caches dependencies: Improves performance by reusing previously downloaded packages

Cons

  • Limited to command-line applications: Not suitable for developing full-fledged iOS or macOS apps
  • Potential security risks: Running scripts with dependencies from untrusted sources may pose security concerns
  • May not support all package configurations: Complex dependency setups might require a traditional Swift package

Code Examples

  1. Basic usage with a single dependency:
#!/usr/bin/swift sh
import Foundation
import Alamofire // @Alamofire ~> 5.0

Alamofire.request("https://httpbin.org/get").responseJSON { response in
    print(response)
}
  1. Using multiple dependencies:
#!/usr/bin/swift sh
import Foundation
import Alamofire // @Alamofire ~> 5.0
import SwiftyJSON // @SwiftyJSON ~> 4.0

Alamofire.request("https://api.example.com/data").responseJSON { response in
    if let data = response.data {
        let json = JSON(data)
        print(json["key"].stringValue)
    }
}
  1. Specifying a GitHub repository as a dependency:
#!/usr/bin/swift sh
import Foundation
import Rainbow // @onevcat/Rainbow

print("Hello".red.bold)
print("World".blue.underline)

Getting Started

  1. Install swift-sh:

    brew install mxcl/made/swift-sh
    
  2. Create a new Swift script file (e.g., script.swift) and add the shebang line:

    #!/usr/bin/swift sh
    
  3. Import dependencies using comments:

    import Dependency // @author/repo ~> 1.0
    
  4. Make the script executable and run it:

    chmod +x script.swift
    ./script.swift
    

Competitor Comparisons

[DEPRECATED] Marathon makes it easy to write, run and manage your Swift scripts 🏃

Pros of Marathon

  • More feature-rich, offering advanced functionality like dependency management and script packaging
  • Supports running scripts from various sources (local files, URLs, GitHub gists)
  • Provides a command-line interface for easier script management

Cons of Marathon

  • Larger and more complex project, potentially harder to set up and use for simple tasks
  • Less frequently updated compared to swift-sh
  • Requires more setup and configuration for basic script execution

Code Comparison

Marathon:

import Marathon
import Foundation

Marathon.run { context in
    print("Hello, World!")
}

swift-sh:

#!/usr/bin/swift sh
import Foundation

print("Hello, World!")

Both projects aim to simplify Swift scripting, but they take different approaches. swift-sh focuses on simplicity and ease of use, allowing users to quickly write and run Swift scripts with minimal setup. It's lightweight and frequently updated.

Marathon, on the other hand, offers a more comprehensive solution with additional features like dependency management and script packaging. It's better suited for more complex scripting tasks but requires more setup and configuration.

The choice between the two depends on the user's needs: swift-sh for quick, simple scripts, or Marathon for more advanced scripting projects with additional functionality.

2,313

A package manager that installs and runs executable Swift packages

Pros of Mint

  • Supports installation and running of Swift command-line tools from various sources (GitHub, GitLab, etc.)
  • Provides version management for installed packages
  • Allows global installation of packages for system-wide use

Cons of Mint

  • Requires explicit installation and management of packages
  • May have a steeper learning curve for beginners
  • Focuses on package management rather than direct script execution

Code Comparison

Mint:

mint run realm/SwiftLint
mint install JohnSundell/Marathon

swift-sh:

#!/usr/bin/swift sh
import Foundation
import PromiseKit // @mxcl ~> 6.5
print(Promise.value("Hello, World!"))

Key Differences

  • swift-sh is designed for running Swift scripts with dependencies directly, while Mint focuses on managing and running Swift packages as command-line tools
  • swift-sh uses inline import statements to specify dependencies, whereas Mint requires separate installation and run commands
  • Mint provides more robust package management features, while swift-sh offers a simpler, more streamlined approach for script execution

Both tools serve different purposes within the Swift ecosystem, with swift-sh being more suitable for quick scripts and prototyping, and Mint being better for managing and running multiple Swift command-line tools across projects.

14,957

A simple, decentralized dependency manager for Cocoa

Pros of Carthage

  • Supports multiple platforms (iOS, macOS, tvOS, watchOS)
  • Allows for version pinning and dependency resolution
  • Integrates well with Xcode projects

Cons of Carthage

  • Requires manual framework linking in Xcode
  • Longer build times compared to Swift-sh
  • More complex setup and configuration process

Code Comparison

Swift-sh:

#!/usr/bin/swift sh
import Foundation
import Alamofire // @Alamofire ~> 5.0
print(Alamofire.AF.session)

Carthage:

# Cartfile
github "Alamofire/Alamofire" ~> 5.0
// In your Swift file
import Alamofire
print(Alamofire.AF.session)

Key Differences

  • Swift-sh is designed for quick scripts and prototyping, while Carthage is for larger project dependency management
  • Swift-sh allows inline dependency specification, whereas Carthage uses a separate Cartfile
  • Carthage builds frameworks, while Swift-sh directly imports dependencies into scripts
  • Swift-sh is more lightweight and requires less setup, but Carthage offers more robust dependency management for complex projects

Use Cases

Swift-sh is ideal for:

  • Quick scripts and prototypes
  • Command-line tools
  • Simple projects with few dependencies

Carthage is better suited for:

  • Large-scale iOS/macOS applications
  • Projects with complex dependency graphs
  • Teams requiring strict version control of dependencies

The Package Manager for the Swift Programming Language

Pros of Swift Package Manager

  • Official Apple-supported tool for managing Swift dependencies
  • Integrated with Xcode and the Swift ecosystem
  • Supports a wide range of package management features, including version pinning and dependency resolution

Cons of Swift Package Manager

  • More complex setup and configuration required
  • Steeper learning curve for beginners
  • Primarily designed for larger projects and may be overkill for simple scripts

Code Comparison

swift-sh:

#!/usr/bin/swift sh
import Foundation
import Alamofire // @Alamofire ~> 5.0
print(Alamofire.version)

Swift Package Manager:

// Package.swift
let package = Package(
    name: "MyProject",
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.0.0")
    ],
    targets: [
        .target(name: "MyProject", dependencies: ["Alamofire"])
    ]
)

Swift Package Manager requires a separate Package.swift file and more setup, while swift-sh allows for inline dependency declaration and simpler script execution. However, Swift Package Manager offers more robust dependency management for larger projects.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

swift sh badge-platforms badge-languages Build Status

Writing Swift scripts is easy:

$ cat <<EOF > script
#!/usr/bin/swift
print("Hi!")
EOF
$ chmod u+x script
$ ./script
Hi!

Sadly, to use third-party dependencies we have to migrate our script to a swift package and use swift build, a relatively heavy solution when all we wanted was to whip up a quick script. swift-sh gives us the best of both worlds:

$ cat <<EOF > script
#!/usr/bin/swift sh
import PromiseKit  // @mxcl ~> 6.5
print(Promise.value("Hi!"))
EOF
$ chmod u+x script
$ ./script
Promise("Hi!")

In case it’s not clear, swift-sh reads the comment after the import and uses this information to fetch your dependencies.


Let’s work through an example: if you had a single file called foo.swift and you wanted to import mxcl/PromiseKit:

#!/usr/bin/swift sh

import Foundation
import PromiseKit  // @mxcl ~> 6.5

firstly {
    after(.seconds(2))
}.then {
    after(.milliseconds(500))
}.done {
    print("notice: two and a half seconds elapsed")
    exit(0)
}

RunLoop.main.run()

You could run it with:

$ swift sh foo.swift

Or to make it more “scripty”, first make it executable:

$ chmod u+x foo.swift
$ mv foo.swift foo    # optional step!

And then run it directly:

$ ./foo

Sponsorship

If your company depends on swift-sh please consider sponsoring the project. Otherwise it is hard for me to justify maintaining it.

Installation

brew install swift-sh

Or you can build manually using swift build.

Installation results in a single executable called swift-sh, the swift executable will call this (provided it is in your PATH) when you type: swift sh.

We actively support both Linux and Mac and will support Windows as soon as it is possible to do so.

Usage

Add the shebang as the first line in your script: #!/usr/bin/swift sh.

Your dependencies are determined via your import lines:

#!/usr/bin/swift sh
import AppUpdater    // @mxcl
// ^^ https://github.com/mxcl/AppUpdater, latest version

import PromiseKit    // @mxcl ~> 6.5
// ^^ mxcl/PromiseKit, version 6.5.0 or higher up to but not including 7.0.0 or higher

import Chalk         // @mxcl == 0.3.1
// ^^ mxcl/Chalk, only version 0.3.1

import LegibleError  // @mxcl == b4de8c12
// ^^ mxcl/LegibleError, the precise commit `b4de8c12`

import Path          // mxcl/Path.swift ~> 0.16
// ^^ for when the module-name and repo-name are not identical

import BumbleButt    // https://example.com/bb.git ~> 9
// ^^ non-GitHub URLs are fine

import CommonTaDa    // git@github.com:mxcl/tada.git ~> 1
// ^^ ssh URLs are fine

import TaDa          // ssh://git@github.com:mxcl/tada.git ~> 1
// ^^ this style of ssh URL is also fine

import Foo  // ./my/project
import Bar  // ../my/other/project
import Baz  // ~/my/other/other/project
import Fuz  // /I/have/many/projects
// ^^ local dependencies must expose library products in their `Package.swift`
// careful: `foo/bar` will be treated as a GitHub dependency; prefix with `./`
// local dependencies do *not* need to be versioned


import Floibles  // @mxcl ~> 1.0.0-alpha.1
import Bloibles  // @mxcl == 1.0.0-alpha.1
// ^^ alphas/betas will only be fetched if you specify them explicitly like so
// this is per Semantic Versioning guidelines

swift-sh reads the comments after your imports and fetches the requested SwiftPM dependencies.

It is not necessary to add a comment specification for transitive dependencies.

Editing in Xcode

The following will generate an Xcode project (not in the working directory, we keep it out the way in our cache directory) and open it, edits are saved to your script file.

$ swift sh edit ./myScript

Examples

Converting your script to a package

Simple scripts can quickly become bigger projects that would benefit from being packages that you build with SwiftPM. To help you migrate your project we provide swift sh eject, for example:

$ swift sh eject foo.swift

creates a Swift package in ./Foo, from now on use swift build in the Foo directory. Your script is now ./Foo/Sources/main.swift.

Use in CI

If you want to make scripts available to people using CI; use stdin:

brew install mxcl/made/swift-sh
swift sh <(curl http://example.com/yourscript) arg1 arg2

Internal Details

swift sh creates a Swift Package.swift package manager project with dependencies in a directory below the swift-sh cache directory †, builds the executable, and then executes it via swift run. The script is (only) rebuilt when the script file is newer than the executable.

† Specify the cache parent directory using the (FreeDesktop) environment variable XDG_CACHE_HOME. If unspecified, on macOS swif-sh uses $HOME/Library/Developer/swift-sh.cache, and otherwise it uses $HOME/.cache/swift-sh.

Swift Versions

swfit-sh v2 requires Swift 5.1. We had to drop support for Swift v4.2 because maintenance was just too tricky.

swift-sh uses the active tools version, (ie: xcode-select) or whichever Swift is first in the PATH on Linux. It writes a manifest for the package it will swift build with that tools-version. Thus Xcode 11.0 builds with Swift 5.1. Dependencies build with the Swift versions they declare support for, provided the active toolchain can do that (eg. Xcode 11.0 supports Swift 4.2 and above)

To declare a support for specific Swift versions in your script itself, use #if swift or #if compiler directives.

Alternatives


Troubleshooting

error: unable to invoke subcommand: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-sh

If you got here via Google, you have a script that uses this tool, if you now install swift-sh, you will be able to run your script:

brew install mxcl/made/swift-sh

Or see the above installation instructions.