Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.2.0 Introduce client Clone task #12

Merged
merged 6 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
elixir: [1.17.2]
otp: [26.2.5.1, 27.0]
otp: [26.2.5.1, 27.0.1]
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
strategy:
matrix:
elixir: [1.17.2]
otp: [26.2.5.1, 27.0]
otp: [26.2.5.1, 27.0.1]
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
fail-fast: false
matrix:
elixir: [1.17.2]
otp: [26.2.5.1, 27.0]
otp: [26.2.5.1, 27.0.1]
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.17.2
erlang 27.0
erlang 27.0.1
43 changes: 33 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
# Umwelt ![Umwelt CI](https://github.com/sovetnik/umwelt/actions/workflows/elixir.yml/badge.svg?event=push) [![wakatime](https://wakatime.com/badge/user/7542de1a-027f-4ed7-bc4b-c31d4cf9aa2a/project/018c9f92-bb93-4303-816f-bc0799a61194.svg)](https://wakatime.com/badge/user/7542de1a-027f-4ed7-bc4b-c31d4cf9aa2a/project/018c9f92-bb93-4303-816f-bc0799a61194)
Client for [umwelt.dev](https://umwelt.dev)

## Implemented actions:

### Dump

Extracts Umwelt from Elixir project and dumps it into `root_name.bin`

## Installation

[available in Hex](https://hex.pm/packages/umwelt), the package can be installed
Expand All @@ -22,24 +16,53 @@ end

## Usage

Right now it is a proof of concept, and in this version parser can parse some business-logic related code, via `mix dump`.
### Dump

Extracts Umwelt from Elixir project and dumps it into `root_name.bin`

In common case, when you want to parse your project and it's name from `Mix.Project.config()[:app]` matches root folder name `lib/root_name`, use:
```bash
mix dump
mix umwelt.dump
```

When you wanna parse another folder in lib, `lib/another_root_name`, use:
```bash
mix dump another_root_name
mix umwelt.dump another_root_name
```

### Clone

Fetch and write all modules from specified phase.

When your project is ready, you can get its code and specs.
Create a new elixir or phoenix app, add umwelt and pull the code.
```bash
mix new project_name
cd project_name
```
add umwelt to deps in `mix.exs`.

You have to obtain a token on [profile page](https://umwelt.dev/auth/profile)
```bash
export UMWELT_TOKEN="your_token"
mix umwelt.clone phase_id
mix test --trace
```
And now you will see all messages for failing tests and can start coding.

If you want to reduce logger add this to your `config.exs`
```
config :logger,
compile_time_purge_matching: [
[application: :umwelt, level_lower_than: :warning]
]
```

## Planned
Here is the list of planned features:

### Client functions
Set of push/pull/sync mix tasks to sync local code with remote representation on [umwelt.dev](https://umwelt.dev)
Set of pull/push/sync mix tasks to sync local code with remote representation on [umwelt.dev](https://umwelt.dev)

### Unparser
Tools for update local code with changes made on web side.
79 changes: 79 additions & 0 deletions lib/mix/tasks/clone.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
defmodule Mix.Tasks.Umwelt.Clone do
@moduledoc "Clones phase modules and code"
@shortdoc "The code puller"
use Mix.Task
require Logger

@impl Mix.Task
def run([phase_id]) do
case System.get_env("UMWELT_TOKEN", "no_token") do
"no_token" ->
"""
Token not found in env!
You can get it on umwelt.dev/auth/profile and do

export UMWELT_TOKEN="token"

or pass it directly in

mix clone phase_id "token"

"""
|> Logger.warning()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mix.shell.info/1 makes it fancier, see this for an inspiration.


token ->
run([phase_id, token])
end
end

@impl Mix.Task
def run([phase_id, token]) do
Umwelt.Client.Application.start(nil, nil)
sovetnik marked this conversation as resolved.
Show resolved Hide resolved

Umwelt.Client.Supervisor
|> Process.whereis()
|> Process.monitor()
sovetnik marked this conversation as resolved.
Show resolved Hide resolved

%{phase_id: phase_id, token: token}
|> assign_host()
|> assign_port()
|> Umwelt.Client.pull()

receive do
{:DOWN, _, :process, _, _} ->
Logger.info("Done!")

other ->
Logger.warning(inspect(other))
end
end

defp assign_host(params) do
host =
case Mix.env() do
:dev ->
System.get_env("UMWELT_HOST", "https://umwelt.dev")

:test ->
"http://localhost"
sovetnik marked this conversation as resolved.
Show resolved Hide resolved
end

Map.put(params, :api_host, host)
end

defp assign_port(params) do
port =
case Mix.env() do
:dev ->
case params.api_host do
"http://localhost" -> 4000
"https://umwelt.dev" -> 443
end

:test ->
Application.get_env(:umwelt, :api_port)
end

Map.put(params, :port, port)
end
end
2 changes: 1 addition & 1 deletion lib/mix/tasks/dump.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Mix.Tasks.Dump do
defmodule Mix.Tasks.Umwelt.Dump do
@moduledoc "This task for self-parse umwelt"
@shortdoc "The lib parser"

Expand Down
11 changes: 11 additions & 0 deletions lib/umwelt/client.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule Umwelt.Client do
@moduledoc "Client for umwelt.dev"

alias Umwelt.Client.Clone

require Logger

def pull(params) do
GenServer.cast(Clone, {:pull, params})
end
end
93 changes: 93 additions & 0 deletions lib/umwelt/client/agent.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
defmodule Umwelt.Client.Agent do
@moduledoc "Keeps pulling metadata"

use Agent
require Logger

def start_link(_args) do
Agent.start_link(
fn ->
%{
modules: %{},
waiting: [],
fetching: [],
fetched: [],
writing: [],
written: [],
total: 0
}
end,
name: __MODULE__
)
end

def all_waiting, do: Agent.get(__MODULE__, fn state -> state.waiting end)

def completed?,
do: Agent.get(__MODULE__, fn state -> state.total == Enum.count(state.written) end)

def state, do: Agent.get(__MODULE__, fn state -> state end)
def total, do: Agent.get(__MODULE__, fn state -> state.total end)
def ready, do: Agent.get(__MODULE__, fn state -> Enum.count(state.written) end)

def add_modules(modules) do
Agent.update(__MODULE__, fn state ->
%{
state
| modules: modules,
waiting: Map.keys(modules),
fetching: [],
fetched: [],
writing: [],
written: [],
total: map_size(modules)
}
end)
end

def next_waiting do
Agent.get_and_update(__MODULE__, fn state ->
case state.waiting do
[mod_name | modules] ->
{
%{id: state.modules[mod_name], name: mod_name},
state
|> Map.put(:waiting, modules)
|> Map.put(:fetching, [mod_name | state.fetching])
}

[] ->
{nil, state}
end
end)
end

def update_status(mod_name, :fetched) do
Agent.update(__MODULE__, fn state ->
state
|> Map.put(:fetching, List.delete(state.fetching, mod_name))
|> Map.put(:fetched, [mod_name | state.fetched])
end)
end

def update_status(mod_name, :writing) do
Agent.update(__MODULE__, fn state ->
state
|> Map.put(:writing, [mod_name | state.writing])
end)
end

def update_status(mod_name, :written) do
Agent.update(__MODULE__, fn state ->
state
|> Map.put(:writing, List.delete(state.writing, mod_name))
|> Map.put(:written, [mod_name | state.written])
end)

render_progress()
end

def render_progress do
ProgressBar.render(ready(), total(), suffix: :count)
end
end
15 changes: 15 additions & 0 deletions lib/umwelt/client/application.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Umwelt.Client.Application do
@moduledoc "Client app & Supervisor"

use Application

def start(_type, _args) do
children = [
{Umwelt.Client.Agent, []},
{Umwelt.Client.Clone, []}
]

opts = [strategy: :one_for_one, name: Umwelt.Client.Supervisor]
Supervisor.start_link(children, opts)
end
end
Loading