{"id":17540335,"url":"https://github.com/bitwit/slurp","last_synced_at":"2025-04-23T22:52:27.767Z","repository":{"id":63905923,"uuid":"122140790","full_name":"bitwit/Slurp","owner":"bitwit","description":"A Swift task runner and file watcher with an interface inspired by Gulp.js","archived":false,"fork":false,"pushed_at":"2018-12-09T04:00:25.000Z","size":175,"stargazers_count":12,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-23T22:52:18.696Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitwit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-20T01:01:24.000Z","updated_at":"2022-05-23T16:54:07.000Z","dependencies_parsed_at":"2022-11-28T19:52:47.805Z","dependency_job_id":null,"html_url":"https://github.com/bitwit/Slurp","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwit%2FSlurp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwit%2FSlurp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwit%2FSlurp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwit%2FSlurp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitwit","download_url":"https://codeload.github.com/bitwit/Slurp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250528697,"owners_count":21445511,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-20T22:23:26.313Z","updated_at":"2025-04-23T22:52:27.750Z","avatar_url":"https://github.com/bitwit.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Slurp Logo](https://raw.githubusercontent.com/bitwit/Slurp/master/slurp-logo.jpg)\n\n[![Build Status](https://www.bitrise.io/app/000a61c8091db1a1/status.svg?token=HJjORiUavGh7lyVYVx794g\u0026branch=master)](https://www.bitrise.io/app/000a61c8091db1a1)\n[![Swift Package Manager Compatible](https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat)](https://swift.org/package-manager)\n[![Releases](https://img.shields.io/github/tag/bitwit/slurp.svg)](https://github.com/bitwit/Slurp/releases)\n\n\nA Swift task runner and file watcher that you can run from your Xcode Workspace or the Command line. Comes with everything you need to build and deploy an iOS app just by running an XCode Scheme. \nInspired by Gulp.js. \n\n## Contents\n- [Intended Uses](#intended-uses)\n- [Installation](#installation)\n- [Developing and Running in Xcode](#developing-and-running-in-xcode)\n- [Available Tasks](#currently-available-tasks)\n- [Writing your own task](#writing-your-own-task)\n- [The Pipe Operator](#the-pipe-operator)\n- [Roadmap](#roadmap)\n- [Feedback](#feedback)\n\n## Intended Uses\n\n### For automating workflows\nBuild your Slurp Task module as an executable. Run it from your CI server, the command line or Xcode. For example, this code builds and deploys an iOS app to the iTunes App Store:\n\n```swift\nimport Slurp\nimport SlurpXCTools\n\nlet xcBuildConfig = XcodeBuild.Config(...)\nlet uploadConfig = ApplicationLoader.Config(...)\nlet slurp = Slurp()\nslurp\n    .register(\"buildAndDeploy\") {\n        return slurp\n            |\u003e Pod.Install()\n            |\u003e Version(.incrementBuildNumber, all: true)\n            |\u003e Version(.setMarketingVersion(\"1.0.1\"), all: true)\n            |\u003e XcodeBuild([.archive, .export], config: xcBuildConfig)\n            |\u003e ApplicationLoader(.uploadApp, config: uploadConfig)\n    }\n\ntry! slurp.runAndExit(taskName: \"buildAndDeploy\")\n\n```\n\n### Monitoring the filesystem for changes, then running tasks\nThis is useful for development workflows that involve files generated from 3rd party tools (e.g. graphics editors). If you are looking for ways to develop in Swift without using Xcode, this may be useful for running tests and linters automatically also. \n\n```swift\nimport Slurp\n\nlet slurp = Slurp()\nslurp.watch(paths: [\"Tests/**.swift\"], recursive: true)\n.flatMap { _ in\n  return try! slurp.run(taskName: \"runTests\")\n}\n.subscribe(onError: { err in\n  print(err)\n})\n\nRunLoop.main.run() // Keep the task running indefinitely\n```\n\n## Installation\n\n1. `$ git clone git@github.com:bitwit/Slurp.git`\n2. `$ cd Slurp \u0026\u0026 make`\n3. The Slurp CLI will now be installed and the repo copied to `~/.slurp/clone` for local reference in your projects\n\n## Adding Slurp to your project\nIn the root of the project:\n1. `$ slurp init`. This will create a new SlurpTasks package in `\u003cproject root\u003e/Slurp`.\n2. `$ slurp edit` will open the the SlurpTasks Xcode project, but you can also add this project to your regular Workspace.\n3. `$ slurp` will run your SlurpTasks executable\n\n## Your first slurp task\n\nA basic `Sources/SlurpTasks/main.swift` file would look like:\n\n```swift\nimport Slurp\n\nlet slurp = Slurp()\n\nslurp.register(\"sayHello\", Shell(arguments: [\"echo\", \"hello world\"]))\n\ntry! slurp.runAndExit(taskName: \"sayHello\")\n```\n\n### Developing and Running in Xcode\n\nWhen you run your Tasks from XCode it will execute from the build folder. To get around this there are several ways to set the current working directly correctly:\n\n1. Set it at the top of your main.swift\n\n```swift\nSlurp.currentWorkingDirectory = \"/path/to/app\"\n```\n2. Pass it as an environment variable\n\n`$ SLURP_CWD=/path/to/app slurp`\n\n3. Change it at any point in the task flow\n```swift\nslurp\n    .register(\"example\") {\n        return slurp\n            |\u003e CWD(\"~/Development/personal/Slurp\")\n            |\u003e ...\n    }\n```\n\n\u003e **Note**: You can pass this as an environment variable too through `SLURP_CWD`. This can be set in your task scheme's configuration\n\nThis git repo contains an xcworkspace and example app that mimic this suggested structure.\n\n## Currently Available Tasks\n- Shell\n- Xcodebuild (`xcodebuild`)\n- Version (`agvtool`)\n- ApplicationLoader (`altool`)\n- Cocoapods (`pod`)\n\n## Writing your own task\nThere are 3 ways to build your own task:\n\n1. Simply register an RxSwift Observable\n\n    ```swift\n    let myTaskObservable: Observable\u003cInt\u003e = Observable.create { observer in\n    \tobserver.onNext(100)\n    \tobserver.onCompleted()\n    \treturn Disposables.create()\n    }\n    \n    slurp\n    .register(\"myTask\") {\n        return myTaskObservable\n    }\n    ```\n\n2. Use the `BasicTask` class either directly or through inheritance. It can be initialized with either an RxSwift Observable or a callback function with a `(Error?, T?) -\u003e Void` method signature\n\n    ```swift\n    open class BasicTask\u003cT\u003e: SlurpTask {\n  \n      public init(observable: Observable\u003cT\u003e)\n    \n      public convenience init(asyncTask: @escaping ( (Error?, T?) -\u003e Void ) -\u003e Void) \n    }\n    ```\n\n3. Make your class conform to the `SlurpTask` protocol:\n\n    ```swift\n    public protocol SlurpTask {\n   \n        associatedtype OutputType\n    \n        func onPipe\u003cU\u003e(from input: U) -\u003e Observable\u003cOutputType\u003e\n    }\n    ```\n\u003e **Note:** `onPipe\u003cU\u003e`'s generic format is mostly there for posterity since all current tasks do not consume from the previous task's output. This may change in the future, particularly for file system management tasks\n\nOptions 2 \u0026 3, which involve conforming to `SlurpTask`, are eligible for piping to and from other tasks.\n\n## The Pipe Operator\nFor convenience and cleanliness Slurp uses the pipe operator i.e `|\u003e`. This is a substitute for calling `func pipe(to: SlurpTask)`. \n\n```swift\nreturn slurp\n            |\u003e XcodeBuild([.archive, .export], config: xcBuildConfig)\n            |\u003e ApplicationLoader(.uploadApp, config: uploadConfig)\n```\nIs equivalent to\n\n```swift\nreturn slurp\n            .pipe(to: XcodeBuild([.archive, .export], config: xcBuildConfig))\n            .pipe(to: ApplicationLoader(.uploadApp, config: uploadConfig))\n```\n\n## Roadmap\nSome future desires/plans. Requests and contributions very welcome!\n\n- Solidify API\n- Dry run flag\n- Prettier output\n- Make more tasks. Personal wish list:\n\t- Slack API task\n\t- File system tasks\n\t- AWS S3 Management\n\t- AWS Cloudfront\n\t- Download Dsyms\n\t- Upload Dsyms to New Relic (and others)\n\n## Feedback\nFeel free to [open an issue](https://github.com/bitwit/Slurp/issues/new) or [find me on twitter](http://www.twitter.com/kylnew)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitwit%2Fslurp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitwit%2Fslurp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitwit%2Fslurp/lists"}