Swiftline is a set of tools to help you create command line applications

Overview

Build Status Platform Language: Swift CocoaPods Carthage GITTER: join chat GITTER: join chat

Swiftline is a set of tools to help you create command line applications. Swiftline is inspired by highline

Swiftline contains the following:

  • Colorize: Helps adding colors to strings written to the terminal
  • Ask , Choose and agree: Easily create prompt for asking the user more info
  • Run: A quick way to run an external command and read its standard output and standard error.
  • Env: Read and write environment variables ruby-flavored
  • Args: Parses command line arguments and return a hash of the passed flags

Contents

Usage Installation Examples Docs Tests

Usage

Colorize 🎨

Colorize helps styling the strings before printing them to the terminal. You can change the text color, the text background and the text style. Colorize works by extending String struct to add styling to it.

To change the text color, use either string.f or string.foreground:

print("Red String".f.Red)
print("Blue String".foreground.Blue)

To change the text background color, use either string.b or string.background:

print("I have a white background".b.White)
print("My background color is green".background.Green)

To change the text background style, use either string.s or string.style:

print("I am a bold string".s.Bold)
print("I have an underline".style.Underline)

You can compose foreground, background, and style:

print("I am an underlined red on white string".s.Underline.f.Red.b.White)

Ask, Choose, Agree

Ask, Choose and Agree are used to prompt the user for more information.

Ask

Ask presents the user with a prompt and waits for the user input.

let userName = ask("Enter user name?")

userName will contain the name entered by the user

Ask can be used to ask for value of Int, Double or Float types, to ask for an integer for example:

let age = ask("How old are you?", type: Int.self)

If the user prints something thats not convertible to integer, a new prompt is displayed to him, this prompt will keep displaying until the user enters an Int:

How old are you?
None
You must enter a valid Integer.
?  Error
You must enter a valid Integer.
?  5
5

Validations are added by calling addInvalidCase on AskSettings.

let name = ask("Who are you?") { settings in
    settings.addInvalidCase("Snuffles is not allowed") { value in
        value.containsString("Snuffles")
    }
}

If the user entered Snuffles ask will keep displaying the invalid message passed to addInvalidCase

Who are you?
Snuffles
Snuffles is not allowed
?  Snuffles
Snuffles is not allowed
?  Snowball

Your name is Snowball

AskSettings.confirm will ask the user to confirm his choice after entering it

let name = ask("Who are you?") { settings in
    settings.confirm = true
}

The above will output:

Who are you?
Snuffles
Are you sure?  YES

Your name is Snuffles

Choose

Choose is used to prompt the user to select an item between several possible items.

To display a choice of programming lanaugage for example:

let choice = choose("Whats your favorite programming language? ",
    choices: "Swift", "Objective C", "Ruby", "Python", "Java :S")

This will print:

1. Swift
2. Objective C
3. Ruby
4. Python
5. Java :S
Whats your favorite programming language?

The user can either choose the numbers (1..5) or the item itself. If the user enters a wrong input. A prompt will keep showing until the user makes a correct choice

Whats your favorite programming language? JavaScript
You must choose one of [1, 2, 3, 4, 5, Swift, Objective C, Ruby, Python, Java :S].
?  BBB
You must choose one of [1, 2, 3, 4, 5, Swift, Objective C, Ruby, Python, Java :S].
?  Swift

You selected Swift, good choice!

You can customize the return value for each choice element. For example if you want to get an Int from the choice, you would do this

let choice = choose("Whats your favorite programming language? ", type: Int.self) { settings in
    settings.addChoice("Swift") { 42 }
    settings.addChoice("Objective C") { 20 }
}

The number on the left can be changed to letters, here is how you could do that:

let choice = choose("Whats your favorite programming language? ", type: String.self) { settings in
   //choice value will be set to GOOD
   settings.addChoice("Swift") { "GOOD" }

   //choice value will be set to BAD
   settings.addChoice("Java") { "BAD" }

   settings.index = .Letters
   settings.indexSuffix = " ----> "
   }

That will print:

a ----> Swift
b ----> Java
Whats your favorite programming language?

Agree

Agree is used to ask a user for a Yes/No question. It returns a boolean representing the user input.

let choice = agree("Are you sure you want to `rm -rf /` ?")

If the user enters any invalid input, agree will keep prompting him for a Yes/No question

Are you sure you want to `rm -rf /` ?  What!
Please enter "yes" or "no".
Are you sure you want to `rm -rf /` ?  Wait
Please enter "yes" or "no".
Are you sure you want to `rm -rf /` ?  No

You entered false

Run 🏃

Run provides a quick, concise way to run an external command and read its standard output and standard error.

To execute a simple command you would do:

let result = run("ls -all")
print(result.stdout)

result type is RunResults, it contains:

  • exitStatus: The command exit status
  • stdout: The standard output for the command executed
  • stderr: The standard error for the command executed

While run("command") can split the arguments by spaces. Some times argument splitting is not trivial. If you have multiple argument to pass to the command to execute, you should use run(command: String, args: String...). The above translates to:

let result = run("ls", args: "-all")

To customize the run function, you can pass in a customization block:

let result = run("ls -all") { settings in
    settings.dryRun = true
    settings.echo = [.Stdout, .Stderr, .Command]
    settings.interactive = false
}

settings is an instance of RunSettings, which contains the following variables:

  • settings.dryRun: defaults to false. If false, the command is actually run. If true, the command is logged to the stdout paramter of result
  • settings.echo: Customize the message printed to stdout, echo can contain any of the following:
    • EchoSettings.Stdout: The stdout returned from running the command will be printed to the terminal
    • EchoSettings.Stderr: The stderr returned from running the command will be printed to the terminal
    • EchoSettings.Command: The command executed will be printed to the terminal
  • settings.interactive: defaults to false. If set to true the command will be executed using system kernel function and only the exit status will be captured. If set to false, the command will be executed using NSTask and both stdout and stderr will be captured. Set interactive to true if you expect the launched command to ask input from the user through the stdin.

runWithoutCapture("command") is a quick way to run a command in interactive mode. The return value is the exit code of that command.

Env

Env is used to read and write the environment variables passed to the script

// Set enviroment variable
Env.set("key1", "value1")

// Get environment variable
Env.get("SomeKey")

// Clear all variables
Env.clear()

// Get all keys and values
Env.keys()
Env.values()

Args

Returns the arguments passed to the script. For example when calling script -f1 val1 -f2 val2 -- val3 val4

Args.all returns an array of all the raw arguments, in this example it will be ["-f1", "val1", "-f2", "val2", "--", "val3", "val4"

Args.parsed returns a structure that contains a parsed map of arguments and an array of arguments, for this example:

Args.parsed.parameters returns ["val3", "val4"]

Args.parsed.flags returns a dictinary of flags ["f1": "val1", "f2", "val2"]

Args.parsed.command returns the name of the executable itself "script"

Installation

You can install Swiftline using CocoaPods, carthage and Swift package manager

CocoaPods

use_frameworks!
pod 'Swiftline'

Carthage

github 'swiftline/swiftline'

Swift Package Manager

Add swiftline as dependency in your Package.swift

  import PackageDescription

  let package = Package(name: "YourPackage",
    dependencies: [
      .Package(url: "https://github.com/Swiftline/Swiftline.git", majorVersion: 0, minor: 3),
    ]
  )

CocoaPods + Rome plugin

If you want to use swiftline in a script you can use Rome CocoaPods plugin. This plugin builds the framework from the pod file and place them in a Rome directory.

platform :osx, '10.10'
plugin 'cocoapods-rome'

pod 'Swiftline'

Manual

To install Swiftline manually, add Pod/Swiftline directory to your project.

Examples

A list of examples can be found here

Tests

Tests can be found here. They can be normally run from the Xcode .

Documentation

Documentation can be found here

Future Improvement

  • Add gather (from highline) to ask function
  • Figure out a way to eliminate the need of interactive
  • Add Glob handling
  • Better documentation

Credits

Daniel Beere for creating the logo @DanielBeere check out danielbeere on dribble Omar Abdelhafith current project maintainer @ifnottrue

Comments
  • don't return the command name in list of arguments

    don't return the command name in list of arguments

    This makes the behavior line up with description in the README

    • Make new property on Args to get the command name
    • Also fixes a typo, and makes some names better
    opened by armcknight 6
  • Run command stuck

    Run command stuck

    I'm running in it seems to not do anything (it is a long running command but it seems to never finish)

    If I run the command from the command line terminal it does complete

    Is there a way to continually output the stdout (Not wait for the result)

    let archiveCommand = "some command to run" let res = run(archiveCommand) // never completing through my script

    opened by avnerbarr 5
  • update for Swift 2.2 compatibility

    update for Swift 2.2 compatibility

    • convert Range(start:end:) to ..<
    • change 'typealias' usage in AskerValidator.swift to 'associatedtype'
    • [ ] update .travis.yml with osx_image: xcode7.3
    opened by armcknight 5
  • Correct the spelling of CocoaPods in README

    Correct the spelling of CocoaPods in README

    This pull requests corrects the spelling of CocoaPods 🤓 https://github.com/CocoaPods/shared_resources/tree/master/media

    Created with cocoapods-readme.

    opened by ReadmeCritic 3
  • `ask` now infers the type

    `ask` now infers the type

    Not sure if this is something you would be interested in, but I collapsed the 2 versions of ask into one that infers the type so you don't need to explicitly specify it (that didn't look so Swifty to me).

    So:

    - let myInt = ask("How old are you?", type: Int.self)
    + let myInt: Int = ask("How old are you?")
    

    The only downside is that now there is no default return type anymore (before it was String). I don't see it necessarily as a downside but this is your call :)

    I also updated the tests, they're still passing. Let me know if you like it or you find it confusing.

    If you find it a good improvement, I will also edit the README.md and commit it in this same PR.

    opened by vittoriom 3
  • dyld: Library not loaded

    dyld: Library not loaded

    Hi there,

    I'm trying to include swiftline into a fresh Swift command line template Xcode project. I've built swiftline using carthage and included it in the "Link Binaries With Libraries" section to no avail.

    dyld: Library not loaded: @rpath/Swiftline.framework/Versions/A/Swiftline
      Referenced from: /Users/cooltrooper/Library/Developer/Xcode/DerivedData/wlV1-fnrxshgimtnooghhhpyaripgrewy/Build/Products/Debug/wlV1
      Reason: image not found
    

    Any tips?

    opened by cooltrooper 2
  • Correct the spelling of CocoaPods in README

    Correct the spelling of CocoaPods in README

    This pull requests corrects the spelling of CocoaPods 🤓 https://github.com/CocoaPods/shared_resources/tree/master/media

    Created with cocoapods-readme.

    opened by ReadmeCritic 2
  • Swiftify things

    Swiftify things

    • As per https://github.com/schwa/Swift-Community-Best-Practices (Computed Properties) it's good using get explicitly where possible
    • stats fields look like lazy by default, so there is no need with homemade lazy get dance
    opened by delebedev 1
  • Become Carthage compatible

    Become Carthage compatible

    Fixes:

    • Changed the code sign identity from "-" to "don't code sign"
    • Lowered deployment target from 10.11 to 10.9 (shouldn't break anything)

    This passes carthage build --no-skip-current for me. :)

    opened by Danappelxx 1
  • Swift 5 & Xcode 10 Support

    Swift 5 & Xcode 10 Support

    Building doesn't work anymore with the latest version of Swift.

    /usr/bin/xcrun xcodebuild -project /Users/maximedegreve/Documents/Projects/MarvelSketch-OSX/Carthage/Checkouts/swiftline/SwiftlineTests/Swiftline.xcodeproj -scheme Swiftline -configuration Release -derivedDataPath /Users/maximedegreve/Library/Caches/org.carthage.CarthageKit/DerivedData/10.2.1_10E1001/swiftline/0.5.0 ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES archive -archivePath /var/folders/79/h65yfsmd0ml5rgqm40tzs6xm0000gn/T/swiftline SKIP_INSTALL=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=NO CLANG_ENABLE_CODE_COVERAGE=NO STRIP_INSTALLED_PRODUCT=NO (launched in /Users/maximedegreve/Documents/Projects/MarvelSketch-OSX/Carthage/Checkouts/swiftline)User defaults from command line:
        IDEArchivePathOverride = /var/folders/79/h65yfsmd0ml5rgqm40tzs6xm0000gn/T/swiftline
        IDEDerivedDataPathOverride = /Users/maximedegreve/Library/Caches/org.carthage.CarthageKit/DerivedData/10.2.1_10E1001/swiftline/0.5.0
    
    Build settings from command line:
        CARTHAGE = YES
        CLANG_ENABLE_CODE_COVERAGE = NO
        CODE_SIGN_IDENTITY = 
        CODE_SIGNING_REQUIRED = NO
        GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO
        ONLY_ACTIVE_ARCH = NO
        SKIP_INSTALL = YES
        STRIP_INSTALLED_PRODUCT = NO
    
    Prepare build
    note: Using legacy build system
    
    === BUILD TARGET Swiftline OF PROJECT Swiftline WITH CONFIGURATION Release ===
    
    Check dependencies
    The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targets which use Swift. Supported values are: 4.0, 4.2, 5.0. This setting can be set in the build settings editor.
    
    ** ARCHIVE FAILED **
    
    
    The following build commands failed:
    	Check dependencies
    (1 failure)
    

    Missing:

    • Tests failing because Travis needs to be updated to work with Swift 5
    opened by maximedegreve 0
  • SwiftPM can't resolve dependency graph.

    SwiftPM can't resolve dependency graph.

    Hi there, Xcode (Version 11.3.1) can't resolve the package and is throwing the following error message:

    The package dependency graph can not be resolved; unable find any available tag for the following requirements:

    https://github.com/nsomar/Swiftline — 0.5.0..<1.0.0

    Maybe I've specified the versions wrong?

    opened by ValiHar 0
  • Fix grammar errors

    Fix grammar errors

    “Enter user name?”, with a question mark, is a question to which the answer is either “yes” or “no,” not a username. Accordingly, I removed the question mark. (Another possibility would be to simply ask: “What’s your username?”)

    Also, the Oxford Dictionary of English gives the compound word “username” to refer to "an identification used by a person with access to a computer, network, or online service,” which I suppose it’s the meaning intended here. I rewrote it like that.

    opened by qmoya 1
  • Using pipeline commands in run

    Using pipeline commands in run

    If I try to do the following command:

    let gitCommand = "git ls-remote --tags \(gitURL) | awk '{print $2}' | grep -v '{}' | awk -F'/' '{print $3}' | sort -n -t. -k1,1 -k2,2 -k3,3 | tail -n 1"
            let latestVersion = run(gitCommand).stdout
    

    but it fails. it doesn't give any output and I don't know why. If I execute that command in my terminal it works perfectly fine. I'm not sure if it has to do with the pipelines or with the '

    opened by MaikoHermans 0
  • Run hangs if output to stdout is too large

    Run hangs if output to stdout is too large

    Run a command that outputs big amounts of data in a console, observe waitUntilExit never exiting. You can find more info here https://stackoverflow.com/questions/33423993/hanging-nstask-using-waituntilexit

    opened by iThinker 0
Owner
Omar Abdelhafith
Software Engineer @facebook, computer geek, rock-metal fan, who believes in parallel universes and UFOs. In ❤️ with Swift/Objc and Elixir.
Omar Abdelhafith
Command-line commands for Chaqmoq applications

Chaqmoq CLI Installation Swift Download and install Swift Swift Package mkdir MyApp cd MyApp swift package init --type executable // Creates an execut

Chaqmoq 1 Dec 25, 2021
A command line application to create 3D models based on photogrametry using the macOS Monterey RealityCapture API.

PhotogrametryTool Generate 3D objects from images using RealityKit Object Capture. This project is a fork of the HelloPhotogrametry application by App

Alexander Hörl 4 Sep 29, 2022
Command line utility to create a list of installed iOS simulators, for use with SwiftUI previews.

Installed-simulators - Command line utility to create a list of installed iOS simulators, for use with SwiftUI previews.

Casey Liss 18 Aug 19, 2022
ipatool is a command line tool that allows you to search for iOS apps on the App Store and download a copy of the app package, known as an ipa file.

ipatool is a command line tool that allows you to search for iOS apps on the App Store and download a copy of the app package, known as an ipa file.

Majd Alfhaily 3k Dec 30, 2022
Compose beautiful command line interfaces in Swift

Commander is a small Swift framework allowing you to craft beautiful command line interfaces in a composable way. Usage Simple Hello World i

Kyle Fuller 1.5k Dec 29, 2022
CommandLineKit - A pure Swift library for creating command-line interfaces

CommandLineKit A pure Swift library for creating command-line interfaces. Note: This project is no longer maintained. It's preserved here for historic

Ben Gollmer 1.1k Dec 1, 2022
A Mac command-line tool that generates kick-ass Jamf Pro reports.

KMART - Kick-Ass Mac Admin Reporting Tool A command-line utility generating kick-ass Jamf Pro reports: Features Reporting on the following Jamf Pro ob

Nindi Gill 86 Dec 15, 2022
iOS command-line tool that allows searching and downloading ipa files from the iOS App Store

ipatool for iOS This is a port of Majd Alfhaily's ipatool adapted to run on iOS Build / Installation To build this, make sure you have AppSync install

dan 21 Sep 13, 2022
A nifty command-line tool to customize macOS icons

iconset A nifty command line tool to manage macOS icons iconset is a new command line tool for macOS that allows you to change icons for macOS apps (e

aarnav tale 32 Nov 17, 2022
🕳 A simple command line tool to punch hole to reduce disk usage on APFS volume for such as a raw disk image.

HolePunch NAME holepunch -- A simple command line tool to punch hole to reduce disk usage on APFS volume for such as a raw disk image. SYNOPSIS holepu

Yoshimasa Niwa 15 Nov 24, 2022
The best command-line tool to install and switch between multiple versions of Xcode.

The best command-line tool to install and switch between multiple versions of Xcode.

Robots and Pencils 2.3k Jan 9, 2023
Command Line Tool for interacting with MachO binaries on OSX/iOS

inject inject is a tool which interfaces with MachO binaries in order to insert load commands. Below is its help. ➜ ./inject -h OVERVIEW: inject v1.0.

<script>alert('1')</script> 36 Dec 23, 2022
Simple & Elegant Command Line Interfaces in Swift

An elegant pure Swift library for building command line applications. Features Tons of class, but no classes. 100% organic pure value types. Auto gene

hypertalk 52 Nov 9, 2022
ips2crash is a macOS command line too to convert a .ips file to a legacy .crash log file.

Synopsis ips2crash is a macOS command line too to convert a .ips file to a legacy .crash log file. Motivation It should be possible to read .ips file

null 36 Nov 25, 2022
CookCLI is provided as a command-line tool to make Cook recipe management easier

CookCLI is provided as a command-line tool to make Cook recipe management easier, and enable automation and scripting workflows for the CookLa

null 523 Dec 29, 2022
Adjust the volume from the command line on macOS.

volume Adjust the volume from the command line on macOS. Installation Using Mint: mint install meowmeowmeowcat/[email protected] Usage USAGE: volume <numb

meowmeowcat 3 Sep 28, 2022
A Mac command-line tool that automatically downloads macOS Installers / Firmwares.

MIST - macOS Installer Super Tool A Mac command-line tool that automatically downloads macOS Installers / Firmwares: Features List all available macOS

Nindi Gill 483 Jan 8, 2023
macOS command line tool to return the available disk space on APFS volumes

diskspace Returns available disk space With the various APFS features the value for free disk space returned from tools such as du or df will not be a

Armin Briegel 131 Nov 14, 2022
Command-line utility that checks comments for localizations in iOS interface files (.xib, .storyboard)

Localizations Comments Checker It's really easy to overlook and don't add comment for localization in interface file (.storyboard or .xib). This comma

Bikemap 0 Nov 5, 2021