I am trying to configure an “umbrella project” for my Elixir studies, to keep common configuration and dependencies in a single place for all projects.
To simplify configuration of said project, I believe that workspace configuration should be a bit more complex; I envision something like this
This way, all exercises would essentially become modules of a single project inside {track}, so with proper configuration it would be easier to launch tests from editors like Visual Studio Code.
If you want more customized paths, you could also use symlinks/shortcuts to configure your project. You can store the Exercism files in the Exercism workspace and have your IDE live in a different location. By using symlinks/shortcuts, you can share/layer these views.
Maybe I’m just trying to do something specially weird; I might end up creating some custom scripts for it.
The idea here is to have a single elixir project, which contains Exercism exercises inside of apps, by using Elixir’s Umbrella Project feature.
This way I wouldn’t need to open a new Visual Studio Code window per exercise, or to manually add each project to a Workspace in VS Code; all exercises would be instantly visible in VS Code, with other assorted extensions working without issue (like using the Language Server).
In other words, I want to configure my track environment exactly once, and just focus on doing each exercise with as few steps as possible.
Symlinks could maybe work; I might look into doing that, specially if this request isn’t popular enough to warrant development time.
Edit: I tried using symlinks, but while it seems to work, I see this kind of warning on VS Code:
Warning: "** (File.Error) could not read file "/home/kay/.local/share/exercism/config/config.exs": no such file or directory
(elixir 1.15.0) lib/file.ex:358: File.read!/1
(elixir 1.15.0) lib/config/reader.ex:110: Config.Reader.read_imports!/2
(mix 1.15.0) lib/mix/tasks/loadconfig.ex:54: Mix.Tasks.Loadconfig.load_compile/1
(mix 1.15.0) lib/mix/task.ex:447: anonymous fn/3 in Mix.Task.run_task/5
(mix 1.15.0) lib/mix/cli.ex:91: Mix.CLI.run_task/2
"
This might be because I also modified the mix.exs file in the exercise to use the umbrella app’s configuration with relative paths, which seem to resolve to the real folder instead of the symlink.
Moving the exercises also doesn’t work, because exercism requires that I run exercism submit from within the workspace. This would also be annoying with symlinks too, since I’d have to remember where were they originally downloaded.
I ended up creating a wrapper around exercism download, specifically for Elixir projects (in Fish script):
# Defined in /home/kay/.config/fish/functions/exercism-elixir.fish @ line 1
function exercism-elixir --argument exercise
# This is the "real" workspace, where we will move all exercises after downloading
set -l workspace $HOME/projects/learning/exercism/elixir
# To be used later; removes hyphens and capitalizes each word
set -l exercise_module_name (string split '-' 'freelancer-rates' | sed 's/[^ _-]*/\u&/g' | string join '')
# Remove previous exercise if it exists
if test -d "$workspace/$exercise"
rm -rf "$workspace/$exercise"
end
# Download the exercise
exercism download --track=elixir --exercise=$exercise
# Remove and replace preexisting build folder;
# we will use global one from umbrella project
rm -rf "$workspace/$exercise/_build"
# Uses a template mix.exs file, which we will edit
cp "$workspace/mix.exs.tmpl" "$workspace/$exercise/mix.exs"
# Replace app_name with the exercise name
if string match -rq '-' $exercise
# If the name contains '-' we need to wrap it with single quotes
sed -in "$workspace/$exercise/mix.exs" -e "s|:app_name|:'$exercise'|"
else
sed -in "$workspace/$exercise/mix.exs" -e "s|:app_name|:$exercise|"
end
# Set module name
sed -in "$workspace/$exercise/mix.exs" -e "s|AppName|$exercise_module_name|"
# Symlink credo configuration file from umbrella app
ln -s "$workspace/.credo.exs" "$workspace/$exercise/.credo.exs"
# Move the exercise to the apps directory
mv "$workspace/$exercise" "$workspace/apps/$exercise"
end
The mix.exs.tmpl file only has two differences from the original mix.exs present in current exercises:
def project do
[
...
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
...
]
end
...
defp deps do
[
# This has to be present on each exercise, otherwise the Credo VS Code extension breaks
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
]
end
And then in the top folder, before downloading exercises, I generated an umbrella project with this command: mix new --app exercism_elixir elixir --umbrella
A bit convoluted, but it’s not like I care much if a learning project breaks locally
“.” does seem to work; I do get a warning complaining that the folder credo in the root does not have a mix.exs file and won’t be included in the umbrella (which is fine), but other than that, I tried running tests from VS Code after copying one of the exercises, and it works.
It still requires me to edit/overwrite each exercise’s mix.exs file, but that might be optional; using the default mix.exs file only means that each exercise will have its own _build and deps folder, becoming effectively isolated, and breaking VS Code credo extension (unless I manually add it on each exercise). Everything else should work.
I kinda like keeping them inside a subfolder, but the original “complaint” I had would also be addressed by setting the path to “.” in the umbrella project.