{"id":13484420,"url":"https://github.com/enkessler/childprocess","last_synced_at":"2025-12-16T01:34:51.369Z","repository":{"id":1105613,"uuid":"971162","full_name":"enkessler/childprocess","owner":"enkessler","description":"Cross-platform Ruby library for managing child processes.","archived":false,"fork":false,"pushed_at":"2024-08-06T06:37:24.000Z","size":496,"stargazers_count":580,"open_issues_count":0,"forks_count":79,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-04T09:37:38.895Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/enkessler.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2010-10-08T02:44:39.000Z","updated_at":"2025-03-12T02:20:50.000Z","dependencies_parsed_at":"2024-05-01T10:35:56.884Z","dependency_job_id":"e537b6a5-f6b0-4df0-9239-ae206c318dbb","html_url":"https://github.com/enkessler/childprocess","commit_stats":{"total_commits":515,"total_committers":51,"mean_commits":"10.098039215686274","dds":"0.35922330097087374","last_synced_commit":"c756730c4ac4fc29711964b4cc53dae2fac1c257"},"previous_names":["jarib/childprocess"],"tags_count":73,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enkessler%2Fchildprocess","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enkessler%2Fchildprocess/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enkessler%2Fchildprocess/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enkessler%2Fchildprocess/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/enkessler","download_url":"https://codeload.github.com/enkessler/childprocess/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253417822,"owners_count":21905299,"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-07-31T17:01:24.140Z","updated_at":"2025-12-16T01:34:51.305Z","avatar_url":"https://github.com/enkessler.png","language":"Ruby","readme":"# childprocess\n\nThis gem aims at being a simple and reliable solution for controlling\nexternal programs running in the background on any Ruby / OS combination.\n\nThe code originated in the [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver) gem, but should prove useful as\na standalone library.\n\n[![CI](https://github.com/enkessler/childprocess/actions/workflows/ci.yml/badge.svg)](https://github.com/enkessler/childprocess/actions/workflows/ci.yml)\n![Gem Version](https://img.shields.io/gem/v/childprocess)\n[![Code Climate](https://codeclimate.com/github/enkessler/childprocess.svg)](https://codeclimate.com/github/enkessler/childprocess)\n[![Coverage Status](https://coveralls.io/repos/enkessler/childprocess/badge.svg?branch=master)](https://coveralls.io/r/enkessler/childprocess?branch=master)\n\n# Requirements\n\n* Ruby 2.4+, JRuby 9+\n\n# Usage\n\nThe object returned from `ChildProcess.build` will implement `ChildProcess::AbstractProcess`.\n\n### Basic examples\n\n```ruby\nprocess = ChildProcess.build(\"ruby\", \"-e\", \"sleep\")\n\n# inherit stdout/stderr from parent...\nprocess.io.inherit!\n\n# ...or pass an IO\nprocess.io.stdout = Tempfile.new(\"child-output\")\n\n# modify the environment for the child\nprocess.environment[\"a\"] = \"b\"\nprocess.environment[\"c\"] = nil\n\n# set the child's working directory\nprocess.cwd = '/some/path'\n\n# start the process\nprocess.start\n\n# check process status\nprocess.alive?    #=\u003e true\nprocess.exited?   #=\u003e false\n\n# wait indefinitely for process to exit...\nprocess.wait\nprocess.exited?   #=\u003e true\n\n# get the exit code\nprocess.exit_code #=\u003e 0\n\n# ...or poll for exit + force quit\nbegin\n  process.poll_for_exit(10)\nrescue ChildProcess::TimeoutError\n  process.stop # tries increasingly harsher methods to kill the process.\nend\n```\n\n### Advanced examples\n\n#### Output to pipe\n\n```ruby\nr, w = IO.pipe\n\nbegin\n  process = ChildProcess.build(\"sh\" , \"-c\",\n                               \"for i in {1..3}; do echo $i; sleep 1; done\")\n  process.io.stdout = w\n  process.start # This results in a subprocess inheriting the write end of the pipe.\n\n  # Close parent's copy of the write end of the pipe so when the child\n  # process closes its write end of the pipe the parent receives EOF when\n  # attempting to read from it. If the parent leaves its write end open, it\n  # will not detect EOF.\n  w.close\n\n  thread = Thread.new do\n    begin\n      loop do\n        print r.readpartial(16384)\n      end\n    rescue EOFError\n      # Child has closed the write end of the pipe\n    end\n  end\n\n  process.wait\n  thread.join\nensure\n  r.close\nend\n```\n\nNote that if you just want to get the output of a command, the backtick method on Kernel may be a better fit.\n\n#### Write to stdin\n\n```ruby\nprocess = ChildProcess.build(\"cat\")\n\nout      = Tempfile.new(\"duplex\")\nout.sync = true\n\nprocess.io.stdout = process.io.stderr = out\nprocess.duplex    = true # sets up pipe so process.io.stdin will be available after .start\n\nprocess.start\nprocess.io.stdin.puts \"hello world\"\nprocess.io.stdin.close\n\nprocess.poll_for_exit(exit_timeout_in_seconds)\n\nout.rewind\nout.read #=\u003e \"hello world\\n\"\n```\n\n#### Pipe output to another ChildProcess\n\n```ruby\nsearch           = ChildProcess.build(\"grep\", '-E', %w(redis memcached).join('|'))\nsearch.duplex    = true # sets up pipe so search.io.stdin will be available after .start\nsearch.io.stdout = $stdout\nsearch.start\n\nlisting           = ChildProcess.build(\"ps\", \"aux\")\nlisting.io.stdout = search.io.stdin\nlisting.start\nlisting.wait\n\nsearch.io.stdin.close\nsearch.wait\n```\n\n### Ensure entire process tree dies\n\nBy default, the child process does not create a new process group. This means there's no guarantee that the entire process tree will die when the child process is killed. To solve this:\n\n```ruby\nprocess = ChildProcess.build(*args)\nprocess.leader = true\nprocess.start\n```\n\n#### Detach from parent\n\n```ruby\nprocess = ChildProcess.build(\"sleep\", \"10\")\nprocess.detach = true\nprocess.start\n```\n\n#### Invoking a shell\n\nAs opposed to `Kernel#system`, `Kernel#exec` et al., ChildProcess will not automatically execute your command in a shell (like `/bin/sh` or `cmd.exe`) depending on the arguments.\nThis means that if you try to execute e.g. gem executables (like `bundle` or `gem`) or Windows executables (with `.com` or `.bat` extensions) you may see a `ChildProcess::LaunchError`.\nYou can work around this by being explicit about what interpreter to invoke:\n\n```ruby\nChildProcess.build(\"cmd.exe\", \"/c\", \"bundle\")\nChildProcess.build(\"ruby\", \"-S\", \"bundle\")\n```\n\n#### Log to file\n\nErrors and debugging information are logged to `$stderr` by default but a custom logger can be used instead.\n\n```ruby\nlogger = Logger.new('logfile.log')\nlogger.level = Logger::DEBUG\nChildProcess.logger = logger\n```\n\n## Caveats\n\n* With JRuby on Unix, modifying `ENV[\"PATH\"]` before using childprocess could lead to 'Command not found' errors, since JRuby is unable to modify the environment used for PATH searches in `java.lang.ProcessBuilder`. This can be avoided by setting `ChildProcess.posix_spawn = true`.\n* With JRuby on Java \u003e= 9, the JVM may need to be configured to allow JRuby to access neccessary implementations; this can be done by adding `--add-opens java.base/java.io=org.jruby.dist` and `--add-opens java.base/sun.nio.ch=org.jruby.dist` to the `JAVA_OPTS` environment variable that is used by JRuby when launching the JVM.\n\n# Implementation\n\nChildProcess 5+ uses `Process.spawn` from the Ruby core library for maximum portability.\n\n# Note on Patches/Pull Requests\n\n1. Fork it\n2. Create your feature branch (off of the development branch)\n   `git checkout -b my-new-feature dev`\n3. Commit your changes\n   `git commit -am 'Add some feature'`\n4. Push to the branch\n   `git push origin my-new-feature`\n5. Create new Pull Request\n\n# Publishing a New Release\n\nWhen publishing a new gem release:\n\n1. Ensure [latest build is green on the `dev` branch](https://travis-ci.org/enkessler/childprocess/branches)\n2. Ensure [CHANGELOG](CHANGELOG.md) is updated\n3. Ensure [version is bumped](lib/childprocess/version.rb) following [Semantic Versioning](https://semver.org/)\n4. Merge the `dev` branch into `master`: `git checkout master \u0026\u0026 git merge dev`\n5. Ensure [latest build is green on the `master` branch](https://travis-ci.org/enkessler/childprocess/branches)\n6. Build gem from the green `master` branch: `git checkout master \u0026\u0026 gem build childprocess.gemspec`\n7. Push gem to RubyGems: `gem push childprocess-\u003cVERSION\u003e.gem`\n8. Tag commit with version, annotated with release notes: `git tag -a \u003cVERSION\u003e`\n\n# Copyright\n\nCopyright (c) 2010-2015 Jari Bakken. See [LICENSE](LICENSE) for details.\n","funding_links":[],"categories":["Processes","Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenkessler%2Fchildprocess","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fenkessler%2Fchildprocess","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenkessler%2Fchildprocess/lists"}