https://github.com/jayjun/rambo

Run your command. Send input. Get output.

https://github.com/jayjun/rambo

Science Score: 13.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (9.5%) to scientific vocabulary

Keywords

hacktoberfest
Last synced: 11 months ago · JSON representation

Repository

Run your command. Send input. Get output.

Basic Info
  • Host: GitHub
  • Owner: jayjun
  • License: mit
  • Language: Elixir
  • Default Branch: master
  • Homepage:
  • Size: 49.8 KB
Statistics
  • Stars: 199
  • Watchers: 10
  • Forks: 21
  • Open Issues: 10
  • Releases: 0
Topics
hacktoberfest
Created almost 7 years ago · Last pushed almost 2 years ago
Metadata Files
Readme Changelog License

README.md

Rambo

Rambo is the easiest way to run external programs.

  • Run programs that require EOF to produce output
  • No more zombies, even if the VM crashes! No scripts required!
  • No additional installs or compilers (Linux, macOS & Windows only)
  • Stream logs back to your app
  • Chain commands together
  • Kill stalled commands
  • Set timeout or run indefinitely
  • Powered by asynchronous I/O, incredibly efficient!

Usage

```elixir Rambo.run("echo") {:ok, %Rambo{status: 0, out: "\n", err: ""}}

send standard input

Rambo.run("cat", in: "rambo")

pass arguments

Rambo.run("ls", ["-l", "-a"])

chain commands

Rambo.run("ls") |> Rambo.run("sort") |> Rambo.run("head")

set timeout

Rambo.run("find", "peace", timeout: 1981) ```

Logging

Logs to standard error are printed by default, so errors are visible before your command finishes. Change this with the :log option.

```elixir Rambo.run("ls", log: :stderr) # default Rambo.run("ls", log: :stdout) # log stdout only Rambo.run("ls", log: true) # log both stdout and stderr Rambo.run("ls", log: false) # don’t log output

or to any function

Rambo.run("echo", log: &IO.inspect/1) ```

Kill

Kill your command from another process, Rambo returns with any gathered results so far.

```elixir task = Task.async(fn -> Rambo.run("cat") end)

Rambo.kill(task.pid)

Task.await(task) {:killed, %Rambo{status: nil, out: "", err: ""}} ```

Why?

Erlang ports do not work with programs that expect EOF to produce output. The only way to close standard input is to close the port, which also closes standard output, preventing results from coming back to your app. This gotcha is marked Won’t Fix.

Design

When Rambo is asked to run a command, it starts a shim that spawns your command as a child. After writing to standard input, the file descriptor is closed while output is streamed back to your app.

+-----------------+ stdin | +------+------+ --> +---------+ | Erlang | Port | Shim | | Command | | +------+------+ <-- +---------+ +-----------------+ stdout

If your app exits prematurely, the child is automatically killed to prevent orphans.

Caveats

You cannot call Rambo.run from a GenServer because Rambo uses receive, which interferes with GenServer’s receive loop. However, you can wrap the call in a Task.

```elixir task = Task.async(fn -> Rambo.run("mission") end)

Task.await(task) ```

Comparisons

Rambo does not spawn any processes nor support bidirectional communication with your commands. It is intentionally kept simple to run transient jobs with minimal overhead, such as calling a Python or Node script to transform some data. For more complicated use cases, see below.

System.cmd

If you don’t need to pipe standard input or capture standard error, just use System.cmd.

Porcelain

Porcelain cannot send EOF to trigger output by default. The Goon driver must be installed separately to add this capability. Rambo ships with the required native binaries.

Goon is written in Go, a multithreaded runtime with a garbage collector. To be as lightweight as possible, Rambo’s shim is written in Rust using non-blocking, asynchronous I/O only. No garbage collection runtime, no latency spikes.

Most importantly, Porcelain currently leaks processes. Writing a new driver to replace Goon should fix it, but Porcelain appears to be abandoned so effort went into creating Rambo.

MuonTrap

MuonTrap is designed to run long-running external programs. You can attach the OS process to your supervision tree, and restart it if it crashes. Likewise if your Elixir process crashes, the OS process is terminated too.

You can also limit CPU and memory usage on Linux through cgroups.

erlexec

erlexec is great if you want fine grain control over external programs.

Each external OS process is mirrored as an Erlang process, so you get asynchronous and bidirectional communication. You can kill your OS processes with any signal or monitor them for termination, among many powerful features.

Choose erlexec if you want a kitchen sink solution.

ExCmd

ExCmd can stream data with backpressure, wrapped in a convenient Stream API. Requires separate install of Odu. By the same author as Exile.

Exile

Exile is also focused on streaming like ExCmd but implemented with NIFs so it does not require shims.

Installation

Add rambo to your list of dependencies in mix.exs:

elixir def deps do [ {:rambo, "~> 0.3"} ] end

Linux, macOS and Windows binaries are bundled (x86-64 architecture only). For other environments, install the Rust compiler or Rambo won’t compile.

To remove unused binaries, set :purge to true in your configuration.

elixir config :rambo, purge: true

Links

License

Rambo is released under MIT license.

Owner

  • Name: Tan Jay Jun
  • Login: jayjun
  • Kind: user

GitHub Events

Total
  • Watch event: 9
  • Issue comment event: 1
  • Fork event: 1
Last Year
  • Watch event: 9
  • Issue comment event: 1
  • Fork event: 1

Committers

Last synced: over 3 years ago

All Time
  • Total Commits: 56
  • Total Committers: 3
  • Avg Commits per committer: 18.667
  • Development Distribution Score (DDS): 0.054
Top Committers
Name Email Commits
Tan Jay Jun t****n@j****m 53
Philip Giuliani p****i@k****o 2
Nathan me@n****m 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: almost 2 years ago

All Time
  • Total issues: 15
  • Total pull requests: 10
  • Average time to close issues: 6 days
  • Average time to close pull requests: 4 months
  • Total issue authors: 11
  • Total pull request authors: 7
  • Average comments per issue: 2.2
  • Average comments per pull request: 1.8
  • Merged pull requests: 5
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 1
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 1
  • Average comments per issue: 0
  • Average comments per pull request: 1.0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • philipgiuliani (4)
  • thbar (2)
  • jayjun (1)
  • Maxximiliann (1)
  • eeide (1)
  • OnigiriJack (1)
  • benvp (1)
  • binaryape (1)
  • lud (1)
  • mmower (1)
  • larshesel (1)
Pull Request Authors
  • jayjun (4)
  • talklittle (2)
  • philipgiuliani (1)
  • prtngn (1)
  • Apelsinka223 (1)
  • MortadaAK (1)
  • myobie (1)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • hex 530,406 total
  • Total docker downloads: 132
  • Total dependent packages: 11
  • Total dependent repositories: 14
  • Total versions: 9
  • Total maintainers: 1
hex.pm: rambo

Run your command. Send input. Get output.

  • Versions: 9
  • Dependent Packages: 11
  • Dependent Repositories: 14
  • Downloads: 530,406 Total
  • Docker Downloads: 132
Rankings
Docker downloads count: 2.0%
Dependent packages count: 2.1%
Average: 4.6%
Stargazers count: 4.7%
Dependent repos count: 5.0%
Downloads: 5.9%
Forks count: 8.1%
Maintainers (1)
Last synced: 11 months ago

Dependencies

priv/Cargo.lock cargo
  • arc-swap 0.4.4
  • bitflags 1.2.1
  • bytes 0.5.4
  • cfg-if 0.1.10
  • fuchsia-zircon 0.3.3
  • fuchsia-zircon-sys 0.3.3
  • futures 0.3.5
  • futures-channel 0.3.5
  • futures-core 0.3.5
  • futures-executor 0.3.5
  • futures-io 0.3.5
  • futures-macro 0.3.5
  • futures-sink 0.3.5
  • futures-task 0.3.5
  • futures-util 0.3.5
  • iovec 0.1.4
  • kernel32-sys 0.2.2
  • lazy_static 1.4.0
  • libc 0.2.67
  • log 0.4.8
  • memchr 2.3.3
  • mio 0.6.21
  • mio-named-pipes 0.1.6
  • mio-uds 0.6.7
  • miow 0.2.1
  • miow 0.3.3
  • net2 0.2.33
  • once_cell 1.4.0
  • pin-project 0.4.17
  • pin-project-internal 0.4.17
  • pin-project-lite 0.1.4
  • pin-utils 0.1.0
  • proc-macro-hack 0.5.11
  • proc-macro-nested 0.1.3
  • proc-macro2 1.0.9
  • quote 1.0.3
  • redox_syscall 0.1.56
  • signal-hook-registry 1.2.0
  • slab 0.4.2
  • socket2 0.3.11
  • syn 1.0.16
  • tokio 0.2.13
  • tokio-macros 0.2.5
  • unicode-xid 0.2.0
  • winapi 0.2.8
  • winapi 0.3.8
  • winapi-build 0.1.1
  • winapi-i686-pc-windows-gnu 0.4.0
  • winapi-x86_64-pc-windows-gnu 0.4.0
  • ws2_32-sys 0.2.1
mix.exs hex
  • ex_doc ~> 0.24
.github/workflows/main.yml actions
  • actions-rs/toolchain v1 composite
  • actions/checkout v1 composite
  • actions/checkout v2 composite
  • erlef/setup-elixir v1 composite
priv/Cargo.toml cargo
mix.lock hex