diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f70d2..d1d9493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changes -* 0.4.next in progress +* v0.4.3 -- 2021-11-28 + * Address #17 by adding `:only` option to copy just named files. * Update `build-clj` to v0.5.5 and `tools.build` to v0.6.8. * v0.4.2 1ec7e62 -- 2021-11-13 diff --git a/README.md b/README.md index 7d2f201..17d6528 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A new, simpler alternative to `clj-new`. Intended to be installed as a "tool" (Clojure CLI 1.10.3.933 or later). ```bash -clojure -Ttools install io.github.seancorfield/deps-new '{:git/tag "v0.4.2"}' :as new +clojure -Ttools install io.github.seancorfield/deps-new '{:git/tag "v0.4.3"}' :as new ``` > `clj-new` inherently carries along all of the baggage of `lein new` and `boot new`, including a modified chunk of Leiningen itself, as well as depending on Pomegranate for loading dependencies (so as to be compatible with Leiningen and Boot), and Stencil for the variable substitution in templates. The recently-released `tools.build` library, from the core Clojure team, provides all of the functionality needed to create new projects from templates, so `deps-new` aims to provide a wrapper around `tools.build`, some standard templates "out of the box", and machinery to allow you to easily write your own templates, mostly with no code needed at all. diff --git a/doc/templates.md b/doc/templates.md index 12db007..4ed5f09 100644 --- a/doc/templates.md +++ b/doc/templates.md @@ -63,6 +63,29 @@ and `test/main_test.clj` will be copied to `/test/com/acme/cool_lib_test Any files in `src` (or `test`) that are not specifically listed in the hash map will be copied as-is. +## Copying Files (Only) + +As seen above, by default the entire folder is copied, with specified files renamed. +Sometimes it is convenient to copy only specified files from a folder and ignore the +other files in that folder. You can specify `:only` as the last element of the +transformation tuple: + +```clojure +;; template.edn +{:transform + [["src" "src/{{top/file}}" + {"main.clj" "{{main/file}}.clj"}] + ["test" "test/{{top/file}}" + {"main_test.clj" "{{main/file}}_test.clj"} + :only]]} +``` + +In this example, `src/main.clj` will be copied to `/src/com/acme/cool_lib.clj` +and `test/main_test.clj` will be copied to `/test/com/acme/cool_lib_test.clj`. +Any files in `src` that are not specifically listed in the hash map will +be copied as-is. Because of the `:only` option, no other files in `test` will be +copied -- just the specified ones (`main_test.clj` in this case). + ## Alternative Delimiters As indicated above, patterns like `{{opt}}` are replaced by the value of the `:opt` option @@ -93,13 +116,14 @@ are templates themselves that will later have substitutions applied to them. By default, `deps-new` passes a `:replace` option to the `copy-dir` of `tools.build` in order to perform the substitutions of `{{opt}}`. That function skips some common -image types (`jpg`, `jpeg`, `png`, `gif`, and `bmp` as of v0.6.1) but treats all other +image types (`jpg`, `jpeg`, `png`, `gif`, and `bmp` as of `tools.build` v0.6.1) +but treats all other as text and attempts to perform textual replacements -- so some binary files will not be copied correctly. In addition, you may want to copy some files as if they were templates and not have substitution performed. You can suppress substitution for a specified directory of files in a template, -such as `"templates"`, by adding `:raw` as the last element of the `:transform` tuple +such as `"templates"`, by adding `:raw` as the last element of the transformation tuple for that directory: ```clojure @@ -114,6 +138,8 @@ will be performed on them but files in `templates` will be copied to the specifi target as raw files -- with no substitutions (and therefore safely treated as binary files, if appropriate). +> Note: you can specify both `:raw` and `:only` as the last elements of the transformation tuple, if needed, and they can be in either order, but they must be after the delimiter string pair if that is also specified. + ## Programmatic Transformation Sometimes you might need more than just a declarative approach and simple string diff --git a/resources/org/corfield/new/template/root/README.md b/resources/org/corfield/new/template/root/README.md index c526d41..ad714b9 100644 --- a/resources/org/corfield/new/template/root/README.md +++ b/resources/org/corfield/new/template/root/README.md @@ -14,7 +14,7 @@ As originally generated, it will produce a new library project when run: Assuming you have installed `deps-new` as your `new` "tool" via: ```bash -clojure -Ttools install io.github.seancorfield/deps-new '{:git/tag "v0.4.2"}' :as new +clojure -Ttools install io.github.seancorfield/deps-new '{:git/tag "v0.4.3"}' :as new ``` > Note: once the template has been published (to a public git repo), the invocation will be the same, except the `:local/root` dependency will be replaced by a git or Maven-like coordinate. diff --git a/test/org/corfield/new/impl_test.clj b/test/org/corfield/new/impl_test.clj index 2ad7394..155642a 100644 --- a/test/org/corfield/new/impl_test.clj +++ b/test/org/corfield/new/impl_test.clj @@ -1,9 +1,11 @@ ;; copyright (c) 2021 sean corfield, all rights reserved (ns org.corfield.new.impl-test - (:require [expectations.clojure.test + (:require [clojure.string :as str] + [clojure.tools.build.api :as b] + [expectations.clojure.test :refer [defexpect expect expecting from-each - more more-> more-of]] + more more-> more-of side-effects]] [org.corfield.new.impl :as sut])) (defexpect test->ns @@ -46,6 +48,41 @@ ;; #'sut/substitute ;; sut/copy-template-dir + +(defexpect test-copy-template-dir + (expect (more-of [[folder-copy] [{:keys [src target]}] [{:keys [replace src-dirs target-dir]}]] + ;; step 1: copy dir with no replace, to temporary folder: + nil? (:replace folder-copy) + ["/tmp/x"] (:src-dirs folder-copy) + #"/y$" (:target-dir folder-copy) + ;; step 2: copy only file a to temporary structure: + "/tmp/x/a" src + #"/y/b$" target + true? (str/starts-with? target (:target-dir folder-copy)) + ;; step 3: copy dir with no replace, from temporary folder to target: + nil? replace + vector? src-dirs + true? (str/starts-with? (:target-dir folder-copy) (first src-dirs)) + "/tmp/y" target-dir) + (side-effects [b/copy-dir b/copy-file] + (sut/copy-template-dir "/tmp" "/tmp/y" + {:src "x" :target "y" :files {"a" "b"} :opts [:raw]} + {"q" "r"}))) + (expect (more-of [[{:keys [src target]}] + [{:keys [replace src-dirs target-dir]}]] + ;; step 1: copy only file a to temporary structure: + "/tmp/x/a" src + #"/y/b$" target + ;; step 2: copy dir with replace, from temporary folder to target: + {"q" "r"} replace + vector? src-dirs + true? (str/starts-with? target (first src-dirs)) + "/tmp/y" target-dir) + (side-effects [b/copy-dir b/copy-file] + (sut/copy-template-dir "/tmp" "/tmp/y" + {:src "x" :target "y" :files {"a" "b"} :opts [:only]} + {"q" "r"})))) + ;; #'sut/deconstruct-project-name (defexpect test-preprocess-options