A few problems were introduced with the choice of using Poweshell scripts on Windows for the clojure cli.
- Quote escaping : 3 escaping rules when using from cmd.exe. Escaping different from Posix systems even from Powershell only.
- Incompatible command line between Powershell and Posix, even worse from cmd.exe
- Quoting issues cannot be fixed on Powershell
- Powershell startup time tax
- Cider cannot “jack-in” a deps.edn project, slowing deps.edn adoption.
Shadow-clj doesn’t work on Windows with a deps.edn project, slowing deps.edn adoption.(this was fixed, shadow-cljs now invokes powershell directly)- Cannot create a clojure batch file or exe in the path because of Powershell aliases discovery causing infinite recursion on first invocation from Powershell
- Competing implementation would probably go away if we fix this
- Need to lower Powershell security by changing global script execution policy
- Current installation process is clunky, and not “Windows idiomatic”
Those issues are not bugs.
- They cannot be fixed as long as we use Powershell
- Almost every issue goes away with a binary wrapper around the Powershell scripts.
- Every single one of those issues goes away with a binary rewrite of the Powershell/bash scripts
I’m of the opinion that “works with my workflow” isn’t good enough. Workflows differ, issues are real and are quite easily fixable.
The goal is to make the dev tools work, that means the command line must work from a regular command shell, and the quoting must ressemble the one on unix. There are several levels of solutions.
- We can completely rewrite the powershell scripts in some other language.
- We can keep these around but write a wrapper for their invocation from the regular command line.
rewrite | wrapper | |
---|---|---|
work is already done | bad | good |
some problems might persist | good | bad |
previous testing is lost | bad | good |
performance penalty | good | slightly bad depending on language |
System complexity | good | bad (more pieces) |
Powershell performance tax | good | bad |
The low hanging fruit | bad | good |
The goal would be to create both a clojure and clj commands, and place these in the path.
- We can invoke directly the powershell command, facing the 3 quote escaping rules
- Create a temporary ps1 file, having to contend with only 2 escaping rules at a time, but do so twice.
- Use the -EncodedCommand powershell command line
Light parsing of the command line is required for maximum Posix compatibility
batch/cmd files | Compiled | .net Compiled | GraalVM exe | |
---|---|---|---|---|
can do temp files | bad | good | good | good |
can deal with escaping | bad | good | good | good |
performance (run time) | good | good | we’re using .net with poweshell so very slightly less good | good |
ease of use | good | good | good | bad (at time of writing) |
ease of build | good | depends | bad | bad |
know-how | good | depends | depends | depends |
complexity | bad | depends | bad | bad |
I went ahead and made an exploratory wrapper using Nim. Been using -EncodedCommand, thus avoiding the temp file. Works well for me at least !
We can completely sidestep the powershell issues.
batch/cmd files | Git bash | compiled (c, c++, D, rust, nim, pascal!) | .net compiled (c#, f#, what else is there?) | GraalVM exe | |
---|---|---|---|---|---|
self-contained | bad | bad | good | good | ? (dll problems ?) |
ease of port/maintenance | bad | good | Can do it in a portable way | we have the powershell implementation that’s a thin .net wrapper : goodish | can use clojure so good i guess ? |
caching/avoid launching java | bad | good | good | good | it is java, but should be fast |
0 to clojure time (newbies) | good | bad | good | good | i don’t know |
professional ease of use | good | depends | good | good | don’t know |
performance | good | good | good | bad .net is also slow to start | good |
can be done at all | bad | good | good | good | good |
know-how | good | depends | depends | slightly better, c# so easy, good standard lib | borkdude is our specialist ! |
available services | very bad | good enough | depends | very good | good |
a joy to work with | bad | nope | depends | depends | good |
build process | good | good | Can do it in a portable way | depends | don’t know |
ease of feature parity | bad | good | good i we make it the main implementation | bad | clojure so good |
ease of maintenance | bad | good | good if portable | medium | good |
can use it on unix too | no | yes | yes if portable | not in a self contained manner | good |
clojure all the way down | no | no | no | possibly | yes |
I went ahead and made a portable implementation using Nim. Tested on Windows and Linux.
I leaned toward a compiled wrapper, and made one to explore the possibility : exploratory wrapper using Nim. Been using -EncodedCommand, thus avoiding the temp file. It works well enough, but we’re still paying the Powershell performance tax this way, we also still face the Alias discovery Powershell bug.
IMO the perfect solution is the portable compiled rewrite of the shell script. An example of what it could look like is here : portable implementation.
- I’m not entirely certain if this fulfills Alex Miller’s requirements.
- I winged it on many table cells, i expect some help in filling/amending those judgment calls and adding more dimensions.
- English is not my native language, so yeah approximate spelling !
- I left out the installation part, I made a tentative native windows installer containing the exploratory wrapper and powershell modules