Skip to content

Commit 5469181

Browse files
authored
Merge branch 'main' into refactoring
2 parents 360013e + 9f14ebf commit 5469181

16 files changed

+267
-59
lines changed

Diff for: CONTRIBUTING.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
This is a [Clojure contrib] project.
2+
3+
Under the Clojure contrib [guidelines], this project cannot accept
4+
pull requests. All patches must be submitted via [JIRA].
5+
6+
See [Contributing] on the Clojure website for
7+
more information on how to contribute.
8+
9+
[Clojure contrib]: https://clojure.org/community/contrib_libs
10+
[Contributing]: https://clojure.org/community/contributing
11+
[JIRA]: https://clojure.atlassian.net/browse/TNS
12+
[guidelines]: https://clojure.org/community/contrib_howto

Diff for: README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ For ClojureCLR on .NET 6 and later.
66

77
## Releases
88

9-
The current release is 0.0.1-alpha2.
9+
The current release is 0.1.0-alpha6.
1010

1111

1212
## Installation
@@ -17,14 +17,14 @@ Prerequisite: ClojureCLR must be installed as a tool. See [Getting started (Cl
1717
To install as a global tool:
1818

1919
```
20-
dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha2
20+
dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha6
2121
```
2222

2323
To install as a local tool:
2424

2525
```
2626
dotnet new tool-manifest # if you are setting up this repo
27-
dotnet tool install --local Clojure.Cljr --version 0.1.0-alpha2
27+
dotnet tool install --local Clojure.Cljr --version 0.1.0-alpha6
2828
```
2929

3030
For other installation approaches, check out the [Clojure.Cljr Nuget page](https://www.nuget.org/packages/Clojure.Cljr/).

Diff for: doc/Prepare-distribution.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Preparing a distribution
2+
3+
## Dependencies
4+
5+
Clojure.Cljr depends on several ClojureCLR libraries. There are not pulled in as NuGet packages, but are included in the distribution zip files. The libraries are:
6+
7+
- clr.tools.gitlibs
8+
- clr.tools.deps
9+
- clr.tools.deps.cli
10+
11+
If there have been any changes to these libraries, the source files need to be copied into the project in the appropriate directories.
12+
13+
## Set the version
14+
15+
Edit Cljr.csproj and set the version number in the `Version` property. This is the version number that will be used in the NuGet package.
16+
17+
## Build and test
18+
19+
There is a test project, Cljr.Tests. This mostly tests parsing.
20+
21+
To really test, set the command line parameters for debugging. Good luck.
22+
23+
Beyond that, the best test is to use the tool. I typically do the build, which creates the package.
24+
Then go into the `nupkg` directory and install the package with
25+
26+
```
27+
dotnet tool install -g --add-source . Cljr` --version 0.1.0-alphaX
28+
```
29+
30+
whatever version is current. Then go into a few of the other libraries and run `cljr -X:test`.
31+
32+
## Publish
33+
34+
```
35+
dotnet nuget push Clojure.Cljr.WHATEVER -s nuget.org
36+
```
37+

Diff for: doc/intro.md

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# An introduction to `cljr`
2+
3+
Start by reading [Deps and CLI Reference Rationale](https://clojure.org/reference/deps_and_cli).
4+
5+
The CLR port of [tools.deps](https://github.com/clojure/tools.deps) is currently located at [clr.tools.deps](https://github.com/clojure/clr.tools.deps).
6+
7+
This repo contains the .NET equivalent of the command line programs `cli` and `clojure`.
8+
9+
## How it works
10+
11+
The main program follows the outline of the `cli` tool.
12+
The first step is the parse the command-line arguments.
13+
14+
If the arg list contains `-h`, a help message will be printed.
15+
This will give you the clues for other options. (I need to edit the help text a bit to make it `cljr`-specific.)
16+
17+
At the moment, there is no distinction betwee `cli` and `clojure`.
18+
(I don't see any difference in the JVM world either, despite what they say in the help text.)
19+
20+
```
21+
...> Deps.Cljr.exe -h
22+
Version: 1.0.0.0
23+
24+
You use the Clojure tools('clj' or 'clojure') to run Clojure programs
25+
on the JVM, e.g.to start a REPL or invoke a specific function with data. The Clojure tools will configure the JVM process by defining a classpath (of desired libraries), an execution environment(JVM options) and specifying a main class and args.
26+
27+
Using a deps.edn file(or files), you tell Clojure where your source code resides and what libraries you need.Clojure will then calculate the full set of required libraries and a classpath, caching expensive parts of this process for better performance.
28+
29+
The internal steps of the Clojure tools, as well as the Clojure functions you intend to run, are parameterized by data structures, often maps. Shell command lines are not optimized for passing nested data, so instead you will put the data structures in your deps.edn file and refer to them on the command line via 'aliases' - keywords that name data structures.
30+
31+
'clj' and 'clojure' differ in that 'clj' has extra support for use as a REPL in a terminal, and should be preferred unless you don't want that support, then use 'clojure'.
32+
33+
Usage:
34+
35+
Start a REPL
36+
clj [clj-opt*] [-Aaliases]
37+
38+
Exec fn(s)
39+
clojure [clj-opt*] -X[aliases][a / fn *][kpath v]*
40+
41+
Run main
42+
clojure[clj-opt *] -M[aliases][init-opt *][main-opt][arg*]
43+
44+
Run tool
45+
clojure [clj-opt*] -T[name | aliases] a/fn[kpath v] kv-map?
46+
47+
Prepare
48+
clojure[clj-opt*] -P[other exec opts]
49+
50+
exec-opts:
51+
-Aaliases Use concatenated aliases to modify classpath
52+
-X[aliases] Use concatenated aliases to modify classpath or supply exec fn/args
53+
-M[aliases] Use concatenated aliases to modify classpath or supply main opts
54+
-P Prepare deps - download libs, cache classpath, but don't exec
55+
56+
clj-opts:
57+
-Jopt Pass opt through in java_opts, ex: -J-Xmx512m
58+
-Sdeps EDN Deps data to use as the last deps file to be merged
59+
-Spath Compute classpath and echo to stdout only
60+
-Stree Print dependency tree
61+
-Scp CP Do NOT compute or cache classpath, use this one instead
62+
-Srepro Ignore the ~/.clojure/deps.edn config file
63+
-Sforce Force recomputation of the classpath(don't use the cache)
64+
-Sverbose Print important path info to console
65+
-Sdescribe Print environment and command parsing info as data
66+
-Sthreads Set specific number of download threads
67+
-Strace Write a trace.edn file that traces deps expansion
68+
-- Stop parsing dep options and pass remaining arguments to clojure.main
69+
--version Print the version to stdout and exit
70+
-version Print the version to stdout and exit
71+
72+
The following non-standard options are available only in deps.clj:
73+
74+
-Sdeps-file Use this file instead of deps.edn
75+
-Scommand A custom command that will be invoked. Substitutions: { { classpath} }, {{main-opts
76+
}}.
77+
78+
init - opt:
79+
-i, --init path Load a file or resource
80+
-e, --eval string Eval exprs in string; print non-nil values
81+
--report target Report uncaught exception to "file" (default), "stderr", or "none"
82+
83+
main-opt:
84+
-m, --main ns - name Call the -main function from namespace w/args
85+
-r, --repl Run a repl
86+
path Run a script from a file or resource
87+
- Run a script from standard input
88+
-h, -?, --help Print this help message and exit
89+
90+
Programs provided by :deps alias:
91+
-X:deps mvn-pom Generate (or update) pom.xml with deps and paths
92+
-X:deps list List full transitive deps set and licenses
93+
-X:deps tree Print deps tree
94+
-X:deps find-versions Find available versions of a library
95+
-X:deps prep Prepare all unprepped libs in the dep tree
96+
-X:deps mvn-install Install a maven jar to the local repository cache
97+
-X:deps git-resolve-tags Resolve git coord tags to shas and update deps.edn
98+
99+
For more info, see:
100+
https://clojure.org/guides/deps_and_cli
101+
https://clojure.org/reference/repl_and_main
102+
103+
```
104+
105+
- If the arg list contains `-h`, `-?`, or `--help`, a help message will be printed. (Above)
106+
- If the arg list contains `-version` or `--version`, version info will be printed.
107+
108+
```
109+
...> Deps.Cljr.exe -version
110+
ClojureCLR CLI Version: 1.0.0.0
111+
```
112+
113+
- If the arg list contains `-pom` or `-Jwhatever`, it will be ignored, other than printing a warning, "We are the CLR!". Eventually we will come up with a substitute for the `-Jwhatever` that allows passing information to the CLR runtime. Maybe. When I figure out what that might be.
114+
115+
- If the arg list containts `-Sverbose`, you will get extra information printed out, including information on installation and configuration directories that might be helpful in debugging.
116+
117+
118+
After parsing the command line, the short-circuits help and version are checked for. This followed by computing a bunch of environmental information: the install, config and cache directories, the tools directory (including making sure there is a `tools.edn` file in there and copying a blank one if necessary).
119+
120+
Then the various aliases (`-X`, `-M`, `-T`, etc.) are computed and used to form the cache key, which is then hashed. This determines the subdirectory in the cache file to look at and store cached info into.
121+
122+
You can see all this by running with `-Sverbose`:
123+
124+
```
125+
> Deps.Cljr.exe -Sverbose
126+
version = 1.0.0.0
127+
install_dir = C:\work\clojure\deps.cljr\src\dotnet\Deps.Cljr\bin\Debug\net6.0\
128+
config_dir = C:\Users\dmill\.clojure
129+
config_paths = C:\work\clojure\deps.cljr\src\dotnet\Deps.Cljr\bin\Debug\net6.0\deps.edn C:\Users\dmill\.clojure\deps.edn deps.edn
130+
cache_dir = C:\Users\dmill\.clojure\.cpcache
131+
cp_file = C:\Users\dmill\.clojure\.cpcache\D79F9C6847CA7B8A630F9F8E6C23BEE0.cp
132+
133+
Refreshing classpath
134+
...
135+
```
136+
137+
The string `D79F9C6847CA7B8A630F9F8E6C23BEE0` is the cache key hash.
138+
139+
The next step is to see if the classpath information is stale and refresh if necessary. The classpath is computed by the ClojureCLR function `clojure.tools.deps.script.make-classpath2`. This is run by running a PowerShell script that starts up ClojureCLR and runs this function, with a bunch of arguments passed on the command line.
140+
141+
Here is what is executed:
142+
143+
```
144+
run-clojure-main.ps1 -m clojure.tools.deps.script.make-classpath2 --config-user C:\Users\dmill\.clojure\deps.edn --config-project deps.edn --cp-file C:\Users\dmill\.clojure\.cpcache\D79F9C6847CA7B8A630F9F8E6C23BEE0.cp --jvm-file C:\Users\dmill\.clojure\.cpcache\D79F9C6847CA7B8A630F9F8E6C23BEE0.jvm --main-file C:\Users\dmill\.clojure\.cpcache\D79F9C6847CA7B8A630F9F8E6C23BEE0.main --manifest-file C:\Users\dmill\.clojure\.cpcache\D79F9C6847CA7B8A630F9F8E6C23BEE0.manifest
145+
```
146+
147+
The script `run-clojure-main.ps1` is trivial:
148+
149+
```
150+
clojure.main @args
151+
```
152+
153+
Seriously, that's it.
154+
155+
You will note some oddities in the command line arguments, such as the `.jvm` file -- those will eventually be replaced. The arguments passed to `clojure.tools.deps.script.make-classpath2` here are what that program is currently written to accept.
156+
157+
In order for this to work, we must have the `clr.tools.deps` code in the appropriate `bin` subdirectory. This is a dependence that we must build in by hand -- we are building the tool that calculates dependencies and pulls in code, but there is no obvious way to have it bootstrap itself, other than to pull in the code as needed from being hardwired. (to do -- for now, we just bring it in by hand.)

Diff for: src/dotnet/Cljr/Cljr.csproj

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
<ToolCommandName>cljr</ToolCommandName>
1111
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1212
<PackageOutputPath>./nupkg</PackageOutputPath>
13-
<Version>0.1.0-alpha2</Version>
13+
<Version>0.1.0-alpha6</Version>
1414
<PackageId>Clojure.$(AssemblyName)</PackageId>
1515
<Authors>ClojureCLR contributors</Authors>
1616
<Description>The deps.edn-powered CLI tool for ClojureCLR.</Description>
17-
<Copyright>ClojureCLR contributors, 2024</Copyright>
17+
<Copyright>ClojureCLR contributors, 2025</Copyright>
1818
<PackageProjectUrl>https://github.com/clojure/clr.core.cli</PackageProjectUrl>
1919
<RepositoryUrl>https://github.com/clojure/clr.core.cli</RepositoryUrl>
2020
<PackageLicenseExpression>EPL-1.0</PackageLicenseExpression>
@@ -38,5 +38,4 @@
3838
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3939
</Content>
4040
</ItemGroup>
41-
4241
</Project>

Diff for: src/dotnet/Cljr/Program.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ static Process CreateClojureProcess(string installDir, string[] args, Dictionary
494494
foreach (var (key, value) in env)
495495
process.StartInfo.EnvironmentVariables[key] = value;
496496

497-
List<string> prependArgs = [];
497+
List<string> prependArgs = [];
498498

499499
if (Platform.IsWindows)
500500
prependArgs.AddRange([
@@ -509,4 +509,5 @@ static Process CreateClojureProcess(string installDir, string[] args, Dictionary
509509
process.StartInfo.ArgumentList.Add(arg.Contains(' ') ? $"\"{arg}\"" : arg);
510510

511511
return process;
512+
512513
}

Diff for: src/dotnet/Cljr/Properties/launchSettings.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"profiles": {
3+
"Cljr": {
4+
"commandName": "Project",
5+
"commandLineArgs": "-X:test",
6+
"workingDirectory": "C:\\work\\temp\\testretcode"
7+
}
8+
}
9+
}

Diff for: src/dotnet/Cljr/clojure/run/exec.cljc

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454

5555
(defn- envelope
5656
[args tag val out-wr err-wr start]
57-
(let [end #?(:clj (System/currentTimeMillis) :cljr (int (/ (.Ticks (DateTime/Now)) (TimeSpan/TicksPerMillisecond))))]
57+
(let [end #?(:clj (System/currentTimeMillis) :cljr (long (/ (.Ticks (DateTime/Now)) (TimeSpan/TicksPerMillisecond))))]
5858
(cond-> {:tag tag
5959
:val (binding [*print-namespace-maps* false] (pr-str val))
6060
:ms (- end start)}
@@ -66,7 +66,7 @@
6666
(let [clean-args (remove-ns-keys args "clojure.exec")
6767
out-wr (StringWriter.)
6868
err-wr (StringWriter.)
69-
start #?(:clj (System/currentTimeMillis) :cljr (int (/ (.Ticks (DateTime/Now)) (TimeSpan/TicksPerMillisecond))))
69+
start #?(:clj (System/currentTimeMillis) :cljr (long (/ (.Ticks (DateTime/Now)) (TimeSpan/TicksPerMillisecond))))
7070
envelope (binding [*out* out-wr, *err* err-wr]
7171
(try
7272
(envelope args :ret (f clean-args) out-wr err-wr start)

Diff for: src/dotnet/Cljr/clojure/tools/cli/api.cljc

+4-1
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,10 @@
417417
[{:keys [lib tool n] :or {n 8} :as args}]
418418
(let [{:keys [root-edn user-edn]} (deps/find-edn-maps)
419419
master-edn (deps/merge-edns [root-edn user-edn])
420-
trunc-fn (if (= n :all) (fn [_n x] x) #(apply take-last %&))
420+
trunc-fn (fn [n x]
421+
(if (= n :all)
422+
x
423+
(mapcat #(take-last n %) (vals (group-by keys x)))))
421424
coords (cond
422425
tool
423426
(if-let [{:keys [lib coord]} (tool/resolve-tool (name tool))]

Diff for: src/dotnet/Cljr/clojure/tools/deps.cljc

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@
2424
[clojure.lang PersistentQueue]
2525
#?(:clj [java.io File InputStreamReader BufferedReader]
2626
:cljr [System.IO Path FileInfo DirectoryInfo])
27-
#?(:clj [java.lang ProcessBuilder ProcessBuilder$Redirect] :cljr [System.Diagnostics ProcessStartInfo Process])
27+
#?(:clj [java.lang ProcessBuilder ProcessBuilder$Redirect] ) ;;; :cljr [System.Diagnostics ProcessStartInfo Process] -- defer until after we load the dll, if required.
2828
#?(:clj [java.util List]
2929
:cljr [System.Collections ArrayList])
3030
#?(:cljr [System.Threading CancellationTokenSource CancellationToken])
3131
))
3232

33+
(try
34+
(assembly-load-from (str clojure.lang.RT/SystemRuntimeDirectory "System.Diagnostics.Process.dll"))
35+
(catch Exception e)) ;; failing silently okay -- if we need it and didn't find it, a type reference will fail later
36+
37+
(import '[System.Diagnostics Process ProcessStartInfo])
38+
3339
(set! *warn-on-reflection* true)
3440

3541
;;;; deps.edn reading
@@ -489,7 +495,7 @@
489495
:ppath use-path
490496
:child-pred child-pred})]
491497
(loop [pendq nil ;; a resolved child-lookup thunk to look at first
492-
q (into (PersistentQueue/EMPTY) (map vector deps)) ;; queue of nodes or child-lookups
498+
q (into PersistentQueue/EMPTY (map vector deps)) ;; queue of nodes or child-lookups
493499
version-map nil ;; track all seen versions of libs and which version is selected
494500
exclusions nil ;; tracks exclusions marked in the tree
495501
cut nil ;; tracks cuts made of child nodes based on exclusions
@@ -536,7 +542,7 @@
536542
:ppath use-path
537543
:child-pred child-pred})]
538544
(loop [pendq nil ;; a resolved child-lookup thunk to look at first
539-
q (into (PersistentQueue/EMPTY) (map vector deps)) ;; queue of nodes or child-lookups
545+
q (into PersistentQueue/EMPTY (map vector deps)) ;; queue of nodes or child-lookups
540546
version-map {} ;; track all seen versions of libs and which version is selected
541547
exclusions nil ;; tracks exclusions marked in the tree
542548
cut nil ;; tracks cuts made of child nodes based on exclusions
@@ -667,7 +673,7 @@
667673
(defn- make-tree
668674
[lib-map]
669675
(let [{roots false, nonroots true} (group-by #(-> % val :dependents boolean) lib-map)]
670-
(loop [q (into (PersistentQueue/EMPTY) roots)
676+
(loop [q (into PersistentQueue/EMPTY roots)
671677
remaining nonroots
672678
tree {}]
673679
(let [[lib coord :as node] (peek q)

Diff for: src/dotnet/Cljr/clojure/tools/deps/deps.edn

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
:paths ["."]
2+
:paths ["src"]
33

44
;;; eventually, we need to be able to declare the clojure version to use.
55
;;;:deps {

Diff for: src/dotnet/Cljr/clojure/tools/deps/extensions.cljc

+4-3
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,11 @@
146146
(throw-bad-coord lib coord))
147147

148148
(defn find-all-versions
149-
"Find versions across all registered procurer types and return first that finds some.
150-
Returns coll of coordinates for this lib (based on lib and partial coordinate)."
149+
"Find versions across all registered procurer types.
150+
Returns coll of coordinates for this lib (based on lib and partial coordinate).
151+
For each procurer type, coordinates are returned in chronological order."
151152
[lib coord config]
152-
(some #(find-versions lib coord % config) (procurer-types)))
153+
(mapcat #(find-versions lib coord % config) (procurer-types)))
153154

154155
;; Methods switching on manifest type
155156

Diff for: src/dotnet/Cljr/clojure/tools/deps/tree.cljc

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
subprocesses (tool, resolve-deps, make-classpath-map).
6161
6262
Options:
63+
:dir - directory root path, defaults to current directory
6364
:root - dep source, default = :standard
6465
:user - dep source, default = :standard
6566
:project - dep source, default = :standard (\"./deps.edn\")

0 commit comments

Comments
 (0)