Skip to content

Commit

Permalink
added new example
Browse files Browse the repository at this point in the history
  • Loading branch information
clsource committed Apr 27, 2024
1 parent 91ec633 commit 64ae82e
Show file tree
Hide file tree
Showing 26 changed files with 361 additions and 102 deletions.
15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,7 @@ for technologies that:
2. Are not available as _NIF_.
3. Other reasons for fun and profit?.

#### Why not Erlang Ports?

The problem with _Erlang Ports_ is zombie processes and that not every
technology has a proper _CLI_. With this approach you can implement
a simple communication interface using standard tools.

More details about problems with Erlang Ports in the awesome lib

- https://github.com/fhunleth/muontrap
### Starting Pods

The example process manager uses https://github.com/saleyn/erlexec/
but you can implement the pod services using `System.cmd` or `Erlang Ports`
Expand Down Expand Up @@ -151,6 +143,11 @@ defp deps do
end
```

##### Examples

- [Simple Pod](pod_lispyclouds_sqlite): Just a simple python script
- [Advanced Pod](pod_babashka_sqlite3): A program that requires installation pipeline

## Installation

```bash
Expand Down
4 changes: 4 additions & 0 deletions pod_babashka_sqlite3/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
26 changes: 26 additions & 0 deletions pod_babashka_sqlite3/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
pod_babashka_hsqldb-*.tar

# Temporary files, for example, from tests.
/tmp/
49 changes: 49 additions & 0 deletions pod_babashka_sqlite3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Pod Babashka SQLite3

This is an example pod that uses an external installation
pipeline for the artifacts.

## Installation

Requires `babashka` (`bb`) executable to install the pod.
It will install the artifacts inside the `pods` directory
on the project.

- Add to `mix.exs`

```elixir
{:pod_babashka_sqlite3, path: "../pod_babashka_sqlite3"}
```

```elixir
mix compile
```

- Install the artifacts

```elixir
mix pod.babashka.sqlite3.check # Checks if babashka runtime is on the $PATH

mix pod.babashka.sqlite3.install # Installs the sqlite3 pod in pods directory
```

## Note on Babashka Pods

Some pods are specially created for clojure language (defines macros and other stuff), so it won't work well with elixir.

_Elixir Pods_ is meant to fill a gap between a CLI and a RPC,
so if you stick to following the bencode + json approach it will work well.

Example Incompatible Pod

- https://github.com/babashka/pod-babashka-filewatcher/blob/master/src/main.rs#L50

Since it requires clojure code to be executed in the client.

## Is this Working?

At least the `describe` command works. Other command does not work
due to parser issues.

Is best to create some pods that can be properly tested with Elixir Pods,
but at least this serves as an example of a more advanced pod configuration and installation procedure.
4 changes: 4 additions & 0 deletions pod_babashka_sqlite3/artifacts/pod.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
; We will use babashka pods to install the artifacts
; we only pin the desired version
(require '[babashka.pods :as pods])
(pods/load-pod 'org.babashka/go-sqlite3 "0.1.0")
45 changes: 45 additions & 0 deletions pod_babashka_sqlite3/lib/manifest.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule Pod.Babashka.SQLite3.Manifest do
@moduledoc """
Stores the information for the pod
"""

def version, do: "0.1.0"

@doc """
Returns the namespace that will be used when invoking the commands
Example: pod.babashka.go-sqlite3/execute!
"""
def namespace, do: "pod.babashka.go-sqlite3"

@doc """
Which format will the payload be encoded/decoded:
- json
- transit+json
"""
def format, do: "transit+json"

@doc """
Which programming language this pod is implemented
"""
def language, do: "golang"

defp directory(), do: Path.join([
"pods",
"repository",
"org.babashka",
"go-sqlite3",
version(),
])

@doc """
The executable artifact that will be returned
depending on the requested os and arch params.
values are from :os.type() and :erlang.system_info(:system_architecture)
You can add other os and archs executables if needed.
"""
def executable(%{type: _type, os: :darwin, arch: "x86_64" <> _arch}),
do:
Path.expand(
Path.join([directory(), "mac_os_x", "x86_64", "pod-babashka-go-sqlite3"])
)
end
15 changes: 15 additions & 0 deletions pod_babashka_sqlite3/lib/mix/tasks/check.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Mix.Tasks.Pod.Babashka.Sqlite3.Check do
@moduledoc """
Provides helper commands to check SQLite3 pod
"""

use Mix.Task

@shortdoc """
Checks if babashka runtime is on the $PATH
"""
def run(_) do
Pod.Babashka.SQLite3.babashka()
|> IO.inspect()
end
end
35 changes: 35 additions & 0 deletions pod_babashka_sqlite3/lib/mix/tasks/install.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Mix.Tasks.Pod.Babashka.Sqlite3.Install do
@moduledoc """
Provides helper commands to install Sqlite3 pod
"""

use Mix.Task

@shortdoc """
Installs the sqlite3 pod in pods directory
"""
def run(_) do
{:ok, {exe, _}} = Pod.Babashka.SQLite3.babashka()
artifact = Path.expand(
Path.join([
Path.dirname(__ENV__.file),
"..",
"..",
"..",
"artifacts",
"pod.edn"
])
)

project_pods_directory = Path.expand(Path.join(["pods"]))
File.mkdir_p!(project_pods_directory)

# Check https://github.com/babashka/pods/
# Will install for the current system only
# If you want other artifacts set env
# Other env BABASHKA_PODS_OS_NAME=Linux
# BASHKA_PODS_OS_ARCH=aarch64

System.cmd(exe, [artifact], env: [{"BABASHKA_PODS_DIR", project_pods_directory}])
end
end
50 changes: 50 additions & 0 deletions pod_babashka_sqlite3/lib/pod.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
defmodule Pod.Babashka.SQLite3 do

alias __MODULE__.Manifest

def db(name \\ "testdb"), do: "#{name}.db"

def babashka() do
{type, _} = :os.type()
exe = case type do
:unix -> {"which", ["bb"]}
_ -> {"where", ["bb.exe"]}
end

{command, args} = exe
{bin, _} = System.cmd(command, args)
{version, _} = System.cmd(String.trim(bin), ["--version"])

case version do
"babashka v" <> number -> {:ok, {String.trim(bin), String.trim(number)}}
_ -> {:error, "babashka runtime not found"}
end
end

def manifest, do: Manifest

# options when loading the pod with the process manager
def opts, do: []

def setup(),
do: Pods.Core.setup(__MODULE__, Manifest)

def describe(pods) do
Pods.Core.describe(pods, __MODULE__)
pods
end

def invoke(pods, command, args \\ []) do
Pods.Core.invoke(pods, __MODULE__, command, args)
pods
end

def execute!(pods, db, args \\ []) do
invoke(pods, "execute!", [db, args])
end

def query(pods, db, args \\ []) do
invoke(pods, "query", [db, args])
end

end
29 changes: 29 additions & 0 deletions pod_babashka_sqlite3/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule Pod.Babashka.SQLite3.MixProject do
use Mix.Project

def project do
[
app: :pod_babashka_sqlite3,
version: "0.1.0",
elixir: "~> 1.12",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:pods_core, path: "../pods_core"}
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
8 changes: 8 additions & 0 deletions pod_babashka_sqlite3/test/pod_babashka_hsqldb_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule PodBabashkaHsqldbTest do
use ExUnit.Case
doctest PodBabashkaHsqldb

test "greets the world" do
assert PodBabashkaHsqldb.hello() == :world
end
end
1 change: 1 addition & 0 deletions pod_babashka_sqlite3/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()
24 changes: 7 additions & 17 deletions pod_lispyclouds_sqlite/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
# PodLispycloudsSqlite
# Pod Lispyclouds Sqlite

**TODO: Add description**
This is an example pod for a simple python script.
Does not require a heavy pipeline to install.

## Installation
Remember to check that `main.py` has execution permissions
(655).

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `pod_lispyclouds_sqlite` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:pod_lispyclouds_sqlite, "~> 0.1.0"}
]
end
```bash
chmod +x main.py
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/pod_lispyclouds_sqlite>.

6 changes: 5 additions & 1 deletion pod_lispyclouds_sqlite/lib/manifest.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule Pod.LispyClouds.SQLite.Manifest do
Stores the information for the pod
"""

def version, do: "1.0.0"

@doc """
Returns the namespace that will be used when invoking the commands
Example: pod.lispyclouds.sqlite/execute!
Expand All @@ -24,7 +26,9 @@ defmodule Pod.LispyClouds.SQLite.Manifest do
@doc """
The executable artifact that will be returned
depending on the requested os and arch params.
values are from :os.type() and :erlang.system_info(:system_architecture)
values are from :os.type() and :erlang.system_info(:system_architecture).
This do not need to be installed in pods directory, since is just a python script.
and is not handled by babashka pods.
"""
def executable(%{type: _type, os: _os, arch: _arch}),
do:
Expand Down
23 changes: 4 additions & 19 deletions pods_core/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
# PodsCore
# Pods Core

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `pods_core` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:pods_core, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/pods_core>.
This handles the main communication and decoding
from stdout.

And provides helper functions to pod creation.
2 changes: 2 additions & 0 deletions pods_core/lib/pods.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ defmodule Pods.Core do
pod = module.setup()

decode_out = fn %{origin: origin, pid: pid, response: response} = raw ->

decoded_response = decoder.decode!(response, :bencode)

result =
Expand Down Expand Up @@ -100,6 +101,7 @@ defmodule Pods.Core do
pid:
manager.load(
module.manifest().executable(os_type()),
decoder,
decode_out,
decode_error,
module.opts()
Expand Down
Loading

0 comments on commit 64ae82e

Please sign in to comment.