{"id":19156298,"url":"https://github.com/ess/spawning","last_synced_at":"2025-10-05T02:10:30.849Z","repository":{"id":66321379,"uuid":"86758036","full_name":"ess/spawning","owner":"ess","description":"A package for spawning shell commands","archived":false,"fork":false,"pushed_at":"2017-04-04T04:57:09.000Z","size":1001,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-02-22T21:41:54.403Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ess.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-30T23:26:26.000Z","updated_at":"2017-04-04T18:56:54.000Z","dependencies_parsed_at":"2024-06-20T14:10:05.631Z","dependency_job_id":"7a43513e-db88-4f4f-b410-d806c0ab5b36","html_url":"https://github.com/ess/spawning","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ess/spawning","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ess%2Fspawning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ess%2Fspawning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ess%2Fspawning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ess%2Fspawning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ess","download_url":"https://codeload.github.com/ess/spawning/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ess%2Fspawning/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278399690,"owners_count":25980332,"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","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-11-09T08:34:02.231Z","updated_at":"2025-10-05T02:10:30.803Z","avatar_url":"https://github.com/ess.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"The `spawning` package provides a handy API for spawning shell commands on\nUNIXish environments.\n\n## Installation ##\n\nI suggest the use of [glide](https://glide.sh) for managing your Go deps, but\nyou should be able to install it directly without much issue:\n\n```\ngo get github.com/ess/spawning\n```\n\nAs mentioned, though, a better idea is to use glide (or another package manager\nthat supports SemVer).\n\n## Usage ##\n\nCommands (run via `bash -c`) can be spawned in a one-off manner, or one can\nadd a collection of commands to a Pool, then run the pool either sequentially,\nconcurrently, or with a custom Runner.\n\n### Spawning One-off Commands ###\n\nRunning a one-off command is pretty easy, really:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ess/spawning\"\n)\n\nfunc main() {\n\tresult := spawning.Run(\"echo 'My sausages turned to gold!'\")\n\n\tif result.Success {\n\t\tfmt.Println(\"The sausages were successfully turned to gold.\")\n\t}\n}\n```\n\n### Spawning Multiple Commands ###\n\nRunning multiple commands is fairly easy, too, and you can execute them either\nSequentially, Concurrently, or with a custom Runner implementation.\n\n#### Sequentially ####\n\nEffectively, the sequential runner could be used to create minimal shell\nscripts. The important caveat there is that as every command is executed via\n`bash -c`, there is no shared environment between the commands in a given Pool.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/ess/spawning\"\n)\n\nfunc main() {\n\tscript := spawning.NewPool()\n\tscript.Add(\"mkdir -p output\")\n\tscript.Add(\"date \u003e output/begin\")\n\tscript.Add(`echo \"The operation has succeeded\" \u003e output/result`)\n\tscript.Add(\"date \u003e output/end\")\n\tscript.Add(`for step in begin result end ; do cat output/${step} ; done`)\n\n\t// Run the commands sequentially and process the results\n\tfor _, result := range script.Run(spawning.Sequentially()) {\n\t\tprocessResult(result)\n\t}\n}\n\nfunc processResult(result *spawning.Result) {\n\tif !result.Success {\n\t\tfmt.Println(\"The following command failed:\", result.Command)\n\t\treturn\n\t}\n\n\tfmt.Println(result.Output)\n}\n```\n\n#### Concurrently ####\n\nRunning commands concurrently isn't at all great for running locally, but it is\nquite handy for, say, controlling a cluster via SSH.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/ess/spawning\"\n)\n\nfunc main() {\n\n\tlogins := []string{\n\t\t\"joe@192.168.1.1\",\n\t\t\"joe@192.168.1.2\",\n\t\t\"joe@192.168.1.3\",\n\t\t\"jim@10.1.1.1\",\n\t}\n\n\tpool := spawning.NewPool()\n\n\tfor _, login := range logins {\n\t\tpool.Add(sshCommand(login, \"date\"))\n\t}\n\n\t// Run the commands concurrently and process the results\n\tfor _, result := range pool.Run(spawning.Concurrently()) {\n\t\tprocessResult(result)\n\t}\n}\n\nfunc processResult(result *spawning.Result) {\n\tif !result.Success {\n\t\tfmt.Println(\"The following command failed:\", result.Command)\n\t\treturn\n\t}\n\n\tfmt.Println(result.Output)\n}\n\nfunc sshCommand(login string, command string) string {\n\treturn fmt.Sprintf(\"ssh %s '$s'\", login, command)\n}\n```\n\n#### Running With A Custom Runner ####\n\n`spawning.Pool`'s `Run()` method requires that one pass in a `Runner`. If\nneither `Sequentially` nor `Concurrently` are suitable for your purposes, you\ncan implement your own Runner:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/ess/spawning\"\n)\n\ntype RoadRunner struct{}\n\nfunc (runner *RoadRunner) Run(commands []string) []*spawning.Result {\n\tresults := make([]*spawning.Result, 0)\n\n\tfor _, command := range commands {\n\t\tresults = append(\n\t\t\tresults,\n\t\t\t\u0026spawning.Result{Command: command, Output: \"meep meep\", Success: true},\n\t\t)\n\t}\n\n\treturn results\n}\n\nfunc main() {\n  runner := \u0026RoadRunner{}\n\n\tfor _, result := range spawning.NewPool().Add(\"sudo ls -lah /\").Run(runner) {\n\t\tprocessResult(result)\n\t}\n}\n\nfunc processResult(result *spawning.Result) {\n\tif !result.Success {\n\t\tfmt.Println(\"The following command failed:\", result.Command)\n\t\treturn\n\t}\n\n\tfmt.Println(result.Output)\n}\n```\n\n## History ##\n\n* v0.1.1 - I'm a jerk that forgets to include a license\n* v0.1.0 - Initial release\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fess%2Fspawning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fess%2Fspawning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fess%2Fspawning/lists"}