-
-
Notifications
You must be signed in to change notification settings - Fork 27
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
Support for Mix.exs project function changes #162
Comments
Yeah, you end up figuring out your own zipper eg. https://github.com/atomvm/exatomvm/pull/32/files Igniter.update_elixir_file(igniter, "mix.exs", fn zipper ->
with {:ok, zipper} <- Igniter.Code.Function.move_to_def(zipper, :project, 0),
{:ok, zipper} <-
Igniter.Code.Keyword.put_in_keyword(
zipper,
[:atomvm],
start: Igniter.Project.Module.module_name_prefix(igniter),
esp32_flash_offset: 0x250000,
stm32_flash_offset: 0x8080000,
chip: "auto",
port: "auto"
) do
{:ok, zipper}
end
end) |
@zachdaniel I have a need for this as well, might go ahead and knock it out. I'm curious if you have opinions on where this stuff should live and what direction we should go in. Some thoughts:
So at a high level, when you're modifying Igniter.Project.MixProject.update(igniter, :project, [:aliases, :"some.task"], fn
nil -> {:ok, ["some.task.one", "some.task.two"]}
zipper -> {:ok, zipper}
end)
# above could be used to make higher-level general-purpose utils
Igniter.Project.MixProject.put_new_in(
igniter,
:project,
[:aliases, :"some.task"],
["some.task.one", "some.task.two"]
) In the above example, def project do
[
aliases: [...]
]
end
# or
def project do
[
aliases: aliases()
]
end
defp aliases do
[...]
end For @petermm, the above snippet would become something like: Igniter.Project.MixProject.put_in(igniter, :project, [:atomvm],
start: Igniter.Project.Module.module_name_prefix(igniter),
esp32_flash_offset: 0x250000,
stm32_flash_offset: 0x8080000,
chip: "auto",
port: "auto"
) Thoughts? |
To help think through this proposed API a bit more, I wrote out a docstring and spec: @doc """
Updates the project configuration AST at the given path.
This function accepts a `function_name` atom corresponding to a function
like `project/0`, `application/0`, or `cli/0` and navigates to the given
path, jumping to private functions if necessary and creating nested
keyword lists if they don't already exist. It then calls the given
`update_fun`, using the return value to update the AST.
`update_fun` must be a function that accepts one argument, a zipper
targeting the current AST at the given configuration path or `nil` if
there was no value at that path. It then must return one of the
following:
* `{:ok, zipper}` - the updated zipper
* `{:ok, {:code, quoted}}` - a quoted expression that should be
inserted as the new value at `path`
* `{:ok, nil}` - indicates that the last key in `path` should be
removed
* `{:error, message}` - an error that will be accumulated in the
`igniter`
* `{:warning, message}` - a warning that will be accumulated in the
`igniter`
* `:error` - the `igniter` should be returned without change
## Examples
Assuming a newly-generated Mix project that looks like this:
defmodule Example.MixProject do
use Mix.Project
def project do
[
app: :example,
version: "0.1.0",
elixir: "~> 1.17",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
def application do
[
extra_applications: [:logger]
]
end
defp deps do
[]
end
end
Increment the project version by one patch level:
Igniter.Project.MixProject.update(igniter, :project, [:version], fn zipper ->
new_version =
zipper.node
|> Version.parse!()
|> Map.update!(:patch, &(&1 + 1))
|> to_string()
{:ok, {:code, new_version}}
end)
# would result in
def project do
[
...,
version: "0.1.1",
...
]
end
Set the preferred env for a task to `:test`:
Igniter.Project.MixProject.update(
igniter,
:cli,
[:preferred_envs, :"some.task"],
fn _ -> {:ok, {:code, :test}} end
)
# would create `cli/0` and set the env:
def cli do
[
preferred_envs: [
"some.task": :test
]
]
end
Add `:some_application` to `:extra_applications`:
Igniter.Project.MixProject.update(igniter, :application, [:extra_applications], fn
nil -> {:ok, {:code, [:some_application]}}
zipper -> Igniter.Code.List.append_to_list(zipper, :some_application)
end)
# would result in
def application do
[
extra_applications: [:logger, :some_application]
]
end
Remove `:extra_applications` altogether:
Igniter.Project.MixProject.update(
igniter,
:application,
[:extra_applications],
fn _ -> {:ok, nil} end
)
# would result in
def application do
[]
end
"""
@spec update(
Igniter.t(),
function_name :: atom(),
path :: nonempty_list(atom()),
update_fun ::
(Zipper.t() | nil ->
{:ok, Zipper.t() | {:code, quoted :: Macro.t()} | nil}
| {:error | :warning, term()}
| :error)
) :: Igniter.t()
def update(%Igniter{} = igniter, function_name, path, update_fun)
when is_atom(function_name) and is_list(path) and is_function(update_fun, 1) do
...
end |
🤔 its an interesting case. Honestly I'm not sure how ultimately successful this abstraction will be. There is enough variation in the "typical ways" that something might be configured, that I feel like supporting things like For example, the code in With that said, I'm open to having this to start, and then advising people to use other more specific functions as they are developed. |
The project version is actually a good example of such a thing, specifically its very common for the project version to live in |
I agree with you that higher-level abstractions should be built. Another is That said, I'm not yet convinced that My strong inclination is to implement |
Is your feature request related to a problem? Please describe.
I could not find a way to update the options in the project function of a mix.exs file. Would be awesome if we could so we can update specific params or add/remove new options. I am currently trying to write an upgrade style igniter for phx 1.6to 1.7 and one of the change involve clean the :compilers option to remove phoenix and gettext too
Describe the solution you'd like
An api to modify or add/remote options for the project function in a mix.exs file
Describe alternatives you've considered
Dont have any other than using Zipper myself and figure it out
The text was updated successfully, but these errors were encountered: