├── src ├── dotnet │ ├── Cljr.Tests │ │ ├── Usings.cs │ │ ├── Cljr.Tests.csproj │ │ └── ParsingTests.cs │ └── Cljr │ │ ├── tools │ │ ├── run-clojure-main.sh │ │ └── run-clojure-main.ps1 │ │ ├── example-deps.edn │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── Platform.cs │ │ ├── deps.edn │ │ ├── clojure │ │ ├── tools │ │ │ ├── deps │ │ │ │ ├── deps.edn │ │ │ │ ├── util │ │ │ │ │ ├── concurrent.cljr │ │ │ │ │ ├── session.cljc │ │ │ │ │ ├── io.cljc │ │ │ │ │ └── dir.cljc │ │ │ │ ├── license-abbrev.edn │ │ │ │ ├── script │ │ │ │ │ ├── parse.cljc │ │ │ │ │ ├── resolve_tags.cljc │ │ │ │ │ └── make_classpath2.cljc │ │ │ │ ├── tool.cljc │ │ │ │ ├── extensions │ │ │ │ │ ├── deps.cljc │ │ │ │ │ ├── local.cljc │ │ │ │ │ └── git.cljc │ │ │ │ ├── tree.cljc │ │ │ │ ├── specs.cljc │ │ │ │ └── extensions.cljc │ │ │ ├── gitlibs │ │ │ │ ├── config.cljr │ │ │ │ └── impl.cljr │ │ │ ├── cli │ │ │ │ ├── help.cljc │ │ │ │ └── api.cljc │ │ │ └── gitlibs.cljc │ │ └── run │ │ │ └── exec.cljc │ │ ├── Cljr.sln │ │ ├── Cljr.csproj │ │ ├── ParseItems.cs │ │ └── CommandLineParser.cs └── clojure │ ├── time-lib │ ├── deps.edn │ └── src │ │ └── hello_time.clj │ ├── README.txt │ └── hello-world │ ├── deps.edn │ └── src │ └── hello.clj ├── CONTRIBUTING.md ├── doc ├── Prepare-distribution.md └── intro.md ├── scripts ├── diff.bat └── diff.out ├── .gitignore ├── README.md ├── LICENSE.txt └── epl-v10.html /src/dotnet/Cljr.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /src/dotnet/Cljr/tools/run-clojure-main.sh: -------------------------------------------------------------------------------- 1 | Clojure.Main "$@" -------------------------------------------------------------------------------- /src/clojure/time-lib/deps.edn: -------------------------------------------------------------------------------- 1 | { 2 | :paths 3 | ["src" ] 4 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/tools/run-clojure-main.ps1: -------------------------------------------------------------------------------- 1 | clojure.main @args ; exit $LASTEXITCODE -------------------------------------------------------------------------------- /src/dotnet/Cljr/example-deps.edn: -------------------------------------------------------------------------------- 1 | { 2 | :aliases { 3 | ;; Add cross-project aliases here 4 | } 5 | } -------------------------------------------------------------------------------- /src/clojure/README.txt: -------------------------------------------------------------------------------- 1 | The projects in this folder were used to do testing of local coordinates, deps chaining, etc. -------------------------------------------------------------------------------- /src/clojure/time-lib/src/hello_time.clj: -------------------------------------------------------------------------------- 1 | (ns hello-time) 2 | 3 | (defn now [] (DateTime/Now)) 4 | (defn time-str [t] (.ToString ^DateTime t "F")) 5 | -------------------------------------------------------------------------------- /src/clojure/hello-world/deps.edn: -------------------------------------------------------------------------------- 1 | { :deps 2 | {time-lib/time-lib { :local/root "../time-lib"} 3 | io.github.dmiller/deps-cljr-test1 {:git/tag "v1.0.0" :git/sha "9084c83"}} 4 | :paths 5 | ["src" ] 6 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Cljr": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-Sforce -X:test", 6 | "workingDirectory": "C:\\work\\clojure\\clr.tools.namespace" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/Platform.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Cljr; 5 | 6 | public static class Platform 7 | { 8 | public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); 9 | public static string HomeDir => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); 10 | public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown"; 11 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /src/clojure/hello-world/src/hello.clj: -------------------------------------------------------------------------------- 1 | (ns hello 2 | (:require [hello-time :as ht] 3 | [dct1.test :as t1])) 4 | 5 | (defn run [opts] 6 | (println "This is hello/run talking.") 7 | (println "opts = " opts) 8 | (println "Hello world, the time is " (ht/time-str (ht/now)))) 9 | 10 | (defn -main [] 11 | (println "This is hello/-main talking.") 12 | (println "Hello world, the time is " (ht/time-str (ht/now)))) 13 | 14 | 15 | 16 | (defn test1 [opts] 17 | (println "this is hello/test1 talking.") 18 | (println "going to call out to deps-cljr-test1 (github coords)") 19 | (t1/g 12)) -------------------------------------------------------------------------------- /src/dotnet/Cljr/deps.edn: -------------------------------------------------------------------------------- 1 | { 2 | :paths ["src"] 3 | 4 | ;;; eventually, we need to be able to declare the clojure version to use. 5 | ;;;:deps { 6 | ;;; org.clojure/clojure {:mvn/version "${clojure.version}"} 7 | ;;;} 8 | 9 | :aliases { 10 | :deps {:replace-paths [] 11 | :replace-deps {io.github.clojure/clr.tools.deps.cli {:git/tag "v0.1.7" :git/sha "e8e5491" }} 12 | :ns-default clojure.tools.deps.cli.api 13 | :ns-aliases {help clojure.tools.deps.cli.help}} 14 | :test {:extra-paths ["test"]} 15 | } 16 | 17 | ;;; no need for this 18 | ;;;:mvn/repos { 19 | ;;; "central" {:url "https://repo1.maven.org/maven2/"} 20 | ;;; "clojars" {:url "https://repo.clojars.org/"} 21 | ;;;} 22 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/deps.edn: -------------------------------------------------------------------------------- 1 | { 2 | :paths ["src"] 3 | 4 | ;;; eventually, we need to be able to declare the clojure version to use. 5 | ;;;:deps { 6 | ;;; org.clojure/clojure {:mvn/version "${clojure.version}"} 7 | ;;;} 8 | 9 | :aliases { 10 | :deps {:replace-paths [] 11 | :replace-deps {io.github.clojure/clr.tools.deps.cli {:git/tag "v0.1.7" :git/sha "e8e5491" }} 12 | :ns-default clojure.tools.deps.cli.api 13 | :ns-aliases {help clojure.tools.deps.cli.help}} 14 | :test {:extra-paths ["test"]} 15 | } 16 | 17 | ;;; no need for this 18 | ;;;:mvn/repos { 19 | ;;; "central" {:url "https://repo1.maven.org/maven2/"} 20 | ;;; "clojars" {:url "https://repo.clojars.org/"} 21 | ;;;} 22 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/util/concurrent.cljr: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.util.concurrent 11 | (:import 12 | [System.Threading.Tasks TaskFactory] 13 | [System.Threading CancellationToken])) 14 | 15 | (set! *warn-on-reflection* true) 16 | 17 | (def processors (long Environment/ProcessorCount)) 18 | 19 | (defn create-task-factory ^TaskFactory [^CancellationToken ctoken] 20 | (TaskFactory. ctoken)) 21 | 22 | (defn submit-task [^TaskFactory tf f] 23 | (let [p (promise) 24 | ;;bindings (get-thread-bindings) 25 | task (bound-fn* f)] 26 | (.StartNew tf (sys-action [] (deliver p (task)))) 27 | p)) 28 | -------------------------------------------------------------------------------- /src/dotnet/Cljr.Tests/Cljr.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /doc/Prepare-distribution.md: -------------------------------------------------------------------------------- 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 . Clojure.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 | 38 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/license-abbrev.edn: -------------------------------------------------------------------------------- 1 | ;; Map of "name found in the wild" => abbreviated name 2 | ;; not exhaustive, just trying to catch 80% 3 | ;; useful resource: https://github.com/spdx/license-list-data 4 | {"3-Clause BSD License" "BSD-3-Clause-Attribution" 5 | "Apache 2.0" "Apache-2.0" 6 | "Apache License 2.0" "Apache-2.0" 7 | "Apache License Version 2.0" "Apache-2.0" 8 | "Apache License, Version 2.0" "Apache-2.0" 9 | "Apache Software License - Version 2.0" "Apache-2.0" 10 | "Apache v2" "Apache-2.0" 11 | "BSD 3-Clause License" "BSD-3-Clause-Attribution" 12 | "Eclipse Public License" "EPL-1.0" 13 | "Eclipse Public License (EPL)" "EPL-1.0" 14 | "Eclipse Public License - v 1.0" "EPL-1.0" 15 | "Eclipse Public License 1.0" "EPL-1.0" 16 | "Eclipse Public License, Version 1.0" "EPL-1.0" 17 | "Eclipse Public License 2.0" "EPL-2.0" 18 | "Eclipse Public License version 2" "EPL-2.0" 19 | "GNU Affero General Public License (AGPL) version 3.0" "AGPL-3.0" 20 | "GNU General Public License, version 2 (GPL2), with the classpath exception" "GPL-2.0-with-classpath-exception" 21 | "GNU General Public License, version 2 with the GNU Classpath Exception" "GPL-2.0-with-classpath-exception" 22 | "GNU General Public License, version 2" "GPL-2.0" 23 | "GNU Lesser General Public License (LGPL)" "LGPL" 24 | "JSON License" "JSON" 25 | "MIT License" "MIT" 26 | "MIT license" "MIT" 27 | "Mozilla Public License" "MPL" 28 | "The Apache Software License, Version 2.0" "Apache-2.0" 29 | "The BSD 3-Clause License (BSD3)" "BSD-3-Clause-Attribution" 30 | "The MIT License" "MIT"} -------------------------------------------------------------------------------- /src/dotnet/Cljr/Cljr.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34601.278 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cljr", "Cljr.csproj", "{3F0102A4-E6A0-4B58-9B98-534556E1EDCC}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cljr.Tests", "..\Cljr.Tests\Cljr.Tests.csproj", "{C611CDA8-F619-4C8D-A31F-7EFD8E0E0020}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3F0102A4-E6A0-4B58-9B98-534556E1EDCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {3F0102A4-E6A0-4B58-9B98-534556E1EDCC}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {3F0102A4-E6A0-4B58-9B98-534556E1EDCC}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {3F0102A4-E6A0-4B58-9B98-534556E1EDCC}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {C611CDA8-F619-4C8D-A31F-7EFD8E0E0020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {C611CDA8-F619-4C8D-A31F-7EFD8E0E0020}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {C611CDA8-F619-4C8D-A31F-7EFD8E0E0020}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {C611CDA8-F619-4C8D-A31F-7EFD8E0E0020}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {C3DE4A57-4547-4F3F-B982-FCE746E7AD73} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/Cljr.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0;net8.0;net9.0 6 | 12 7 | enable 8 | enable 9 | true 10 | cljr 11 | true 12 | ./nupkg 13 | 0.1.0-alpha11 14 | Clojure.$(AssemblyName) 15 | ClojureCLR contributors 16 | The deps.edn-powered CLI tool for ClojureCLR. 17 | ClojureCLR contributors, 2025 18 | https://github.com/clojure/clr.core.cli 19 | https://github.com/clojure/clr.core.cli 20 | EPL-1.0 21 | Clojure;ClojureCLR 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | PreserveNewest 33 | 34 | 35 | PreserveNewest 36 | 37 | 38 | PreserveNewest 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/ParseItems.cs: -------------------------------------------------------------------------------- 1 | namespace Cljr; 2 | 3 | public enum EMode 4 | { 5 | Version, 6 | Help, 7 | Repl, 8 | Tool, 9 | Exec, 10 | Main 11 | } 12 | 13 | public class ParseItems 14 | { 15 | readonly HashSet Flags = new(); 16 | public string? Deps { get; set; } = null; 17 | public string? ForceClasspath { get; set; } = null; 18 | public int Threads { get; set; } = 0; 19 | public string? ToolName { get; set; } = null; 20 | public List JvmOpts { get; } = new(); 21 | public List CommandArgs { get; set; } = new(); 22 | public EMode Mode { get; set; } = EMode.Repl; 23 | public bool IsError { get; set; } = false; 24 | public string? ErrorMessage { get; set; } = null; 25 | public Dictionary CommandAliases { get; } = new(); 26 | 27 | public ParseItems SetError(string message) 28 | { 29 | IsError = true; 30 | ErrorMessage = message; 31 | return this; 32 | } 33 | 34 | public void AddReplAliases(string aliases) 35 | { 36 | var currValue = CommandAliases.TryGetValue(EMode.Repl, out var currVal) ? currVal : ""; 37 | CommandAliases[EMode.Repl] = currValue + aliases; 38 | } 39 | 40 | public void SetCommandAliases(EMode mode, string? alias) 41 | { 42 | if (alias is not null) 43 | CommandAliases[mode] = alias; 44 | } 45 | 46 | public string GetCommandAlias(EMode mode) => 47 | CommandAliases.TryGetValue(mode, out var alias) 48 | ? alias 49 | : string.Empty; 50 | 51 | public bool TryGetCommandAlias(EMode mode, out string? alias) => 52 | CommandAliases.TryGetValue(mode, value: out alias); 53 | 54 | public void AddFlag(string flag) 55 | { 56 | Flags.Add(flag); 57 | } 58 | 59 | public bool HasFlag(string flag) 60 | { 61 | return Flags.Contains(flag); 62 | } 63 | 64 | public int FlagCount => Flags.Count; 65 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/script/parse.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.script.parse 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] :cljr [clojure.clr.io :as cio]) 13 | [clojure.string :as str] 14 | [clojure.edn :as edn] 15 | [clojure.tools.deps :as deps]) 16 | (:import 17 | #?(:clj [java.io File] :cljr [System.IO FileInfo]))) 18 | 19 | #?( 20 | :clj 21 | (defn parse-files 22 | "Parses a string of comma-delimited files into a collection of 23 | Files, filtering only those that exist." 24 | [s] 25 | (->> (str/split s #",") 26 | (map jio/file) 27 | (filter #(.exists ^File %)))) 28 | :cljr 29 | (defn parse-files 30 | "Parses a string of comma-delimited files into a collection of 31 | Files, filtering only those that exist." 32 | [s] 33 | (->> (str/split s #",") 34 | (map cio/file-info) 35 | (filter #(.Exists ^FileInfo %)))) 36 | 37 | ) 38 | (defn parse-kws 39 | "Parses a concatenated string of keywords into a collection of keywords 40 | Ex: (parse-kws \":a:b:c\") ;; returns: (:a :b :c)" 41 | [s] 42 | (->> (str/split (or s "") #":") 43 | (remove str/blank?) 44 | (map 45 | #(if-let [i (str/index-of % \/)] 46 | (keyword (subs % 0 i) (subs % (inc i))) 47 | (keyword %))))) 48 | 49 | (defn parse-config 50 | "Parses a string of edn into a deps map." 51 | [s] 52 | (#'deps/canonicalize-all-syms ;; to be removed in the future 53 | (edn/read-string {:default tagged-literal} s))) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/gitlibs/config.cljr: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.gitlibs.config 10 | "Implementation, use at your own risk" 11 | (:require 12 | [clojure.clr.io :as cio] ;;; [clojure.java.io :as jio] 13 | [clojure.string :as str])) 14 | 15 | (set! *warn-on-reflection* true) 16 | 17 | (defn- read-config-value 18 | "Read a config value from each of these in order, taking the first value found: 19 | * Java system property 20 | * env variable 21 | * default value" 22 | [property env default] 23 | (or 24 | #_(.get_Item System.Configuration.ConfigurationManager/AppSettings ^String property) ;;; (System/getProperty property) 25 | (Environment/GetEnvironmentVariable env) ;;; (System/getenv env) 26 | default)) 27 | 28 | (defn- init-config 29 | [] 30 | {:gitlibs/dir 31 | (.FullName ;;; .getCanonicalPath 32 | (let [lib-dir (read-config-value "clojure.gitlibs.dir" "GITLIBS" nil)] ;;; (or (System/getProperty "clojure.gitlibs.dir") (System/getenv "GITLIBS")) 33 | (if (str/blank? lib-dir) 34 | (System.IO.DirectoryInfo. (System.IO.Path/Join (Environment/GetFolderPath System.Environment+SpecialFolder/UserProfile) ".gitlibs")) ;;; (jio/file (System/getProperty "user.home") ".gitlibs") 35 | (System.IO.DirectoryInfo. lib-dir)))) ;;; jio/file 36 | 37 | :gitlibs/command 38 | (read-config-value "clojure.gitlibs.command" "GITLIBS_COMMAND" "git") ;;; (or (System/getProperty "clojure.gitlibs.command") (System/getenv "GITLIBS_COMMAND") "git") 39 | 40 | :gitlibs/debug 41 | (Boolean/Parse ^String (read-config-value "clojure.gitlibs.debug" "GITLIBS_DEBUG" "false")) ;;; parseBoolean (or (System/getProperty "clojure.gitlibs.debug") (System/getenv "GITLIBS_DEBUG") "false") 42 | 43 | :gitlibs/terminal 44 | (Boolean/Parse ^String (read-config-value "clojure.gitlibs.terminal" "GITLIBS_TERMINAL" "false"))}) ;;; parseBoolean (or (System/getProperty "clojure.gitlibs.terminal") (System/getenv "GITLIBS_TERMINAL") "false") 45 | 46 | (def CONFIG 47 | "Config map - deref to access" 48 | (delay (init-config))) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/util/session.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.util.session 11 | "Maintains session resources during or across runs of the resolver" 12 | (:import 13 | #?(:clj [java.util.concurrent ConcurrentMap ConcurrentHashMap] 14 | :cljr [System.Collections.Concurrent |ConcurrentDictionary`2[System.Object,System.Object]|]) 15 | #?(:clj [java.util.function Function]))) 16 | 17 | 18 | #?( 19 | :clj 20 | (defn make-concurrent-hashmap 21 | ^ConcurrentHashMap [] 22 | (ConcurrentHashMap.)) 23 | 24 | :cljr 25 | (defn make-concurrent-hashmap 26 | ^|System.Collections.Concurrent.ConcurrentDictionary`2[System.Object,System.Object]| 27 | [] 28 | (|System.Collections.Concurrent.ConcurrentDictionary`2[System.Object,System.Object]|.)) 29 | ) 30 | 31 | (def ^|System.Collections.Concurrent.ConcurrentDictionary`2[System.Object,System.Object]| session (make-concurrent-hashmap)) ;; should never be nil 32 | 33 | #?( 34 | :clj 35 | (defn retrieve 36 | "Read the current value of key from the session. If absent, and if-absent-fn 37 | is supplied, invoke the fn, set it in the session (if there is one), 38 | and return the value." 39 | ([key] 40 | (.get ^ConcurrentMap session key)) 41 | ([key if-absent-fn] 42 | (.computeIfAbsent ^ConcurrentMap session key 43 | (reify Function 44 | (apply [_f _k] 45 | (if-absent-fn)))))) 46 | 47 | :cljr 48 | (defn retrieve 49 | "Read the current value of key from the session. If absent, and if-absent-fn 50 | is supplied, invoke the fn, set it in the session (if there is one), 51 | and return the value." 52 | ([key] 53 | (.get_Item session key)) 54 | ([key if-absent-fn] 55 | (.GetOrAdd session key 56 | (sys-func [Object Object] [x] (if-absent-fn))))) 57 | ) 58 | 59 | #?( 60 | 61 | :clj 62 | (defn- get-current-thread-id [] 63 | (.getId (Thread/currentThread))) 64 | 65 | :cljr 66 | (defn- get-current-thread-id [] 67 | (.ManagedThreadId (System.Threading.Thread/CurrentThread))) 68 | 69 | ) 70 | 71 | (defn retrieve-local 72 | "Like retrieve, but scoped to a thread-specific key, so never shared across threads." 73 | ([key] 74 | (retrieve {:thread (get-current-thread-id) :key key})) 75 | ([key if-absent-fn] 76 | (retrieve {:thread (get-current-thread-id) :key key} if-absent-fn))) 77 | 78 | (defmacro with-session 79 | "Create a new empty session and execute the body" 80 | [& body] 81 | `(let [prior# session] 82 | (alter-var-root #'session (constantly (make-concurrent-hashmap))) 83 | (try 84 | ~@body 85 | (finally 86 | (alter-var-root #'session (constantly prior#)))))) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/util/io.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.util.io 11 | (:require 12 | [clojure.edn :as edn] 13 | #?(:clj [clojure.java.io :as jio] 14 | :cljr [clojure.clr.io :as cio]) 15 | [clojure.string :as str]) 16 | (:import 17 | #?(:cljr [clojure.lang PushbackTextReader]) 18 | #?(:clj [java.io Reader FileReader PushbackReader] 19 | :cljr [System.IO TextReader] ))) 20 | 21 | (defonce ^:private nl #?(:clj (System/getProperty "line.separator") 22 | :cljr Environment/NewLine)) 23 | 24 | (defn printerrln 25 | "println to *err*" 26 | [& msgs] 27 | (binding [*out* *err* 28 | *print-readably* nil] 29 | (pr (str (str/join " " msgs) nl)) 30 | (flush))) 31 | 32 | (defn read-edn 33 | "Read the edn file from the specified `reader`. 34 | This file should contain a single edn value. Empty files return nil. 35 | The reader will be read to EOF and closed." 36 | [^#?(:clj Reader :cljr TextReader) reader] 37 | (let [EOF (Object.)] 38 | (with-open [rdr #?(:clj (PushbackReader. reader) 39 | :cljr (PushbackTextReader. reader))] 40 | (let [val (edn/read {:default tagged-literal :eof EOF} rdr)] 41 | (if (identical? EOF val) 42 | nil 43 | (if (not (identical? EOF (edn/read {:eof EOF} rdr))) 44 | (throw (ex-info "Invalid file, expected edn to contain a single value." {})) 45 | val)))))) 46 | 47 | (defn slurp-edn 48 | "Read the edn file specified by f, a string or File. 49 | An empty file will return nil." 50 | [f] 51 | #?(:clj (read-edn (FileReader. (jio/file f))) 52 | :cljr (read-edn (.OpenText (cio/file-info f))))) 53 | 54 | #?( 55 | :clj 56 | (defn write-file 57 | "Write the string s to file f. Creates parent directories for f if they don't exist." 58 | [f s] 59 | (let [the-file (jio/file f) 60 | parent (.getParentFile the-file)] 61 | (when-not (.exists parent) 62 | (when-not (.mkdirs parent) 63 | (let [parent-name (.getCanonicalPath parent)] 64 | (throw (ex-info (str "Can't create directory: " parent-name) {:dir parent-name}))))) 65 | (spit the-file s))) 66 | 67 | :cljr 68 | 69 | (defn write-file 70 | "Write the string s to file f. Creates parent directories for f if they don't exist." 71 | [f s] 72 | (let [the-file (cio/file-info f) 73 | parent (.Directory the-file)] 74 | (when-not (.Exists parent) 75 | (try 76 | (.Create parent) 77 | (catch Exception e 78 | (let [parent-name (.Name parent)] 79 | (throw (ex-info (str "Can't create directory: " parent-name ", " (.Message e)) {:dir parent-name})))))) 80 | (spit the-file s :file-mode System.IO.FileMode/Create))) 81 | ) 82 | 83 | 84 | 85 | (comment 86 | (slurp-edn "deps.edn") 87 | ) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/cli/help.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.deps.cli.help 10 | (:require 11 | [clojure.string :as str] 12 | [clojure.repl :as repl])) 13 | 14 | (defn- garner-ns-defaults [] 15 | (try 16 | (require 'clojure.run.exec) 17 | (let [nsd (some-> "clojure.run.exec/*ns-default*" symbol resolve deref) 18 | nsa (some-> "clojure.run.exec/*ns-aliases*" symbol resolve deref)] 19 | (cond-> {} 20 | nsd (assoc :ns-default nsd) 21 | nsa (assoc :ns-aliases nsa))) 22 | (catch Exception e 23 | (throw (ex-info (.getMessage e) {} e))))) 24 | 25 | (defn- qualify-fn 26 | "Compute function symbol based on exec-fn, ns-aliases, and ns-default" 27 | [fsym ns-aliases ns-default] 28 | ;; validation - make specs? 29 | (when (and fsym (not (symbol? fsym))) 30 | (throw (ex-info (str "Expected function symbol:" fsym) {}))) 31 | 32 | (when fsym 33 | (if (qualified-ident? fsym) 34 | (let [nsym (get ns-aliases (symbol (namespace fsym)))] 35 | (if nsym 36 | (symbol (str nsym) (name fsym)) 37 | fsym)) 38 | (if ns-default 39 | (symbol (str ns-default) (str fsym)) 40 | (throw (ex-info (str "Unqualified function can't be resolved:" fsym) {})))))) 41 | 42 | (defn doc 43 | "Print doc for the specified namespace or function. If neither is specified, print docs 44 | for :ns-default. 45 | 46 | Options: 47 | :ns Print docs for namespace 48 | :fn Print docs for function" 49 | [{:keys [ns fn] :as args}] 50 | (let [{:keys [ns-default ns-aliases]} (merge args (garner-ns-defaults))] 51 | (if fn 52 | (#'repl/print-doc (meta (requiring-resolve (qualify-fn fn ns-aliases ns-default)))) 53 | (let [ns-maybe (or ns ns-default) 54 | ns (if ns-aliases (get ns-aliases ns-maybe ns-maybe) ns-maybe)] 55 | (when (nil? ns) 56 | (throw (ex-info "No namespace or function specified" {}))) 57 | (require ns) 58 | (let [my-ns (the-ns ns) 59 | ns-doc (:doc (meta my-ns))] 60 | ;; Print namespace docs 61 | (when (not (str/blank? ns-doc)) 62 | (println ns-doc) 63 | (println)) 64 | ;; Print function docs 65 | (doseq [[k v] (->> my-ns ns-publics (sort-by key))] 66 | (when (instance? clojure.lang.Fn @v) 67 | (#'repl/print-doc (meta v))))))))) 68 | 69 | (defn dir 70 | "Prints a sorted directory of public vars in a namespace. If a namespace is not 71 | specified :ns-default is used instead." 72 | [{:keys [ns] :as args}] 73 | (let [{:keys [ns-default ns-aliases]} (merge args (garner-ns-defaults)) 74 | ns-maybe (or ns ns-default) 75 | ns (if ns-aliases (get ns-aliases ns-maybe ns-maybe) ns-maybe) 76 | _ (require ns) 77 | my-ns (the-ns ns)] 78 | (doseq [[s v] (->> my-ns ns-publics (sort-by key))] 79 | (when (instance? clojure.lang.Fn @v) 80 | (println s))))) 81 | 82 | (comment 83 | (doc {:ns 'clojure.tools.cli.help}) 84 | (doc {:fn 'clojure.tools.cli.help/doc}) 85 | (dir {:ns 'clojure.tools.cli.help}) 86 | ) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/script/resolve_tags.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.script.resolve-tags 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] 13 | :cljr [clojure.clr.io :as cio]) 14 | [clojure.pprint :as pp] 15 | [clojure.walk :as walk] 16 | [clojure.tools.deps :as deps] 17 | [clojure.tools.deps.extensions.git :as git] 18 | [clojure.tools.deps.util.io :refer [printerrln]] 19 | [clojure.tools.gitlibs :as gitlibs] 20 | [clojure.tools.cli :as cli]) 21 | (:import 22 | [clojure.lang IExceptionInfo])) 23 | 24 | (def ^:private opts 25 | [[nil "--deps-file PATH" "deps.edn file to update"]]) 26 | 27 | (defn- resolve-git-dep 28 | [counter lib {untag :tag, unsha :sha, :git/keys [url tag sha] :as git-coord}] 29 | (let [the-url (or url (git/auto-git-url lib)) 30 | the-tag (or tag untag) 31 | the-sha (or sha unsha)] 32 | (if the-tag 33 | (let [new-sha (gitlibs/resolve the-url the-tag)] 34 | (if (= the-sha new-sha) 35 | git-coord ;; no change 36 | (do 37 | (printerrln "Resolved" the-tag "=>" new-sha "in" the-url) 38 | (swap! counter inc) 39 | (cond-> {:git/tag the-tag 40 | :git/sha (subs new-sha 0 7)} 41 | url (assoc :git/url url))))) 42 | git-coord))) 43 | 44 | (defn- resolve-git-deps 45 | [counter deps-map] 46 | (let [f (partial resolve-git-dep counter)] 47 | (walk/postwalk 48 | (fn [node] 49 | (if (map? node) 50 | (reduce-kv 51 | (fn [new-deps k v] 52 | (if (and (symbol? k) (map? v) 53 | (contains? (->> v keys (map namespace) set) "git")) 54 | (assoc new-deps k (resolve-git-dep counter k v)) 55 | new-deps)) 56 | node node) 57 | node)) 58 | deps-map))) 59 | 60 | (defn exec 61 | [{:keys [deps-file]}] 62 | (try 63 | (let [deps-map (deps/slurp-deps (#?(:clj jio/file :cljr cio/file-info) deps-file)) 64 | counter (atom 0)] 65 | (printerrln "Resolving git tags in" deps-file "...") 66 | (let [resolved-map (resolve-git-deps counter deps-map)] 67 | (if (zero? @counter) 68 | (printerrln "No unresolved tags found.") 69 | (spit deps-file 70 | (with-out-str 71 | (with-bindings {#'pp/*print-right-margin* 100 72 | #'pp/*print-miser-width* 80 73 | #'*print-namespace-maps* false} 74 | (pp/pprint resolved-map))) 75 | #?@(:cljr (:file-mode System.IO.FileMode/Create)))))) 76 | (catch #?(:clj Throwable :cljr Exception) t 77 | (printerrln "Error resolving tags." (#?(:clj .getMessage :cljr .Message) t)) 78 | (when-not (instance? IExceptionInfo t) 79 | #?(:clj (.printStackTrace t) 80 | :cljr (System.Console/WriteLine (.StackTrace t)))) 81 | (#?(:clj System/exit :cljr Environment/Exit) 1)))) 82 | 83 | (defn -main 84 | "Main entry point for resolve-tags script. 85 | 86 | Required: 87 | --deps-file deps.edn - deps.edn files in which to resolve git tags 88 | 89 | Read deps.edn, find git coordinates with :tag but without :sha, resolve those 90 | tags to shas, and over-write the deps.edn." 91 | [& args] 92 | (let [{:keys [options]} (cli/parse-opts args opts)] 93 | (exec options))) 94 | 95 | (comment 96 | (-main "--deps-file" "deps.edn") 97 | ) -------------------------------------------------------------------------------- /scripts/diff.bat: -------------------------------------------------------------------------------- 1 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\gitlibs.cljc C:\work\clojure\clr.tools.gitlibs\src\main\clojure\clojure\tools\gitlibs.cljc 2 | 3 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\gitlibs\config.cljr C:\work\clojure\clr.tools.gitlibs\src\main\clojure\clojure\tools\gitlibs\config.cljr 4 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\gitlibs\impl.cljr C:\work\clojure\clr.tools.gitlibs\src\main\clojure\clojure\tools\gitlibs\impl.cljr 5 | 6 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps.cljc 7 | 8 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions.cljc 9 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\specs.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\specs.cljc 10 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\tool.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\tool.cljc 11 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\tree.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\tree.cljc 12 | 13 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\concurrent.clj C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\concurrent.clj 14 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\concurrent.cljr C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\concurrent.cljr 15 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\dir.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\dir.cljc 16 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\io.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\io.cljc 17 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\session.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\session.cljc 18 | 19 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\script\make_classpath2.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\script\make_classpath2.cljc 20 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\script\parse.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\script\parse.cljc 21 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\script\resolve_tags.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\script\resolve_tags.cljc 22 | 23 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions\deps.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions\deps.cljc 24 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions\git.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions\git.cljc 25 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions\local.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions\local.cljc 26 | 27 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\cli.cljc C:\work\clojure\tools.cli\src\main\clojure\clojure\tools\cli.cljc 28 | 29 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\cli\api.cljc C:\work\clojure\clr.tools.deps.cli\src\main\clojure\clojure\tools\deps\cli\api.cljc 30 | fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\cli\help.cljc C:\work\clojure\clr.tools.deps.cli\src\main\clojure\clojure\tools\deps\cli\help.cljc -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/tool.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.deps.tool 10 | (:require 11 | #?(:clj [clojure.java.io :as jio] :cljr [clojure.clr.io :as cio]) 12 | [clojure.pprint :as pprint] 13 | [clojure.string :as str] 14 | [clojure.tools.deps :as deps] 15 | [clojure.tools.deps.extensions :as ext] 16 | [clojure.tools.deps.util.io :as io]) 17 | (:import 18 | #?(:clj [java.io File] :cljr [System.IO FileInfo DirectoryInfo]))) 19 | 20 | #?( 21 | :clj 22 | (defn- tool-dir 23 | ^File [] 24 | (jio/file (.getParentFile (jio/file (deps/user-deps-path))) "tools")) 25 | 26 | :cljr 27 | (defn- tool-dir 28 | ^DirectoryInfo [] 29 | (cio/dir-info (.Parent (cio/dir-info (deps/user-deps-path))) "tools")) 30 | ) 31 | 32 | #?( 33 | :clj 34 | (defn- tool-file 35 | "Create File location for tool name" 36 | ^File [tool] 37 | (jio/file (tool-dir) (str tool ".edn"))) 38 | 39 | :cljr 40 | (defn- tool-file 41 | "Create File location for tool name" 42 | ^FileInfo [tool] 43 | (cio/file-info (tool-dir) (str tool ".edn"))) 44 | ) 45 | 46 | 47 | (defn install-tool 48 | "Procure the lib+coord, install the tool to the user tools dir (with lib, coord)" 49 | [lib coord as] 50 | (let [{:keys [root-edn user-edn]} (deps/find-edn-maps) 51 | master-edn (deps/merge-edns [root-edn user-edn]) 52 | deps-info (ext/manifest-type lib coord master-edn) 53 | f (tool-file as)] 54 | ;; procure 55 | (ext/coord-paths lib (merge coord deps-info) (:deps/manifest deps-info) master-edn) 56 | ;; ensure tool dir 57 | #?(:clj (.mkdirs (.getParentFile f)) 58 | :cljr (.Create (.Directory f))) 59 | ;; write tool file 60 | (spit f 61 | (with-out-str 62 | (binding [*print-namespace-maps* false 63 | pprint/*print-right-margin* 100] 64 | (pprint/pprint {:lib lib :coord coord}))) 65 | #?@(:cljr (:file-mode System.IO.FileMode/Create))))) 66 | 67 | (defn resolve-tool 68 | "Resolve a tool by name, look up and return: 69 | {:lib lib 70 | :coord coord} 71 | Or nil if unknown." 72 | [tool] 73 | (let [f (tool-file tool)] 74 | (when (#?(:clj .exists :cljr .Exists)f) 75 | (io/slurp-edn f)))) 76 | 77 | (defn usage 78 | "Resolve a tool and return it's usage data, which may be nil. 79 | Throws ex-info if tool is unknown." 80 | [tool] 81 | (if-let [{:keys [lib coord]} (resolve-tool tool)] 82 | (let [{:keys [root-edn user-edn]} (deps/find-edn-maps) 83 | config (deps/merge-edns [root-edn user-edn]) 84 | [lib coord] (ext/canonicalize lib coord config) 85 | manifest-type (ext/manifest-type lib coord config)] 86 | (ext/coord-usage lib (merge coord manifest-type) (:deps/manifest manifest-type) config)) 87 | (throw (ex-info (str "Unknown tool: " tool) {:tool tool})))) 88 | 89 | (defn list-tools 90 | "Return seq of available tool names" 91 | [] 92 | (->> (#?(:clj .listFiles :cljr .GetFiles) (tool-dir)) 93 | #?(:clj (filter #(.isFile ^File %))) 94 | #?(:clj (map #(.getName ^File %)) 95 | :cljr (map #(.Name ^FileInfo %))) 96 | (filter #(str/ends-with? % ".edn")) 97 | (map #(subs % 0 (- (count %) 4))) 98 | sort)) 99 | 100 | (defn remove-tool 101 | "Removes tool installation, if it exists. Returns true if it exists and was deleted." 102 | [tool] 103 | (let [f (tool-file tool)] 104 | (when (#?(:clj .exists :cljr .Exists) f) 105 | (#?(:clj .delete :cljf .Delete) f)))) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/extensions/deps.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.extensions.deps 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] :cljr [clojure.clr.io :as cio]) 13 | [clojure.tools.deps :as deps] 14 | [clojure.tools.deps.extensions :as ext] 15 | [clojure.tools.deps.util.dir :as dir] 16 | [clojure.tools.deps.util.io :as io] 17 | [clojure.tools.deps.util.session :as session]) 18 | (:import 19 | #?(:clj [java.io File] :cljr [System.IO FileInfo DirectoryInfo]))) 20 | 21 | (set! *warn-on-reflection* true) 22 | 23 | #?( 24 | :clj 25 | (defn- deps-map 26 | [config dir] 27 | (let [f (jio/file dir "deps.edn")] 28 | (session/retrieve 29 | {:deps :map :file (.getAbsolutePath f)} ;; session key 30 | #(if (.exists f) 31 | (deps/merge-edns [(deps/root-deps) (deps/slurp-deps f)]) 32 | (deps/root-deps))))) 33 | 34 | :cljr 35 | ;; We can use "deps.edn" as the key in the session map -- we just need a consistent key. 36 | ;; The value under that key will be the deps file we actually read, whether it is "deps.edn" or "deps-clr.edn". 37 | (defn- deps-map 38 | [config dir] 39 | (let [f1 (cio/file-info dir "deps-clr.edn") 40 | f2 (cio/file-info dir "deps.edn")] 41 | (session/retrieve 42 | {:deps :map :file (.FullName f2)} ;; session key 43 | #(cond 44 | (.Exists f1) 45 | (deps/merge-edns [(deps/root-deps) (deps/slurp-deps f1)]) 46 | (.Exists f2) 47 | (deps/merge-edns [(deps/root-deps) (deps/slurp-deps f2)]) 48 | :else 49 | (deps/root-deps))))) 50 | ) 51 | 52 | (defmethod ext/coord-deps :deps 53 | [_lib {:keys [deps/root] :as _coord} _mf config] 54 | (dir/with-dir (#?(:clj jio/file :cljr cio/file-info) root) 55 | (seq (:deps (deps-map config root))))) 56 | 57 | (defmethod ext/coord-paths :deps 58 | [_lib {:keys [deps/root] :as _coord} _mf config] 59 | (dir/with-dir (#?(:clj jio/file :cljr cio/file-info) root) 60 | (->> (:paths (deps-map config root)) 61 | (map #(dir/canonicalize (#?(:clj jio/file :cljr identity) %))) 62 | (map #(do 63 | (when (not (dir/sub-path? %)) 64 | (io/printerrln "WARNING: Deprecated use of path" % "external to project" root)) 65 | %)) 66 | #?(:clj (map #(.getCanonicalPath ^File %)) 67 | :cljr (map #(.FullName ^FileInfo %))) 68 | vec))) 69 | 70 | #?( 71 | :clj 72 | (defmethod ext/manifest-file :deps 73 | [_lib {:keys [deps/root] :as _coord} _mf _config] 74 | (let [manifest (jio/file root "deps.edn")] 75 | (when (.exists manifest) 76 | (.getAbsolutePath manifest)))) 77 | 78 | :cljr 79 | (defmethod ext/manifest-file :deps 80 | [_lib {:keys [deps/root] :as _coord} _mf _config] 81 | (let [manifest1 (cio/file-info root "deps-clr.edn") 82 | manifest2 (cio/file-info root "deps.edn")] 83 | (cond (.Exists manifest1) 84 | (.FullName manifest1) 85 | (.Exists manifest2) 86 | (.FullName manifest2)))) 87 | ) 88 | 89 | (defmethod ext/coord-usage :deps [lib {:keys [deps/root] :as _coord} manifest-type config] 90 | (dir/with-dir (#?(:clj jio/file :cljr cio/file-info) root) 91 | (:tools/usage (deps-map config root)))) 92 | 93 | (defmethod ext/prep-command :deps [lib {:keys [deps/root] :as _coord} manifest-type config] 94 | (dir/with-dir (#?(:clj jio/file :cljr cio/file-info) root) 95 | (let [external-deps (deps-map config root)] 96 | (when-let [prep-info (:deps/prep-lib external-deps)] 97 | (let [exec-args (-> external-deps :aliases (get (:alias prep-info)) :exec-args)] 98 | (cond-> prep-info 99 | exec-args (assoc :exec-args exec-args))))))) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/util/dir.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.util.dir 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] 13 | :cljr [clojure.clr.io :as cio])) 14 | (:import 15 | #?(:clj [java.io File] 16 | :cljr [System.IO Path DirectoryInfo FileInfo FileSystemInfo]) 17 | #?(:clj [java.nio.file Files Path]))) 18 | 19 | (set! *warn-on-reflection* true) 20 | 21 | (def ^:dynamic ^#?(:clj File :cljr DirectoryInfo) *the-dir* 22 | "Thread-local directory context for resolving relative directories. 23 | Defaults to current directory. Should always hold an absolute directory 24 | java.io.File, never null." 25 | #?(:clj (jio/file (System/getProperty "user.dir")) 26 | :cljr (cio/dir-info Environment/CurrentDirectory))) 27 | 28 | #? 29 | (:clj 30 | (defn canonicalize 31 | "Make canonical File in terms of the current directory context. 32 | f may be either absolute or relative." 33 | ^File [^File f] 34 | (.getCanonicalFile 35 | (if (.isAbsolute f) 36 | f 37 | (jio/file *the-dir* f)))) 38 | 39 | :cljr ;; no equivalent notion of canonical. A FileInfo is always absolute. 40 | ;; if relative paths are involved we must be sure to pass a string instead. 41 | (defn canonicalize 42 | "Make canonical File in terms of the current directory context. 43 | f may be either absolute or relative." 44 | ^FileSystemInfo [f] 45 | (let [f (if (instance? FileSystemInfo f) (.FullName ^FileSystemInfo f) (str f))] 46 | (if (Path/IsPathRooted f) 47 | (cio/file-info f) 48 | (cio/file-info (Path/Join (.FullName *the-dir*) f))))) 49 | ) 50 | 51 | (defmacro with-dir 52 | "Push directory into current directory context for execution of body." 53 | [^#?(:clj File :cljr DirectoryInfo) dir & body] 54 | `(binding [*the-dir* (canonicalize ~dir)] 55 | ~@body)) 56 | #? 57 | (:clj 58 | (defn- same-file? 59 | "If a file can't be read (most common reason is directory does not exist), then 60 | treat this as not the same file (ie unknown)." 61 | [^Path p1 ^Path p2] 62 | (try 63 | (Files/isSameFile p1 p2) 64 | (catch Exception _ false))) 65 | 66 | :cljr 67 | (defn- same-file? 68 | [^FileSystemInfo p1 ^FileSystemInfo p2] 69 | (= (.FullName p1) (.FullName p2))) 70 | ) 71 | 72 | #?( 73 | :clj 74 | (defn sub-path? 75 | "True if the path is a sub-path of the current directory context. 76 | path may be either absolute or relative. Will return true if path 77 | has a parent that is the current directory context, false otherwise. 78 | Handles relative paths, .., ., etc. The sub-path does not need to 79 | exist on disk (but the current directory context must)." 80 | [^File path] 81 | (if (nil? path) 82 | false 83 | (let [root-path (.toPath ^File *the-dir*)] 84 | (loop [check-path (.toPath (canonicalize path))] 85 | (cond 86 | (nil? check-path) false 87 | (same-file? root-path check-path) true 88 | :else (recur (.getParent check-path))))))) 89 | 90 | :cljr ;; not sure yet if this is what is needed. Need to see it in action. 91 | (defn sub-path? 92 | [^FileInfo path] 93 | (if (nil? path) 94 | false 95 | (let [root-path *the-dir*] 96 | (loop [check-path (.Directory path)] 97 | (cond 98 | (nil? check-path) false 99 | (same-file? root-path check-path) true 100 | :else (recur (.Parent check-path))))))) 101 | ) 102 | 103 | 104 | ;; DEPRECATED 105 | #?( 106 | :clj 107 | (defn as-canonical 108 | ^File [^File dir] 109 | (canonicalize dir)) 110 | 111 | :cljr 112 | (defn as-canonical 113 | ^FileSystemInfo [^FileSystemInfo dir] 114 | (canonicalize dir)) 115 | 116 | ) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/tree.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.deps.tree 10 | (:require 11 | [clojure.walk :as walk] 12 | [clojure.tools.deps :as deps] 13 | [clojure.tools.deps.extensions :as ext])) 14 | 15 | ;; Data manipulation 16 | 17 | (defn trace->tree 18 | "Convert a deps trace data structure into a deps tree. 19 | 20 | A deps tree has the structure of the full dependency expansion. 21 | Each node of the tree is a map from lib to coord-info with at least these keys: 22 | :lib - library symbol 23 | :coord - the coord map that was used (may not be the original coord if replaced 24 | due to default-deps or override-deps) 25 | :include - boolean of whether this node is included in the returned deps 26 | :reason - why the node was or was not included 27 | :children - vector of child nodes" 28 | [trace] 29 | (let [{:keys [log]} trace] 30 | (loop [[{:keys [lib path reason] :as step} & steps] log 31 | i 0 32 | tree {}] 33 | (if step 34 | (let [nstep (assoc step :step i) 35 | full-path (conj path lib) 36 | tree-path (interleave (repeat :children) full-path) 37 | tree' (if (= reason :newer-version) 38 | (walk/postwalk 39 | (fn [v] 40 | (if (and (map? v) (contains? v lib) (-> v lib :include)) 41 | (assoc v lib (merge (get v lib) {:include false, :reason :superseded})) 42 | v)) 43 | tree) 44 | tree)] 45 | (recur steps (inc i) (assoc-in tree' tree-path nstep))) 46 | tree)))) 47 | 48 | (defn calc-trace 49 | "Like calc-basis, but create and return the dep expansion trace. The trace 50 | can be passed to trace->tree to get tree data. 51 | 52 | The opts map includes the same opts accepted by clojure.tools.deps/create-basis. 53 | By default, uses the root, user, and project deps and no argmaps (essentially the same 54 | classpath you get by default from the Clojure CLI). 55 | 56 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 57 | Sources are merged in the order - :root, :user, :project, :extra. 58 | 59 | Aliases refer to argmaps in the merged deps that will be supplied to the basis 60 | subprocesses (tool, resolve-deps, make-classpath-map). 61 | 62 | Options: 63 | :dir - directory root path, defaults to current directory 64 | :root - dep source, default = :standard 65 | :user - dep source, default = :standard 66 | :project - dep source, default = :standard (\"./deps.edn\") 67 | :extra - dep source, default = nil 68 | :aliases - coll of aliases of argmaps to apply to subprocesses" 69 | ([] (calc-trace nil)) 70 | ([opts] 71 | (let [{:keys [extra aliases]} opts 72 | trace-opts (merge opts 73 | {:extra (assoc-in extra [:aliases :__TRACE__ :trace] true)} 74 | {:aliases (conj (or aliases []) :__TRACE__)})] 75 | 76 | (-> trace-opts deps/create-basis :libs meta :trace)))) 77 | 78 | ;; Printing 79 | 80 | (defn- space 81 | [n] 82 | (apply str (repeat n \space))) 83 | 84 | (defn- print-node 85 | [{:keys [lib coord include reason]} indented {:keys [hide-libs]}] 86 | (when (and lib (or (= reason :new-top-dep) (not (contains? hide-libs lib)))) 87 | (let [pre (space indented) 88 | summary (ext/coord-summary lib coord)] 89 | (println 90 | (case reason 91 | :new-top-dep 92 | (str pre summary) 93 | 94 | (:new-dep :same-version) 95 | (str pre ". " summary) 96 | 97 | :newer-version 98 | (str pre ". " summary " " reason) 99 | 100 | (:use-top :older-version :excluded :parent-omitted :superseded) ;; :superseded is internal here 101 | (str pre "X " summary " " reason) 102 | 103 | ;; fallthrough, unknown reason 104 | (str pre "? " summary include reason)))))) 105 | 106 | (defn print-tree 107 | "Print the tree to the console. 108 | Options: 109 | :indent Indent spacing (default = 2) 110 | :hide-libs Set of libs to ignore as deps under top deps, default = #{org.clojure/clojure}" 111 | ([tree {:keys [indent] :or {indent 2} :as opts}] 112 | (print-tree tree (- 0 indent) opts)) 113 | ([{:keys [children] :as tree} indented opts] 114 | (let [opts' (merge {:indent 2, :hide-libs '#{org.clojure/clojure}} opts)] 115 | (print-node tree indented opts') 116 | (doseq [child (sort-by :step (vals children))] 117 | (print-tree child (+ indented (:indent opts')) opts'))))) 118 | 119 | (comment 120 | (require '[clojure.tools.deps.util.io :as io]) 121 | (-> "/Users/alex.miller/tmp/20201124/trace.edn" io/slurp-edn trace->tree (print-tree {})) 122 | (-> "/Users/alex.miller/code/tools.deps/trace.edn" io/slurp-edn trace->tree (print-tree {})) 123 | (-> "/Users/alex.miller/tmp/20201022/trace.edn" io/slurp-edn trace->tree (print-tree {})) 124 | (let [log (:log (io/slurp-edn "/Users/alex.miller/tmp/20201124/trace.edn"))] 125 | (distinct (map :reason log))) 126 | 127 | ) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/gitlibs.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.gitlibs 10 | "An API for retrieving and caching git repos and working trees. 11 | 12 | The git url can be either an https url for anonymous checkout or an ssh url 13 | for private access. revs can be either full sha, prefix sha, or tag name." 14 | (:refer-clojure :exclude [resolve]) 15 | (:require 16 | [clojure.clr.io :as cio] ;;; [clojure.java.io :as jio] 17 | [clojure.tools.gitlibs.config :as config] 18 | [clojure.tools.gitlibs.impl :as impl]) 19 | (:import [System.IO DirectoryInfo Path]) 20 | ) 21 | 22 | (set! *warn-on-reflection* true) 23 | 24 | (defn cache-dir 25 | "Return the root gitlibs cache directory. By default ~/.gitlibs or 26 | override by setting the environment variable GITLIBS." 27 | [] 28 | (:gitlibs/dir @config/CONFIG)) 29 | 30 | ;; Possible new API, internal for now 31 | (defn- resolve-all 32 | "Takes a git url and a coll of revs, and returns the full commit shas. 33 | Each rev may be a partial sha, full sha, or tag name. Returns nil for 34 | unresolveable revs." 35 | [url revs] 36 | (let [git-dir (impl/ensure-git-dir url)] 37 | (reduce 38 | (fn [rs r] 39 | (if-let [res (impl/git-rev-parse git-dir r)] 40 | (conj rs res) 41 | (do ;; could not resolve - fetch and try again 42 | (impl/git-fetch (cio/as-dir git-dir)) ;;; jio/file 43 | (conj rs (impl/git-rev-parse git-dir r))))) 44 | [] revs))) 45 | 46 | (defn resolve 47 | "Takes a git url and a rev, and returns the full commit sha or nil if can't 48 | resolve. rev may be a partial sha, full sha, or tag name." 49 | [url rev] 50 | (first (resolve-all url [rev]))) 51 | 52 | (defn object-type 53 | "Takes a git url and rev, and returns the object type, one of :tag :tree 54 | :commit or :blob, or nil if not known or ambiguous." 55 | [url rev] 56 | (let [git-dir (impl/ensure-git-dir url)] 57 | (if-let [type (impl/git-type git-dir rev)] 58 | type 59 | (do 60 | (impl/git-fetch (DirectoryInfo. git-dir)) ;;; jio/file 61 | (impl/git-type git-dir rev))))) 62 | 63 | (defn procure 64 | "Procure a working tree at rev for the git url representing the library lib, 65 | returns the directory path. lib is a qualified symbol where the qualifier is a 66 | controlled or conveyed identity, or nil if rev is unknown." 67 | [url lib rev] 68 | (let [lib-dir (impl/lib-dir lib) 69 | git-dir-path (impl/ensure-git-dir url) 70 | sha (or (impl/match-exact lib-dir rev) (impl/match-prefix lib-dir rev) (resolve url rev))] 71 | (when sha 72 | (let [sha-dir (DirectoryInfo. (Path/Join (.FullName lib-dir) ^String sha))] ;;; jio/file 73 | (when-not (.Exists sha-dir) ;;; .exists 74 | (impl/printerrln "Checking out:" url "at" rev) 75 | (impl/git-checkout git-dir-path lib-dir sha)) 76 | (.FullName sha-dir))))) ;;; .getCanonicalPath 77 | 78 | (defn descendant 79 | "Returns rev in git url which is a descendant of all other revs, 80 | or nil if no such relationship can be established." 81 | [url revs] 82 | (when (seq revs) 83 | (let [shas (resolve-all url revs)] 84 | (if (seq (filter nil? shas)) 85 | nil ;; can't resolve all shas in this repo 86 | (let [git-dir (impl/ensure-git-dir url)] 87 | (->> shas (sort (partial impl/commit-comparator git-dir)) first)))))) 88 | 89 | (defn tags 90 | "Fetches, then returns coll of tags in git url" 91 | [url] 92 | (impl/tags (impl/ensure-git-dir url))) 93 | 94 | (defn commit-sha 95 | "Returns unpeeled full commit sha, given a rev (which may be tag, branch, etc)" 96 | [url rev] 97 | (impl/git-rev-parse (impl/ensure-git-dir url) rev)) 98 | 99 | (comment 100 | 101 | 102 | (System/setProperty "clojure.gitlibs.debug" "true") 103 | (resolve "git@github.com:clojure/tools.gitlibs.git" "11fc774") 104 | (descendant "https://github.com/clojure/tools.gitlibs.git" ["5e2797a487c" "11fc774" "d82adc29" "815e312310"]) 105 | 106 | (println 107 | @(future (procure "https://github.com/clojure/tools.gitlibs.git" 'org.clojure/tools.gitlibs "11fc77496f013871c8af3514bbba03de0af28061")) 108 | @(future (procure "https://github.com/clojure/tools.gitlibs.git" 'org.clojure/tools.gitlibs "11fc77496f013871c8af3514bbba03de0af28061"))) 109 | 110 | (println 111 | @(future (procure "https://github.com/cognitect-labs/test-runner.git" 'cognitect-labs/test-runner "b6b3193fcc42659d7e46ecd1884a228993441182")) 112 | @(future (procure "https://github.com/cognitect-labs/test-runner.git" 'cognitect-labs/test-runner "cb96e80f6f3d3b307c59cbeb49bb0dcb3a2a780b")) 113 | @(future (procure "https://github.com/cognitect-labs/test-runner.git" 'cognitect-labs/test-runner "9e1098965f2089c8cf492d23c0b7520f8690440a"))) 114 | 115 | (tags "https://github.com/clojure/tools.gitlibs.git") 116 | 117 | ;; big output 118 | (tags "https://github.com/confluentinc/kafka-streams-examples.git") 119 | ) -------------------------------------------------------------------------------- /src/dotnet/Cljr/CommandLineParser.cs: -------------------------------------------------------------------------------- 1 | namespace Cljr; 2 | 3 | public static class CommandLineParser 4 | { 5 | static readonly List DeprecatedPrefixes = new() { "-R", "-C", "-O" }; 6 | static bool StartsWithDeprecatedPrefix(string arg) => DeprecatedPrefixes.Any(p => arg.StartsWith(p)); 7 | static string? NonBlank(string s) => string.IsNullOrEmpty(s) ? null : s; 8 | static string ExtractAlias(string s) => s[2..]; 9 | static List GetArgs(int i, string[] args) => args.Skip(i).ToList(); 10 | 11 | public static ParseItems Parse(string[] args) 12 | { 13 | ParseItems items = new(); 14 | 15 | int i = 0; 16 | while (i < args.Length) 17 | { 18 | var arg = args[i++]; 19 | 20 | // PowerShell workaround 21 | if (Platform.IsWindows) 22 | { 23 | switch (arg) 24 | { 25 | case "-M:": 26 | case "-X:": 27 | case "-T:": 28 | case "-A:": 29 | if (i >= args.Length) 30 | return items.SetError($"Invalid arguments, no value following {arg}."); 31 | else 32 | arg += args[i++]; 33 | break; 34 | } 35 | } 36 | 37 | if (StartsWithDeprecatedPrefix(arg)) 38 | return items.SetError( 39 | $"{arg[..2]} is no longer supported, use -A with repl, -M for main, -X for exec, -T for tool"); 40 | 41 | if (arg == "-Sresolve-tags") 42 | return items.SetError("Option changed, use: clj -X:deps git-resolve-tags"); 43 | 44 | 45 | if (arg == "-version" || arg == "--version") 46 | { 47 | items.Mode = EMode.Version; 48 | return items; 49 | } 50 | 51 | if (arg == "-h" || arg == "--help" || arg == "-?") 52 | { 53 | items.Mode = EMode.Help; 54 | return items; 55 | } 56 | 57 | if (arg.StartsWith("-J")) 58 | { 59 | items.JvmOpts.Add(ExtractAlias(arg)); 60 | continue; 61 | } 62 | 63 | if (arg == "-P") 64 | { 65 | items.AddFlag("prep"); 66 | continue; 67 | } 68 | 69 | if (arg.StartsWith("-S")) 70 | { 71 | var flag = ExtractAlias(arg); 72 | switch (flag) 73 | { 74 | case "pom": 75 | case "path": 76 | case "tree": 77 | case "repro": 78 | case "force": 79 | case "verbose": 80 | case "describe": 81 | case "trace": 82 | items.AddFlag(flag); 83 | break; 84 | 85 | case "deps": 86 | if (i >= args.Length) 87 | return items.SetError($"Invalid arguments, no value following {arg}."); 88 | items.Deps = args[i++]; 89 | break; 90 | 91 | case "cp": 92 | if (i >= args.Length) 93 | return items.SetError($"Invalid arguments, no value following {arg}."); 94 | items.ForceClasspath = args[i++]; 95 | break; 96 | 97 | case "threads": 98 | if (i >= args.Length) 99 | return items.SetError($"Invalid arguments, no value following {arg}."); 100 | if (Int32.TryParse(args[i++], out var numThreads)) 101 | items.Threads = numThreads; 102 | else 103 | return items.SetError($"Invalid argument, non-integer following {arg}"); 104 | break; 105 | 106 | default: 107 | return items.SetError($"Unknown option: {arg}"); 108 | } 109 | 110 | continue; 111 | } 112 | 113 | if (arg == "-A") 114 | { 115 | return items.SetError("-A requires an alias"); 116 | } 117 | 118 | if (arg.StartsWith("-A")) 119 | { 120 | items.AddReplAliases(ExtractAlias(arg)); 121 | continue; 122 | } 123 | 124 | if (arg.StartsWith("-M")) 125 | { 126 | items.Mode = EMode.Main; 127 | items.SetCommandAliases(EMode.Main, NonBlank(ExtractAlias(arg))); 128 | items.CommandArgs = GetArgs(i, args); 129 | return items; 130 | } 131 | 132 | if (arg.StartsWith("-X")) 133 | { 134 | items.Mode = EMode.Exec; 135 | items.SetCommandAliases(EMode.Exec, NonBlank(ExtractAlias(arg))); 136 | items.CommandArgs = GetArgs(i, args); 137 | return items; 138 | } 139 | 140 | if (arg.StartsWith("-T:")) 141 | { 142 | items.Mode = EMode.Tool; 143 | items.SetCommandAliases(EMode.Tool, NonBlank(ExtractAlias(arg))); 144 | items.CommandArgs = GetArgs(i, args); 145 | return items; 146 | } 147 | 148 | if (arg.StartsWith("-T")) 149 | { 150 | items.Mode = EMode.Tool; 151 | items.ToolName = NonBlank(ExtractAlias(arg)); 152 | items.CommandArgs = GetArgs(i, args); 153 | return items; 154 | } 155 | 156 | if (arg == "--") 157 | { 158 | items.CommandArgs = GetArgs(i, args); 159 | return items; 160 | } 161 | 162 | items.CommandArgs.Add(arg); 163 | items.CommandArgs.AddRange(GetArgs(i, args)); 164 | return items; 165 | } 166 | 167 | return items; 168 | } 169 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/extensions/local.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.extensions.local 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] :cljr [clojure.clr.io :as cio]) 13 | [clojure.string :as str] 14 | [clojure.tools.deps.extensions :as ext] 15 | #?(:clj [clojure.tools.deps.extensions.pom :as pom]) 16 | [clojure.tools.deps.util.dir :as dir] 17 | #?(:clj [clojure.tools.deps.util.maven :as maven]) 18 | [clojure.tools.deps.util.session :as session]) 19 | (:import 20 | #?(:clj [java.io File IOException] :cljr [System.IO FileInfo DirectoryInfo]) 21 | #?(:clj [java.net URL]) 22 | #?(:clj [java.util.jar JarFile JarEntry]) 23 | ;; maven-builder-support 24 | #?(:clj [org.apache.maven.model.building UrlModelSource]) 25 | #?(:clj [org.apache.maven.model License]))) 26 | 27 | (defmethod ext/coord-type-keys :local 28 | [_type] 29 | #{:local/root}) 30 | 31 | (defmethod ext/dep-id :local 32 | [lib {:keys [local/root] :as _coord} _config] 33 | {:lib lib 34 | :root root}) 35 | 36 | (defn- ensure-file 37 | ^#?(:clj File :cljr FileInfo) [lib root] 38 | (let [f (#?(:clj jio/file :cljr cio/file-info) root)] 39 | (if (#?(:clj .exists :cljr .Exists) f) 40 | f 41 | (throw (ex-info (format "Local lib %s not found: %s" lib root) {:lib lib :root root}))))) 42 | 43 | 44 | #?( 45 | :cljr 46 | (defn- ensure-directory 47 | ^DirectoryInfo [lib root] 48 | (let [d (cio/dir-info root)] 49 | (if (.Exists d) 50 | d 51 | (throw (ex-info (format "Local lib %s not found: %s" lib root) {:lib lib :root root}))))) 52 | ) 53 | 54 | (defmethod ext/canonicalize :local 55 | [lib {:keys [local/root] :as coord} _config] 56 | (let [canonical-root #?(:clj (.getCanonicalPath (dir/canonicalize (jio/file root))) 57 | :cljr (.FullName (dir/canonicalize root)))] 58 | (#?(:clj ensure-file :cljr ensure-directory) lib canonical-root) ;; throw if missing 59 | [lib (assoc coord :local/root canonical-root)])) 60 | 61 | (defmethod ext/lib-location :local 62 | [_lib {:keys [local/root]} _config] 63 | {:base root 64 | :path "" 65 | :type :local}) 66 | 67 | (defmethod ext/find-versions :local 68 | [_lib _coord _type _config] 69 | nil) 70 | 71 | 72 | #?(:cljr 73 | (defn normal? [^System.IO.FileSystemInfo fsi] 74 | (pos? (enum-and (.Attributes fsi) 75 | (enum-or System.IO.FileAttributes/Normal System.IO.FileAttributes/Archive)))) 76 | ) 77 | 78 | (defmethod ext/manifest-type :local 79 | [lib {:keys [local/root deps/manifest] :as _coord} _config] 80 | (cond 81 | manifest {:deps/manifest manifest :deps/root root} 82 | #?(:clj (.isFile (ensure-file lib root)) 83 | :cljr (normal? (ensure-directory lib root))) {:deps/manifest :jar, :deps/root root} 84 | :else (ext/detect-manifest root))) 85 | 86 | (defmethod ext/coord-summary :local [lib {:keys [local/root]}] 87 | (str lib " " root)) 88 | 89 | (defmethod ext/license-info :local 90 | [lib coord config] 91 | (let [coord (merge coord (ext/manifest-type lib coord config))] 92 | (ext/license-info-mf lib coord (:deps/manifest coord) config))) 93 | 94 | #?( 95 | :clj 96 | (defn find-pom 97 | "Find path of pom file in jar file, or nil if it doesn't exist" 98 | [^JarFile jar-file] 99 | (try 100 | (loop [[^JarEntry entry & entries] (enumeration-seq (.entries jar-file))] 101 | (when entry 102 | (let [name (.getName entry)] 103 | (if (and (str/starts-with? name "META-INF/") 104 | (str/ends-with? name "pom.xml")) 105 | name 106 | (recur entries))))) 107 | (catch IOException _t nil))) 108 | ) 109 | 110 | #?( 111 | :clj 112 | (defmethod ext/coord-deps :jar 113 | [lib {:keys [local/root] :as _coord} _manifest config] 114 | (let [jar (JarFile. (ensure-file lib root))] 115 | (if-let [path (find-pom jar)] 116 | (let [url (URL. (str "jar:file:" root "!/" path)) 117 | src (UrlModelSource. url) 118 | settings (session/retrieve :mvn/settings #(maven/get-settings)) 119 | model (pom/read-model src config settings)] 120 | (pom/model-deps model)) 121 | []))) 122 | ) 123 | 124 | (defmethod ext/coord-paths :jar 125 | [_lib coord _manifest _config] 126 | [(:local/root coord)]) 127 | 128 | ;; 0 if x and y are the same jar or dir 129 | (defmethod ext/compare-versions [:local :local] 130 | [lib {x-root :local/root :as x} {y-root :local/root :as y} _config] 131 | (if (= x-root y-root) 132 | 0 133 | (throw (ex-info (str "No known ancestor relationship between local versions for " lib ": " x-root " and " y-root) 134 | {:lib lib :x x :y y})))) 135 | 136 | 137 | (defmethod ext/manifest-file :jar 138 | [_lib {:keys [deps/root] :as _coord} _mf _config] 139 | nil) 140 | 141 | #?( 142 | :clj 143 | 144 | (defmethod ext/license-info-mf :jar 145 | [lib {:keys [local/root] :as _coord} _mf config] 146 | (let [jar (JarFile. (ensure-file lib root))] 147 | (when-let [path (find-pom jar)] 148 | (let [url (URL. (str "jar:file:" root "!/" path)) 149 | src (UrlModelSource. url) 150 | settings (session/retrieve :mvn/settings #(maven/get-settings)) 151 | model (pom/read-model src config settings) 152 | licenses (.getLicenses model) 153 | ^License license (when (and licenses (pos? (count licenses))) (first licenses))] 154 | (when license 155 | (let [name (.getName license) 156 | url (.getUrl license)] 157 | (when (or name url) 158 | (cond-> {} 159 | name (assoc :name name) 160 | url (assoc :url url))))))))) 161 | ) 162 | 163 | 164 | (defmethod ext/coord-usage :jar 165 | [_lib _coord _manifest-type _config] 166 | ;; TBD 167 | nil) 168 | 169 | (defmethod ext/prep-command :jar 170 | [_lib _coord _manifest-type _config] 171 | ;; TBD - could look in jar 172 | nil) -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/specs.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.deps.specs 10 | (:require [clojure.spec.alpha :as s])) 11 | 12 | ;;;; generic types 13 | 14 | (s/def ::lib symbol?) 15 | (s/def ::path string?) 16 | (s/def ::alias keyword?) 17 | 18 | ;;;; coordinates 19 | 20 | ;; generic coord attributes 21 | (s/def :deps/root ::path) 22 | (s/def :deps/manifest keyword?) 23 | (s/def :deps/exclusions (s/coll-of ::lib)) 24 | (s/def :deps/coord (s/keys :opt [:deps/root :deps/manifest] :opt-un [:deps/exclusions])) 25 | 26 | ;; maven coords 27 | (s/def :mvn/version string?) 28 | (s/def :mvn/coord (s/merge :deps/coord 29 | (s/keys :req [:mvn/version]))) 30 | 31 | ;; local coords 32 | (s/def :local/root string?) 33 | (s/def :local/coord (s/merge :deps/coord 34 | (s/keys :req [:local/root]))) 35 | 36 | ;; git coords 37 | (s/def :git/url string?) 38 | (s/def :git/sha string?) 39 | (s/def :git/tag string?) 40 | (s/def :git/coord (s/merge :deps/coord 41 | (s/keys :opt [:git/url :git/sha :git/tag]))) 42 | 43 | ;; should this become a multispec? 44 | (s/def ::coord (s/nilable 45 | (s/or :mvn :mvn/coord 46 | :local :local/coord 47 | :git :git/coord))) 48 | 49 | (s/def ::path-ref (s/or :path ::path :alias ::alias)) 50 | (s/def :aliased/paths (s/coll-of ::path-ref :kind vector? :into [])) 51 | 52 | ;; tool args 53 | ;; ::replace-deps - map of lib to coordinate to replace the 54 | (s/def ::tool-args (s/keys :opt-un [::replace-deps ::replace-paths ::deps ::paths])) 55 | (s/def ::replace-deps (s/map-of ::lib ::coord)) 56 | (s/def ::replace-paths :aliased/paths) 57 | 58 | ;; resolve-deps args - used to modify the expanded deps tree 59 | ;; ::extra-deps - map of lib to coordinate added to the initial deps collection 60 | ;; ::override-deps - map of lib to coordinate to use instead of the coord found during expansion 61 | ;; ::default-deps - map of lib to coordinate to use if no coord is specified in extension 62 | (s/def ::resolve-args (s/keys :opt-un [::extra-deps ::override-deps ::default-deps])) 63 | (s/def ::extra-deps (s/map-of ::lib ::coord)) 64 | (s/def ::override-deps (s/map-of ::lib ::coord)) 65 | (s/def ::default-deps (s/map-of ::lib ::coord)) 66 | (s/def ::threads pos-int?) 67 | (s/def ::trace boolean?) 68 | 69 | ;; make-classpath args - used when constructing the classpath 70 | ;; ::classpath-overrides - map of lib to path to use instead of the artifact found during resolution 71 | ;; ::extra-paths - collection of extra paths to add to the classpath in addition to ::paths 72 | (s/def ::classpath-args (s/keys :opt-un [::classpath-overrides ::extra-paths])) 73 | (s/def ::classpath-overrides (s/map-of ::lib ::path)) 74 | (s/def ::extra-paths :aliased/paths) 75 | 76 | ;; exec args - used when executing a function with -X or -T 77 | ;; ::exec-args - map of default function args 78 | ;; ::exec-fn - default function symbol 79 | ;; ::ns-default - default namespace to use when resolving functions 80 | ;; ::ns-aliases - map of alias to namespace to use when resolving functions 81 | (s/def ::exec-args (s/keys :opt-un [::exec-args ::exec-fn ::ns-default ::ns-aliases])) 82 | (s/def ::exec-args (s/nilable map?)) 83 | (s/def ::ns-default simple-symbol?) 84 | (s/def ::ns-aliases (s/map-of simple-symbol? simple-symbol?)) 85 | 86 | ;; deps map (format of the deps.edn file) 87 | (s/def ::paths :aliased/paths) 88 | (s/def ::deps (s/map-of ::lib ::coord)) 89 | (s/def ::aliases (s/map-of ::alias any?)) 90 | (s/def ::deps-map (s/nilable (s/keys 91 | :opt-un [::paths ::deps ::aliases] 92 | :opt [:mvn/repos :mvn/local-repo 93 | :tools/usage :deps/prep-lib]))) 94 | 95 | ;; lib map 96 | ;; a map of lib to resolved coordinate (a coord with a ::path) and dependent info 97 | (s/def ::dependents (s/coll-of ::lib)) 98 | (s/def ::resolved-coord (s/merge ::coord (s/keys :opt-un [:aliased/paths ::dependents]))) 99 | (s/def ::lib-map (s/map-of ::lib ::resolved-coord)) 100 | 101 | ;; classpath 102 | (s/def ::classpath string?) 103 | 104 | ;; Procurers 105 | 106 | ;; Maven 107 | (s/def :mvn/repos (s/map-of ::repo-id ::repo)) 108 | (s/def ::repo-id string?) 109 | (s/def ::repo (s/nilable (s/keys :opt-un [::url :mvn/releases :mvn/snapshots]))) 110 | (s/def ::url string?) 111 | (s/def :mvn-repo/enabled boolean?) 112 | (s/def :mvn-repo/update (s/or :policy #{:daily :always :never} :interval int?)) 113 | (s/def :mvn-repo/checksum #{:warn :fail :ignore}) 114 | (s/def :mvn/repo-policy (s/keys :opt-un [:mvn-repo/enabled :mvn-repo/update :mvn-repo/checksum])) 115 | (s/def :mvn/releases :mvn/repo-policy) 116 | (s/def :mvn/snapshots :mvn/repo-policy) 117 | (s/def :mvn/local-repo string?) 118 | 119 | ;; Tool usage 120 | (s/def :tools/usage (s/keys :opt-un [::ns-default ::ns-aliases])) 121 | 122 | ;; Prep lib 123 | (s/def :deps/prep-lib (s/keys :req-un [:prep/ensure ::alias :prep/fn])) 124 | (s/def :prep/ensure ::path) 125 | (s/def :prep/fn symbol?) 126 | 127 | (defn valid-deps? 128 | "Determine whether the deps map is valid according to the specs" 129 | [deps-map] 130 | (s/valid? ::deps-map deps-map)) 131 | 132 | (defn explain-deps 133 | "If a spec is invalid, return a message explaining why, suitable 134 | for an error message" 135 | [deps-map] 136 | (let [err-data (s/explain-data ::deps-map deps-map)] 137 | (if (nil? err-data) 138 | "Failed spec, reason unknown" 139 | (let [problems (->> (::s/problems err-data) 140 | (sort-by #(- (count (:in %)))) 141 | (sort-by #(- (count (:path %))))) 142 | {:keys [path pred val reason via in]} (first problems)] 143 | (str "Found: " (pr-str val) ", expected: " (if reason reason (s/abbrev pred))))))) 144 | 145 | ;; API 146 | 147 | (s/fdef clojure.tools.deps/resolve-deps 148 | :args (s/cat :deps ::deps-map :options ::resolve-args) 149 | :ret ::lib-map) 150 | 151 | (s/fdef clojure.tools.deps/make-classpath-map 152 | :args (s/cat :deps ::deps-map, :libs ::lib-map, :classpath-args ::classpath-args) 153 | :ret map?) 154 | 155 | (s/fdef clojure.tools.deps/make-classpath 156 | :args (s/cat :libs ::lib-map, :paths ::paths, :classpath-args ::classpath-args) 157 | :ret string?) 158 | 159 | (comment 160 | ;; some scratch code to recursively check every deps.edn under 161 | ;; a root directory whether it's valid against the specs 162 | (require 163 | '[clojure.spec.test.alpha :as stest] 164 | '[clojure.tools.deps :as deps]) 165 | (import '[java.nio.file Files Paths FileVisitor FileVisitResult]) 166 | (stest/instrument (stest/enumerate-namespace 'clojure.tools.deps)) 167 | 168 | (Files/walkFileTree 169 | (Paths/get "../" (into-array String [])) 170 | (reify FileVisitor 171 | (postVisitDirectory [_ dir ex] FileVisitResult/CONTINUE) 172 | (preVisitDirectory [_ dir attrs] FileVisitResult/CONTINUE) 173 | (visitFileFailed [_ f ex] FileVisitResult/CONTINUE) 174 | (visitFile [_ f attrs] 175 | (when (.endsWith (str f) "/deps.edn") 176 | (print "Checking" (str f)) 177 | (let [v (s/valid? ::deps-map (#'deps/slurp-edn-map (.toFile f)))] 178 | (println ":" v) 179 | (when-not v 180 | (s/explain ::deps-map (#'deps/slurp-edn-map (.toFile f)))))) 181 | FileVisitResult/CONTINUE))) 182 | ) -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 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.) 158 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clr.core.cli 2 | 3 | An implementation of the Clojure CLI tool and deps.edn tooling for ClojureCLR. 4 | 5 | For ClojureCLR on .NET 6 and later. 6 | 7 | ## Releases 8 | 9 | The current release is 0.1.0-alpha8. 10 | 11 | 12 | ## Installation 13 | 14 | Prerequisite: ClojureCLR must be installed as a tool. See [Getting started (ClojureCLR)](https://github.com/clojure/clojure-clr/wiki/Getting-started). 15 | 16 | `cljr` is also installed as a tool. 17 | To install as a global tool: 18 | 19 | ``` 20 | dotnet tool install -g Clojure.Cljr --version 0.1.0-alpha8 21 | ``` 22 | 23 | To install as a local tool: 24 | 25 | ``` 26 | dotnet new tool-manifest # if you are setting up this repo 27 | dotnet tool install --local Clojure.Cljr --version 0.1.0-alpha8 28 | ``` 29 | 30 | For other installation approaches, check out the [Clojure.Cljr Nuget page](https://www.nuget.org/packages/Clojure.Cljr/). 31 | 32 | ## Running `cljr` 33 | 34 | Once installed, you should ube able to invoke (globally or locally) via `cljr`. 35 | 36 | ## An introduction to deps.edn and the CLI 37 | 38 | You can start by reading these references: 39 | 40 | - [Clojure CLI Reference](https://clojure.org/reference/clojure_cli) 41 | - Ignore the nstallation and usage sections; we'll cover this below. 42 | - [deps.edn Reference](https://clojure.org/reference/deps_edn) 43 | 44 | 45 | 46 | ## Functionality 47 | 48 | A significant portion of the functionality of the JVM version is available. 49 | Some parts await development. Some likly will never be implemented. 50 | 51 | There are two ways to invoke the JVM tool: as 'clj' and as 'clojure'. 52 | As the docs state: "In general, you can treat these interchangeably but `clj` includes `rlwrap` for extended keyboard editing, particularly useful with the REPL. 53 | This reference uses `clj` for REPL examples and `clojure` for non-REPL examples." 54 | 55 | `cljr` does not have this distinction (for now). There is just `cljr`. 56 | 57 | The status of the primary commands and the command line options is detailed below. 58 | In general terms, tools and deps prep are not supported yet. Anything related to Maven or JVM is not supported. 59 | Most other things are ready for testing. 60 | 61 | 62 | | Command | Invocation | Implemented? | 63 | |:------------|:-----------|:-------------| 64 | | Start a repl (default) | `cljr [clj-opts] [-Aaliases]` | Yes | 65 | | Execute a function (-X) | `cljr [clj-opts] -Xaliases my/fn? [kpath v ... ] kv-map? `| Yes | 66 | | Run a tool (-T) | `cljr [clj-opts] -T[name\|aliases] my/fn [kpath v ...] kv-map?` | Not yet | 67 | | Run a main namespace or script (-M) | `cljr [clj-opts] -M[aliases] [init-opts] [main-opts] [args]` | Yes | 68 | 69 | The status of the options: 70 | 71 | | Option | Description | Status | 72 | |:-------|:------------|:-------| 73 | |exec-opts:| 74 | | -Aaliases | Apply aliases | Supported | 75 | | -X[aliases] | Invoke function, using aliases | Supported | 76 | | -Ttoolname | Invoke tool by local name | Supported | 77 | | -T[aliases] | Invoke tool using aliases | Supported | 78 | | -M[aliases] | Invoke clojure.main, using aliases | Supported | 79 | | -P | Prepare deps but don't exec | Not yet | 80 | || 81 | |clj-opts: | 82 | | -Jopt | Pass JVM option | Irrelevant | 83 | | -Sdeps EDN | Extra deps.edn data | Supported | 84 | | -Srepro | Ignore user deps.edn file | Supported | 85 | | -Spath | Compute and echo classpath | Supported | 86 | | -Stree | Print dependency tree | Supported | 87 | | -Scp CP | Use this classpath, ignore deps.edn | Supported | 88 | | -Sforce | Force classpath computation | Supported | 89 | | -Sverbose | Print path info | Supported | 90 | | -Sdescribe | Print env and command parsing info | Supported | 91 | | -Sthreads | Set specific number of download threads | Not supported | 92 | | -Strace | Write dep expansion trace.edn | Supported | 93 | | --version | Print version to stdout and exit | Supported | 94 | | -version | Print version to stderr and exit | Supported | 95 | | --help -h -? | Print this help message | Supported | 96 | || 97 | |Programs provided by :deps alias: 98 | | -X:deps list | Print deps list+licenses | Supported | 99 | | -X:deps tree | Print deps tree | Supported | 100 | | -X:deps find-versions | Find available lib versions | Supported | 101 | | -X:deps prep | Prepare all unprepped libs in deps | Not supported (yet) | 102 | | -X:deps mvn-pom | Generate pom.xml for deps.edn | Not supported | 103 | | -X:deps mvn-install | Install maven jar to local repo | Not supported | 104 | 105 | ## deps.edn features 106 | 107 | Most of the features of `deps.edn` files are supported. 108 | 109 | -- We support git lib and local directory dependencies only. We do not support maven dependencie or local jars. (Though we should have a discussion about the latter.) 110 | -- We are still thinking about how nuget might come into play. It's complicated. 111 | -- We do not yet have support for tool publishing and preparation steps. See below. 112 | 113 | Generally, one puts a `deps.edn` file in the root directory of your code. However, for projects that support multiple Clojure ports (JVM, CLR, Clojurescript), this will not always work. 114 | For example, the JVM version may want to use Maven repos for dependencies, which the CLR version does not support. 115 | 116 | However, we cannot just read-conditionalization the `deps.edn` file because read-conditionalization is not supported in EDN files. 117 | The workaround is that `cljr` will look for a file named `deps-clr.edn` first, then look for `deps.edn`. This provides an override that `cljr` can see and the JVM tools will ignore. 118 | 119 | 120 | ## Running tests 121 | 122 | If you would like to run tests of your project from the command line, you can take advantage of a port of [cognitect-labs/test-runner](https://github.com/cognitect-labs/test-runner) available at [dmiller/test-runner](https://github.com/dmiller/test-runner). 123 | (If you want to look at the code, look in branch `clr-port`.) 124 | 125 | Here is a sample `deps.edn` file set up to use this port of `test-runner`: 126 | 127 | ```Clojure 128 | {:paths ["src/main/clojure"] 129 | :deps 130 | {io.github.clojure/clr.data.generators {:git/tag "v1.1.0" :git/sha "d25d292"}} 131 | 132 | :aliases 133 | {:test 134 | {:extra-paths ["src/test/clojure"] 135 | :extra-deps {io.github.dmiller/test-runner {:git/tag "v0.5.1clr" :git/sha "814e06f"}} 136 | :exec-fn cognitect.test-runner.api/test 137 | :exec-args {:dirs ["src/test/clojure"]}}}} 138 | ``` 139 | 140 | You would invoke test running via 141 | 142 | ```Clojure 143 | cljr -X:test 144 | ``` 145 | 146 | ## Things that need work 147 | 148 | This is an alpha release. Have at it. 149 | 150 | ### Tools and prepping 151 | We need some design thinking around tools and prepping. Most of the library support on the JVM side are very specific to the JVM world: Maven, jars, Java-ish things. 152 | 153 | What is needed to support robust program development and installation in the CLR world? 154 | 155 | ## Clojure versioning 156 | 157 | One thing supported on the JVM side is the ability to specify the version of Clojure(JVM) that you want to run under. This is fairly easily accommodated. Clojure(JVM) is available as a Maven artifact. Specify the desired version of Clojure in your application's :deps. That version will get downloaded and added to the classpath. And off you go. 158 | 159 | We are in a different world entirely on the CLR side. We don't have a seamless way of incorporating general assemblies into program loading. At present, ClojureCLR is usually installed as a dotnet tool. 160 | 161 | How can we provide ClojureCLR runtime versioning? 162 | 163 | ## Nuget 164 | 165 | How can we incorporate Nuget packages into the mix. I can write a Nuget provider that pulls down and caches a Nuget package. (I found an open-source library that does this; it's pretty easy to adapt to our needs.) The problem is the variety of things that Nuget package might contain and how it can be used. It could be a collection of assemblies. It could be the kind of packaging I've been doing for ClojureCLR libraries: an assembly containing Clojure source files as embedded resources. (In some ways, I regret that choice.) A Nuget package could contain Clojure source files in a library folder. 166 | 167 | What design will work for us? 168 | 169 | 170 | # Copyright and License 171 | 172 | Copyright © Rich Hickey and contributors 173 | 174 | All rights reserved. The use and 175 | distribution terms for this software are covered by the 176 | [Eclipse Public License 1.0] which can be found in the file 177 | epl-v10.html at the root of this distribution. By using this software 178 | in any fashion, you are agreeing to be bound by the terms of this 179 | license. You must not remove this notice, or any other, from this 180 | software. 181 | 182 | [Eclipse Public License 1.0]: https://opensource.org/license/epl-1-0 -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/extensions/git.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.extensions.git 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] :cljr [clojure.clr.io :as cio]) 13 | [clojure.tools.deps.extensions :as ext] 14 | [clojure.tools.gitlibs :as gitlibs])) 15 | 16 | (def ^:private git-services 17 | {:github {:service #"^(?:com|io).github.([^.]+)$" :url "https://github.com/%s/%s.git"} 18 | :gitlab {:service #"^(?:com|io).gitlab.([^.]+)$" :url "https://gitlab.com/%s/%s.git"} 19 | :bitbucket {:service #"^(?:org|io).bitbucket.([^.]+)$" :url "https://bitbucket.org/%s/%s.git"} 20 | :beanstalk {:service #"^(?:com|io).beanstalkapp.([^.]+)$" :url "https://%s.git.beanstalkapp.com/%s.git"} 21 | :sourcehut {:service #"^ht.sr.([^.]+)$" :url "https://git.sr.ht/~%s/%s"}}) 22 | 23 | (defn auto-git-url 24 | "Create url from lib name, ie: 25 | io.github.foo/bar => https://github.com/foo/bar.git 26 | or return nil if not a name that can be auto converted to a url." 27 | [lib] 28 | (let [group (namespace lib) 29 | project (name lib)] 30 | (when group 31 | (some (fn [{:keys [service url]}] 32 | (when-let [matches (re-matches service group)] 33 | (format url (second matches) project))) 34 | (vals git-services))))) 35 | 36 | (defn full-sha? 37 | [sha] 38 | (boolean (and sha (= 40 (count sha))))) 39 | 40 | (defmethod ext/coord-type-keys :git 41 | [_type] 42 | #{:git/url :git/sha :git/tag :sha}) 43 | 44 | (defn- coord-err 45 | ^#?(:clj Throwable :cljr Exception) [msg lib coord] 46 | (ex-info msg {:lib lib :coord coord})) 47 | 48 | (defn- make-standard 49 | [coord url sha tag] 50 | (-> 51 | (cond-> coord 52 | url (assoc :git/url url) 53 | sha (assoc :git/sha sha) 54 | tag (assoc :git/tag tag)) 55 | (dissoc :sha :tag))) 56 | 57 | (defmethod ext/canonicalize :git 58 | [lib {unsha :sha untag :tag :git/keys [url sha tag] :as coord} _config] 59 | (when (nil? (namespace lib)) (throw (coord-err (format "Invalid lib name: %s" lib) lib coord))) 60 | (when (and unsha sha) (throw (coord-err (format "git coord has both :sha and :git/sha for %s" lib) lib coord))) 61 | (when (and untag tag) (throw (coord-err (format "git coord has both :tag and :git/tag for %s" tag) lib coord))) 62 | 63 | (let [canon-sha (or sha unsha) 64 | canon-tag (or tag untag) 65 | canon-url (or url (auto-git-url lib))] 66 | (when (nil? canon-url) 67 | (throw (coord-err (format "Failed to infer git url for: %s" lib) lib coord))) 68 | (when (and canon-tag (not (some #{canon-tag} (gitlibs/tags canon-url)))) 69 | (throw (coord-err (format "Library %s has invalid tag: %s" lib canon-tag) lib coord))) 70 | (if canon-sha 71 | (if canon-tag 72 | (let [full-sha (if (full-sha? canon-sha) canon-sha (gitlibs/resolve canon-url canon-sha))] 73 | (when-not (= (gitlibs/resolve canon-url canon-sha) (gitlibs/resolve canon-url canon-tag)) 74 | (throw (coord-err (format "Library %s has sha and tag that point to different commits" lib) lib coord))) 75 | [lib (make-standard coord canon-url full-sha canon-tag)]) 76 | (if (full-sha? canon-sha) 77 | [lib (make-standard coord canon-url canon-sha canon-tag)] 78 | (throw (ex-info (format "Library %s has prefix sha, use full sha or add tag" lib) {:lib lib :coord coord})))) 79 | (throw (ex-info (format "Library %s has coord with missing sha" lib) {:lib lib :coord coord}))))) 80 | 81 | (defn- to-canonical 82 | [lib {:git/keys [url sha] :as coord} config] 83 | (if (and url (full-sha? sha)) 84 | [lib coord] 85 | (ext/canonicalize lib coord config))) 86 | 87 | (defmethod ext/lib-location :git 88 | [lib coord config] 89 | (let [[lib {:git/keys [sha]}] (to-canonical lib coord config)] 90 | {:base (str (gitlibs/cache-dir) "/libs") ;; gitlibs repo location is not in a public API... 91 | :path (str lib "/" sha) 92 | :type :git})) 93 | 94 | (defmethod ext/dep-id :git 95 | [lib coord config] 96 | (let [[_lib {:git/keys [url sha]}] (to-canonical lib coord config)] 97 | {:git/url url, :git/sha sha})) 98 | 99 | (defmethod ext/manifest-type :git 100 | [lib coord config] 101 | (let [[lib {:git/keys [url sha] :deps/keys [manifest root]}] (to-canonical lib coord config)] 102 | (when-not url 103 | (throw (ex-info (format ":git/url not found or inferred for %s" lib) {:lib lib :coord coord}))) 104 | (let [sha-dir (gitlibs/procure url lib sha)] 105 | (if sha-dir 106 | (let [root-dir (if root 107 | #?(:clj (let [root-file (jio/file root)] 108 | (if (.isAbsolute root-file) ;; should be only after coordinate resolution 109 | (.getCanonicalPath root-file) 110 | (.getCanonicalPath (jio/file sha-dir root-file)))) 111 | :cljr (let [root-file (cio/file-info root)] 112 | ;; there is no notion of absolute vs nonabsolute for FileInfo. 113 | ;; how do we make sure the sha-dir is in there? 114 | (.FullName root-file))) 115 | sha-dir)] 116 | (if manifest 117 | {:deps/manifest manifest, :deps/root root-dir} 118 | (ext/detect-manifest root-dir))) 119 | (throw (ex-info (format "Commit not found for %s in repo %s at %s" lib url sha) 120 | {:lib lib :coord coord})))))) 121 | 122 | (defmethod ext/coord-summary :git [lib coord] 123 | (let [[lib {:git/keys [url tag sha]}] (to-canonical lib coord nil)] 124 | (str lib " " (if tag tag (subs sha 0 7))))) 125 | 126 | (defmethod ext/license-info :git 127 | [lib coord config] 128 | (let [coord (merge coord (ext/manifest-type lib coord config))] 129 | (ext/license-info-mf lib coord (:deps/manifest coord) config))) 130 | 131 | ;; 0 if x and y are the same commit 132 | ;; negative if x is parent of y (y derives from x) 133 | ;; positive if y is parent of x (x derives from y) 134 | (defmethod ext/compare-versions [:git :git] 135 | [lib x-coord y-coord config] 136 | (let [[_ {x-url :git/url, x-sha :git/sha, :as x}] (to-canonical lib x-coord config) 137 | [_ {y-url :git/url, y-sha :git/sha, :as y}] (to-canonical lib y-coord config)] 138 | (if (= x-sha y-sha) 139 | 0 140 | (let [desc (if (= x-url y-url) 141 | (or 142 | (gitlibs/descendant x-url [x-sha y-sha]) 143 | (gitlibs/descendant y-url [x-sha y-sha])) 144 | (and 145 | (gitlibs/descendant x-url [x-sha y-sha]) 146 | (gitlibs/descendant y-url [x-sha y-sha])))] 147 | (cond 148 | (nil? desc) (throw (ex-info (str "No known ancestor relationship between git versions for " lib "\n" 149 | " " x-url " at " x-sha "\n" 150 | " " y-url " at " y-sha) 151 | {:x x :y y})) 152 | (= desc x-sha) 1 153 | (= desc y-sha) -1))))) 154 | 155 | (defmethod ext/find-versions :git 156 | [lib coord _coord-type config] 157 | (let [url (or (:git/url coord) (auto-git-url lib))] 158 | (when url 159 | (try 160 | (map 161 | (fn [tag] {:git/tag tag :git/sha (subs (gitlibs/commit-sha url tag) 0 7)}) 162 | (gitlibs/tags url)) 163 | (catch #?(:clj Throwable :cljr Exception) _ nil))))) 164 | 165 | (comment 166 | (ext/find-versions 'io.github.cognitect-labs/test-runner {} :git nil) 167 | 168 | (ext/find-versions 'org.clojure/spec.alpha 169 | {:git/url "https://github.com/clojure/spec.alpha.git"} :git nil) 170 | 171 | (ext/lib-location 'foo/foo 172 | {:git/url "https://github.com/clojure/core.async.git" 173 | :sha "ecea2539a724a415b15e50f12815b4ab115cfd35"} {}) 174 | 175 | (binding [*print-namespace-maps* false] 176 | (run! prn 177 | (ext/find-versions 'io.github.clojure/tools.deps.alpha nil :git nil))) 178 | 179 | ;; error - prefix sha 180 | (ext/canonicalize 'org.clojure/spec.alpha 181 | {:git/url "https://github.com/clojure/spec.alpha.git" :sha "739c1af5"} 182 | nil) 183 | 184 | (ext/dep-id 'org.clojure/spec.alpha 185 | {:git/url "https://github.com/clojure/spec.alpha.git" :sha "739c1af56dae621aedf1bb282025a0d676eff713"} 186 | nil) 187 | 188 | (ext/manifest-type 'org.clojure/spec.alpha 189 | {:git/url "https://github.com/clojure/spec.alpha.git" :git/sha "739c1af56dae621aedf1bb282025a0d676eff713"} 190 | nil) 191 | 192 | (ext/compare-versions 193 | 'org.clojure/spec.alpha 194 | {:git/url "https://github.com/clojure/spec.alpha.git" :git/sha "739c1af56dae621aedf1bb282025a0d676eff713"} 195 | {:git/url "git@github.com:clojure/spec.alpha.git" :git/sha "a65fb3aceec67d1096105cab707e6ad7e5f063af"} 196 | nil) 197 | 198 | ) -------------------------------------------------------------------------------- /scripts/diff.out: -------------------------------------------------------------------------------- 1 | 2 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\gitlibs.cljc C:\work\clojure\clr.tools.gitlibs\src\main\clojure\clojure\tools\gitlibs.cljc 3 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\gitlibs.cljc and C:\WORK\CLOJURE\CLR.TOOLS.GITLIBS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\GITLIBS.CLJC 4 | FC: no differences encountered 5 | 6 | 7 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\gitlibs\config.cljr C:\work\clojure\clr.tools.gitlibs\src\main\clojure\clojure\tools\gitlibs\config.cljr 8 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\GITLIBS\config.cljr and C:\WORK\CLOJURE\CLR.TOOLS.GITLIBS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\GITLIBS\CONFIG.CLJR 9 | FC: no differences encountered 10 | 11 | 12 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\gitlibs\impl.cljr C:\work\clojure\clr.tools.gitlibs\src\main\clojure\clojure\tools\gitlibs\impl.cljr 13 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\GITLIBS\impl.cljr and C:\WORK\CLOJURE\CLR.TOOLS.GITLIBS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\GITLIBS\IMPL.CLJR 14 | FC: no differences encountered 15 | 16 | 17 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps.cljc 18 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\deps.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS.CLJC 19 | FC: no differences encountered 20 | 21 | 22 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions.cljc 23 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\extensions.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\EXTENSIONS.CLJC 24 | FC: no differences encountered 25 | 26 | 27 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\specs.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\specs.cljc 28 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\specs.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\SPECS.CLJC 29 | FC: no differences encountered 30 | 31 | 32 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\tool.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\tool.cljc 33 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\tool.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\TOOL.CLJC 34 | FC: no differences encountered 35 | 36 | 37 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\tree.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\tree.cljc 38 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\tree.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\TREE.CLJC 39 | FC: no differences encountered 40 | 41 | 42 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\concurrent.clj C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\concurrent.clj 43 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\UTIL\concurrent.clj and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\UTIL\CONCURRENT.CLJ 44 | FC: no differences encountered 45 | 46 | 47 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\concurrent.cljr C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\concurrent.cljr 48 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\UTIL\concurrent.cljr and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\UTIL\CONCURRENT.CLJR 49 | FC: no differences encountered 50 | 51 | 52 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\dir.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\dir.cljc 53 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\UTIL\dir.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\UTIL\DIR.CLJC 54 | FC: no differences encountered 55 | 56 | 57 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\io.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\io.cljc 58 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\UTIL\io.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\UTIL\IO.CLJC 59 | FC: no differences encountered 60 | 61 | 62 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\util\session.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\util\session.cljc 63 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\UTIL\session.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\UTIL\SESSION.CLJC 64 | FC: no differences encountered 65 | 66 | 67 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\script\make_classpath2.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\script\make_classpath2.cljc 68 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\SCRIPT\make_classpath2.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\SCRIPT\MAKE_CLASSPATH2.CLJC 69 | FC: no differences encountered 70 | 71 | 72 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\script\parse.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\script\parse.cljc 73 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\SCRIPT\parse.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\SCRIPT\PARSE.CLJC 74 | FC: no differences encountered 75 | 76 | 77 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\script\resolve_tags.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\script\resolve_tags.cljc 78 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\SCRIPT\resolve_tags.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\SCRIPT\RESOLVE_TAGS.CLJC 79 | FC: no differences encountered 80 | 81 | 82 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions\deps.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions\deps.cljc 83 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\EXTENSIONS\deps.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\EXTENSIONS\DEPS.CLJC 84 | FC: no differences encountered 85 | 86 | 87 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions\git.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions\git.cljc 88 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\EXTENSIONS\git.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\EXTENSIONS\GIT.CLJC 89 | FC: no differences encountered 90 | 91 | 92 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\deps\extensions\local.cljc C:\work\clojure\clr.tools.deps\src\main\clojure\clojure\tools\deps\extensions\local.cljc 93 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\DEPS\EXTENSIONS\local.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\EXTENSIONS\LOCAL.CLJC 94 | FC: no differences encountered 95 | 96 | 97 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\cli.cljc C:\work\clojure\tools.cli\src\main\clojure\clojure\tools\cli.cljc 98 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\cli.cljc and C:\WORK\CLOJURE\TOOLS.CLI\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\CLI.CLJC 99 | FC: no differences encountered 100 | 101 | 102 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\cli\api.cljc C:\work\clojure\clr.tools.deps.cli\src\main\clojure\clojure\tools\deps\cli\api.cljc 103 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\CLI\api.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS.CLI\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\CLI\API.CLJC 104 | FC: no differences encountered 105 | 106 | 107 | C:\work\clojure\deps.cljr>fc C:\work\clojure\deps.cljr\src\dotnet\cljr\clojure\tools\cli\help.cljc C:\work\clojure\clr.tools.deps.cli\src\main\clojure\clojure\tools\deps\cli\help.cljc 108 | Comparing files C:\WORK\CLOJURE\DEPS.CLJR\SRC\DOTNET\CLJR\CLOJURE\TOOLS\CLI\help.cljc and C:\WORK\CLOJURE\CLR.TOOLS.DEPS.CLI\SRC\MAIN\CLOJURE\CLOJURE\TOOLS\DEPS\CLI\HELP.CLJC 109 | FC: no differences encountered 110 | 111 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/extensions.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.extensions 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] 13 | :cljr [clojure.clr.io :as cio]) 14 | [clojure.set :as set])) 15 | 16 | ;; Helper for autodetect of manifest type 17 | 18 | ;; vector to control ordering 19 | (def manifest-types 20 | [#?(:cljr "deps-clr.edn") #?(:cljr :deps), 21 | "deps.edn" :deps, 22 | "pom.xml" :pom 23 | ;; "project.clj" :lein 24 | ]) 25 | 26 | (defn detect-manifest 27 | "Given a directory, detect the manifest type and return the manifest info." 28 | [dir] 29 | (loop [[file-name manifest-type & others] manifest-types] 30 | (when file-name 31 | (let [f (#?(:clj jio/file :cljr cio/file-info) dir file-name)] 32 | (if #?(:clj (and (.exists f) (.isFile f)) 33 | :cljr (and (.Exists f))) 34 | {:deps/manifest manifest-type, :deps/root dir} 35 | (recur others)))))) 36 | 37 | ;; Methods switching on coordinate type 38 | 39 | (defmulti coord-type-keys 40 | "Takes a coordinate type and returns valid set of keys indicating that coord type" 41 | (fn [type] type)) 42 | 43 | (defmethod coord-type-keys :default [type] #{}) 44 | 45 | (defn procurer-types 46 | "Returns set of registerd procurer types (results may change if procurer methods are registered)." 47 | [] 48 | (disj (-> (.getMethodTable ^clojure.lang.MultiFn coord-type-keys) keys set) :default)) 49 | 50 | (defn coord-type 51 | "Determine the coordinate type of the coordinate, based on the self-published procurer 52 | keys from coord-type-keys." 53 | [coord] 54 | (when (map? coord) 55 | (let [exts (procurer-types) 56 | coord-keys (-> coord keys set) 57 | matches (reduce (fn [ms type] 58 | (cond-> ms 59 | (seq (set/intersection (coord-type-keys type) coord-keys)) 60 | (conj type))) 61 | [] exts)] 62 | (case (count matches) 63 | 0 (throw (ex-info (format "Coord of unknown type: %s" (pr-str coord)) {:coord coord})) 64 | 1 (first matches) 65 | (throw (ex-info (format "Coord type is ambiguous: %s" (pr-str coord)) {:coord coord})))))) 66 | 67 | (defmulti lib-location 68 | "Takes a coordinate and returns the location where the lib would be 69 | installed locally. Location keys: 70 | 71 | :base local repo base directory path 72 | :path path within base dir 73 | :type coordinate type" 74 | (fn [lib coord config] (coord-type coord))) 75 | 76 | (defmulti canonicalize 77 | "Takes a lib and coordinate and returns a canonical form. 78 | For example, a Maven coordinate might resolve LATEST to a version or a Git 79 | coordinate might resolve a partial sha to a full sha. Returns [lib coord]." 80 | (fn [lib coord config] (coord-type coord))) 81 | 82 | (defmethod canonicalize :default [lib coord config] 83 | [lib coord]) 84 | 85 | (defmulti dep-id 86 | "Returns an identifier value that can be used to detect a lib/coord cycle while 87 | expanding deps. This will only be called after canonicalization so it can rely 88 | on the canonical form." 89 | (fn [lib coord config] (coord-type coord))) 90 | 91 | (defn- throw-bad-coord 92 | [lib coord] 93 | (if (map? coord) 94 | (let [type (coord-type coord)] 95 | (if (nil? type) 96 | (throw (ex-info (str "No coordinate type found for library " lib " in coordinate " (pr-str coord)) {:lib lib :coord coord})) 97 | (throw (ex-info (str "Coordinate type " type " not loaded for library " lib " in coordinate " (pr-str coord)) 98 | {:lib lib :coord coord})))) 99 | (throw (ex-info (str "Bad coordinate for library " lib ", expected map: " (pr-str coord)) {:lib lib :coord coord})))) 100 | 101 | (defmethod dep-id :default [lib coord config] 102 | (throw-bad-coord lib coord)) 103 | 104 | (defmulti manifest-type 105 | "Takes a lib, a coord, and the root config. Dispatch based on the 106 | coordinate type. Detect and return the manifest type and location 107 | for this coordinate." 108 | (fn [lib coord config] (coord-type coord))) 109 | 110 | (defmethod manifest-type :default [lib coord config] 111 | (throw-bad-coord lib coord)) 112 | 113 | (defmulti coord-summary 114 | "Takes a coord, and returns a concise description, used when printing tree" 115 | (fn [lib coord] (coord-type coord))) 116 | 117 | (defmethod coord-summary :default [lib coord] 118 | (str lib " " (coord-type coord))) 119 | 120 | (defmulti license-info 121 | "Return map of license info (:name and :url) or nil if unknown" 122 | (fn [lib coord config] (coord-type coord))) 123 | 124 | (defmethod license-info :default [lib coord config] nil) 125 | 126 | ;; Version comparison, either within or across coordinate types 127 | 128 | (defmulti compare-versions 129 | "Given two coordinates, use this as a comparator returning a negative number, zero, 130 | or positive number when coord-x is logically 'less than', 'equal to', or 'greater than' 131 | coord-y. The dispatch occurs on the type of x and y." 132 | (fn [lib coord-x coord-y config] [(coord-type coord-x) (coord-type coord-y)])) 133 | 134 | (defmethod compare-versions :default 135 | [lib coord-x coord-y config] 136 | (throw (ex-info (str "Unable to compare versions for " lib ": " (pr-str coord-x) " and " (pr-str coord-y)) 137 | {:lib lib :coord-x coord-x :coord-y coord-y}))) 138 | 139 | ;; Find coords 140 | 141 | (defmulti find-versions 142 | "Return a coll of coords based on a lib and a partial coord" 143 | (fn [lib coord coord-type config] coord-type)) 144 | 145 | (defmethod find-versions :default [lib coord coord-type config] 146 | (throw-bad-coord lib coord)) 147 | 148 | (defn find-all-versions 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." 152 | [lib coord config] 153 | (mapcat #(find-versions lib coord % config) (procurer-types))) 154 | 155 | ;; Methods switching on manifest type 156 | 157 | (defn- throw-bad-manifest 158 | [lib coord manifest-type] 159 | (if manifest-type 160 | (throw (ex-info (str "Manifest type " manifest-type " not loaded for " lib " in coordinate " (pr-str coord)) 161 | {:lib lib :coord coord})) 162 | (throw (ex-info (str "Manifest file not found for " lib " in coordinate " (pr-str coord)) 163 | {:lib lib :coord coord})))) 164 | 165 | (defmulti coord-deps 166 | "Return coll of immediate [lib coord] external deps for this library." 167 | (fn [lib coord manifest-type config] manifest-type)) 168 | 169 | (defmethod coord-deps :default [lib coord manifest-type config] 170 | (throw-bad-manifest lib coord manifest-type)) 171 | 172 | (defmulti coord-paths 173 | "Return coll of classpath roots for this library on disk." 174 | (fn [lib coord manifest-type config] manifest-type)) 175 | 176 | (defmethod coord-paths :default [lib coord manifest-type config] 177 | (throw-bad-manifest lib coord manifest-type)) 178 | 179 | (defmulti manifest-file 180 | "Return path to manifest file (if any). If this file is updated, 181 | causes the cache to be recomputed." 182 | (fn [lib coord manifest-type config] manifest-type)) 183 | 184 | (defmethod manifest-file :default [lib coord manifest-type config] 185 | (throw-bad-manifest lib coord manifest-type)) 186 | 187 | (defmulti license-info-mf 188 | "Return map of license info (:name and :url) or nil if unknown 189 | based on the manifest." 190 | (fn [lib coord manifest-type config] manifest-type)) 191 | 192 | (defmethod license-info-mf :default [lib coord manifest-type config] nil) 193 | 194 | (defmulti coord-usage 195 | "Return usage info map for this library with the following optional keys: 196 | :ns-default - default namespace symbol 197 | :ns-aliases - map of alias to namespace symbol" 198 | (fn [lib coord manifest-type config] manifest-type)) 199 | 200 | (defmethod coord-usage :default [lib coord manifest-type config] 201 | (throw-bad-manifest lib coord manifest-type)) 202 | 203 | (defmulti prep-command 204 | "Return prep command for this library with the following keys: 205 | :alias - alias to use when invoking (keyword) 206 | :fn - function to invoke in alias (symbol) 207 | :ensure - relative path in repo to ensure exists after prep" 208 | (fn [lib coord manifest-type config] manifest-type)) 209 | 210 | (defmethod prep-command :default [lib coord manifest-type config] 211 | (throw-bad-manifest lib coord manifest-type)) 212 | 213 | (comment 214 | (require '[clojure.tools.deps.util.maven :as maven]) 215 | 216 | (binding [*print-namespace-maps* false] 217 | (run! prn 218 | (find-all-versions 'io.github.clojure/tools.deps.alpha nil {:mvn/repos maven/standard-repos}))) 219 | 220 | (binding [*print-namespace-maps* false] 221 | (run! prn 222 | (find-all-versions 'org.clojure/tools.deps.alpha nil {:mvn/repos maven/standard-repos}))) 223 | 224 | ) -------------------------------------------------------------------------------- /src/dotnet/Cljr.Tests/ParsingTests.cs: -------------------------------------------------------------------------------- 1 | namespace Cljr.Tests; 2 | 3 | public class ParsingTests 4 | { 5 | [Theory] 6 | [InlineData("-h")] 7 | [InlineData("--help")] 8 | [InlineData("-A:X:Y --help")] 9 | [InlineData("-Srepro --help")] 10 | public void HelpTests(string cli) 11 | { 12 | string[] args = cli.Split(new char[] { ' ' }); 13 | var items = CommandLineParser.Parse(args); 14 | Assert.True(items.Mode == EMode.Help); 15 | } 16 | 17 | [Theory] 18 | [InlineData("-version")] 19 | [InlineData("--version")] 20 | [InlineData("-A:X:Y -version")] 21 | [InlineData("-Srepro --version")] 22 | public void VersionTests(string cli) 23 | { 24 | string[] args = cli.Split(new char[] { ' ' }); 25 | var items = CommandLineParser.Parse(args); 26 | Assert.True(items.Mode == EMode.Version); 27 | } 28 | 29 | 30 | [Theory] 31 | [InlineData("describe")] 32 | [InlineData("force")] 33 | [InlineData("path")] 34 | [InlineData("pom")] 35 | [InlineData("repro")] 36 | [InlineData("trace")] 37 | [InlineData("tree")] 38 | [InlineData("verbose")] 39 | public void SFlagTests(string flag) 40 | { 41 | var cli = $"-S{flag} -X:A: B 12 13"; 42 | string[] args = cli.Split(new char[] { ' ' }); 43 | var items = CommandLineParser.Parse(args); 44 | Assert.True(items.FlagCount == 1); 45 | Assert.True(items.HasFlag(flag)); 46 | } 47 | 48 | 49 | //[InlineData("-P -X:A:B 12 13", CommandLineFlags.Prep)] 50 | [Fact] 51 | public void PFlagTests() 52 | { 53 | var cli = "-P -X:A:B 12 13"; 54 | string[] args = cli.Split(new char[] { ' ' }); 55 | var items = CommandLineParser.Parse(args); 56 | Assert.True(items.FlagCount == 1); 57 | Assert.True(items.HasFlag("prep")); 58 | } 59 | 60 | [Theory] 61 | [InlineData("-Srepro -Sresolve-tags -X:A: B 12 13")] 62 | [InlineData("-Srepro -Othing -X:A: B 12 13")] 63 | [InlineData("-Srepro -Cthing -X:A: B 12 13")] 64 | [InlineData("-Srepro -Rthing -X:A: B 12 13")] 65 | public void DeprecatedOptionsTests(string cli) 66 | { 67 | string[] args = cli.Split(new char[] { ' ' }); 68 | var cmd = CommandLineParser.Parse(args); 69 | Assert.True(cmd.IsError); 70 | Assert.NotNull(cmd.ErrorMessage); 71 | } 72 | 73 | [Theory] 74 | [InlineData("-Srepro -Sdeps", "Invalid arguments")] 75 | [InlineData("-Srepro -Scp", "Invalid arguments")] 76 | [InlineData("-Srepro -Sthreads", "Invalid arguments")] 77 | [InlineData("-Srepro -Sthreads a", "Invalid argument")] 78 | [InlineData("-Srepro -Swhat! things", "Unknown option")] 79 | public void MissingOrBadArgumentsToOptions(string cli, string msgPrefix) 80 | { 81 | string[] args = cli.Split(new char[] { ' ' }); 82 | var cmd = CommandLineParser.Parse(args); 83 | Assert.True(cmd.IsError); 84 | Assert.NotNull(cmd.ErrorMessage); 85 | Assert.StartsWith(msgPrefix, cmd.ErrorMessage); 86 | } 87 | 88 | [Fact] 89 | public void StringArgumentsForOptionsTests() 90 | { 91 | string cli = "-Srepro -Sdeps ABC -Scp DEF -Sthreads 12 -X:A: B 12 13"; 92 | string[] args = cli.Split(new char[] { ' ' }); 93 | var items = CommandLineParser.Parse(args); 94 | Assert.True(items.Deps?.Equals("ABC")); 95 | Assert.True(items.ForceClasspath?.Equals("DEF")); 96 | Assert.True(items.Threads == 12); 97 | } 98 | 99 | [Fact] 100 | public void AOptionRequiresAnAliasTest() 101 | { 102 | string cli = "-Srepro -A -X:A: B 12 13"; 103 | string[] args = cli.Split(new char[] { ' ' }); 104 | var cmd = CommandLineParser.Parse(args); 105 | Assert.True(cmd.IsError); 106 | Assert.NotNull(cmd.ErrorMessage); 107 | Assert.StartsWith("-A requires an alias", cmd.ErrorMessage); 108 | } 109 | 110 | [Theory] 111 | [InlineData("-Srepro -X:A: B 12 13", "B", "12", "13")] 112 | [InlineData("-Srepro -- B 12 13", "B", "12", "13")] 113 | public void ArgsGetPassedTests(string cli, params string[] expectedAargs) 114 | { 115 | string[] args = cli.Split(new char[] { ' ' }); 116 | var cmd = CommandLineParser.Parse(args); 117 | Assert.True(cmd.CommandArgs.Zip(expectedAargs.ToList()).All(x => x.First.Equals(x.Second))); 118 | } 119 | 120 | [Theory] 121 | [InlineData("-Srepro -X:A:B 12 13", EMode.Exec, ":A:B", "12", "13")] 122 | [InlineData("-Srepro -M:A:B 12 13", EMode.Main, ":A:B", "12", "13")] 123 | [InlineData("-Srepro -T:A:B 12 13", EMode.Tool, ":A:B", "12", "13")] 124 | [InlineData("-Srepro -- 12 13", EMode.Repl, null, "12", "13")] 125 | [InlineData("-Srepro 12 13", EMode.Repl, null, "12", "13")] 126 | public void CorrectCommandTypeCreated(string cli, EMode mode, string cmdAliases, params string[] expectedArgs) 127 | { 128 | string[] args = cli.Split(new char[] { ' ' }); 129 | var items = CommandLineParser.Parse(args); 130 | Assert.True(items.Mode == mode); 131 | Assert.True(items.CommandArgs.Zip(expectedArgs.ToList()).All(x => x.First.Equals(x.Second))); 132 | 133 | if (cmdAliases != null) 134 | Assert.Equal(cmdAliases, items.CommandAliases[mode]); 135 | else 136 | Assert.False(items.CommandAliases.ContainsKey(mode)); 137 | } 138 | 139 | [Fact] 140 | public void ToolWithAliasTest() 141 | { 142 | string cli = "-Srepro -T:A:B 12 13"; 143 | string[] args = cli.Split(new char[] { ' ' }); 144 | var items = CommandLineParser.Parse(args); 145 | Assert.True(items.Mode == EMode.Tool); 146 | Assert.Null(items.ToolName); 147 | Assert.Equal(":A:B", items.CommandAliases[EMode.Tool]); 148 | } 149 | 150 | 151 | [Fact] 152 | public void ToolWithToolNameTest() 153 | { 154 | string cli = "-Srepro -Tname 12 13"; 155 | string[] args = cli.Split(new char[] { ' ' }); 156 | var items = CommandLineParser.Parse(args); 157 | Assert.True(items.Mode == EMode.Tool); 158 | Assert.Equal("name", items.ToolName); 159 | Assert.False(items.CommandAliases.ContainsKey(EMode.Tool)); 160 | } 161 | 162 | 163 | [Theory] 164 | [InlineData("-Srepro -X 12 13", EMode.Exec, "12", "13")] 165 | [InlineData("-Srepro -M 12 13", EMode.Main, "12", "13")] 166 | [InlineData("-Srepro -T 12 13", EMode.Tool, "12", "13")] 167 | public void CommandWithNoAliasTests(string cli, EMode mode, params string[] expectedArgs) 168 | { 169 | string[] args = cli.Split(new char[] { ' ' }); 170 | var items = CommandLineParser.Parse(args); 171 | Assert.True(items.Mode == mode); 172 | Assert.False(items.CommandAliases.ContainsKey(mode)); 173 | Assert.True(items.CommandArgs.Zip(expectedArgs.ToList()).All(x => x.First.Equals(x.Second))); 174 | } 175 | 176 | [Theory] 177 | [InlineData("-Srepro -A:A:B -A:C:D -X:A:B 12 13", EMode.Exec, ":A:B:C:D")] 178 | [InlineData("-Srepro -A:A:B -A:C:D -M:A:B 12 13", EMode.Main, ":A:B:C:D")] 179 | [InlineData("-Srepro -A:A:B -A:C:D -T:A:B 12 13", EMode.Tool, ":A:B:C:D")] 180 | [InlineData("-Srepro -A:A:B -A:C:D -- 12 13", EMode.Repl, ":A:B:C:D")] 181 | public void AArgPassesReplAliases(string cli, EMode mode, string replAliases) 182 | { 183 | string[] args = cli.Split(new char[] { ' ' }); 184 | var items = CommandLineParser.Parse(args); 185 | Assert.True(items.Mode == mode); 186 | Assert.Equal(replAliases, items.CommandAliases[EMode.Repl]); 187 | } 188 | 189 | [Theory] 190 | [InlineData("-Srepro -A:A:B -A:C:D -X:")] 191 | [InlineData("-Srepro -A:A:B -A:C:D -M:")] 192 | [InlineData("-Srepro -A:A:B -A:C:D -T:")] 193 | [InlineData("-Srepro -A:A:B -A:C:D -A:")] 194 | public void PowerShellWorkaroundFailTests(string cli) 195 | { 196 | string[] args = cli.Split(new char[] { ' ' }); 197 | var cmd = CommandLineParser.Parse(args); 198 | Assert.True(cmd.IsError); 199 | } 200 | 201 | [Theory] 202 | [InlineData("-Srepro -X: A:B 12 13", EMode.Exec, ":A:B", "12", "13")] 203 | [InlineData("-Srepro -M: A:B 12 13", EMode.Main, ":A:B", "12", "13")] 204 | [InlineData("-Srepro -T: A:B 12 13", EMode.Tool, ":A:B", "12", "13")] 205 | [InlineData("-Srepro -A: A:B -- 12 13", EMode.Repl, ":A:B", "12", "13")] 206 | public void PowerShellWorkaroundSuccessTests(string cli, EMode mode, string cmdAliases, params string[] expectedArgs) 207 | { 208 | string[] args = cli.Split(new char[] { ' ' }); 209 | var items = CommandLineParser.Parse(args); 210 | Assert.True(items.Mode == mode); 211 | Assert.True(items.CommandArgs.Zip(expectedArgs.ToList()).All(x => x.First.Equals(x.Second))); 212 | Assert.Equal(cmdAliases, items.CommandAliases[mode]); 213 | } 214 | 215 | [Theory] 216 | [InlineData("-Srepro -A: A:B -A: C:D -X:A:B 12 13", EMode.Exec, ":A:B:C:D")] 217 | [InlineData("-Srepro -A: A:B -A: C:D -M:A:B 12 13", EMode.Main, ":A:B:C:D")] 218 | [InlineData("-Srepro -A: A:B -A: C:D -T:A:B 12 13", EMode.Tool, ":A:B:C:D")] 219 | [InlineData("-Srepro -A: A:B -A: C:D -- 12 13", EMode.Repl, ":A:B:C:D")] 220 | public void PowerShellWorkaroundForASuccessTests(string cli, EMode mode, string replAliases) 221 | { 222 | string[] args = cli.Split(new char[] { ' ' }); 223 | var items = CommandLineParser.Parse(args); 224 | Assert.True(items.Mode == mode); 225 | Assert.Equal(replAliases, items.CommandAliases[EMode.Repl]); 226 | } 227 | } -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/deps/script/make_classpath2.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:skip-wiki true} 10 | clojure.tools.deps.script.make-classpath2 11 | (:require 12 | #?(:clj [clojure.java.io :as jio] 13 | :cljr [clojure.clr.io :as cio]) 14 | [clojure.pprint :as pprint] 15 | [clojure.string :as str] 16 | [clojure.tools.cli :as cli] 17 | [clojure.tools.deps :as deps] 18 | [clojure.tools.deps.extensions :as ext] 19 | [clojure.tools.deps.tool :as tool] 20 | [clojure.tools.deps.util.io :as io :refer [printerrln]] 21 | [clojure.tools.deps.script.parse :as parse] 22 | [clojure.tools.deps.tree :as tree]) 23 | (:import 24 | [clojure.lang IExceptionInfo])) 25 | 26 | (def ^:private opts 27 | [;; deps.edn inputs 28 | [nil "--config-user PATH" "User deps.edn location"] 29 | [nil "--config-project PATH" "Project deps.edn location"] 30 | [nil "--config-data EDN" "Final deps.edn data to treat as the last deps.edn file" :parse-fn parse/parse-config] 31 | #?(:cljr [nil "--install-dir PATH" "Installation directory (CLJR only), internal use"] ) 32 | ;; tool args to resolve 33 | [nil "--tool-mode" "Tool mode (-T), may optionally supply tool-name or tool-aliases"] 34 | [nil "--tool-name NAME" "Tool name"] 35 | ;; output files 36 | [nil "--cp-file PATH" "Classpatch cache file to write"] 37 | [nil "--jvm-file PATH" "JVM options file"] 38 | [nil "--main-file PATH" "Main options file"] 39 | [nil "--manifest-file PATH" "Manifest list file"] 40 | [nil "--basis-file PATH" "Basis file"] 41 | [nil "--skip-cp" "Skip writing .cp files"] 42 | ;; aliases 43 | ["-A" "--repl-aliases ALIASES" "Concatenated repl alias names" :parse-fn parse/parse-kws] 44 | ["-M" "--main-aliases ALIASES" "Concatenated main option alias names" :parse-fn parse/parse-kws] 45 | ["-X" "--exec-aliases ALIASES" "Concatenated exec alias names" :parse-fn parse/parse-kws] 46 | ["-T" "--tool-aliases ALIASES" "Concatenated tool alias names" :parse-fn parse/parse-kws] 47 | ;; options 48 | [nil "--trace" "Emit trace log to trace.edn"] 49 | [nil "--threads THREADS" "Threads for concurrent downloads"] 50 | [nil "--tree" "Print deps tree to console"]]) 51 | 52 | (defn parse-opts 53 | "Parse the command line opts to make-classpath" 54 | [args] 55 | (cli/parse-opts args opts)) 56 | 57 | (defn check-aliases 58 | "Check that all aliases are known and warn if aliases are undeclared" 59 | [deps aliases] 60 | (when-let [unknown (seq (remove #(contains? (:aliases deps) %) (distinct aliases)))] 61 | (printerrln "WARNING: Specified aliases are undeclared and are not being used:" (vec unknown)))) 62 | 63 | (defn resolve-tool-args 64 | "Resolves the tool by name to the coord + usage data. 65 | Returns the proper alias args as if the tool was specified as an alias." 66 | [tool-name config] 67 | (if-let [{:keys [lib coord]} (tool/resolve-tool tool-name)] 68 | (let [manifest-type (ext/manifest-type lib coord config) 69 | coord' (merge coord manifest-type) 70 | {:keys [ns-default ns-aliases]} (ext/coord-usage lib coord' (:deps/manifest coord') config)] 71 | {:replace-deps {lib coord'} 72 | :replace-paths ["."] 73 | :ns-default ns-default 74 | :ns-aliases ns-aliases}) 75 | (throw (ex-info (str "Unknown tool: " tool-name) {:tool tool-name})))) 76 | 77 | (defn run-core 78 | "Run make-classpath script from/to data (no file stuff). Returns: 79 | {;; Outputs: 80 | :basis ;; the basis, including classpath roots 81 | :trace ;; if requested, trace.edn file 82 | :manifests ;; manifest files used in making classpath 83 | }" 84 | [{:keys [install-deps user-deps project-deps config-data ;; all deps.edn maps 85 | tool-mode tool-name tool-resolver ;; -T options 86 | main-aliases exec-aliases repl-aliases tool-aliases 87 | skip-cp threads trace tree] :as _opts}] 88 | (when (and main-aliases exec-aliases) 89 | (throw (ex-info "-M and -X cannot be used at the same time" {}))) 90 | (let [pretool-edn (deps/merge-edns [install-deps user-deps project-deps config-data]) 91 | ;; tool use - :deps/:paths/:replace-deps/:replace-paths in project if needed 92 | tool-args (cond 93 | tool-name (tool-resolver tool-name pretool-edn) 94 | tool-mode {:replace-deps {} :replace-paths ["."]}) 95 | tool-edn (when tool-args {:aliases {:deps/TOOL tool-args}}) 96 | ;; :deps/TOOL is a synthetic deps.edn combining the tool definition and usage 97 | ;; it is injected at the end of the deps chain and added as a pseudo alias 98 | ;; the effects are seen in the basis but this pseduo alias should not escape 99 | combined-tool-args (deps/combine-aliases 100 | (deps/merge-edns [pretool-edn tool-edn]) 101 | (concat main-aliases exec-aliases repl-aliases tool-aliases (when tool-edn [:deps/TOOL]))) 102 | project-deps (deps/tool project-deps combined-tool-args) 103 | 104 | ;; calc basis 105 | merge-edn (deps/merge-edns [install-deps user-deps project-deps config-data (when tool-edn tool-edn)]) ;; recalc to get updated project-deps 106 | combined-exec-aliases (concat main-aliases exec-aliases repl-aliases tool-aliases (when tool-edn [:deps/TOOL])) 107 | _ (check-aliases merge-edn combined-exec-aliases) 108 | argmap (deps/combine-aliases merge-edn combined-exec-aliases) 109 | resolve-args (cond-> argmap 110 | threads (assoc :threads (#?(:clj Long/parseLong :cljr Int64/Parse) threads)) 111 | trace (assoc :trace trace) 112 | tree (assoc :trace true)) 113 | basis (cond-> nil 114 | (not skip-cp) (merge 115 | (deps/calc-basis merge-edn {:resolve-args resolve-args, :classpath-args argmap}) 116 | {:basis-config (cond-> {} ;; :root and :project are always :standard 117 | (nil? user-deps) (assoc :user nil) ;; -Srepro => :user nil 118 | config-data (assoc :extra config-data) ;; -Sdeps => :extra ... 119 | (seq combined-exec-aliases) (assoc :aliases (vec combined-exec-aliases)))}) 120 | (pos? (count argmap)) (assoc :argmap argmap)) 121 | libs (:libs basis) 122 | trace (-> libs meta :trace) 123 | 124 | ;; check for unprepped libs 125 | _ (deps/prep-libs! libs {:action :error} basis) 126 | 127 | ;; determine manifest files to add to cache check 128 | manifests (->> 129 | (for [[lib coord] libs] 130 | (let [mf (ext/manifest-type lib coord basis)] 131 | (ext/manifest-file lib coord (:deps/manifest mf) basis))) 132 | (remove nil?) 133 | seq)] 134 | (when (and (-> argmap :main-opts seq) repl-aliases) 135 | (io/printerrln "WARNING: Use of :main-opts with -A is deprecated. Use -M instead.")) 136 | (cond-> {:basis basis} 137 | trace (assoc :trace trace) 138 | manifests (assoc :manifests manifests)))) 139 | 140 | (defn read-deps 141 | [name] 142 | (when (not (str/blank? name)) 143 | (let [f (#?(:clj jio/file :cljr cio/file-info) name)] 144 | (when (#?(:clj .exists :cljr .Exists) f) 145 | (deps/slurp-deps f))))) 146 | 147 | (defn write-lines 148 | [lines file] 149 | (if lines 150 | (io/write-file file (apply str (interleave lines (repeat "\n")))) 151 | (let [jf (#?(:clj jio/file :cljr cio/file-info) file)] 152 | (when (#?(:clj .exists :cljr .Exists) jf) 153 | (#?(:clj .delete :cljr .Delete) jf))))) 154 | 155 | (defn run 156 | "Run make-classpath script. See -main for details." 157 | [{:keys [install-dir config-user config-project cp-file jvm-file main-file basis-file manifest-file skip-cp trace tree] :as opts}] 158 | 159 | (reset! clojure.tools.deps/install-dir install-dir) 160 | 161 | (let [opts' (merge opts {:install-deps (deps/root-deps) 162 | :user-deps (read-deps config-user) 163 | :project-deps (or (read-deps "deps-clr.edn") (read-deps config-project)) 164 | :tool-resolver resolve-tool-args}) 165 | {:keys [basis manifests], trace-log :trace} (run-core opts') 166 | {:keys [argmap libs classpath-roots]} basis 167 | {:keys [jvm-opts main-opts]} argmap] 168 | (when trace 169 | (spit "trace.edn" 170 | (binding [*print-namespace-maps* false] (with-out-str (pprint/pprint trace-log))) 171 | #?@(:cljr (:file-mode System.IO.FileMode/Create)))) 172 | (when tree 173 | (-> trace-log tree/trace->tree (tree/print-tree nil))) 174 | (when-not skip-cp 175 | (io/write-file cp-file (-> classpath-roots deps/join-classpath))) 176 | (io/write-file basis-file (binding [*print-namespace-maps* false] (pr-str basis))) 177 | (write-lines (seq jvm-opts) jvm-file) 178 | (write-lines (seq main-opts) main-file) ;; FUTURE: add check to only do this if main-aliases were passed 179 | (write-lines manifests manifest-file))) 180 | 181 | (defn -main 182 | "Main entry point for make-classpath script. 183 | 184 | Options: 185 | --config-user=path - user deps.edn file (usually ~/.clojure/deps.edn) 186 | --config-project=path - project deps.edn file (usually ./deps.edn) 187 | --config-data={...} - deps.edn as data (from -Sdeps) 188 | --tool-mode - flag for tool mode 189 | --tool-name - name of tool to run 190 | --cp-file=path - cp cache file to write 191 | --jvm-file=path - jvm opts file to write 192 | --main-file=path - main opts file to write 193 | --manifest-file=path - manifest list file to write 194 | --basis-file=path - basis file to write 195 | -Mmain-aliases - concatenated main-opt alias names 196 | -Aaliases - concatenated repl alias names 197 | -Xaliases - concatenated exec alias names 198 | -Taliases - concatenated tool alias names 199 | 200 | Resolves the dependencies and updates the lib, classpath, etc files. 201 | The cp file is at /.cp 202 | The main opts file is at /.main (if needed) 203 | The jvm opts file is at /.jvm (if needed) 204 | The manifest file is at /.manifest (if needed)" 205 | [& args] 206 | (try 207 | (let [{:keys [options errors]} (parse-opts args)] 208 | (when (seq errors) 209 | (run! println errors) 210 | (#?(:clj System/exit :cljr Environment/Exit) 1)) 211 | (run options)) 212 | (catch #?(:clj Throwable :cljr Exception) t 213 | (printerrln "Error building classpath." (#?(:clj .getMessage :cljr .Message) t)) 214 | (when-not (instance? IExceptionInfo t) 215 | #?(:clj (.printStackTrace t) 216 | :cljr (System.Console/WriteLine (.StackTrace t)))) 217 | (#?(:clj System/exit :cljr Environment/Exit) 1)))) -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial code and documentation 12 | distributed under this Agreement, and 13 | b) in the case of each subsequent Contributor: 14 | i) changes to the Program, and 15 | ii) additions to the Program; 16 | 17 | where such changes and/or additions to the Program originate from and are 18 | distributed by that particular Contributor. A Contribution 'originates' 19 | from a Contributor if it was added to the Program by such Contributor 20 | itself or anyone acting on such Contributor's behalf. Contributions do not 21 | include additions to the Program which: (i) are separate modules of 22 | software distributed in conjunction with the Program under their own 23 | license agreement, and (ii) are not derivative works of the Program. 24 | 25 | "Contributor" means any person or entity that distributes the Program. 26 | 27 | "Licensed Patents" mean patent claims licensable by a Contributor which are 28 | necessarily infringed by the use or sale of its Contribution alone or when 29 | combined with the Program. 30 | 31 | "Program" means the Contributions distributed in accordance with this 32 | Agreement. 33 | 34 | "Recipient" means anyone who receives the Program under this Agreement, 35 | including all Contributors. 36 | 37 | 2. GRANT OF RIGHTS 38 | a) Subject to the terms of this Agreement, each Contributor hereby grants 39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 40 | reproduce, prepare derivative works of, publicly display, publicly 41 | perform, distribute and sublicense the Contribution of such Contributor, 42 | if any, and such derivative works, in source code and object code form. 43 | b) Subject to the terms of this Agreement, each Contributor hereby grants 44 | Recipient a non-exclusive, worldwide, royalty-free patent license under 45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 46 | transfer the Contribution of such Contributor, if any, in source code and 47 | object code form. This patent license shall apply to the combination of 48 | the Contribution and the Program if, at the time the Contribution is 49 | added by the Contributor, such addition of the Contribution causes such 50 | combination to be covered by the Licensed Patents. The patent license 51 | shall not apply to any other combinations which include the Contribution. 52 | No hardware per se is licensed hereunder. 53 | c) Recipient understands that although each Contributor grants the licenses 54 | to its Contributions set forth herein, no assurances are provided by any 55 | Contributor that the Program does not infringe the patent or other 56 | intellectual property rights of any other entity. Each Contributor 57 | disclaims any liability to Recipient for claims brought by any other 58 | entity based on infringement of intellectual property rights or 59 | otherwise. As a condition to exercising the rights and licenses granted 60 | hereunder, each Recipient hereby assumes sole responsibility to secure 61 | any other intellectual property rights needed, if any. For example, if a 62 | third party patent license is required to allow Recipient to distribute 63 | the Program, it is Recipient's responsibility to acquire that license 64 | before distributing the Program. 65 | d) Each Contributor represents that to its knowledge it has sufficient 66 | copyright rights in its Contribution, if any, to grant the copyright 67 | license set forth in this Agreement. 68 | 69 | 3. REQUIREMENTS 70 | 71 | A Contributor may choose to distribute the Program in object code form under 72 | its own license agreement, provided that: 73 | 74 | a) it complies with the terms and conditions of this Agreement; and 75 | b) its license agreement: 76 | i) effectively disclaims on behalf of all Contributors all warranties 77 | and conditions, express and implied, including warranties or 78 | conditions of title and non-infringement, and implied warranties or 79 | conditions of merchantability and fitness for a particular purpose; 80 | ii) effectively excludes on behalf of all Contributors all liability for 81 | damages, including direct, indirect, special, incidental and 82 | consequential damages, such as lost profits; 83 | iii) states that any provisions which differ from this Agreement are 84 | offered by that Contributor alone and not by any other party; and 85 | iv) states that source code for the Program is available from such 86 | Contributor, and informs licensees how to obtain it in a reasonable 87 | manner on or through a medium customarily used for software exchange. 88 | 89 | When the Program is made available in source code form: 90 | 91 | a) it must be made available under this Agreement; and 92 | b) a copy of this Agreement must be included with each copy of the Program. 93 | Contributors may not remove or alter any copyright notices contained 94 | within the Program. 95 | 96 | Each Contributor must identify itself as the originator of its Contribution, 97 | if 98 | any, in a manner that reasonably allows subsequent Recipients to identify the 99 | originator of the Contribution. 100 | 101 | 4. COMMERCIAL DISTRIBUTION 102 | 103 | Commercial distributors of software may accept certain responsibilities with 104 | respect to end users, business partners and the like. While this license is 105 | intended to facilitate the commercial use of the Program, the Contributor who 106 | includes the Program in a commercial product offering should do so in a manner 107 | which does not create potential liability for other Contributors. Therefore, 108 | if a Contributor includes the Program in a commercial product offering, such 109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify 110 | every other Contributor ("Indemnified Contributor") against any losses, 111 | damages and costs (collectively "Losses") arising from claims, lawsuits and 112 | other legal actions brought by a third party against the Indemnified 113 | Contributor to the extent caused by the acts or omissions of such Commercial 114 | Contributor in connection with its distribution of the Program in a commercial 115 | product offering. The obligations in this section do not apply to any claims 116 | or Losses relating to any actual or alleged intellectual property 117 | infringement. In order to qualify, an Indemnified Contributor must: 118 | a) promptly notify the Commercial Contributor in writing of such claim, and 119 | b) allow the Commercial Contributor to control, and cooperate with the 120 | Commercial Contributor in, the defense and any related settlement 121 | negotiations. The Indemnified Contributor may participate in any such claim at 122 | its own expense. 123 | 124 | For example, a Contributor might include the Program in a commercial product 125 | offering, Product X. That Contributor is then a Commercial Contributor. If 126 | that Commercial Contributor then makes performance claims, or offers 127 | warranties related to Product X, those performance claims and warranties are 128 | such Commercial Contributor's responsibility alone. Under this section, the 129 | Commercial Contributor would have to defend claims against the other 130 | Contributors related to those performance claims and warranties, and if a 131 | court requires any other Contributor to pay any damages as a result, the 132 | Commercial Contributor must pay those damages. 133 | 134 | 5. NO WARRANTY 135 | 136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN 137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each 140 | Recipient is solely responsible for determining the appropriateness of using 141 | and distributing the Program and assumes all risks associated with its 142 | exercise of rights under this Agreement , including but not limited to the 143 | risks and costs of program errors, compliance with applicable laws, damage to 144 | or loss of data, programs or equipment, and unavailability or interruption of 145 | operations. 146 | 147 | 6. DISCLAIMER OF LIABILITY 148 | 149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 156 | OF SUCH DAMAGES. 157 | 158 | 7. GENERAL 159 | 160 | If any provision of this Agreement is invalid or unenforceable under 161 | applicable law, it shall not affect the validity or enforceability of the 162 | remainder of the terms of this Agreement, and without further action by the 163 | parties hereto, such provision shall be reformed to the minimum extent 164 | necessary to make such provision valid and enforceable. 165 | 166 | If Recipient institutes patent litigation against any entity (including a 167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 168 | (excluding combinations of the Program with other software or hardware) 169 | infringes such Recipient's patent(s), then such Recipient's rights granted 170 | under Section 2(b) shall terminate as of the date such litigation is filed. 171 | 172 | All Recipient's rights under this Agreement shall terminate if it fails to 173 | comply with any of the material terms or conditions of this Agreement and does 174 | not cure such failure in a reasonable period of time after becoming aware of 175 | such noncompliance. If all Recipient's rights under this Agreement terminate, 176 | Recipient agrees to cease use and distribution of the Program as soon as 177 | reasonably practicable. However, Recipient's obligations under this Agreement 178 | and any licenses granted by Recipient relating to the Program shall continue 179 | and survive. 180 | 181 | Everyone is permitted to copy and distribute copies of this Agreement, but in 182 | order to avoid inconsistency the Agreement is copyrighted and may only be 183 | modified in the following manner. The Agreement Steward reserves the right to 184 | publish new versions (including revisions) of this Agreement from time to 185 | time. No one other than the Agreement Steward has the right to modify this 186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 187 | Eclipse Foundation may assign the responsibility to serve as the Agreement 188 | Steward to a suitable separate entity. Each new version of the Agreement will 189 | be given a distinguishing version number. The Program (including 190 | Contributions) may always be distributed subject to the version of the 191 | Agreement under which it was received. In addition, after a new version of the 192 | Agreement is published, Contributor may elect to distribute the Program 193 | (including its Contributions) under the new version. Except as expressly 194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 195 | licenses to the intellectual property of any Contributor under this Agreement, 196 | whether expressly, by implication, estoppel or otherwise. All rights in the 197 | Program not expressly granted under this Agreement are reserved. 198 | 199 | This Agreement is governed by the laws of the State of New York and the 200 | intellectual property laws of the United States of America. No party to this 201 | Agreement will bring a legal action under this Agreement more than one year 202 | after the cause of action arose. Each party waives its rights to a jury trial in 203 | any resulting litigation. 204 | 205 | 206 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/run/exec.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.run.exec 10 | (:require 11 | ;; NOTE: ONLY depend on Clojure core, loaded in user's classpath so can't have any deps 12 | [clojure.edn :as edn] 13 | #?(:clj [clojure.java.io :as jio] :cljr [clojure.clr.io :as cio]) 14 | #?(:cljr [clojure.tools.deps :as deps]) 15 | [clojure.string :as str] 16 | [clojure.spec.alpha :as s]) 17 | (:import 18 | [clojure.lang ExceptionInfo] 19 | #?(:clj [java.io StringWriter Writer FileNotFoundException PushbackReader] 20 | :cljr [System.IO StringWriter TextWriter FileNotFoundException]) 21 | #?(:cljr [clojure.lang PushbackTextReader]) 22 | #?(:clj [java.util.concurrent Executors ThreadFactory]) )) 23 | 24 | (set! *warn-on-reflection* true) 25 | (def ^:dynamic *ns-default* nil) 26 | (def ^:dynamic *ns-aliases* nil) 27 | 28 | (defn- err 29 | ^#?(:clj Throwable :cljr Exception) [& msg] 30 | (ex-info (str/join " " msg) {:exec-msg true})) 31 | 32 | (defn- requiring-resolve' 33 | ;; copied and modified from core to remove constraints on Clojure 1.10.x 34 | [sym] 35 | (if (nil? (namespace sym)) 36 | (throw (err "Not a qualified symbol:" sym)) 37 | (or (resolve sym) 38 | (do 39 | (-> sym namespace symbol require) 40 | (resolve sym))))) 41 | 42 | (defn remove-ns-keys 43 | "Remove keys in m with namespace string ns-str" 44 | [m ns-str] 45 | (reduce-kv #(if (= ns-str (namespace %2)) %1 (assoc %1 %2 %3)) {} m)) 46 | 47 | (defn- add-stream 48 | [envelope stream-tag ^#?(:clj Writer :cljr TextWriter) writer] 49 | (#?(:clj .flush :cljr .Flush) writer) 50 | (let [s (str writer)] 51 | (if (str/blank? s) 52 | envelope 53 | (assoc envelope stream-tag s)))) 54 | 55 | (defn- envelope 56 | [args tag val out-wr err-wr start] 57 | (let [end #?(:clj (System/currentTimeMillis) :cljr (long (/ (.Ticks (DateTime/Now)) (TimeSpan/TicksPerMillisecond))))] 58 | (cond-> {:tag tag 59 | :val (binding [*print-namespace-maps* false] (pr-str val)) 60 | :ms (- end start)} 61 | (= :capture (:clojure.exec/out args)) (add-stream :out out-wr) 62 | (= :capture (:clojure.exec/err args)) (add-stream :err err-wr)))) 63 | 64 | (defn apply-program 65 | [f args] 66 | (let [clean-args (remove-ns-keys args "clojure.exec") 67 | out-wr (StringWriter.) 68 | err-wr (StringWriter.) 69 | start #?(:clj (System/currentTimeMillis) :cljr (long (/ (.Ticks (DateTime/Now)) (TimeSpan/TicksPerMillisecond)))) 70 | envelope (binding [*out* out-wr, *err* err-wr] 71 | (try 72 | (envelope args :ret (f clean-args) out-wr err-wr start) 73 | (catch #?(:clj Throwable :cljr Exception) t 74 | (envelope args :err (Throwable->map t) out-wr err-wr start)) 75 | (finally 76 | (#?(:clj .close :cljr .Close) out-wr) 77 | (#?(:clj .close :cljr .Close) err-wr))))] 78 | (binding [*print-namespace-maps* false] 79 | (prn envelope)))) 80 | 81 | (defn exec 82 | "Resolve and execute the function f (a symbol) with args" 83 | [f args] 84 | (try 85 | (let [resolved-f (try 86 | (requiring-resolve' f) 87 | (catch FileNotFoundException _ 88 | (throw (err "Namespace could not be loaded:" (namespace f)))))] 89 | (if resolved-f 90 | (if (= :fn (:clojure.exec/invoke args)) 91 | (apply-program resolved-f args) 92 | (resolved-f args)) 93 | (throw (err "Namespace" (namespace f) "loaded but function not found:" (name f))))))) 94 | 95 | (defn- apply-overrides 96 | [args overrides] 97 | (reduce (fn [m [k v]] 98 | (if (sequential? k) 99 | (assoc-in m k v) 100 | (assoc m k v))) 101 | args (partition-all 2 overrides))) 102 | 103 | (defn- qualify-fn 104 | "Compute function symbol based on exec-fn, ns-aliases, and ns-default" 105 | [fsym ns-aliases ns-default] 106 | ;; validation - make specs? 107 | (when (and fsym (not (symbol? fsym))) 108 | (throw (err "Expected function symbol:" fsym))) 109 | 110 | (when fsym 111 | (if (qualified-ident? fsym) 112 | (let [nsym (get ns-aliases (symbol (namespace fsym)))] 113 | (if nsym 114 | (symbol (str nsym) (name fsym)) 115 | fsym)) 116 | (if ns-default 117 | (symbol (str ns-default) (str fsym)) 118 | (throw (err "Unqualified function can't be resolved:" fsym)))))) 119 | 120 | (defn- read-basis 121 | [] 122 | (when-let [f #?(:clj (jio/file (System/getProperty "clojure.basis")) 123 | :cljr (cio/file-info (Environment/GetEnvironmentVariable "clojure.basis")))] 124 | (if (and f (#?(:clj .exists :cljr .Exists) f)) 125 | (->> f slurp (edn/read-string {:default tagged-literal})) 126 | (throw (err "No basis declared in clojure.basis system property"))))) 127 | 128 | (def arg-spec (s/cat :fns (s/? symbol?) :kvs (s/* (s/cat :k (s/nonconforming (s/or :keyword any? :path vector?)) :v any?)) :trailing (s/? map?))) 129 | 130 | (defn- build-fn-descriptor [{:keys [fns kvs trailing] :as extra}] 131 | (cond-> {} 132 | fns (assoc :function fns) 133 | trailing (assoc :trailing trailing) 134 | kvs (assoc :overrides (reduce #(-> %1 (conj (:k %2)) (conj (:v %2))) [] kvs)))) 135 | 136 | (defn- build-error [expl] 137 | (let [err-str (with-out-str 138 | (doseq [problem (:clojure.spec.alpha/problems expl)] 139 | (println (:reason problem) (:clojure.spec.alpha/value expl))))] 140 | (err "Problem parsing arguments: " err-str))) 141 | 142 | (defn- parse-fn 143 | [args] 144 | (when (seq args) 145 | (let [conf (s/conform arg-spec args)] 146 | (if (s/invalid? conf) 147 | (let [expl (s/explain-data arg-spec args)] 148 | (throw (build-error expl))) 149 | (build-fn-descriptor conf))))) 150 | 151 | (defn- read-args-stdin 152 | [prior-args] 153 | (let [eof (Object.) 154 | r #?(:clj (PushbackReader. (java.io.BufferedReader. *in*)) 155 | :cljr (PushbackTextReader. *in*))] 156 | (loop [args prior-args] 157 | (let [arg (edn/read {:eof eof :default tagged-literal} r)] 158 | (if (= eof arg) 159 | args 160 | (recur (conj args arg))))))) 161 | 162 | (defn- read-args 163 | [args] 164 | (loop [[a & as] args 165 | read-args []] 166 | (if a 167 | (if (= a "-") 168 | (read-args-stdin read-args) 169 | (let [r (try 170 | (edn/read-string {:default tagged-literal} a) 171 | (catch #?(:clj Throwable :cljr Exception) _ 172 | (throw (err "Unreadable arg:" (pr-str a)))))] 173 | (recur as (conj read-args r)))) 174 | read-args))) 175 | 176 | #?( 177 | :clj 178 | (defn- set-daemon-agent-executor 179 | "Set Clojure's send-off agent executor (also affects futures). This is almost 180 | an exact rewrite of the Clojure's executor, but the Threads are created as 181 | daemons." 182 | [] 183 | (let [thread-counter (atom 0) 184 | thread-factory (reify ThreadFactory 185 | (newThread [_ runnable] 186 | (doto (Thread. runnable) 187 | (.setDaemon true) ;; DIFFERENT 188 | (.setName (format "CLI-agent-send-off-pool-%d" 189 | (first (swap-vals! thread-counter inc))))))) 190 | executor (Executors/newCachedThreadPool thread-factory)] 191 | (set-agent-send-off-executor! executor))) 192 | ) ;; no :cljr equivalent 193 | 194 | (defn ^:dynamic *exit* 195 | ;; normal exit 196 | ([]) 197 | ;; abnormal exit 198 | ([^#?(:clj Throwable :cljr Exception) t] (#?(:clj System/exit :cljr Environment/Exit) 1))) 199 | 200 | 201 | #?(:cljr 202 | 203 | (defn set-install-dir [] 204 | (let [install-dir (Environment/GetEnvironmentVariable "clojure.cli.install-dir")] 205 | (when install-dir 206 | (reset! deps/install-dir install-dir)))) 207 | ) 208 | 209 | (defn -main 210 | "Execute a function with map kvs. 211 | 212 | The classpath is determined by the clojure script and make-classpath programs 213 | and has already been set. Any execute argmap keys indicated via aliases will 214 | be read from the basis file :argmap passed via -Dclojure.basis. The exec args 215 | have the following possible keys: 216 | :exec-fn - symbol to be resolved in terms of the namespace context, will 217 | be overridden if passed as arg 218 | :exec-args - map of kv args 219 | :ns-default - namespace default for resolving functions 220 | :ns-aliases - map of alias symbol to namespace symbol for resolving functions 221 | 222 | The actual args to exec are essentially same as to -X: 223 | [fn] (kpath v)+ map? 224 | 225 | fn is resolved from either :exec-fn or fn 226 | map to pass to fn is built from merge of: 227 | exec-args map 228 | map built from kpath/v's 229 | trailing map" 230 | [& args] 231 | #?(:cljr (set-install-dir)) 232 | (try 233 | (let [execute-args (:argmap (read-basis)) 234 | {:keys [function overrides trailing]} (-> args read-args parse-fn) 235 | {:keys [exec-fn exec-args ns-aliases ns-default]} execute-args 236 | f (or function exec-fn)] 237 | (when (nil? f) 238 | (if (symbol? (first overrides)) 239 | (throw (err "Key is missing value:" (last overrides))) 240 | (throw (err "No function found on command line or in :exec-fn")))) 241 | #?(:clj (set-daemon-agent-executor)) ;; no :cljr equivalent 242 | (binding [*ns-default* ns-default 243 | *ns-aliases* ns-aliases] 244 | (let [qualified-fn (qualify-fn f ns-aliases ns-default) 245 | args (merge (apply-overrides exec-args overrides) trailing)] 246 | (exec qualified-fn args))) 247 | (*exit*)) 248 | (catch ExceptionInfo e 249 | (if (-> e ex-data :exec-msg) 250 | (binding [*out* *err*] 251 | (println (#?(:clj .getMessage :cljr .Message) e)) 252 | (*exit* e)) 253 | (throw e))))) 254 | 255 | (comment 256 | (parse-fn []) ;;=> nil 257 | (parse-fn [:a:b 'foo/bar]) ;;=> {:function [foo/bar]} 258 | (parse-fn [:a:b 'foo/bar :x 1 :y 2]) ;;=> {:function [foo/bar], :overrides [:x 1 :y 2]} 259 | (parse-fn [:a:b 'foo/bar :x 1 :y]) ;;=> Except, missing value for :y 260 | (parse-fn [:x 1 :k 1]) ;;=> {:overrides [:x 1 :k 1]} 261 | (parse-fn ['foo/bar]) ;;=> {:function [foo/bar]} 262 | (parse-fn ['foo/bar :x 1 :y]) ;;=> Except, missing value for :y 263 | (parse-fn [:x 1 :ZZZZZZZZZZZ]) ;;=> Except, missing value for :ZZZZZZZZZZZ 264 | 265 | (parse-fn [:a 1 :b 2]) ;;=> {:overrides [:a 1 :b 2]} 266 | (parse-fn [:a 1 :b 2 {:b 42}]) ;;=> {:overrides [:a 1 :b 2], :trailing {:b 42}} 267 | (parse-fn ['foo/bar {:a 1}]) ;;=> {:function [foo/bar], :trailing {:a 1}} 268 | (parse-fn [:x 1 :k 1 {:a 1}]) ;;=> {:overrides [:x 1 :k 1], :trailing {:a 1}} 269 | (parse-fn ['foo/bar :x 1 :y 2 {:y 42}]) ;;=> {:function [foo/bar], :overrides [:x 1 :y 2], :trailing {:y 42}} 270 | (parse-fn ['foo/bar :x 1 :y {:y 42}]) ;;=> {:function [foo/bar], :overrides [:x 1 :y {:y 42}]} 271 | 272 | (-> ["clojure.run.test-exec/save" ":a" "1" "[:b,:c]" "2"] 273 | read-args 274 | parse-fn) 275 | 276 | (s/conform arg-spec '[a b :a 1 :b 2 {}]) 277 | (s/conform arg-spec '[a b]) 278 | (s/conform arg-spec '[a]) 279 | (s/conform arg-spec '[a {:a 1 :b 2}]) 280 | (s/conform arg-spec '[:a 1 :b 2]) 281 | (s/conform arg-spec '[foo/bar :x 1 :y]) 282 | (s/conform arg-spec '[clojure.run.test-exec/save :a 1 [:b :c] 2])) 283 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/gitlibs/impl.cljr: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.gitlibs.impl 10 | "Implementation, use at your own risk" 11 | (:require 12 | [clojure.clr.io :as cio] ;;; [clojure.java.io :as jio] 13 | [clojure.string :as str] 14 | [clojure.tools.gitlibs.config :as config]) 15 | (:import 16 | [System.Diagnostics ProcessStartInfo Process] ;;; [java.lang ProcessBuilder$Redirect] 17 | [System.IO Stream StringWriter FileInfo DirectoryInfo Path IOException] ;;; [java.io File FilenameFilter InputStream IOException StringWriter] 18 | [System.Threading Thread ThreadStart])) 19 | (set! *warn-on-reflection* true) 20 | 21 | ;; io util 22 | 23 | (defn printerrln [& msgs] 24 | (binding [*out* *err*] 25 | (apply println msgs))) 26 | 27 | (defn- capture 28 | "Reads from input-stream until EOF and returns a String (or nil if 0 length)." 29 | [^Stream input-stream] ;;; ^InputStream 30 | (let [writer (StringWriter.)] 31 | (cio/copy input-stream writer) ;;; jio/copy 32 | (let [s (str/trim (.ToString writer))] ;;; .toString 33 | (when-not (zero? (.Length s)) ;;; .length 34 | s)))) 35 | 36 | (defmacro background 37 | [& body] 38 | `(let [result# (promise)] 39 | (doto (Thread. ^ThreadStart (gen-delegate ThreadStart [] (deliver result# (do ~@body)))) ;;; (fn [] (deliver result# (do ~@body))) 40 | (.set_IsBackground true) ;;; .setDaemon 41 | (.Start)) ;;; .start 42 | result#)) 43 | 44 | (defn- run-git 45 | [& args] 46 | (let [{:gitlibs/keys [command debug terminal]} @config/CONFIG 47 | command-args (cons command args)] 48 | (when debug 49 | (apply printerrln command-args)) 50 | (let [proc-builder 51 | (doto (ProcessStartInfo. ^String command ^String (clojure.string/join " " args)) ;;; (ProcessBuilder. ^java.util.List command-args) 52 | (.set_RedirectStandardError true) 53 | (.set_RedirectStandardOutput true)) 54 | ;;; (.redirectError proc-builder ProcessBuilder$Redirect/INHERIT) 55 | ;;; ;;; _ (when-not terminal (.put (.environment proc-builder) "GIT_TERMINAL_PROMPT" "0")) 56 | proc (Process/Start proc-builder) ;;; (.start proc-builder) 57 | out (background (capture (.StandardOutput proc))) ;;; .getInputStream 58 | err (background (capture (.StandardError proc))) ;; if debug is true, stderr will be redirected instead .getErrorStream 59 | exit (do (.WaitForExit proc) (.ExitCode proc))] ;;; .waitFor -- but .WaitForExit returns void, so we have to add the ExitCode call 60 | {:args command-args, :exit exit, :out @out, :err @err}))) 61 | 62 | ;; dirs 63 | 64 | (defn lib-dir 65 | ^DirectoryInfo [lib] ;;; ^File 66 | (cio/dir-info (:gitlibs/dir @config/CONFIG) "libs" (namespace lib) (name lib))) ;;; jio/file 67 | 68 | (def ^:private git-url-regex 69 | #"([a-z0-9+.-]+):\/\/(?:(?:(?:[^@]+?)@)?([^/]+?)(?::[0-9]*)?)?(/[^:]+)") 70 | 71 | (def ^:private git-scp-regex 72 | #"(?:(?:[^@]+?)@)?(.+?):([^:]+)") 73 | 74 | (defn- clean-url 75 | "Convert url into a safe relative path (this is not a reversible transformation) 76 | based on scheme, host, and path (drop user and port). 77 | 78 | Examples: 79 | ssh://git@gitlab.com:3333/org/repo.git => ssh/gitlab.com/org/repo 80 | git@github.com:dotted.org/dotted.repo.git => ssh/github.com/dotted.org/dotted.repo 81 | file://../foo => file/REL/_DOTDOT_/foo 82 | file:///Users/user/foo.git => file/Users/user/foo 83 | ../foo => file/REL/_DOTDOT_/foo 84 | ~user/foo.git => file/REL/_TILDE_user/foo 85 | 86 | * https://git-scm.com/docs/git-clone#_git_urls 87 | * https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols 88 | " 89 | [url] 90 | (let [[scheme host path] (cond 91 | (str/starts-with? url "file://") ["file" nil (-> url (subs 7) (str/replace #"^([^/])" "REL/$1"))] 92 | (str/includes? url "://") (let [[_ s h p] (re-matches git-url-regex url)] [s h p]) 93 | (str/includes? url ":") (let [[_ h p] (re-matches git-scp-regex url)] ["ssh" h p]) 94 | :local-repo ["file" nil (str/replace url #"^([^/])" "REL/$1")]) 95 | clean-path (-> path 96 | (str/replace #"\.git/?$" "") ;; remove trailing .git or .git/ 97 | (str/replace #"~" "_TILDE_")) ;; replace ~ with _TILDE_ 98 | dir-parts (->> (concat [scheme host] (str/split clean-path #"/")) ;; split on / 99 | (remove str/blank?) ;; remove any missing path segments 100 | (map #(-> % ({"." "_DOT_", ".." "_DOTDOT_"} %))))] ;; replace . or .. segments 101 | (str/join "/" dir-parts))) 102 | 103 | (defn git-dir 104 | ^DirectoryInfo [url] ;;; ^File 105 | (cio/dir-info (:gitlibs/dir @config/CONFIG) "_repos" (clean-url url))) ;;; jio/file 106 | 107 | (defn git-try-fetch 108 | "Try to fetch and return the error code (0=success)" 109 | [^FileInfo git-dir] ;;; ^File 110 | (let [git-path (.FullName git-dir) ;;; .getCanonicalPath 111 | ;; NOTE: --prune-tags would be desirable here but was added in git 2.17.0 112 | {:keys [exit]} (run-git "--git-dir" git-path 113 | "fetch" "--quiet" "--all" "--tags" "--prune")] 114 | exit)) 115 | 116 | (defn git-fetch 117 | [^DirectoryInfo git-dir] ;;; ^File 118 | (let [git-path (.FullName git-dir) ;;; .getCanonicalPath 119 | ;; NOTE: --prune-tags would be desirable here but was added in git 2.17.0 120 | {:keys [exit err] :as ret} (run-git "--git-dir" git-path 121 | "fetch" "--quiet" "--all" "--tags" "--prune")] 122 | (when-not (zero? exit) 123 | (throw (ex-info (format "Unable to fetch %s%n%s" git-path err) ret))))) 124 | 125 | ;; TODO: restrict clone to an optional refspec? 126 | (defn git-clone-bare 127 | [url ^DirectoryInfo git-dir] ;;; ^File 128 | (printerrln "Cloning:" url) 129 | (let [git-path (.FullName git-dir) ;;; .getCanonicalPath 130 | {:keys [exit err] :as ret} (run-git "clone" "--quiet" "--mirror" url git-path)] 131 | (when-not (zero? exit) 132 | (throw (ex-info (format "Unable to clone %s%n%s" git-path err) ret))) 133 | git-dir)) 134 | 135 | (defn ensure-git-dir 136 | "Ensure the bare git dir for the specified url, return the path to the git dir." 137 | [url] 138 | (let [git-dir-file (git-dir url) 139 | config-file (cio/file-info git-dir-file "config")] ;;; jio/file 140 | (when-not (.Exists config-file) ;;; .exists 141 | (git-clone-bare url git-dir-file)) 142 | (.FullName git-dir-file))) ;;; .getCanonicalPath 143 | 144 | (defn git-checkout 145 | [git-dir-path ^DirectoryInfo lib-dir ^String rev] ;;; ^File 146 | (let [rev-file (cio/file-info lib-dir rev)] ;;; jio/file 147 | (when-not (.Exists rev-file) ;;; .exists 148 | (let [{:keys [exit err] :as ret} 149 | (run-git "--git-dir" git-dir-path 150 | "worktree" "add" "--force" "--detach" 151 | (.FullName rev-file) rev)] ;;; .getCanonicalPath 152 | (when-not (zero? exit) 153 | (throw (ex-info (format "Unable to checkout %s%n%s" rev err) ret))))))) 154 | 155 | (defn git-rev-parse 156 | [git-dir rev] 157 | (let [{:keys [exit out]} (run-git "--git-dir" git-dir "rev-parse" (str rev "^{commit}"))] 158 | (when (zero? exit) 159 | (str/trimr out)))) 160 | 161 | (defn git-type 162 | [git-dir rev] 163 | (let [{:keys [exit out]} (run-git "--git-dir" git-dir "cat-file" "-t" rev)] 164 | (when (zero? exit) 165 | (keyword (str/trimr out))))) 166 | 167 | ;; git merge-base --is-ancestor 168 | (defn- ancestor? 169 | [git-dir x y] 170 | (let [{:keys [exit err] :as ret} (run-git "--git-dir" git-dir "merge-base" "--is-ancestor" x y)] 171 | (condp = exit 172 | 0 true 173 | 1 false 174 | (throw (ex-info (format "Unable to compare commits %s%n%s" git-dir err) ret))))) 175 | 176 | (defn commit-comparator 177 | [git-dir x y] 178 | (cond 179 | (= x y) 0 180 | (ancestor? git-dir x y) 1 181 | (ancestor? git-dir y x) -1 182 | :else (throw (ex-info "" {})))) 183 | 184 | (defn match-exact 185 | "In dir, match file in dir with exact, nil if doesn't exist" 186 | [^DirectoryInfo dir exact] ;;; ^File 187 | (when (.Exists (cio/file-info dir exact)) ;;; .exists jio/file 188 | exact)) 189 | 190 | (defn match-prefix 191 | "In dir, match file in dir with prefix, nil if not found, exception if more than one." 192 | [^DirectoryInfo dir prefix] ;;; ^File 193 | (when (.Exists dir) ;;; .exists 194 | (if (.Exists (cio/file-info dir prefix)) ;;; .exists jio/file 195 | prefix 196 | (let [matches (.GetFiles dir (str name "*"))] ;;; (.listFiles dir 197 | ;;; (reify FilenameFilter 198 | ;;; (accept [_this _dir name] 199 | ;;; (str/starts-with? name prefix))))] 200 | (case (alength matches) ;;; alength 201 | 0 nil 202 | 1 (.Name ^FileInfo (first matches)) ;;; (.getName ^File (aget matches 0)) 203 | (throw (IOException. (str "Prefix not unique: " prefix)))))))) 204 | 205 | (defn tags 206 | "Fetch, then return all tags in the git dir." 207 | [git-dir] 208 | (git-try-fetch (cio/as-dir git-dir)) ;;; jio/file 209 | (let [{:keys [exit out err] :as ret} (run-git "--git-dir" git-dir "tag" "--sort=v:refname")] 210 | (when-not (zero? exit) 211 | (throw (ex-info (format "Unable to get tags %s%n%s" git-dir err) ret))) 212 | (remove str/blank? (str/split-lines out)))) -------------------------------------------------------------------------------- /epl-v10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Eclipse Public License - Version 1.0 8 | 25 | 26 | 27 | 28 | 29 | 30 |

Eclipse Public License - v 1.0

31 | 32 |

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 33 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR 34 | DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS 35 | AGREEMENT.

36 | 37 |

1. DEFINITIONS

38 | 39 |

"Contribution" means:

40 | 41 |

a) in the case of the initial Contributor, the initial 42 | code and documentation distributed under this Agreement, and

43 |

b) in the case of each subsequent Contributor:

44 |

i) changes to the Program, and

45 |

ii) additions to the Program;

46 |

where such changes and/or additions to the Program 47 | originate from and are distributed by that particular Contributor. A 48 | Contribution 'originates' from a Contributor if it was added to the 49 | Program by such Contributor itself or anyone acting on such 50 | Contributor's behalf. Contributions do not include additions to the 51 | Program which: (i) are separate modules of software distributed in 52 | conjunction with the Program under their own license agreement, and (ii) 53 | are not derivative works of the Program.

54 | 55 |

"Contributor" means any person or entity that distributes 56 | the Program.

57 | 58 |

"Licensed Patents" mean patent claims licensable by a 59 | Contributor which are necessarily infringed by the use or sale of its 60 | Contribution alone or when combined with the Program.

61 | 62 |

"Program" means the Contributions distributed in accordance 63 | with this Agreement.

64 | 65 |

"Recipient" means anyone who receives the Program under 66 | this Agreement, including all Contributors.

67 | 68 |

2. GRANT OF RIGHTS

69 | 70 |

a) Subject to the terms of this Agreement, each 71 | Contributor hereby grants Recipient a non-exclusive, worldwide, 72 | royalty-free copyright license to reproduce, prepare derivative works 73 | of, publicly display, publicly perform, distribute and sublicense the 74 | Contribution of such Contributor, if any, and such derivative works, in 75 | source code and object code form.

76 | 77 |

b) Subject to the terms of this Agreement, each 78 | Contributor hereby grants Recipient a non-exclusive, worldwide, 79 | royalty-free patent license under Licensed Patents to make, use, sell, 80 | offer to sell, import and otherwise transfer the Contribution of such 81 | Contributor, if any, in source code and object code form. This patent 82 | license shall apply to the combination of the Contribution and the 83 | Program if, at the time the Contribution is added by the Contributor, 84 | such addition of the Contribution causes such combination to be covered 85 | by the Licensed Patents. The patent license shall not apply to any other 86 | combinations which include the Contribution. No hardware per se is 87 | licensed hereunder.

88 | 89 |

c) Recipient understands that although each Contributor 90 | grants the licenses to its Contributions set forth herein, no assurances 91 | are provided by any Contributor that the Program does not infringe the 92 | patent or other intellectual property rights of any other entity. Each 93 | Contributor disclaims any liability to Recipient for claims brought by 94 | any other entity based on infringement of intellectual property rights 95 | or otherwise. As a condition to exercising the rights and licenses 96 | granted hereunder, each Recipient hereby assumes sole responsibility to 97 | secure any other intellectual property rights needed, if any. For 98 | example, if a third party patent license is required to allow Recipient 99 | to distribute the Program, it is Recipient's responsibility to acquire 100 | that license before distributing the Program.

101 | 102 |

d) Each Contributor represents that to its knowledge it 103 | has sufficient copyright rights in its Contribution, if any, to grant 104 | the copyright license set forth in this Agreement.

105 | 106 |

3. REQUIREMENTS

107 | 108 |

A Contributor may choose to distribute the Program in object code 109 | form under its own license agreement, provided that:

110 | 111 |

a) it complies with the terms and conditions of this 112 | Agreement; and

113 | 114 |

b) its license agreement:

115 | 116 |

i) effectively disclaims on behalf of all Contributors 117 | all warranties and conditions, express and implied, including warranties 118 | or conditions of title and non-infringement, and implied warranties or 119 | conditions of merchantability and fitness for a particular purpose;

120 | 121 |

ii) effectively excludes on behalf of all Contributors 122 | all liability for damages, including direct, indirect, special, 123 | incidental and consequential damages, such as lost profits;

124 | 125 |

iii) states that any provisions which differ from this 126 | Agreement are offered by that Contributor alone and not by any other 127 | party; and

128 | 129 |

iv) states that source code for the Program is available 130 | from such Contributor, and informs licensees how to obtain it in a 131 | reasonable manner on or through a medium customarily used for software 132 | exchange.

133 | 134 |

When the Program is made available in source code form:

135 | 136 |

a) it must be made available under this Agreement; and

137 | 138 |

b) a copy of this Agreement must be included with each 139 | copy of the Program.

140 | 141 |

Contributors may not remove or alter any copyright notices contained 142 | within the Program.

143 | 144 |

Each Contributor must identify itself as the originator of its 145 | Contribution, if any, in a manner that reasonably allows subsequent 146 | Recipients to identify the originator of the Contribution.

147 | 148 |

4. COMMERCIAL DISTRIBUTION

149 | 150 |

Commercial distributors of software may accept certain 151 | responsibilities with respect to end users, business partners and the 152 | like. While this license is intended to facilitate the commercial use of 153 | the Program, the Contributor who includes the Program in a commercial 154 | product offering should do so in a manner which does not create 155 | potential liability for other Contributors. Therefore, if a Contributor 156 | includes the Program in a commercial product offering, such Contributor 157 | ("Commercial Contributor") hereby agrees to defend and 158 | indemnify every other Contributor ("Indemnified Contributor") 159 | against any losses, damages and costs (collectively "Losses") 160 | arising from claims, lawsuits and other legal actions brought by a third 161 | party against the Indemnified Contributor to the extent caused by the 162 | acts or omissions of such Commercial Contributor in connection with its 163 | distribution of the Program in a commercial product offering. The 164 | obligations in this section do not apply to any claims or Losses 165 | relating to any actual or alleged intellectual property infringement. In 166 | order to qualify, an Indemnified Contributor must: a) promptly notify 167 | the Commercial Contributor in writing of such claim, and b) allow the 168 | Commercial Contributor to control, and cooperate with the Commercial 169 | Contributor in, the defense and any related settlement negotiations. The 170 | Indemnified Contributor may participate in any such claim at its own 171 | expense.

172 | 173 |

For example, a Contributor might include the Program in a commercial 174 | product offering, Product X. That Contributor is then a Commercial 175 | Contributor. If that Commercial Contributor then makes performance 176 | claims, or offers warranties related to Product X, those performance 177 | claims and warranties are such Commercial Contributor's responsibility 178 | alone. Under this section, the Commercial Contributor would have to 179 | defend claims against the other Contributors related to those 180 | performance claims and warranties, and if a court requires any other 181 | Contributor to pay any damages as a result, the Commercial Contributor 182 | must pay those damages.

183 | 184 |

5. NO WARRANTY

185 | 186 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS 187 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 188 | OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 189 | ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY 190 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely 191 | responsible for determining the appropriateness of using and 192 | distributing the Program and assumes all risks associated with its 193 | exercise of rights under this Agreement , including but not limited to 194 | the risks and costs of program errors, compliance with applicable laws, 195 | damage to or loss of data, programs or equipment, and unavailability or 196 | interruption of operations.

197 | 198 |

6. DISCLAIMER OF LIABILITY

199 | 200 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT 201 | NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, 202 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING 203 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF 204 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 205 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR 206 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 207 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

208 | 209 |

7. GENERAL

210 | 211 |

If any provision of this Agreement is invalid or unenforceable under 212 | applicable law, it shall not affect the validity or enforceability of 213 | the remainder of the terms of this Agreement, and without further action 214 | by the parties hereto, such provision shall be reformed to the minimum 215 | extent necessary to make such provision valid and enforceable.

216 | 217 |

If Recipient institutes patent litigation against any entity 218 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 219 | Program itself (excluding combinations of the Program with other 220 | software or hardware) infringes such Recipient's patent(s), then such 221 | Recipient's rights granted under Section 2(b) shall terminate as of the 222 | date such litigation is filed.

223 | 224 |

All Recipient's rights under this Agreement shall terminate if it 225 | fails to comply with any of the material terms or conditions of this 226 | Agreement and does not cure such failure in a reasonable period of time 227 | after becoming aware of such noncompliance. If all Recipient's rights 228 | under this Agreement terminate, Recipient agrees to cease use and 229 | distribution of the Program as soon as reasonably practicable. However, 230 | Recipient's obligations under this Agreement and any licenses granted by 231 | Recipient relating to the Program shall continue and survive.

232 | 233 |

Everyone is permitted to copy and distribute copies of this 234 | Agreement, but in order to avoid inconsistency the Agreement is 235 | copyrighted and may only be modified in the following manner. The 236 | Agreement Steward reserves the right to publish new versions (including 237 | revisions) of this Agreement from time to time. No one other than the 238 | Agreement Steward has the right to modify this Agreement. The Eclipse 239 | Foundation is the initial Agreement Steward. The Eclipse Foundation may 240 | assign the responsibility to serve as the Agreement Steward to a 241 | suitable separate entity. Each new version of the Agreement will be 242 | given a distinguishing version number. The Program (including 243 | Contributions) may always be distributed subject to the version of the 244 | Agreement under which it was received. In addition, after a new version 245 | of the Agreement is published, Contributor may elect to distribute the 246 | Program (including its Contributions) under the new version. Except as 247 | expressly stated in Sections 2(a) and 2(b) above, Recipient receives no 248 | rights or licenses to the intellectual property of any Contributor under 249 | this Agreement, whether expressly, by implication, estoppel or 250 | otherwise. All rights in the Program not expressly granted under this 251 | Agreement are reserved.

252 | 253 |

This Agreement is governed by the laws of the State of New York and 254 | the intellectual property laws of the United States of America. No party 255 | to this Agreement will bring a legal action under this Agreement more 256 | than one year after the cause of action arose. Each party waives its 257 | rights to a jury trial in any resulting litigation.

258 | 259 | 260 | 261 | 262 | -------------------------------------------------------------------------------- /src/dotnet/Cljr/clojure/tools/cli/api.cljc: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.tools.deps.cli.api 10 | "This api provides functions that can be executed from the Clojure tools using -X:deps." 11 | (:refer-clojure :exclude [list]) 12 | (:require 13 | [clojure.edn :as edn] 14 | #?(:clj [clojure.java.io :as jio] 15 | :cljr [clojure.clr.io :as cio]) 16 | [clojure.pprint :as pprint] 17 | [clojure.string :as str] 18 | [clojure.tools.deps :as deps] 19 | [clojure.tools.deps.tool :as tool] 20 | [clojure.tools.deps.tree :as tree] 21 | [clojure.tools.deps.script.resolve-tags :as resolve-tags] 22 | [clojure.tools.deps.extensions :as ext] 23 | #?(:clj [clojure.tools.deps.extensions.pom :as pom]) 24 | [clojure.tools.deps.extensions.local :as local] 25 | #?(:clj [clojure.tools.deps.gen.pom :as gen-pom]) 26 | #?(:clj [clojure.tools.deps.util.maven :as mvn]) 27 | [clojure.tools.deps.util.io :as io :refer [printerrln]] 28 | [clojure.set :as set]) 29 | (:import 30 | #?(:clj [java.io File FileNotFoundException IOException]) 31 | #?(:clj [java.nio.file Files]) 32 | #?(:clj [java.nio.file.attribute FileAttribute]) 33 | #?(:clj [java.util.jar JarFile]) 34 | #?(:clj [org.apache.maven.model Model]) 35 | #?(:clj [org.eclipse.aether.artifact DefaultArtifact]) 36 | #?(:clj [org.eclipse.aether.installation InstallRequest]) 37 | [clojure.lang IExceptionInfo])) 38 | 39 | (set! *warn-on-reflection* true) 40 | 41 | (defn prep 42 | "Prep the unprepped libs found in the transitive lib set of basis. 43 | 44 | This program accepts the same basis-modifying arguments from the `basis` program. 45 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 46 | Sources are merged in the order - :root, :user, :project, :extra. 47 | 48 | Options: 49 | :force - flag on whether to force prepped libs to re-prep (default = false) 50 | :current - flag on whether to prep current project too (default = false) 51 | :log - :none, :info (default), or :debug 52 | 53 | Basis options: 54 | :root - dep source, default = :standard 55 | :user - dep source, default = :standard 56 | :project - dep source, default = :standard (\"./deps.edn\") 57 | :extra - dep source, default = nil 58 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 59 | 60 | Returns params used." 61 | [{:keys [force log current] :or {log :info, current false} :as params}] 62 | (let [basis (deps/create-basis params) 63 | opts {:action (if force :force :prep) 64 | :log log 65 | :current current}] 66 | (deps/prep-libs! (:libs basis) opts basis) 67 | params)) 68 | 69 | (comment 70 | (do 71 | (prep 72 | {:root {:mvn/repos mvn/standard-repos, :deps nil} 73 | :project {:deps '{org.clojure/clojure {:mvn/version "1.10.3"} 74 | io.github.puredanger/cool-lib 75 | {:git/sha "657d5ce88be340ab2a6c0befeae998366105be84"}}} 76 | :log :debug 77 | :force true}) 78 | nil) 79 | ) 80 | 81 | (defn tree 82 | "Print deps tree for the current project's deps.edn built from either the 83 | a basis, or if provided, the trace file. 84 | 85 | This program accepts the same basis-modifying arguments from the `basis` program. 86 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 87 | Sources are merged in the order - :root, :user, :project, :extra. 88 | 89 | By default, :format will :print to the console in a human friendly tree. Use 90 | :edn mode to print the tree to edn. 91 | 92 | In print mode, deps are printed with prefix of either . (included) or X (excluded). 93 | A reason code for inclusion/exclusion may be added at the end of the line. 94 | 95 | Basis options: 96 | :root - dep source, default = :standard 97 | :user - dep source, default = :standard 98 | :project - dep source, default = :standard (\"./deps.edn\") 99 | :extra - dep source, default = nil 100 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 101 | 102 | Input options (if provided, basis options ignored): 103 | :file Path to trace.edn file (from clj -Strace) to use in computing the tree 104 | 105 | Output mode: 106 | :format :print (default) or :edn 107 | 108 | Print output mode modifiers: 109 | :indent Indent spacing (default = 2) 110 | :hide-libs Set of libs to hide as deps (if not top dep), default = #{org.clojure/clojure}" 111 | [opts] 112 | (try 113 | (let [{:keys [file format] :or {format :print}} opts 114 | trace (if file 115 | (io/slurp-edn file) 116 | (tree/calc-trace opts)) 117 | tree (tree/trace->tree trace)] 118 | (case format 119 | :print (tree/print-tree tree opts) 120 | :edn (pprint/pprint tree) 121 | (throw (ex-info (str "Unknown format " format) {})))) 122 | (catch #?(:clj Throwable :cljr Exception) t 123 | (printerrln "Error generating tree:" (#?(:clj .getMessage :cljr .Message) t)) 124 | (when-not (instance? IExceptionInfo t) 125 | #?(:clj (.printStackTrace t) 126 | :cljr (System.Console/WriteLine (.StackTrace t)))) 127 | (#?(:clj System/exit :cljr Environment/Exit) 1)))) 128 | 129 | (comment 130 | (tree nil) 131 | (tree {:extra {:aliases {:foo {:extra-deps {'criterium/criterium {:mvn/version "0.4.0"}}}}} 132 | :aliases [:foo]}) 133 | ) 134 | 135 | (def ^:private cli-alias-keys 136 | #{:deps :replace-deps :extra-deps :override-deps :default-deps 137 | :paths :replace-paths :extra-paths :classpath-overrides 138 | :exec-fn :exec-args :ns-default :ns-aliases 139 | :main-opts :jvm-opts}) 140 | 141 | (defn aliases 142 | "List all aliases available for use with the CLI using -M, -X or -T execution 143 | (note that some aliases may be usable with more than one of these). Also, the 144 | deps.edn sources of the alias are specified. 145 | 146 | This program accepts the same basis-modifying arguments from the `basis` program. 147 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 148 | Sources are merged in the order - :root, :user, :project, :extra. 149 | 150 | For example, to print only aliases defined in this project: 151 | clj -X:deps aliases :root nil :user nil 152 | 153 | Basis options: 154 | :root - dep source, default = :standard 155 | :user - dep source, default = :standard 156 | :project - dep source, default = :standard (\"./deps.edn\") 157 | :extra - dep source, default = nil 158 | 159 | The aliases are printed to the console." 160 | [params] 161 | (let [edn-srcs (deps/create-edn-maps params) 162 | src-aliases (reduce-kv #(assoc %1 %2 (:aliases %3)) {} edn-srcs) 163 | cli-aliases (reduce-kv 164 | (fn [m src aliases] 165 | (assoc m 166 | src 167 | (reduce-kv 168 | (fn [a alias alias-defn] 169 | (cond-> a 170 | (pos? (count (set/intersection cli-alias-keys (set (keys alias-defn))))) 171 | (assoc alias alias-defn))) 172 | {} aliases))) 173 | {} src-aliases) 174 | all-aliases (->> cli-aliases (map val) (mapcat #(-> % keys sort)) distinct)] 175 | (doseq [alias all-aliases] 176 | (let [srcs (reduce-kv (fn [srcs src deps-edn] 177 | (if (contains? (:aliases deps-edn) alias) 178 | (conj srcs src) 179 | srcs)) 180 | [] edn-srcs)] 181 | (println alias (str "(" (str/join ", " (map name srcs)) ")")))))) 182 | 183 | #?( 184 | :clj 185 | (def ^:private license-abbrev 186 | (delay 187 | (-> "clojure/tools/deps/license-abbrev.edn" jio/resource slurp edn/read-string))) 188 | 189 | :cljr 190 | (def ^:private license-abbrev 191 | (delay 192 | (letfn [(find-file [x] (clojure.lang.RT/FindFile x))] 193 | (-> "clojure/tools/deps/license-abbrev.edn" find-file slurp edn/read-string)))) 194 | ) 195 | 196 | (defn- license-string 197 | [info license-mode] 198 | (let [abbrevs @license-abbrev 199 | license-name (when (#{:full :short} license-mode) (:name info))] 200 | (if (and license-name (= license-mode :short)) 201 | (get abbrevs license-name license-name) 202 | license-name))) 203 | 204 | (defn list 205 | "List all deps on the classpath, optimized for knowing the final set of included 206 | libs. The `tree` program can provide more info on why or why not a particular 207 | lib is included. 208 | 209 | Licenses will be printed in short form by default but can also be listed as 210 | in :full or :none for none at all using the :license key. 211 | 212 | By default, :format will :print to the console in a human friendly tree. Use 213 | :edn mode to print the tree to edn. 214 | 215 | This program accepts the same basis-modifying arguments from the `basis` program. 216 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 217 | Sources are merged in the order - :root, :user, :project, :extra. 218 | 219 | Options: 220 | :license - :full, :short (default), :none 221 | 222 | Output mode options: 223 | :format :print (default) or :edn 224 | 225 | Basis options: 226 | :root - dep source, default = :standard 227 | :user - dep source, default = :standard 228 | :project - dep source, default = :standard (\"./deps.edn\") 229 | :extra - dep source, default = nil 230 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 231 | 232 | The libs are printed to the console." 233 | [params] 234 | (let [{license-mode :license, format :format 235 | :or {license-mode :short, format :print}} params 236 | basis (deps/create-basis params) 237 | libs (:libs basis) 238 | data (into (sorted-map) 239 | (map (fn [lib] 240 | (let [coord (get libs lib) 241 | info (ext/license-info lib coord basis)] 242 | [lib (cond-> coord info (assoc :license info))])) 243 | (-> libs keys sort)))] 244 | (if (= format :edn) 245 | (binding [*print-namespace-maps* false] 246 | (pprint/pprint data)) 247 | (doseq [[lib coord] data] 248 | (let [summary (ext/coord-summary lib coord) 249 | info (:license coord) 250 | license-string (license-string info license-mode)] 251 | (println summary (if license-string (str " (" license-string ")") ""))))))) 252 | 253 | (comment 254 | (list nil) 255 | @license-abbrev 256 | ) 257 | 258 | ;;;; git resolve-tags 259 | 260 | (defn git-resolve-tags 261 | "Resolve git tags in deps.edn git deps to full shas." 262 | [_] 263 | (resolve-tags/exec {:deps-file "deps.edn"})) 264 | 265 | ;;;; Generate pom 266 | 267 | #?( 268 | :clj 269 | (defn mvn-pom 270 | "Sync or create pom.xml from deps.edn. 271 | 272 | This program accepts the same basis-modifying arguments from the `basis` program. 273 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 274 | Sources are merged in the order - :root, :user, :project, :extra. 275 | 276 | Basis options: 277 | :root - dep source, default = :standard 278 | :user - dep source, default = :standard 279 | :project - dep source, default = :standard (\"./deps.edn\") 280 | :extra - dep source, default = nil 281 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 282 | 283 | Deprecated options (use the basis :aliases above instead): 284 | :argmaps - vector of aliases to combine into argmaps to resolve-deps and make-classpath" 285 | [{:keys [argmaps] :as opts}] 286 | (try 287 | (let [opts' (if argmaps (assoc opts :aliases (vec (concat argmaps (:aliases opts)))) opts) 288 | basis (deps/create-basis opts') 289 | ;; treat all transitive deps as top-level deps 290 | updated-deps (reduce-kv (fn [m lib {:keys [dependents] :as coord}] 291 | (if (seq dependents) m (assoc m lib coord))) 292 | {} (:libs basis))] 293 | (gen-pom/sync-pom (merge basis {:deps updated-deps}) (jio/file "."))) 294 | (catch Throwable t 295 | (printerrln "Error generating pom manifest:" (.getMessage t)) 296 | (when-not (instance? IExceptionInfo t) 297 | (.printStackTrace t)) 298 | (System/exit 1)))) 299 | ) 300 | 301 | ;;;; Install jar into local repository 302 | #?( 303 | :clj 304 | (defn- read-pom-file 305 | [pom] 306 | (let [pom-file (jio/file pom)] 307 | (if (.exists pom-file) 308 | (let [^Model model (pom/read-model-file pom-file (deps/root-deps))] 309 | {:group-id (.getGroupId model) 310 | :artifact-id (.getArtifactId model) 311 | :version (.getVersion model) 312 | :pom-file pom}) 313 | (throw (FileNotFoundException. (str "Pom file not found: " (str pom))))))) 314 | ) 315 | 316 | #?( 317 | :clj 318 | (defn- gen-pom-file 319 | [lib version classifier] 320 | (let [group-id (namespace lib) 321 | artifact-id (name lib) 322 | temp-dir (.toString (Files/createTempDirectory "pom" (make-array FileAttribute 0))) 323 | pom-file (str temp-dir "/pom.xml")] 324 | (gen-pom/sync-pom {:params {:target-dir temp-dir 325 | :src-pom pom-file 326 | :lib lib 327 | :version version}}) 328 | {:group-id group-id 329 | :artifact-id artifact-id 330 | :version version 331 | :classifier classifier 332 | :pom-file pom-file})) 333 | ) 334 | 335 | #?( 336 | :clj 337 | (defn- read-pom-in-jar 338 | [jar-name] 339 | (let [jar-file (jio/file jar-name)] 340 | (when (or (nil? jar-name) (not (.exists jar-file))) 341 | (throw (FileNotFoundException. (str "Jar file not found: " jar-name)))) 342 | (let [jar (JarFile. jar-file)] 343 | (if-let [path (local/find-pom jar)] 344 | (let [entry (.getJarEntry jar path) 345 | jis (.getInputStream jar entry) 346 | tmp (File/createTempFile "pom" ".xml")] 347 | (jio/copy jis tmp) 348 | (read-pom-file tmp)) 349 | (throw (IOException. (str "Jar file does not contain pom: " jar-name))))))) 350 | ) 351 | 352 | #?( 353 | :clj 354 | (defn- output-path 355 | [local-repo group-id artifact-id version] 356 | (let [path-parts (concat 357 | [(or local-repo @mvn/cached-local-repo)] 358 | (str/split group-id #"\.") 359 | [artifact-id version])] 360 | (.getAbsolutePath ^File (apply jio/file path-parts)))) 361 | ) 362 | 363 | #?( 364 | :clj 365 | 366 | (defn mvn-install 367 | "Install a jar and pom to the Maven local cache. 368 | The pom file must either be supplied, or generated based 369 | on provided lib/version/classifier, or provided inside the jar. 370 | The group/artifact/version coordinate will be pulled from the 371 | pom source as above. 372 | 373 | Required: 374 | :jar (reqired) - path to jar file (embedded pom used by default) 375 | 376 | Explicit pom options: 377 | :pom - path to pom file (pom in jar ignored) 378 | 379 | Generated pom options: 380 | :lib - qualified symbol like my.org/lib 381 | :version - string 382 | :classifier - string 383 | 384 | Other options: 385 | :local-repo (optional) - path to local repo (default = ~/.m2/repository) 386 | 387 | Execute ad-hoc: 388 | clj -X:deps mvn/install :jar '\"foo-1.2.3.jar\"'" 389 | [{:keys [jar pom lib version classifier local-repo]}] 390 | (println "Installing" jar (if pom (str "and " pom) "")) 391 | (let [{:keys [pom-file group-id artifact-id version classifier]} 392 | (cond 393 | pom (read-pom-file pom) 394 | lib (gen-pom-file lib version classifier) 395 | :else (read-pom-in-jar jar)) 396 | jar-file (jio/file jar) 397 | pom-file (jio/file pom-file) 398 | system (mvn/make-system) 399 | settings (mvn/get-settings) 400 | session (mvn/make-session system settings (or local-repo @mvn/cached-local-repo)) 401 | artifacts [(.setFile (DefaultArtifact. group-id artifact-id classifier "jar" version) jar-file) 402 | (.setFile (DefaultArtifact. group-id artifact-id classifier "pom" version) pom-file)] 403 | install-request (.setArtifacts (InstallRequest.) artifacts)] 404 | (.install system session install-request) 405 | (println "Installed to" (output-path local-repo group-id artifact-id version)))) 406 | ) 407 | 408 | (defn find-versions 409 | "Find available tool versions given either a lib (with :lib) or 410 | existing installed tool (with :tool). If lib, check all registered 411 | procurers and print one coordinate per line when found. 412 | 413 | Options: 414 | :lib Qualified lib symbol 415 | :tool Tool name for installed tool 416 | :n Number of coordinates to return, default = 8, :all for all" 417 | [{:keys [lib tool n] :or {n 8} :as args}] 418 | (let [{:keys [root-edn user-edn]} (deps/find-edn-maps) 419 | master-edn (deps/merge-edns [root-edn user-edn]) 420 | trunc-fn (fn [n x] 421 | (if (= n :all) 422 | x 423 | (mapcat #(take-last n %) (vals (group-by keys x))))) 424 | coords (cond 425 | tool 426 | (if-let [{:keys [lib coord]} (tool/resolve-tool (name tool))] 427 | (ext/find-versions lib coord (ext/coord-type coord) master-edn) 428 | (throw (ex-info (str "Unknown tool: " tool) {:tool tool}))) 429 | 430 | lib 431 | (ext/find-all-versions lib {} master-edn) 432 | 433 | :else 434 | (throw (ex-info "Either :lib or :tool must be provided to find versions" (or args {}))))] 435 | (run! #(binding [*print-namespace-maps* false] (prn %)) (trunc-fn n coords)))) 436 | 437 | (comment 438 | (find-versions '{:lib org.clojure/tools.gitlibs :n 4}) 439 | (find-versions '{:lib io.github.clojure/tools.gitlibs :n 10}) 440 | (find-versions '{:tool tools :n 3}) 441 | (find-versions nil) 442 | ) --------------------------------------------------------------------------------