Save output from the mix shell cmd

mix

#1

I am running the mix shell command in my code like this:

      Mix.Shell.cmd("mix phx.routes", [quiet: true], &IO.puts(&1))          

It works fine. But i need to save it in a variable . How can I do it?


#2

Elixir doesn’t have variables, but you can perhaps use this instead.

def var(), do: Mix.Shell.cmd("mix phx.routes", [quiet: true], &IO.puts(&1))


#3

You need to save what in a variable?

The output? The command? Something else?


#4

The output of this mix command.


#5

Thats a bit tricky and something you usually wouldn’t want to do.

  1. Spawn an agent, which simply stores a list of lines that he has received
  2. Use the callback to send each line to the agent
  3. ask the agent for its state

But please be aware of the fact that Mix-module is usually not available in production code unless you explcitely opt in for that. Perhaps you can retrieve the list of routes by another means?


#6

Can’t you do this with Task and System.Cmd instead?


#7

I couldn’t found any other way to get routes in a module.


#8

One could, but still, mix as a command might still be unavailable in production.


#9

Why do you need them at all?


#10

Why do you need to do this anyway?


#11

I am writing a plug that takes the routes from app and then compare them with the authorisation tables and then pass the conn to the endpoint if user is authorised To do this all dynamically i need routes.


#12

The better approach were to write a drop in replacement for the router, that wraps the router DSL and does some bookkeeping on its own.

Another way were to kindly ask making Router.__routes__/0 public.

Relying on tools that might not be available in production is not a viable solution.


#13

After rereading, Why do you need all routes? Shouldn’t the current route be enough to know if the user is allowed to access it?

Maybe I do understand the problem wrong in which case further explanations might be necessary.-


#14

Current route should be enough. But there is a problem. lets say its a patch request users/:id. then the current path in conn object will be ["users", "1"] instead of ["users", ":id"] (which is needed in order to exactly match with action stored in db)


#15

When we send a request we have current path info in the conn struct. Let’s say for patch request.

      ["v1", "users", "2"] or "v1/users/2"

I am writing a plug for users authorisation based on the path info in the db. In the db the paths are stored like this:

      "v1/users/:id"

This is the path we get from running mix phx.routes .

Is it possible that I can get the "v1/users/:id" instead of "v1/users/2" for the current path? so I can match it with the path stored in the db.


#16

You can preprocess "v1/users/:id" yourself into ["v1", "users", :$_] or something similar (like a function clause) and then make it match ["v1", "users", "2"] at runtime.