├── version.properties ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── boot ├── base │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ └── boot │ │ │ │ │ └── base │ │ │ │ │ └── version.properties │ │ │ └── java │ │ │ │ └── boot │ │ │ │ └── AddableClassLoader.java │ │ └── test │ │ │ └── java │ │ │ └── boot │ │ │ └── AppTest.java │ └── pom.in.xml ├── core │ ├── resources │ │ └── boot-logo-3.png │ ├── build.boot │ ├── project.clj │ ├── src │ │ └── boot │ │ │ ├── git.clj │ │ │ ├── tmpregistry.clj │ │ │ ├── task_helpers │ │ │ └── notify.clj │ │ │ └── task_helpers.clj │ └── test │ │ └── boot │ │ ├── test_test.clj │ │ └── task │ │ └── built_in_test.clj ├── worker │ ├── src │ │ └── boot │ │ │ ├── notify │ │ │ ├── system_failure.mp3 │ │ │ ├── system_success.mp3 │ │ │ ├── system_warning.mp3 │ │ │ ├── ordinance_failure.mp3 │ │ │ ├── ordinance_success.mp3 │ │ │ ├── ordinance_warning.mp3 │ │ │ ├── pillsbury_failure.mp3 │ │ │ ├── pillsbury_success.mp3 │ │ │ ├── pillsbury_warning.mp3 │ │ │ ├── woodblock_failure.mp3 │ │ │ ├── woodblock_success.mp3 │ │ │ └── woodblock_warning.mp3 │ │ │ ├── repl_client.clj │ │ │ ├── namespace.clj │ │ │ ├── notify.clj │ │ │ ├── web.clj │ │ │ ├── jgit.clj │ │ │ ├── xml.clj │ │ │ ├── watcher.clj │ │ │ └── pom.clj │ ├── third_party │ │ ├── barbarywatchservice │ │ │ ├── src │ │ │ │ └── com │ │ │ │ │ └── barbarysoftware │ │ │ │ │ ├── jna │ │ │ │ │ ├── CFArrayRef.java │ │ │ │ │ ├── CFRunLoopRef.java │ │ │ │ │ ├── CFAllocatorRef.java │ │ │ │ │ ├── FSEventStreamRef.java │ │ │ │ │ ├── CFIndex.java │ │ │ │ │ ├── CFStringRef.java │ │ │ │ │ └── CarbonAPI.java │ │ │ │ │ └── watchservice │ │ │ │ │ ├── WatchableFile.java │ │ │ │ │ ├── ClosedWatchServiceException.java │ │ │ │ │ ├── MacOSXWatchKey.java │ │ │ │ │ ├── ProviderMismatchException.java │ │ │ │ │ ├── Demo.java │ │ │ │ │ ├── WatchService.java │ │ │ │ │ ├── StandardWatchEventKind.java │ │ │ │ │ ├── WatchEvent.java │ │ │ │ │ ├── AbstractWatchService.java │ │ │ │ │ ├── Watchable.java │ │ │ │ │ ├── AbstractWatchKey.java │ │ │ │ │ └── WatchKey.java │ │ │ └── test │ │ │ │ └── com │ │ │ │ └── barbarysoftware │ │ │ │ └── watchservice │ │ │ │ └── WatchServiceTest.java │ │ └── README │ ├── build.boot │ ├── project.clj │ └── test │ │ └── boot │ │ └── pom_test.clj ├── aether │ ├── test │ │ └── boot │ │ │ └── aether_test.clj │ ├── project.clj │ └── src │ │ └── boot │ │ └── ssl.clj ├── pod │ ├── src │ │ └── boot │ │ │ ├── filesystem │ │ │ └── patch.clj │ │ │ ├── from │ │ │ ├── io │ │ │ │ └── aviso │ │ │ │ │ ├── clipboard.clj │ │ │ │ │ ├── writer.clj │ │ │ │ │ ├── ansi.clj │ │ │ │ │ └── repl.clj │ │ │ ├── digest.clj │ │ │ ├── backtick.clj │ │ │ ├── table │ │ │ │ └── width.clj │ │ │ └── me │ │ │ │ └── raynes │ │ │ │ └── conch.clj │ │ │ ├── kahnsort.clj │ │ │ ├── pedantic.clj │ │ │ ├── repl.clj │ │ │ ├── repl_server.clj │ │ │ ├── jar.clj │ │ │ ├── tools │ │ │ └── deps.clj_ │ │ │ ├── pod │ │ │ └── deps.clj_ │ │ │ ├── gpg.clj │ │ │ └── xform.clj │ ├── project.clj │ └── test │ │ └── boot │ │ ├── file_test.clj │ │ ├── pod_test.clj │ │ ├── tmpdir_test.clj │ │ └── util_test.clj └── boot │ └── project.clj ├── doc └── README.md ├── .travis.yml ├── appveyor.yml ├── ISSUE_TEMPLATE.md ├── .gitignore ├── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── Makefile └── mkdocs /version.properties: -------------------------------------------------------------------------------- 1 | version=2.8.3 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: boot-clj 2 | -------------------------------------------------------------------------------- /boot/base/src/main/resources/boot/base/version.properties: -------------------------------------------------------------------------------- 1 | version=${pom.version} -------------------------------------------------------------------------------- /boot/core/resources/boot-logo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/core/resources/boot-logo-3.png -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/system_failure.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/system_failure.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/system_success.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/system_success.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/system_warning.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/system_warning.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/ordinance_failure.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/ordinance_failure.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/ordinance_success.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/ordinance_success.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/ordinance_warning.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/ordinance_warning.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/pillsbury_failure.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/pillsbury_failure.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/pillsbury_success.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/pillsbury_success.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/pillsbury_warning.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/pillsbury_warning.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/woodblock_failure.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/woodblock_failure.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/woodblock_success.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/woodblock_success.mp3 -------------------------------------------------------------------------------- /boot/worker/src/boot/notify/woodblock_warning.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boot-clj/boot/HEAD/boot/worker/src/boot/notify/woodblock_warning.mp3 -------------------------------------------------------------------------------- /boot/aether/test/boot/aether_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.aether-test 2 | (:require [clojure.test :refer :all] 3 | [boot.aether :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/CFArrayRef.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.ptr.PointerByReference; 4 | 5 | public class CFArrayRef extends PointerByReference { 6 | 7 | } -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/CFRunLoopRef.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.ptr.PointerByReference; 4 | 5 | public class CFRunLoopRef extends PointerByReference { 6 | 7 | } -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/CFAllocatorRef.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.ptr.PointerByReference; 4 | 5 | public class CFAllocatorRef extends PointerByReference { 6 | 7 | } -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/FSEventStreamRef.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.ptr.PointerByReference; 4 | 5 | public class FSEventStreamRef extends PointerByReference { 6 | 7 | } -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Boot API 2 | 3 | These namespaces are available in all pods: 4 | 5 | * [`boot.pod`](boot.pod.md) 6 | * [`boot.util`](boot.util.md) 7 | 8 | These namespaces are only available in the core pod: 9 | 10 | * [`boot.core`](boot.core.md) 11 | * [`boot.task.built-in`](boot.task.built-in.md) 12 | -------------------------------------------------------------------------------- /boot/pod/src/boot/filesystem/patch.clj: -------------------------------------------------------------------------------- 1 | (ns boot.filesystem.patch) 2 | 3 | (defmulti patch (fn [before after link] (type (or before after)))) 4 | (defmethod patch :default [_ _ _] nil) 5 | 6 | (defmulti patch-result (fn [before after] (type (or before after)))) 7 | (defmethod patch-result :default [_ after] after) 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: java 3 | jdk: 4 | - oraclejdk8 5 | - oraclejdk9 6 | - openjdk10 7 | - openjdk11 8 | - openjdk12 9 | - openjdk13 10 | 11 | install: make deps 12 | script: make test 13 | 14 | cache: 15 | directories: 16 | - $HOME/.m2 17 | - $HOME/.boot/cache 18 | - $HOME/bin 19 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/CFIndex.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.NativeLong; 4 | 5 | public class CFIndex extends NativeLong { 6 | private static final long serialVersionUID = 0; 7 | 8 | public static CFIndex valueOf(int i) { 9 | CFIndex idx = new CFIndex(); 10 | idx.setValue(i); 11 | return idx; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /boot/worker/src/boot/repl_client.clj: -------------------------------------------------------------------------------- 1 | (ns boot.repl-client 2 | (:require 3 | [reply.main :as reply])) 4 | 5 | (def default-opts {:color true :history-file ".nrepl-history"}) 6 | 7 | (defn client [opts] 8 | (let [p (or (:port opts) (try (slurp ".nrepl-port") (catch Throwable _))) 9 | h (or (:host opts) "127.0.0.1") 10 | o (assoc (merge default-opts opts) :attach (str h ":" p))] 11 | (assert (and h p) "host and/or port not specified for REPL client") 12 | (reply/launch-nrepl o))) 13 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/CFStringRef.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.ptr.PointerByReference; 4 | 5 | public class CFStringRef extends PointerByReference { 6 | 7 | public static CFStringRef toCFString(String s) { 8 | final char[] chars = s.toCharArray(); 9 | int length = chars.length; 10 | return CarbonAPI.INSTANCE.CFStringCreateWithCharacters(null, chars, CFIndex.valueOf(length)); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /boot/base/src/main/java/boot/AddableClassLoader.java: -------------------------------------------------------------------------------- 1 | package boot; 2 | 3 | import java.net.URL; 4 | import java.net.URLClassLoader; 5 | 6 | // Allows us to have a modifiable ClassLoader without having to call 7 | // .setAccessible on URLClassLoader.addURL(), since that's not allowed 8 | // by default under Java 9 9 | public class AddableClassLoader extends URLClassLoader { 10 | public AddableClassLoader(URL[] urls, ClassLoader parent) { 11 | super(urls, parent); } 12 | 13 | public void addURL(URL url) { 14 | super.addURL(url); }} 15 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | cache: 3 | - C:\Users\appveyor\.m2 4 | - C:\Users\appveyor\bin 5 | - C:\Users\appveyor\.lein\self-installs 6 | init: 7 | - cmd: 8 | install: 9 | - cmd: >- 10 | set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin\;%PATH% 11 | 12 | set MSYSTEM=MINGW64 13 | 14 | set MSYS=winsymlinks=lnk 15 | build_script: 16 | - cmd: >- 17 | set PATH=%APPVEYOR_BUILD_FOLDER%\bin;%PATH% 18 | 19 | bash -lc "cd $APPVEYOR_BUILD_FOLDER; make deps" 20 | test_script: 21 | - cmd: >- 22 | bash -lc "cd $APPVEYOR_BUILD_FOLDER; make test" 23 | deploy: off 24 | -------------------------------------------------------------------------------- /boot/worker/src/boot/namespace.clj: -------------------------------------------------------------------------------- 1 | (ns boot.namespace 2 | (:require 3 | [clojure.java.io :as io] 4 | [clojure.tools.namespace.track :as tntrack] 5 | [clojure.tools.namespace.file :as tnfile] 6 | [clojure.tools.namespace.find :as tnfind])) 7 | 8 | (defn dependents [src-dirs] 9 | (->> src-dirs 10 | (map io/file) 11 | (mapcat file-seq) 12 | (filter #(and (.isFile %) (.endsWith (.getName %) ".clj"))) 13 | (tnfile/add-files (tntrack/tracker)) 14 | ::tntrack/deps 15 | :dependents)) 16 | 17 | (defn find-namespaces-in-dirs [dirs] 18 | (mapcat #(tnfind/find-namespaces-in-dir (io/file %)) dirs)) 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /boot/boot/project.clj: -------------------------------------------------------------------------------- 1 | (import [java.util Properties]) 2 | (require '[clojure.java.io :as io]) 3 | (def propsfile "../../version.properties") 4 | (def version (-> (doto (Properties.) (.load (io/input-stream propsfile))) 5 | (.getProperty "version"))) 6 | 7 | (defproject boot version 8 | :description "Placeholder to synchronize other boot module versions." 9 | :url "https://github.com/boot-clj/boot" 10 | :scm {:url "https://github.com/boot-clj/boot.git" :dir "../../"} 11 | :repositories [["clojars" {:url "https://clojars.org/repo" :creds :gpg :sign-releases false}]] 12 | :license {:name "Eclipse Public License" 13 | :url "http://www.eclipse.org/legal/epl-v10.html"}) 14 | 15 | -------------------------------------------------------------------------------- /boot/base/src/test/java/boot/AppTest.java: -------------------------------------------------------------------------------- 1 | package boot; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /boot/worker/third_party/README: -------------------------------------------------------------------------------- 1 | barbarywatchservice 2 | -------------------------------------------------------------------------------- 3 | URL: http://barbarywatchservice.googlecode.com/svn/trunk/ 4 | Version: r12 5 | Local modifications: 6 | - Delete pre-built binaries in lib/ and bin/ 7 | - Delete .idea directory 8 | - Delete WatchService.iml 9 | - Add a LICENSE file for the LGPL, which is the distribution license according 10 | to the Google Code page 11 | - Remove support for the polling watch service, since the java.nio.file package 12 | works fine for this, and we don't want to make sure the polling and listening 13 | watch service behave equivalently with our changes. 14 | - Do not find modified files recursively, and do not include the root directory 15 | in the list of modified files. This more closely matches how java.nio.file 16 | works. 17 | -------------------------------------------------------------------------------- /boot/core/build.boot: -------------------------------------------------------------------------------- 1 | (set-env! 2 | :source-paths #{"src" "test"} 3 | :dependencies '[[org.clojure/tools.reader "1.3.2" :exclusions [org.clojure/clojure]] 4 | [metosin/bat-test "0.4.2" :scope "test"]]) 5 | 6 | (ns-unmap 'boot.user 'test) 7 | 8 | (require '[boot.test :refer [runtests test-report test-exit]] 9 | '[metosin.bat-test :refer [bat-test]] 10 | 'boot.task.built-in-test 11 | 'boot.test-test) 12 | 13 | (import boot.App) 14 | 15 | (deftask integration-test [] 16 | (comp 17 | (runtests) 18 | (test-report) 19 | (test-exit))) 20 | 21 | (deftask unit-test [] 22 | (bat-test :test-matcher #"boot\.cli-test")) 23 | 24 | (deftask test [] 25 | (comp 26 | (with-pass-thru [fs] 27 | (boot.util/info "Testing against version %s\n" (App/config "BOOT_VERSION"))) 28 | (unit-test) 29 | (integration-test))) 30 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | If you are reporting a bug, please fill in the template below and label the 2 | issue with `bug` and any other relevant labels. If you wish to contribute an 3 | idea for a feature or improvement, please read the contribution guidelines 4 | linked in the yellow box above before submitting. Thank you! 👍 5 | 6 | ### Problem Description 7 | 8 | > If your problem includes an exception, please provide a stactrace. A full, unfiltered 9 | > stacktrace can be obtained by running boot with the `-vv` option (verbosity lvl2). 10 | 11 | ### Steps to reproduce 12 | 13 | ### Platform details 14 | 15 | Platform (macOS, Linux, Windows): 16 | Platform version: 17 | JRE/JDK version (`java -version`): 18 | 19 | ### Boot details 20 | 21 | Boot version (2.7.1): 22 | `build.boot` present? (yes/no): 23 | `~/.boot/profile` present? (yes/no): 24 | Task name? (if applicable): 25 | 26 | Please also provide the contents of `build.boot` and `~/.boot/profile` (if applicable). 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /boot/core/project.clj: -------------------------------------------------------------------------------- 1 | (import [java.util Properties]) 2 | (require '[clojure.java.io :as io]) 3 | (def propsfile "../../version.properties") 4 | (def version (-> (doto (Properties.) (.load (io/input-stream propsfile))) 5 | (.getProperty "version"))) 6 | 7 | (defproject boot/core version 8 | :jar-exclusions [#"^clojure/core/"] 9 | :description "Core boot module–boot scripts run in this pod." 10 | :url "https://github.com/boot-clj/boot" 11 | :scm {:url "https://github.com/boot-clj/boot.git" :dir "../../"} 12 | :repositories [["clojars" {:url "https://clojars.org/repo" :creds :gpg :sign-releases false}]] 13 | :license {:name "Eclipse Public License" 14 | :url "http://www.eclipse.org/legal/epl-v10.html"} 15 | :plugins [[lein-ancient "0.6.15"]] 16 | :dependencies [[org.clojure/clojure "1.6.0" :scope "provided"] 17 | [boot/base ~version :scope "provided"] 18 | [boot/pod ~version :scope "compile"]]) 19 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/io/aviso/clipboard.clj: -------------------------------------------------------------------------------- 1 | (ns boot.from.io.aviso.clipboard 2 | "Utilities for accessing text on the system clipboard using AWT. 3 | 4 | This is segregated from other code to prevent the AWT stack from initializaing 5 | unnecessarily. On OS X, this is seen as a Java application icon appearing in the Dock" 6 | {:boot/from :AvisoNovate/pretty:0.1.34} 7 | (:import 8 | [java.awt.datatransfer Clipboard DataFlavor StringSelection] 9 | [java.awt Toolkit])) 10 | 11 | (defn ^:private ^Clipboard clipboard 12 | "Returns the current clipboard." 13 | [] 14 | (.getSystemClipboard (Toolkit/getDefaultToolkit))) 15 | 16 | (defn ^String copy 17 | "Copies the current contents of the Clipboard, returning its contents as a string." 18 | [] 19 | (-> (clipboard) 20 | (.getContents nil) 21 | (.getTransferData DataFlavor/stringFlavor))) 22 | 23 | (defn paste 24 | "Pastes a string in as the new content of the Clipboard." 25 | [^String s] 26 | (.setContents (clipboard) (StringSelection. s) nil)) 27 | -------------------------------------------------------------------------------- /boot/core/src/boot/git.clj: -------------------------------------------------------------------------------- 1 | (ns boot.git 2 | (:require 3 | [boot.pod :as pod] 4 | [boot.util :as util])) 5 | 6 | (defn status [] (pod/with-call-worker (boot.jgit/status))) 7 | (defn clean? [] (pod/with-call-worker (boot.jgit/clean?))) 8 | (defn dirty? [] (not (clean?))) 9 | (defn last-commit [] (pod/with-call-worker (boot.jgit/last-commit))) 10 | (defn branch-current [] (pod/with-call-worker (boot.jgit/branch-current))) 11 | (defn describe [] (pod/with-call-worker (boot.jgit/describe))) 12 | 13 | (defn ls-files 14 | [& {:keys [ref untracked]}] 15 | (pod/with-call-worker 16 | (boot.jgit/ls-files :ref ~ref :untracked ~untracked))) 17 | 18 | (defn ls-tags 19 | [] 20 | (pod/with-call-worker 21 | (boot.jgit/ls-tags))) 22 | 23 | (defn tag 24 | [name message] 25 | (pod/with-call-worker 26 | (boot.jgit/tag ~name ~message))) 27 | 28 | (defn make-gitignore-matcher 29 | [] 30 | (let [fs (util/guard (ls-files :untracked true))] 31 | (if-not fs (constantly false) #(not (contains? fs (.getPath %)))))) 32 | -------------------------------------------------------------------------------- /boot/aether/project.clj: -------------------------------------------------------------------------------- 1 | (import [java.util Properties]) 2 | (require '[clojure.java.io :as io]) 3 | (def propsfile "../../version.properties") 4 | (def version (-> (doto (Properties.) (.load (io/input-stream propsfile))) 5 | (.getProperty "version"))) 6 | 7 | (defproject boot/aether version 8 | :jar-exclusions [#"^clojure/core/"] 9 | :description "Boot aether module–performs maven dependency resolution." 10 | :url "https://github.com/boot-clj/boot" 11 | :scm {:url "https://github.com/boot-clj/boot.git" :dir "../../"} 12 | :repositories [["clojars" {:url "https://clojars.org/repo" :creds :gpg :sign-releases false}]] 13 | :license {:name "Eclipse Public License" 14 | :url "http://www.eclipse.org/legal/epl-v10.html"} 15 | :plugins [[lein-ancient "0.6.15"]] 16 | :dependencies [[org.clojure/clojure "1.6.0" :scope "compile"] 17 | [boot/base ~version :scope "provided"] 18 | [boot/pod ~version :scope "compile"] 19 | [com.cemerick/pomegranate "1.1.0" :scope "compile"]]) 20 | -------------------------------------------------------------------------------- /boot/worker/build.boot: -------------------------------------------------------------------------------- 1 | (set-env! 2 | :source-paths #{"src" "test"} 3 | :dependencies '[[net.cgrand/parsley "0.9.3" :exclusions [org.clojure/clojure]] 4 | [mvxcvi/puget "1.1.1"] 5 | [reply "0.4.3"] 6 | [cheshire "5.8.1"] 7 | [clj-jgit "0.8.10"] 8 | [clj-yaml "0.4.0"] 9 | [javazoom/jlayer "1.0.1"] 10 | [net.java.dev.jna/jna "5.7.0"] 11 | [alandipert/desiderata "1.0.2"] 12 | [org.clojure/data.xml "0.0.8"] 13 | [org.clojure/data.zip "0.1.2"] 14 | [org.clojure/tools.namespace "0.2.11"] 15 | 16 | [metosin/bat-test "0.4.2" :scope "test"]]) 17 | 18 | (ns-unmap 'boot.user 'test) 19 | 20 | (require '[metosin.bat-test :refer [bat-test]]) 21 | 22 | (import boot.App) 23 | 24 | (deftask test [] 25 | (comp 26 | (with-pass-thru [fs] 27 | (boot.util/info "Testing against version %s\n" (App/config "BOOT_VERSION"))) 28 | (bat-test))) 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### BOOT ####################################################################### 2 | 3 | /.boot/ 4 | 5 | ### LEININGEN ################################################################## 6 | 7 | .lein-* 8 | 9 | ### MAKE ####################################################################### 10 | 11 | .deployed 12 | .installed 13 | .tested 14 | 15 | ### MAVEN (include pom.xml in /base) ########################################### 16 | 17 | *.jar 18 | *.war 19 | pom.xml 20 | pom.xml.asc 21 | 22 | ### NREPL ###################################################################### 23 | 24 | .repl-* 25 | .nrepl-* 26 | 27 | ### JAVA ####################################################################### 28 | 29 | /hs_err_pid*.log 30 | 31 | ### OSX ######################################################################## 32 | 33 | .DS_Store 34 | 35 | ### EMACS ###################################################################### 36 | 37 | [#]*[#] 38 | 39 | ### VIM ######################################################################## 40 | 41 | *.swn 42 | *.swo 43 | *.swp 44 | 45 | ### PROJECT #################################################################### 46 | 47 | /bin/ 48 | /boot/*/target/ 49 | /zzz/ 50 | /launch4j-config.xml 51 | /launch4j/ 52 | -------------------------------------------------------------------------------- /boot/pod/project.clj: -------------------------------------------------------------------------------- 1 | (import [java.util Properties]) 2 | (require '[clojure.java.io :as io]) 3 | (def propsfile "../../version.properties") 4 | (def version (-> (doto (Properties.) (.load (io/input-stream propsfile))) 5 | (.getProperty "version"))) 6 | 7 | (defproject boot/pod version 8 | :aot [#"^(?!boot\.repl-server).*$"] 9 | :jar-exclusions [#"^clojure/core/"] 10 | :description "Boot pod module–this is included with all pods." 11 | :url "https://github.com/boot-clj/boot" 12 | :scm {:url "https://github.com/boot-clj/boot.git" :dir "../../"} 13 | :repositories [["clojars" {:url "https://clojars.org/repo" :creds :gpg :sign-releases false}] 14 | ["sonatype" {:url "https://oss.sonatype.org/content/repositories/releases"}] 15 | ["sonatype-snaps" {:url "https://oss.sonatype.org/content/repositories/snapshots"}]] 16 | :license {:name "Eclipse Public License" 17 | :url "http://www.eclipse.org/legal/epl-v10.html"} 18 | :plugins [[lein-ancient "0.6.15"]] 19 | :dependencies [[boot/base ~version :scope "provided"] 20 | [org.clojure/clojure "1.6.0" :scope "provided"] 21 | [org.tcrawley/dynapath "1.0.0" :scope "compile"] 22 | [org.projectodd.shimdandy/shimdandy-impl "1.2.1" :scope "compile"]]) 23 | -------------------------------------------------------------------------------- /boot/pod/src/boot/kahnsort.clj: -------------------------------------------------------------------------------- 1 | (ns boot.kahnsort 2 | (:require 3 | [clojure.set :refer [difference union intersection]])) 4 | 5 | (defn choose 6 | "Returns the pair [element, s'] where s' is set s with element removed." 7 | [s] {:pre [(not (empty? s))]} 8 | (let [item (first s)] 9 | [item (disj s item)])) 10 | 11 | (defn no-incoming 12 | "Returns the set of nodes in graph g for which there are no incoming 13 | edges, where g is a map of nodes to sets of nodes." 14 | [g] 15 | (let [nodes (set (keys g)) 16 | have-incoming (apply union (vals g))] 17 | (difference nodes have-incoming))) 18 | 19 | (defn normalize 20 | "Returns g with empty outgoing edges added for nodes with incoming 21 | edges only. Example: {:a #{:b}} => {:a #{:b}, :b #{}}" 22 | [g] 23 | (let [have-incoming (apply union (vals g))] 24 | (reduce #(if (% %2) % (assoc % %2 #{})) g have-incoming))) 25 | 26 | (defn topo-sort 27 | "Proposes a topological sort for directed graph g using Kahn's 28 | algorithm, where g is a map of nodes to sets of nodes. If g is 29 | cyclic, returns nil." 30 | ([g] 31 | (topo-sort (normalize g) [] (no-incoming g))) 32 | ([g l s] 33 | (if (empty? s) 34 | (if (every? empty? (vals g)) l) 35 | (let [[n s'] (choose s) 36 | m (g n) 37 | g' (reduce #(update-in % [n] disj %2) g m)] 38 | (recur g' (conj l n) (union s' (intersection (no-incoming g') m))))))) 39 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Motivation and Context 7 | 8 | 9 | 10 | ## How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | ## Screenshots (if appropriate): 16 | 17 | ## Types of changes 18 | 19 | - [ ] Bug fix (non-breaking change which fixes an issue) 20 | - [ ] New feature (non-breaking change which adds functionality) 21 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 22 | 23 | ## Checklist: 24 | 25 | 26 | - [ ] My code follows the code style of this project. 27 | - [ ] My change requires a change to the documentation. 28 | - [ ] I have updated the documentation accordingly. 29 | - [ ] I have read the **CONTRIBUTING** document. 30 | - [ ] I have added tests to cover my changes. 31 | - [ ] All new and existing tests passed. 32 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/test/com/barbarysoftware/watchservice/WatchServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.watchservice; 2 | 3 | import static com.barbarysoftware.watchservice.StandardWatchEventKind.*; 4 | import org.junit.Assert; 5 | 6 | import java.io.File; 7 | 8 | public class WatchServiceTest { 9 | @org.junit.Test 10 | public void testNewWatchService() throws Exception { 11 | Assert.assertNotNull(WatchService.newWatchService()); 12 | } 13 | 14 | @org.junit.Test 15 | public void testWatchingInvalidFolder() throws Exception { 16 | final WatchService watcher = WatchService.newWatchService(); 17 | WatchableFile f = new WatchableFile(new File("/thisfolderdoesntexist")); 18 | f.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 19 | } 20 | 21 | @org.junit.Test 22 | public void testNonsensePath() throws Exception { 23 | final WatchService watcher = WatchService.newWatchService(); 24 | WatchableFile f = new WatchableFile(new File("/path/to/watch")); 25 | f.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 26 | } 27 | 28 | @org.junit.Test(expected = NullPointerException.class) 29 | public void testWatchingNull() throws Exception { 30 | new WatchableFile(null); 31 | } 32 | 33 | @org.junit.Test 34 | public void testWatchingFile() throws Exception { 35 | final WatchService watcher = WatchService.newWatchService(); 36 | WatchableFile f = new WatchableFile(File.createTempFile("watcher_", null)); 37 | f.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/WatchableFile.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.watchservice; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | public class WatchableFile implements Watchable { 7 | 8 | private final File file; 9 | 10 | public WatchableFile(File file) { 11 | if (file == null) { 12 | throw new NullPointerException("file must not be null"); 13 | } 14 | this.file = file; 15 | } 16 | 17 | public File getFile() { 18 | return file; 19 | } 20 | 21 | public File toFile() { 22 | return file; 23 | } 24 | 25 | @Override 26 | public WatchKey register(WatchService watcher, 27 | WatchEvent.Kind[] events, 28 | WatchEvent.Modifier... modifiers) 29 | throws IOException { 30 | if (watcher == null) 31 | throw new NullPointerException(); 32 | if (!(watcher instanceof AbstractWatchService)) 33 | throw new ProviderMismatchException(); 34 | return ((AbstractWatchService) watcher).register(this, events, modifiers); 35 | } 36 | 37 | private static final WatchEvent.Modifier[] NO_MODIFIERS = new WatchEvent.Modifier[0]; 38 | 39 | @Override 40 | public final WatchKey register(WatchService watcher, 41 | WatchEvent.Kind... events) 42 | throws IOException { 43 | return register(watcher, events, NO_MODIFIERS); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "Path{" + 49 | "file=" + file + 50 | '}'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /boot/worker/src/boot/notify.clj: -------------------------------------------------------------------------------- 1 | (ns boot.notify 2 | (:require 3 | [clojure.java.io :as io] 4 | [boot.pod :as pod] 5 | [boot.util :as util] 6 | [clojure.java.shell :refer [sh]]) 7 | (:import 8 | (java.io File FileInputStream))) 9 | 10 | (defn path-for [theme type] 11 | (let [p (format "boot/notify/%s_%s.mp3" (or theme "system") type)] 12 | (if (io/resource p) p (path-for "system" type)))) 13 | 14 | (let [notified? (atom 0)] 15 | (defn- fg-first-time! [future] 16 | ((if (< 1 (swap! notified? inc)) identity deref) future))) 17 | 18 | (defn play! [file] 19 | (fg-first-time! 20 | (future 21 | (try 22 | (-> (or (.getResourceAsStream (clojure.lang.RT/baseLoader) file) 23 | (FileInputStream. (io/file file)) 24 | (throw (RuntimeException. (str file " not found.")))) 25 | java.io.BufferedInputStream. 26 | javazoom.jl.player.Player. 27 | .play) 28 | (catch Exception e 29 | (util/warn "\nError attempting to play sound file: %s\n\n" 30 | (.getMessage e))))))) 31 | 32 | (defn success! [theme file] (play! (or file (path-for theme "success")))) 33 | (defn failure! [theme file] (play! (or file (path-for theme "failure")))) 34 | 35 | (defn warning! [theme n file] 36 | (fg-first-time! 37 | (future 38 | (let [msg (str n "warning" (if (> n 1) "s"))] 39 | (cond 40 | (.exists (File. "/usr/bin/espeak")) 41 | (sh "espeak" "-v+f2" msg) 42 | (.exists (File. "/usr/bin/say")) 43 | (sh "say" msg) 44 | :else (play! (or file (path-for theme "warning")))))))) 45 | 46 | (defn notify! [{:keys [file theme type]}] 47 | (play! (or file (path-for theme (name type))))) 48 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/jna/CarbonAPI.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.jna; 2 | 3 | import com.sun.jna.*; 4 | 5 | public interface CarbonAPI extends Library { 6 | CarbonAPI INSTANCE = (CarbonAPI) Native.loadLibrary("Carbon", CarbonAPI.class); 7 | 8 | CFArrayRef CFArrayCreate( 9 | CFAllocatorRef allocator, // always set to Pointer.NULL 10 | Pointer[] values, 11 | CFIndex numValues, 12 | Void callBacks // always set to Pointer.NULL 13 | ); 14 | 15 | CFStringRef CFStringCreateWithCharacters( 16 | Void alloc, // always pass NULL 17 | char[] chars, 18 | CFIndex numChars 19 | ); 20 | 21 | public FSEventStreamRef FSEventStreamCreate( 22 | Pointer v, // always use Pointer.NULL 23 | FSEventStreamCallback callback, 24 | Pointer context, // always use Pointer.NULL 25 | CFArrayRef pathsToWatch, 26 | long sinceWhen, // use -1 for events since now 27 | double latency, // in seconds 28 | int flags // 0 is good for now 29 | 30 | ); 31 | 32 | boolean FSEventStreamStart(FSEventStreamRef streamRef); 33 | 34 | void FSEventStreamStop(FSEventStreamRef streamRef); 35 | 36 | void FSEventStreamScheduleWithRunLoop(FSEventStreamRef streamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode); 37 | 38 | CFRunLoopRef CFRunLoopGetCurrent(); 39 | 40 | void CFRunLoopRun(); 41 | 42 | void CFRunLoopStop(CFRunLoopRef rl); 43 | 44 | public interface FSEventStreamCallback extends Callback { 45 | @SuppressWarnings({"UnusedDeclaration"}) 46 | void invoke(FSEventStreamRef streamRef, Pointer clientCallBackInfo, NativeLong numEvents, Pointer eventPaths, Pointer eventFlags, Pointer eventIds); 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/ClosedWatchServiceException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | /** 29 | * Unchecked exception thrown when an attempt is made to invoke an operation on 30 | * a watch service that is closed. 31 | */ 32 | 33 | public class ClosedWatchServiceException 34 | extends IllegalStateException 35 | { 36 | static final long serialVersionUID = 1853336266231677732L; 37 | 38 | /** 39 | * Constructs an instance of this class. 40 | */ 41 | public ClosedWatchServiceException() { 42 | } 43 | } -------------------------------------------------------------------------------- /boot/pod/test/boot/file_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.file-test 2 | (:refer-clojure :exclude [sync file-seq]) 3 | (:require 4 | [clojure.string :as str] 5 | [clojure.test :refer :all] 6 | [boot.file :as file :refer :all :exclude [name]] 7 | [clojure.java.io :as io])) 8 | 9 | (def test-file (io/file "public/js/main.js")) 10 | (def test-dir (parent test-file)) 11 | (def abs-dir (parent (io/file "/foo/bar/main.js"))) 12 | 13 | (deftest parent-seq-test 14 | (let [f test-file] 15 | (is (= (seq [f (parent f) (parent (parent f))]) (parent-seq f))))) 16 | 17 | (deftest split-path-test 18 | (is (= (seq ["public" "js" "main.js"]) (split-path test-file)))) 19 | 20 | (deftest parent?-test 21 | (is (parent? test-dir (io/file "public/js/out/goog/base.js"))) 22 | (is (not (parent? test-dir (io/file "foo/js/public/out/goog/base.js"))))) 23 | 24 | (deftest relative-to-test 25 | (let [normalize #(if-not windows? % (str/replace % #"\\" "/"))] 26 | (testing "File inside base" 27 | (is (= "out/goog/base.js" (str (normalize (relative-to test-dir (io/file "public/js/out/goog/base.js"))))))) 28 | 29 | (testing "File not inside base" 30 | (is (= "../../cljsjs/dev/react.js" (str (normalize (relative-to test-dir (io/file "cljsjs/dev/react.js"))))))) 31 | 32 | (testing "File not inside base" 33 | (is (= "../cljsjs/dev/react.js" (str (normalize (relative-to test-dir (io/file "public/cljsjs/dev/react.js"))))))) 34 | 35 | (testing "Two absolute paths" 36 | (is (= "js/test.js" (str (normalize (relative-to abs-dir (io/file "/foo/bar/js/test.js"))))))))) 37 | 38 | (deftest match-filter?-test 39 | (let [filters #{#"^META-INF/MANIFEST.MF$"}] 40 | (testing "Valid paths" 41 | (is (match-filter? filters (io/file "META-INF" "MANIFEST.MF")))) 42 | (testing "Sanity check for failure" 43 | (is (not (match-filter? filters (io/file "META-INF" "MANIFEST.NO"))))))) 44 | -------------------------------------------------------------------------------- /boot/worker/project.clj: -------------------------------------------------------------------------------- 1 | (import [java.util Properties]) 2 | (require '[clojure.java.io :as io]) 3 | (def propsfile "../../version.properties") 4 | (def version (-> (doto (Properties.) (.load (io/input-stream propsfile))) 5 | (.getProperty "version"))) 6 | 7 | (defproject boot/worker version 8 | :jar-exclusions [#"^clojure/core/"] 9 | :description "Boot worker module–this is the worker pod for built-in tasks." 10 | :url "https://github.com/boot-clj/boot" 11 | :scm {:url "https://github.com/boot-clj/boot.git" :dir "../../"} 12 | :repositories [["clojars" {:url "https://clojars.org/repo" :creds :gpg :sign-releases false}]] 13 | :license {:name "Eclipse Public License" 14 | :url "http://www.eclipse.org/legal/epl-v10.html"} 15 | :java-source-paths ["third_party/barbarywatchservice/src"] 16 | :javac-options ["-target" "1.8" "-source" "1.8"] 17 | :plugins [[lein-ancient "0.6.15"]] 18 | :dependencies [[org.clojure/clojure "1.6.0" :scope "provided"] 19 | [boot/base ~version :scope "provided"] 20 | [boot/aether ~version] 21 | ;; Suppress warnings from SLF4J via pomegranate via aether 22 | [org.slf4j/slf4j-nop "1.7.26"] 23 | ;; see https://github.com/boot-clj/boot/issues/82 24 | [net.cgrand/parsley "0.9.3" :exclusions [org.clojure/clojure]] 25 | [mvxcvi/puget "1.1.2"] 26 | [reply "0.4.3"] 27 | [cheshire "5.8.1"] 28 | [clj-jgit "0.8.10"] 29 | [clj-yaml "0.4.0"] 30 | [javazoom/jlayer "1.0.1"] 31 | [net.java.dev.jna/jna "5.7.0"] 32 | [alandipert/desiderata "1.0.2"] 33 | [org.clojure/data.xml "0.0.8"] 34 | [org.clojure/data.zip "0.1.3"] 35 | [org.clojure/tools.namespace "0.2.11"]]) 36 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/MacOSXWatchKey.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.watchservice; 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean; 4 | 5 | public class MacOSXWatchKey extends AbstractWatchKey { 6 | private final AtomicBoolean cancelled = new AtomicBoolean(false); 7 | private final boolean reportCreateEvents; 8 | private final boolean reportModifyEvents; 9 | private final boolean reportDeleteEvents; 10 | private final WatchableFile watchableFile; 11 | 12 | public MacOSXWatchKey(AbstractWatchService macOSXWatchService, WatchEvent.Kind[] events, WatchableFile wf) { 13 | super(macOSXWatchService); 14 | boolean reportCreateEvents = false; 15 | boolean reportModifyEvents = false; 16 | boolean reportDeleteEvents = false; 17 | 18 | for (WatchEvent.Kind event : events) { 19 | if (event == StandardWatchEventKind.ENTRY_CREATE) { 20 | reportCreateEvents = true; 21 | } else if (event == StandardWatchEventKind.ENTRY_MODIFY) { 22 | reportModifyEvents = true; 23 | } else if (event == StandardWatchEventKind.ENTRY_DELETE) { 24 | reportDeleteEvents = true; 25 | } 26 | } 27 | this.reportCreateEvents = reportCreateEvents; 28 | this.reportDeleteEvents = reportDeleteEvents; 29 | this.reportModifyEvents = reportModifyEvents; 30 | this.watchableFile = wf; 31 | } 32 | 33 | @Override 34 | public boolean isValid() { 35 | return !cancelled.get() && watcher().isOpen(); 36 | } 37 | 38 | @Override 39 | public void cancel() { 40 | cancelled.set(true); 41 | } 42 | 43 | public WatchableFile watchable() { 44 | return watchableFile; 45 | } 46 | 47 | public boolean isReportCreateEvents() { 48 | return reportCreateEvents; 49 | } 50 | 51 | public boolean isReportModifyEvents() { 52 | return reportModifyEvents; 53 | } 54 | 55 | public boolean isReportDeleteEvents() { 56 | return reportDeleteEvents; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /boot/worker/src/boot/web.clj: -------------------------------------------------------------------------------- 1 | (ns boot.web 2 | (:require 3 | [clojure.java.io :as io] 4 | [clojure.data.xml :as xml] 5 | [boot.pod :as pod] 6 | [boot.util :as util])) 7 | 8 | (defn splice [xml-expr] 9 | (let [splice? #(and (seq? %) (not (vector? %)))] 10 | (if (vector? xml-expr) 11 | (let [[tag attr & kids] xml-expr] 12 | (into [tag attr] (mapcat (comp #(if (splice? %) % [%]) splice) kids))) 13 | xml-expr))) 14 | 15 | (defn params* [ctor & kvs] 16 | (for [[k v] (partition 2 kvs) :when v] 17 | [ctor {} [:param-name {} k] [:param-value {} (str v)]])) 18 | 19 | (defn web-xml [name desc serve create destroy context-create context-destroy] 20 | (-> [:web-app {:xmlns "http://java.sun.com/xml/ns/javaee" 21 | :xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance" 22 | :xsi:schemaLocation "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 23 | :version "3.0" 24 | :metadata-complete "true"} 25 | [:display-name {} name] 26 | [:description {} desc] 27 | [:servlet {} 28 | [:servlet-name {} name] 29 | [:servlet-class {} "tailrecursion.ClojureAdapterServlet"] 30 | (params* :init-param 31 | "create" create 32 | "serve" serve 33 | "destroy" destroy)] 34 | (if (or context-create context-destroy) 35 | [:listener {} 36 | [:listener-class {} "tailrecursion.ClojureAdapterServletContextListener"]]) 37 | (params* :context-param 38 | "context-create" context-create 39 | "context-destroy" context-destroy) 40 | [:servlet-mapping {} 41 | [:servlet-name {} name] 42 | [:url-pattern {} "/*"]]] 43 | splice 44 | xml/sexp-as-element 45 | xml/indent-str)) 46 | 47 | (defn spit-web! [webxmlfile serve create destroy context-create context-destroy] 48 | (let [xmlfile (io/file webxmlfile)] 49 | (spit 50 | (doto xmlfile io/make-parents) 51 | (web-xml "boot-webapp" "boot-webapp" serve create destroy context-create context-destroy)))) 52 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/ProviderMismatchException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | /** 29 | * Unchecked exception thrown when an attempt is made to invoke a method on an 30 | * object created by one file system provider with a parameter created by a 31 | * different file system provider. 32 | */ 33 | public class ProviderMismatchException 34 | extends java.lang.IllegalArgumentException 35 | { 36 | static final long serialVersionUID = 4990847485741612530L; 37 | 38 | /** 39 | * Constructs an instance of this class. 40 | */ 41 | public ProviderMismatchException() { 42 | } 43 | 44 | /** 45 | * Constructs an instance of this class. 46 | * 47 | * @param msg 48 | * the detail message 49 | */ 50 | public ProviderMismatchException(String msg) { 51 | super(msg); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /boot/pod/src/boot/pedantic.clj: -------------------------------------------------------------------------------- 1 | (ns boot.pedantic 2 | (:require 3 | [boot.pod :as pod] 4 | [clojure.set :as set] 5 | [clojure.string :as string] 6 | [boot.from.io.aviso.ansi :as ansi])) 7 | 8 | (defn safe-read-string [s] 9 | (try (read-string s) (catch Throwable _ s))) 10 | 11 | (defn sortable-version [ver] 12 | (map safe-read-string (string/split ver #"[.-]"))) 13 | 14 | (defn compare-version [a b] 15 | (let [[a b] (map sortable-version [a b]) 16 | [p q] (map count [a b]) 17 | [a b] (cond (= p q) [a b] 18 | (< p q) [(concat a (repeat nil)) b] 19 | (> p q) [a (concat b (repeat nil))])] 20 | (->> (map compare a b) 21 | (remove zero?) 22 | first 23 | ((fnil identity 0))))) 24 | 25 | (defn dep-conflicts [env] 26 | (->> (for [[id & _ :as dep] (:dependencies env)] 27 | (->> (assoc env :dependencies [dep]) 28 | pod/resolve-dependencies 29 | (map (comp (fn [[i v & _]] {:id i :ver v :via id}) :dep)))) 30 | flatten 31 | (group-by :id) 32 | (map (fn [[k v]] 33 | [k (->> (map (fn [[k' v']] [k' (map :via v')]) 34 | (group-by :ver v)) 35 | (into (sorted-map-by compare-version)))])) 36 | (filter #(< 1 (count (second %)))) 37 | (into (sorted-map)))) 38 | 39 | (defn resolved-versions [env] 40 | (->> env pod/resolve-dependencies (map #(vec (take 2 (:dep %)))) (into {}))) 41 | 42 | (defn prn-conflicts [env] 43 | (let [version (resolved-versions env) 44 | deps (->> env :dependencies (map #(vec (take 2 %))) (into {}))] 45 | (doseq [[k v] (dep-conflicts env) 46 | m (if (deps k) "\u2714" "!")] 47 | (print (ansi/bold-white (format "[%s] %s\n" m k))) 48 | (doseq [[k' v'] (reverse v) 49 | :let [v? (= k' (version k)) 50 | m (if v? "\u2714" "\u2718") 51 | c1 #((cond (= k %) ansi/bold-green 52 | v? ansi/green 53 | :else ansi/yellow) %) 54 | c2 (if v? ansi/bold-green ansi/bold-yellow)]] 55 | (print (->> (string/join "\n " (map c1 (sort v'))) 56 | (format " %s %s\n %s\n" (c2 m) (c2 k')))))))) 57 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/io/aviso/writer.clj: -------------------------------------------------------------------------------- 1 | (ns boot.from.io.aviso.writer 2 | "The StringWriter protocol is used as the target of any written output." 3 | {:boot/from :AvisoNovate/pretty:0.1.34} 4 | (:import 5 | [java.io Writer])) 6 | 7 | (defprotocol StringWriter 8 | "May receive strings, which are printed, or stored. 9 | 10 | `StringWriter` is extended onto `java.lang.Appendable`, a common interface implemented by both `PrintWriter` and `StringBuilder` (among 11 | many others)." 12 | 13 | (write-string [this string] "Writes the string to the `StringWriter`.") 14 | (flush-writer [this] "Flushes output to the `StringWriter`, where supported.")) 15 | 16 | (extend-protocol StringWriter 17 | StringBuilder 18 | (write-string [this ^CharSequence string] (.append this string)) 19 | (flush-writer [this] nil) 20 | 21 | Writer 22 | (write-string [this ^CharSequence string] (.append this string)) 23 | (flush-writer [this] (.flush this))) 24 | 25 | (def eol 26 | "End-of-line terminator, platform specific." 27 | (System/getProperty "line.separator")) 28 | 29 | (defn write 30 | "Constructs a string from the values (with no seperator) and writes the string to the StringWriter. 31 | 32 | This is used to get around the fact that protocols do not support varadic parameters." 33 | ([writer value] 34 | (write-string writer (str value))) 35 | ([writer value & values] 36 | (write writer value) 37 | (doseq [value values] 38 | (write writer value)))) 39 | 40 | (defn writeln 41 | "Constructs a string from the values (with no seperator) and writes the string to the `StringWriter`, 42 | followed by an end-of-line terminator, then flushes the writer." 43 | ([writer] 44 | (write-string writer eol) 45 | (flush-writer writer)) 46 | ([writer & values] 47 | (apply write writer values) 48 | (writeln writer))) 49 | 50 | (defn writef 51 | "Writes formatted data." 52 | [writer fmt & values] 53 | (write-string writer (apply format fmt values))) 54 | 55 | (defn into-string 56 | "Creates a `StringBuilder` and passes that as the first parameter to the function, along with the other parameters. 57 | 58 | Returns the value of the `StringBuilder` after invoking the function." 59 | [f & params] 60 | (let [sb (StringBuilder. 2000)] 61 | (apply f sb params) 62 | (.toString sb))) 63 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/Demo.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.watchservice; 2 | 3 | import static com.barbarysoftware.watchservice.StandardWatchEventKind.*; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | 8 | public class Demo { 9 | 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | 12 | final WatchService watcher = WatchService.newWatchService(); 13 | 14 | final String home = System.getProperty("user.home"); 15 | final WatchableFile file1 = new WatchableFile(new File(home + "/Downloads")); 16 | final WatchableFile file2 = new WatchableFile(new File(home + "/Documents")); 17 | 18 | file1.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 19 | file2.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 20 | 21 | final Thread consumer = new Thread(createRunnable(watcher)); 22 | consumer.start(); 23 | System.out.println("Watching for changes for 1 minute..."); 24 | Thread.sleep(6000000); 25 | consumer.interrupt(); 26 | watcher.close(); 27 | 28 | } 29 | 30 | private static Runnable createRunnable(final WatchService watcher) { 31 | return new Runnable() { 32 | public void run() { 33 | for (; ;) { 34 | 35 | // wait for key to be signaled 36 | WatchKey key; 37 | try { 38 | key = watcher.take(); 39 | } catch (InterruptedException x) { 40 | return; 41 | } 42 | for (WatchEvent event : key.pollEvents()) { 43 | WatchEvent.Kind kind = event.kind(); 44 | 45 | if (kind == OVERFLOW) { 46 | continue; 47 | } 48 | // The filename is the context of the event. 49 | @SuppressWarnings({"unchecked"}) WatchEvent ev = (WatchEvent) event; 50 | System.out.println("detected file system event: " + ev.context() + " " + kind); 51 | 52 | } 53 | 54 | // Reset the key -- this step is critical to receive further watch events. 55 | 56 | boolean valid = key.reset(); 57 | if (!valid) { 58 | break; 59 | } 60 | 61 | } 62 | } 63 | }; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /boot/pod/test/boot/pod_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.pod-test 2 | (:import [java.nio.file Files] 3 | [java.nio.file.attribute FileAttribute] 4 | [boot.tmpdir TmpDir TmpFileSet]) 5 | (:require [clojure.test :refer :all] 6 | [clojure.java.io :as io] 7 | [boot.file :as file] 8 | [boot.tmpdir :as tmp] 9 | [boot.pod :as pod])) 10 | 11 | (defn tempdir [] 12 | (.toFile (Files/createTempDirectory "tmpdir" (into-array FileAttribute [])))) 13 | 14 | (defn make-fs [] 15 | (let [dir (tempdir)] 16 | {:dir dir 17 | :fs (TmpFileSet. [(tmp/map->TmpDir {:dir dir})] {} (tempdir) {})})) 18 | 19 | (defn spit-to [dir path contents] 20 | (spit (doto (apply io/file dir path) io/make-parents) contents)) 21 | 22 | (defn map-fs-contents [fs] 23 | (let [path-list #(file/split-path (tmp/path %)) 24 | contents #(slurp (tmp/file %))] 25 | (->> fs tmp/ls (reduce #(assoc %1 (path-list %2) (contents %2)) {})))) 26 | 27 | (deftest fileset-test 28 | (testing "fileset is a fileset" 29 | (let [{:keys [dir fs]} (make-fs)] 30 | (is (tmp/tmpfileset? fs)))) 31 | 32 | (testing "initial fileset is empty" 33 | (let [{:keys [dir fs]} (make-fs)] 34 | (is (empty? (tmp/ls fs))))) 35 | 36 | (let [{:keys [dir fs]} (make-fs) 37 | src1 (doto (tempdir) 38 | (spit-to ["a"] "foo") 39 | (spit-to ["b" "c"] "bar")) 40 | src2 (doto (tempdir) 41 | (spit-to ["b" "c"] "baz")) 42 | fs (-> fs (tmp/add dir src1 {}) tmp/commit!) 43 | before {'("a") "foo" '("b" "c") "bar"} 44 | after {'("a") "foo" '("b" "c") "baz"}] 45 | 46 | (testing "fileset with files is not empty" 47 | (is (not (empty? (tmp/ls fs))))) 48 | 49 | (testing "fileset with files has correct number of them" 50 | (is (= 2 (count (tmp/ls fs))))) 51 | 52 | (testing "fileset with files has correct paths and contents" 53 | (is (= before (map-fs-contents fs)))) 54 | 55 | (testing "adding dir to fileset can clobber paths" 56 | (let [fs (-> fs (tmp/add dir src2 {}) tmp/commit!)] 57 | (is (= after (map-fs-contents fs))))) 58 | 59 | (testing "re-committing fileset restores former contents" 60 | (let [fs (-> fs tmp/commit!)] 61 | (is (= before (map-fs-contents fs))))) 62 | 63 | )) 64 | 65 | (deftest canonical 66 | (testing "boot.pod/canonical-id" 67 | (is (= 'foo (pod/canonical-id 'foo)) "In case there is no group, return artifact") 68 | (is (= 'foo (pod/canonical-id 'foo/foo)) "In case group and artifact are the same, return only one of them") 69 | (is (= 'foo/bar (pod/canonical-id 'foo/bar)) "In case group and artifact are the different, return the entire symbol"))) 70 | -------------------------------------------------------------------------------- /boot/core/test/boot/test_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.test-test 2 | (:require [boot.core :as core] 3 | [boot.test :refer :all] 4 | [clojure.test :refer :all])) 5 | 6 | (deftesttask macro-splitting-tests 7 | "Testing the splitting and recomposing algorithm of the deftesttask macro." 8 | [] 9 | (core/with-pass-thru fileset 10 | (testing "boot.test/replace-body for null-task V1" 11 | (let [null-task '(deftask null-task 12 | "Does nothing." 13 | [a a-option VAL kw "The option." 14 | c counter int "The counter."] 15 | (fn [_] _)) 16 | null-task-no-doc (remove string? null-task) 17 | expected-null-task (concat (butlast (rest null-task)) '((comp (fn [_] _)))) 18 | expected-null-task-no-doc (remove string? expected-null-task)] 19 | (is (= (rest null-task) (update-body (rest null-task) identity)) "It should rebuild the same task form, round-tripping") 20 | (is (= (rest null-task-no-doc) (update-body (rest null-task-no-doc) identity)) "Even with no docstring it should rebuild the same task form") 21 | (is (= expected-null-task (update-body (rest null-task) #(cons 'comp (list %)))) "Updating body should work, of course") 22 | (is (= expected-null-task-no-doc (update-body (rest null-task-no-doc) #(cons 'comp (list %)))) "Updating body should work, of course"))) 23 | 24 | (testing "boot.test/replace-body for null-task V2" 25 | (let [null-task '(deftask null-task 26 | "Does nothing." 27 | [a a-option VAL kw "The option." 28 | c counter int "The counter."] 29 | identity) 30 | null-task-no-doc (remove string? null-task) 31 | expected-null-task (concat (butlast (rest null-task)) '((comp identity))) 32 | expected-null-task-no-doc (remove string? expected-null-task)] 33 | (is (= (rest null-task) (update-body (rest null-task) identity)) "It should rebuild the same task form, round-tripping") 34 | (is (= (rest null-task-no-doc) (update-body (rest null-task-no-doc) identity)) "Even with no docstring it should rebuild the same task form") 35 | (is (= expected-null-task (update-body (rest null-task) #(cons 'comp (list %)))) "Updating body should work, of course") 36 | (is (= expected-null-task-no-doc (update-body (rest null-task-no-doc) #(cons 'comp (list %)))) "Updating body should work, of course"))))) 37 | 38 | (deftesttask vars 39 | "Testing the test var fetching transformation." 40 | [] 41 | (core/with-pass-thru fileset 42 | (testing "namespaces->commands" 43 | (is (every? var? (namespaces->vars test-me-pred (all-ns))) "The result should be a seq of vars") 44 | (is (empty? (namespaces->vars test-me-pred [])) "If no namespace in input return the empty sequence")))) 45 | -------------------------------------------------------------------------------- /boot/worker/src/boot/jgit.clj: -------------------------------------------------------------------------------- 1 | (ns boot.jgit 2 | (:require 3 | [clojure.set :as set] 4 | [clojure.java.io :as io] 5 | [clj-jgit.porcelain :as jgit] 6 | [boot.util :as util]) 7 | (:import 8 | [org.eclipse.jgit.api Git] 9 | [org.eclipse.jgit.treewalk TreeWalk] 10 | [org.eclipse.jgit.lib Ref Repository ObjectIdRef$PeeledNonTag ObjectIdRef$PeeledTag ObjectIdRef$Unpeeled] 11 | [org.eclipse.jgit.revwalk RevCommit RevTree RevWalk] 12 | [org.eclipse.jgit.storage.file FileRepositoryBuilder])) 13 | 14 | (def repo-dir 15 | (delay (let [repo #(and (util/guard (jgit/with-repo % repo)) %)] 16 | (loop [d (.getCanonicalFile (io/file "."))] 17 | (when d (or (repo d) (recur (.getParentFile d)))))))) 18 | 19 | (defmacro with-repo 20 | [& body] 21 | `(do (assert @repo-dir "This does not appear to be a git repo.") 22 | (jgit/with-repo @repo-dir ~@body))) 23 | 24 | (defn status 25 | [] 26 | (with-repo (jgit/git-status repo))) 27 | 28 | (defn describe 29 | [] 30 | (with-repo (.. repo describe call))) 31 | 32 | (defn branch-current 33 | [] 34 | (with-repo (jgit/git-branch-current repo))) 35 | 36 | (defn clean? 37 | [] 38 | (->> (status) vals (reduce set/union) empty?)) 39 | 40 | (defn last-commit 41 | [] 42 | (with-repo (->> (jgit/git-log repo) first .getName))) 43 | 44 | (defn ls-files 45 | [& {:keys [ref untracked]}] 46 | (with-repo 47 | (let [r (.getRepository repo) 48 | walk (RevWalk. r) 49 | head (.getRef r (or ref "HEAD")) 50 | commit (.parseCommit walk (.getObjectId head)) 51 | tree (.getTree commit) 52 | twalk (doto (TreeWalk. r) (.addTree tree) (.setRecursive true)) 53 | files (when untracked 54 | (->> (jgit/git-status repo) 55 | ((juxt :untracked :added)) 56 | (apply into))) 57 | files (let [{a :added u :untracked} (jgit/git-status repo)] 58 | (into a (when untracked u)))] 59 | (->> (loop [go? (.next twalk) files files] 60 | (if-not go? 61 | files 62 | (recur (.next twalk) (conj files (.getPathString twalk))))) 63 | (remove (comp #(or (not (.exists %)) (.isDirectory %)) io/file)) 64 | set)))) 65 | 66 | (defn ls-tags 67 | [] 68 | (with-repo 69 | (let [r (.getRepository repo)] 70 | (reduce (fn [m t] 71 | ;; PeeledNonTags are returned if working dir isn't clean 72 | (condp instance? t 73 | ObjectIdRef$PeeledTag (assoc m (subs (.getName t) 10) (.getName (.getPeeledObjectId (.peel r t)))) 74 | ObjectIdRef$Unpeeled (assoc m (subs (.getName t) 10) (.getName (.getObjectId (.peel r t)))) 75 | ObjectIdRef$PeeledNonTag m)) 76 | {} 77 | (.call (.tagList repo)))))) 78 | 79 | (defn tag 80 | [name message] 81 | (with-repo (.. repo tag (setName name) (setMessage message) call))) 82 | 83 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/digest.clj: -------------------------------------------------------------------------------- 1 | (ns boot.from.digest 2 | {:boot/from :tebeka/clj-digest 3 | :author "Miki Tebeka " 4 | :doc "Message digest algorithms for Clojure"} 5 | (:use [clojure.string :only (split lower-case)]) 6 | (:import java.util.Arrays 7 | (java.security MessageDigest Security Provider) 8 | (java.io FileInputStream File InputStream))) 9 | 10 | ; Default buffer size for reading 11 | (def ^:dynamic *buffer-size* 1024) 12 | 13 | (defn- read-some 14 | "Read some data from reader. Return [data size] if there's more to read, 15 | otherwise nil." 16 | [^InputStream reader] 17 | (let [^bytes buffer (make-array Byte/TYPE *buffer-size*) 18 | size (.read reader buffer)] 19 | (when (> size 0) 20 | (if (= size *buffer-size*) buffer (Arrays/copyOf buffer size))))) 21 | 22 | (defn- byte-seq 23 | "Return a sequence of [data size] from reader." 24 | [^InputStream reader] 25 | (take-while (complement nil?) (repeatedly (partial read-some reader)))) 26 | 27 | (defn- signature 28 | "Get signature (string) of digest." 29 | [^MessageDigest algorithm] 30 | (let [size (* 2 (.getDigestLength algorithm)) 31 | sig (.toString (BigInteger. 1 (.digest algorithm)) 16) 32 | padding (apply str (repeat (- size (count sig)) "0"))] 33 | (str padding sig))) 34 | 35 | (defprotocol Digestible 36 | (-digest [message algorithm])) 37 | 38 | (extend-protocol Digestible 39 | (class (make-array Byte/TYPE 0)) 40 | (-digest [message algorithm] 41 | (-digest [message] algorithm)) 42 | 43 | java.util.Collection 44 | ;; Code "borrowed" from 45 | ;; * http://www.holygoat.co.uk/blog/entry/2009-03-26-1 46 | ;; * http://www.rgagnon.com/javadetails/java-0416.html 47 | (-digest [message algorithm] 48 | (let [^MessageDigest algo (MessageDigest/getInstance algorithm)] 49 | (.reset algo) 50 | (doseq [^bytes b message] (.update algo b)) 51 | (signature algo))) 52 | 53 | String 54 | (-digest [message algorithm] 55 | (-digest [(.getBytes message)] algorithm)) 56 | 57 | InputStream 58 | (-digest [reader algorithm] 59 | (-digest (byte-seq reader) algorithm)) 60 | 61 | File 62 | (-digest [file algorithm] 63 | (with-open [f (FileInputStream. file)] 64 | (-digest f algorithm))) 65 | 66 | nil 67 | (-digest [message algorithm] 68 | nil)) 69 | 70 | (defn digest 71 | "Returns digest for message with given algorithm." 72 | [algorithm message] 73 | (-digest message algorithm)) 74 | 75 | (defn algorithms [] 76 | "List support digest algorithms." 77 | (let [providers (into [] (Security/getProviders)) 78 | names (mapcat (fn [^Provider p] (enumeration-seq (.keys p))) providers) 79 | digest-names (filter #(re-find #"MessageDigest\.[A-Z0-9-]+$" %) names)] 80 | (set (map #(last (split % #"\.")) digest-names)))) 81 | 82 | (defn- create-fns [] 83 | "Create utility function for each digest algorithms. 84 | For example will create an md5 function for MD5 algorithm." 85 | (dorun (map #(intern 'boot.from.digest (symbol (lower-case %)) (partial digest %)) 86 | (algorithms)))) 87 | 88 | ; Create utililty functions such as md5, sha-2 ... 89 | (create-fns) 90 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/backtick.clj: -------------------------------------------------------------------------------- 1 | (ns boot.from.backtick 2 | {:boot/from :bbloom/backtick 3 | :boot/from-version "0.3.2"} 4 | (:refer-clojure :exclude [eval resolve])) 5 | 6 | (def ^:dynamic *resolve*) 7 | 8 | (def ^:dynamic ^:private *gensyms*) 9 | 10 | (defn- resolve [sym] 11 | (let [ns (namespace sym) 12 | n (name sym)] 13 | (if (and (not ns) (= (last n) \#)) 14 | (if-let [gs (@*gensyms* sym)] 15 | gs 16 | (let [gs (gensym (str (subs n 0 (dec (count n))) "__auto__"))] 17 | (swap! *gensyms* assoc sym gs) 18 | gs)) 19 | (*resolve* sym)))) 20 | 21 | (defn unquote? [form] 22 | (and (seq? form) (= (first form) 'clojure.core/unquote))) 23 | 24 | (defn unquote-splicing? [form] 25 | (and (seq? form) (= (first form) 'clojure.core/unquote-splicing))) 26 | 27 | (defn- quote-fn* [form] 28 | (cond 29 | (symbol? form) `'~(resolve form) 30 | (unquote? form) (second form) 31 | (unquote-splicing? form) (throw (Exception. "splice not in list")) 32 | (record? form) `'~form 33 | (coll? form) 34 | (let [xs (if (map? form) (apply concat form) form) 35 | parts (for [x xs] 36 | (if (unquote-splicing? x) 37 | (second x) 38 | [(quote-fn* x)])) 39 | cat (doall `(concat ~@parts))] 40 | (cond 41 | (vector? form) `(vec ~cat) 42 | (map? form) `(apply hash-map ~cat) 43 | (set? form) `(set ~cat) 44 | (seq? form) `(apply list ~cat) 45 | :else (throw (Exception. "Unknown collection type")))) 46 | :else `'~form)) 47 | 48 | (defn quote-fn [resolver form] 49 | (binding [*resolve* resolver 50 | *gensyms* (atom {})] 51 | (quote-fn* form))) 52 | 53 | (defmacro defquote [name resolver] 54 | `(let [resolver# ~resolver] 55 | (defn ~(symbol (str name "-fn")) [form#] 56 | (quote-fn resolver# form#)) 57 | (defmacro ~name [form#] 58 | (quote-fn resolver# form#)))) 59 | 60 | (defquote template identity) 61 | 62 | (defn- class-symbol [^java.lang.Class cls] 63 | (symbol (.getName cls))) 64 | 65 | (defn- namespace-name [^clojure.lang.Namespace ns] 66 | (name (.getName ns))) 67 | 68 | (defn- var-namespace [^clojure.lang.Var v] 69 | (name (.name (.ns v)))) 70 | 71 | (defn- var-name [^clojure.lang.Var v] 72 | (name (.sym v))) 73 | 74 | (defn- var-symbol [^clojure.lang.Var v] 75 | (symbol (var-namespace v) (var-name v))) 76 | 77 | (defn- ns-resolve-sym [sym] 78 | (let [x (ns-resolve *ns* sym)] 79 | (cond 80 | (instance? java.lang.Class x) (class-symbol x) 81 | (instance? clojure.lang.Var x) (var-symbol x) 82 | :else nil))) 83 | 84 | (defn resolve-symbol [sym] 85 | (let [ns (namespace sym) 86 | nm (name sym)] 87 | (if (nil? ns) 88 | (if-let [[_ ctor-name] (re-find #"(.*)\.$" nm)] 89 | (symbol nil (-> (symbol nil ctor-name) 90 | resolve-symbol 91 | name 92 | (str "."))) 93 | (if (or (special-symbol? sym) 94 | (re-find #"^\." nm)) ; method name 95 | sym 96 | (or (ns-resolve-sym sym) 97 | (symbol (namespace-name *ns*) nm)))) 98 | (or (ns-resolve-sym sym) sym)))) 99 | 100 | (defquote syntax-quote resolve-symbol) 101 | -------------------------------------------------------------------------------- /boot/base/pom.in.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | boot 5 | base 6 | jar 7 | __VERSION__ 8 | base 9 | https://github.com/boot-clj/boot 10 | Boot Java application loader and class. 11 | 12 | scm:git:git://github.com/boot-clj/boot.git 13 | scm:git:ssh://git@github.com/boot-clj/boot.git 14 | HEAD 15 | https://github.com/boot-clj/boot.git 16 | 17 | 18 | 19 | Eclipse Public License 1.0 20 | http://opensource.org/licenses/eclipse-1.0.php 21 | repo 22 | 23 | 24 | 25 | 26 | sonatype 27 | https://oss.sonatype.org/content/repositories/releases/ 28 | 29 | 30 | sonatype-snaps 31 | https://oss.sonatype.org/content/repositories/snapshots/ 32 | 33 | 34 | clojars 35 | https://repo.clojars.org/ 36 | 37 | 38 | maven-central 39 | http://repo1.maven.org/maven2/ 40 | 41 | 42 | 43 | UTF-8 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-assembly-plugin 50 | 51 | 52 | 53 | boot.App 54 | 55 | 56 | 57 | 58 | 59 | maven-compiler-plugin 60 | 3.1 61 | 62 | 1.7 63 | 1.7 64 | 65 | 66 | 67 | 68 | 69 | 70 | src/main/resources 71 | true 72 | 73 | **/*.properties 74 | 75 | 76 | 77 | src/main/resources 78 | false 79 | 80 | **/*.properties 81 | 82 | 83 | 84 | 85 | 86 | 87 | org.projectodd.shimdandy 88 | shimdandy-api 89 | 1.2.0 90 | 91 | 92 | junit 93 | junit 94 | 3.8.1 95 | test 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/WatchService.java: -------------------------------------------------------------------------------- 1 | package com.barbarysoftware.watchservice; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public abstract class WatchService implements Closeable { 8 | 9 | protected WatchService() { 10 | } 11 | 12 | /** 13 | * Closes this watch service. 14 | *

15 | *

If a thread is currently blocked in the {@link #take take} or {@link 16 | * #poll(long,TimeUnit) poll} methods waiting for a key to be queued then 17 | * it immediately receives a {@link ClosedWatchServiceException}. Any 18 | * valid keys associated with this watch service are {@link WatchKey#isValid 19 | * invalidated}. 20 | *

21 | *

After a watch service is closed, any further attempt to invoke 22 | * operations upon it will throw {@link ClosedWatchServiceException}. 23 | * If this watch service is already closed then invoking this method 24 | * has no effect. 25 | * 26 | * @throws IOException if an I/O error occurs 27 | */ 28 | @Override 29 | public abstract void close() throws IOException; 30 | 31 | /** 32 | * Retrieves and removes the next watch key, or {@code null} if none are 33 | * present. 34 | * 35 | * @return the next watch key, or {@code null} 36 | * @throws ClosedWatchServiceException if this watch service is closed 37 | */ 38 | public abstract WatchKey poll(); 39 | 40 | /** 41 | * Retrieves and removes the next watch key, waiting if necessary up to the 42 | * specified wait time if none are yet present. 43 | * 44 | * @param timeout how to wait before giving up, in units of unit 45 | * @param unit a {@code TimeUnit} determining how to interpret the timeout 46 | * parameter 47 | * @return the next watch key, or {@code null} 48 | * @throws ClosedWatchServiceException if this watch service is closed, or it is closed while waiting 49 | * for the next key 50 | * @throws InterruptedException if interrupted while waiting 51 | */ 52 | public abstract WatchKey poll(long timeout, TimeUnit unit) 53 | throws InterruptedException; 54 | 55 | /** 56 | * Retrieves and removes next watch key, waiting if none are yet present. 57 | * 58 | * @return the next watch key 59 | * @throws ClosedWatchServiceException if this watch service is closed, or it is closed while waiting 60 | * for the next key 61 | * @throws InterruptedException if interrupted while waiting 62 | */ 63 | public abstract WatchKey take() throws InterruptedException; 64 | 65 | public static WatchService newWatchService() { 66 | final String[] osVersion = System.getProperty("os.version").split("\\."); 67 | final int majorVersion = Integer.parseInt(osVersion[0]); 68 | final int minorVersion = Integer.parseInt(osVersion[1]); 69 | if ((majorVersion < 11) & (minorVersion < 5)) { 70 | throw new UnsupportedOperationException("barbarywatchservice not " 71 | + "supported on Mac OS X prior to Leopard (10.5)"); 72 | 73 | } else { 74 | // for Mac OS X Leopard (10.5) and upwards 75 | return new MacOSXListeningWatchService(); 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /boot/pod/src/boot/repl.clj: -------------------------------------------------------------------------------- 1 | (ns boot.repl 2 | (:require 3 | [clojure.java.io :as io] 4 | [boot.pod :as pod] 5 | [boot.file :as file] 6 | [boot.util :as util] 7 | [boot.from.io.aviso.repl :as pretty-repl] 8 | [boot.from.io.aviso.exception :refer [*fonts*]])) 9 | 10 | (def ^:dynamic *default-dependencies* 11 | (atom '[[nrepl/nrepl "0.6.0"]])) 12 | 13 | (defn ^:private disable-exception-colors 14 | [handler] 15 | (fn [msg] 16 | (binding [*fonts* nil] 17 | (handler msg)))) 18 | 19 | (def ^:dynamic *default-middleware* 20 | (atom (if-not @util/*colorize?* [disable-exception-colors] []))) 21 | 22 | (def ^:private start-server 23 | (delay (require 'boot.repl-server) 24 | @(resolve 'boot.repl-server/start-server))) 25 | 26 | (defn- nrepl-dependencies 27 | [{:keys [default-dependencies]}] 28 | (seq (->> (or default-dependencies @*default-dependencies*) 29 | (remove pod/dependency-loaded?)))) 30 | 31 | (defn- nrepl-middleware 32 | [{:keys [default-middleware] :as opts}] 33 | (assoc opts :default-middleware (or default-middleware @*default-middleware*))) 34 | 35 | (defn- rm-rf! 36 | [^java.io.File dir] 37 | (->> dir io/file file/file-seq-nofollow reverse (map (memfn delete)) doall)) 38 | 39 | (defn- delete-on-exit! 40 | [^java.io.File dir] 41 | (util/with-let [dir dir] 42 | (->> #(rm-rf! dir) Thread. (.addShutdownHook (Runtime/getRuntime))))) 43 | 44 | (defn- compile-path 45 | [opts] 46 | (->> "boot-repl" file/tmpdir delete-on-exit! (assoc opts :compile-path))) 47 | 48 | (defn- setup-nrepl-env! 49 | [opts] 50 | (util/with-let [{:keys [compile-path]} (-> opts compile-path nrepl-middleware)] 51 | (pod/add-classpath compile-path) 52 | (pretty-repl/install-pretty-exceptions) 53 | (when-let [deps (nrepl-dependencies opts)] 54 | (pod/add-dependencies (assoc pod/env :dependencies deps))))) 55 | 56 | (defn launch-nrepl 57 | "See #boot.task.built-in/repl for explanation of options." 58 | [{:keys [bind port init-ns middleware handler] :as options}] 59 | (let [opts (->> options setup-nrepl-env!)] 60 | (@start-server opts))) 61 | 62 | (defn launch-bare-repl 63 | [{to-eval :eval, 64 | :keys [init init-ns] 65 | :or {init-ns 'boot.user}}] 66 | (require 'clojure.main 'clojure.repl) 67 | ((resolve 'clojure.main/repl) 68 | :init (fn [] 69 | (when init 70 | (load-file init)) 71 | (when to-eval 72 | (eval to-eval)) 73 | (in-ns init-ns) 74 | (when (= 'boot.user init-ns) 75 | (refer 'clojure.repl))))) 76 | 77 | (defn launch-socket-server 78 | "See #boot.task.built-in/socket-server for explanation of options." 79 | [{:keys [bind port accept]}] 80 | (let [opts {:host (or bind "127.0.0.1") 81 | :port (or port 0) 82 | :name (gensym "socket-server") 83 | :accept (or accept 'clojure.core.server/repl)}] 84 | (try 85 | (require 'clojure.core.server) 86 | (catch java.io.FileNotFoundException e 87 | (throw (ex-info "Socket server requires Clojure version 1.8.0 or above" 88 | {:version (clojure-version)} 89 | e)))) 90 | (let [effective-port (-> ((resolve 'clojure.core.server/start-server) opts) 91 | (.getLocalPort))] 92 | (doto (io/file ".socket-port") .deleteOnExit (spit effective-port)) 93 | (util/info "Socket server started on port %s on host %s.\n" effective-port (:host opts))))) 94 | -------------------------------------------------------------------------------- /boot/core/src/boot/tmpregistry.clj: -------------------------------------------------------------------------------- 1 | (ns boot.tmpregistry 2 | (:refer-clojure :exclude [get]) 3 | (:require 4 | [boot.file :as file] 5 | [boot.kahnsort :as ksort] 6 | [boot.pod :as pod] 7 | [clojure.java.io :as io] 8 | [clojure.core :as core] 9 | [clojure.set :refer [union intersection difference]]) 10 | (:import 11 | java.io.File 12 | java.lang.management.ManagementFactory)) 13 | 14 | ;; helpers 15 | 16 | (defn munged-file [dir kw & n] 17 | (apply io/file dir (-> kw hash (Integer/toString 36)) (remove nil? n))) 18 | 19 | (defn delete! [f] 20 | (let [delete (io/file f)] 21 | (doseq [child (.listFiles delete)] (delete! child)) 22 | (.delete delete))) 23 | 24 | (defn dir-id [] 25 | (apply str 26 | (-> (->> (.. ManagementFactory getRuntimeMXBean getName) 27 | (take-while (partial not= \@)) 28 | (apply str) 29 | Long/parseLong) 30 | (Long/toString 36)) 31 | (when-not (= 1 pod/pod-id) ["-" (Long/toString pod/pod-id 36)]))) 32 | 33 | (defn mark-delete-me! [dir] 34 | #(when (.exists dir) (.createNewFile (io/file dir ".delete-me")))) 35 | 36 | (defn clean-delete-me! [dir] 37 | (doseq [f (->> (.listFiles (io/file dir)) 38 | (mapcat #(seq (.listFiles %))) 39 | (filter #(= ".delete-me" (.getName %))))] 40 | (delete! (.getParentFile f)))) 41 | 42 | (defmulti make-file! (fn [type f] type)) 43 | (defmethod make-file! ::file [type f] (doto f delete! (.createNewFile))) 44 | (defmethod make-file! ::dir [type f] (doto f delete! (.mkdirs))) 45 | 46 | ;;; tmpregistry interface 47 | 48 | (defprotocol ITmpRegistry 49 | (-init! [this] "Initialize temp registry.") 50 | (-get [this k] "Retrieve a temp file or directory.") 51 | (-unmk! [this k] "Remove a temp file or directory.") 52 | (-mk! [this type key name] "Create a temp file or directory.") 53 | (-tmpfile? [this f] "Is f a file in the tmpregistry?")) 54 | 55 | (defn init! [this] (doto this -init!)) 56 | (defn get [this key] (-get this key)) 57 | (defn unmk! [this key] (doto this (-unmk! key))) 58 | (defn mk! [this key & [name]] (-mk! this ::file key (or name "file.tmp"))) 59 | (defn mkdir! [this key & [name]] (-mk! this ::dir key name)) 60 | (defn tmp-file? [this f] (-tmpfile? this f)) 61 | 62 | ;;; tmpregistry implementation 63 | 64 | (defn- persist! [dir initialized? oldreg newreg] 65 | (let [[o n] (map set [oldreg newreg]) 66 | rmv (difference o n) 67 | add (difference n o)] 68 | (locking initialized? 69 | (when-not @initialized? (delete! dir)) 70 | (reset! initialized? true)) 71 | (doseq [[k v] rmv] 72 | (delete! (munged-file dir k))) 73 | (doseq [[k [t _ n]] add] 74 | (make-file! t (doto (munged-file dir k n) io/make-parents))))) 75 | 76 | (defrecord TmpRegistry [dir initialized? reg syncs] 77 | ITmpRegistry 78 | (-init! [this] 79 | (clean-delete-me! (.getParentFile (io/file dir))) 80 | (pod/add-shutdown-hook! (mark-delete-me! (io/file dir))) 81 | (add-watch reg ::_ #(persist! dir initialized? %3 %4))) 82 | (-get [this k] 83 | (munged-file dir k (nth (@reg k) 2))) 84 | (-unmk! [this k] 85 | (swap! reg dissoc k)) 86 | (-mk! [this t k n] 87 | (swap! reg assoc k [t (gensym) n]) 88 | (-get this k)) 89 | (-tmpfile? [this f] 90 | (when (file/parent? dir f) f))) 91 | 92 | (defn registry [dir] 93 | (TmpRegistry. (io/file dir (dir-id)) (atom false) (atom {}) (atom {}))) 94 | -------------------------------------------------------------------------------- /boot/pod/src/boot/repl_server.clj: -------------------------------------------------------------------------------- 1 | (ns boot.repl-server 2 | (:require 3 | [boot.repl :as repl] 4 | [boot.util :as util] 5 | [clojure.java.io :as io] 6 | [nrepl.server :as server] 7 | [nrepl.middleware :as middleware] 8 | [nrepl.middleware.session :as session])) 9 | 10 | (def ^:private default-opts 11 | {:bind nil 12 | :port nil 13 | :handler nil 14 | :middleware []}) 15 | 16 | (defn- ^{:boot/from :technomancy/leiningen} wrap-init-vars 17 | [init-ns compile-path] 18 | (with-local-vars 19 | [wrap-init-vars' 20 | (fn [h] 21 | ;; this needs to be a var, since it's in the nREPL session 22 | (with-local-vars [init-ns-sentinel nil] 23 | (fn [{:keys [session] :as msg}] 24 | (when-not (@session init-ns-sentinel) 25 | (#'clojure.core/load-data-readers) 26 | (swap! session assoc 27 | init-ns-sentinel true 28 | (var *data-readers*) (.getRawRoot #'*data-readers*) 29 | (var *compile-path*) compile-path 30 | (var *ns*) (try (require init-ns) 31 | (create-ns init-ns) 32 | (catch Throwable t 33 | (.printStackTrace t) 34 | (create-ns 'user))))) 35 | (h msg))))] 36 | (doto wrap-init-vars' 37 | ;; set-descriptor! currently nREPL only accepts a var 38 | (middleware/set-descriptor! 39 | {:requires #{#'session/session} 40 | :expects #{"eval"}}) 41 | (alter-var-root (constantly @wrap-init-vars'))))) 42 | 43 | (defn ->var 44 | [thing] 45 | (if-not (symbol? thing) 46 | thing 47 | (do (assert (and (symbol? thing) (namespace thing)) 48 | (format "expected namespaced symbol (%s)" thing)) 49 | (require (symbol (namespace thing))) 50 | (resolve thing)))) 51 | 52 | (defn ->mw-list 53 | [thing] 54 | (when thing 55 | (let [thing* (->var thing) 56 | thing (if (var? thing*) @thing* thing*)] 57 | (if-not (sequential? thing) 58 | [thing*] 59 | (mapcat ->mw-list thing))))) 60 | 61 | (defn start-server 62 | [opts] 63 | (let [{:keys [bind handler middleware init-ns compile-path default-middleware] 64 | :as opts} (merge default-opts opts) 65 | init-ns (or init-ns 'boot.user) 66 | init-ns-mw [(wrap-init-vars init-ns compile-path)] 67 | user-mw (->mw-list middleware) 68 | default-mw (->mw-list @repl/*default-middleware*) 69 | middleware (concat init-ns-mw default-mw user-mw) 70 | handler (if handler 71 | (->var handler) 72 | (apply server/default-handler middleware)) 73 | {:keys [bind] 74 | :as opts} (->> (-> (assoc opts :handler handler) 75 | (select-keys [:bind :port :handler]) 76 | (update-in [:bind] #(or % "127.0.0.1"))) 77 | (reduce-kv #(if-not %3 %1 (assoc %1 %2 %3)) {}))] 78 | (util/with-let [{:keys [port]} (apply server/start-server (mapcat identity opts))] 79 | (doto (io/file ".nrepl-port") .deleteOnExit (spit port)) 80 | (util/info "nREPL server started on port %d on host %s - nrepl://%s:%d\n" port bind bind port)))) 81 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at matt@degree9.io. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /boot/pod/src/boot/jar.clj: -------------------------------------------------------------------------------- 1 | (ns boot.jar 2 | (:require 3 | [clojure.java.io :as io] 4 | [boot.util :as util] 5 | [boot.filesystem :as fs]) 6 | (:import 7 | [java.util.zip ZipEntry ZipOutputStream ZipException] 8 | [java.util.jar JarEntry JarOutputStream Manifest Attributes$Name])) 9 | 10 | (set! *warn-on-reflection* true) 11 | 12 | (defn- create-manifest [main ext-attrs] 13 | (util/with-let [manifest (Manifest.)] 14 | (let [attributes (.getMainAttributes manifest)] 15 | (.put attributes Attributes$Name/MANIFEST_VERSION "1.0") 16 | (when-let [m (and main (.replaceAll (str main) "-" "_"))] 17 | (.put attributes Attributes$Name/MAIN_CLASS m)) 18 | (doseq [[k v] ext-attrs] 19 | (.put attributes (Attributes$Name. (name k)) v))))) 20 | 21 | (defn- write! [^java.io.OutputStream stream file] 22 | (let [buf (byte-array 1024)] 23 | (with-open [in (io/input-stream file)] 24 | (loop [n (.read in buf)] 25 | (when-not (= -1 n) 26 | (.write stream buf 0 n) 27 | (recur (.read in buf))))))) 28 | 29 | (defn dupe? [^Throwable t] 30 | (and (instance? ZipException t) 31 | (.startsWith (.getMessage t) "duplicate entry:"))) 32 | 33 | (defn jarentry [^String path ^java.io.File f & [dir?]] 34 | (doto (JarEntry. (str (.replaceAll path "\\\\" "/") (when dir? "/"))) 35 | (.setTime (.lastModified f)))) 36 | 37 | (defn spit-jar! [jarpath files attr main] 38 | (let [manifest (create-manifest main attr) 39 | jarfile (io/file jarpath) 40 | dirs (atom #{}) 41 | getparent (fn [^java.io.File f] (.getParent f)) 42 | parents* #(iterate (comp getparent io/file) %) 43 | parents #(->> % parents* (drop 1) 44 | (take-while (complement empty?)) 45 | (remove (partial contains? @dirs)))] 46 | (io/make-parents jarfile) 47 | (with-open [s (JarOutputStream. (io/output-stream jarfile) manifest)] 48 | (doseq [[jarpath srcpath] files :let [f (io/file srcpath)]] 49 | (let [e (jarentry jarpath f)] 50 | (try 51 | (doseq [d (parents jarpath) :let [f (io/file d)]] 52 | (swap! dirs conj d) 53 | (doto s (.putNextEntry (jarentry d f true)) .closeEntry)) 54 | (doto s (.putNextEntry e) (write! srcpath) .closeEntry) 55 | (catch Throwable t 56 | (if-not (dupe? t) (throw t) (util/warn "%s\n" (.getMessage t)))))))))) 57 | 58 | (defn spit-zip! [zippath files] 59 | (let [zipfile (io/file zippath)] 60 | (io/make-parents zipfile) 61 | (with-open [s (ZipOutputStream. (io/output-stream zipfile))] 62 | (doseq [[^String zippath ^String srcpath] files :let [f (io/file srcpath)]] 63 | (when-not (.isDirectory f) 64 | (let [entry (doto (ZipEntry. zippath) (.setTime (.lastModified f)))] 65 | (try 66 | (doto s (.putNextEntry entry) (write! srcpath) .closeEntry) 67 | (catch Throwable t 68 | (if-not (dupe? t) (throw t) (util/warn "%s\n" (.getMessage t))))))))))) 69 | 70 | ;; new jar fns ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 71 | 72 | (defn update-zip! 73 | [zipfile old-fs new-fs] 74 | (with-open [^java.nio.file.FileSystem fs (fs/mkjarfs zipfile :create true)] 75 | (fs/patch! (fs/->path fs) old-fs new-fs))) 76 | 77 | (defn update-jar! 78 | [jarfile old-fs new-fs attr main] 79 | (with-open [^java.nio.file.FileSystem fs (fs/mkjarfs jarfile :create true)] 80 | (let [^java.util.jar.Manifest manifest (create-manifest main attr)] 81 | (fs/write! (fs/->path fs) #(.write manifest %) ["META-INF" "MANIFEST.MF"])) 82 | (fs/patch! (fs/->path fs) old-fs new-fs))) 83 | -------------------------------------------------------------------------------- /boot/pod/test/boot/tmpdir_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.tmpdir-test 2 | (:refer-clojure :exclude [hash time]) 3 | (:require 4 | [clojure.test :refer :all] 5 | [boot.tmpdir :as tmpd])) 6 | 7 | (defn has-path? [fs path] 8 | (contains? (:tree fs) path)) 9 | 10 | (deftest diff*-scalar-test 11 | (let [before (tmpd/map->TmpFileSet {:tree {}}) 12 | after (tmpd/map->TmpFileSet {:tree {"path" {:adding true}}}) 13 | diff (#'tmpd/diff* before after [:adding])] 14 | (testing "Added" 15 | (is (has-path? (:added diff) "path")) 16 | (is (not (has-path? (:removed diff) "path"))) 17 | (is (not (has-path? (:changed diff) "path"))))) 18 | (let [before (tmpd/map->TmpFileSet {:tree {"path" {:removing true}}}) 19 | after (tmpd/map->TmpFileSet {:tree {}}) 20 | diff (#'tmpd/diff* before after [:removing])] 21 | (testing "Removed" 22 | (is (has-path? (:removed diff) "path")) 23 | (is (not (has-path? (:added diff) "path"))) 24 | (is (not (has-path? (:changed diff) "path"))))) 25 | (let [before (tmpd/map->TmpFileSet {:tree {"path" {:changing true}}}) 26 | after (tmpd/map->TmpFileSet {:tree {"path" {:changing false}}}) 27 | diff (#'tmpd/diff* before after [:changing])] 28 | (testing "Changed" 29 | (is (has-path? (:changed diff) "path")) 30 | (is (not (has-path? (:added diff) "path"))) 31 | (is (not (has-path? (:removed diff) "path")))))) 32 | 33 | (deftest diff*-nested-test 34 | (let [before (tmpd/map->TmpFileSet {:tree {}}) 35 | after (tmpd/map->TmpFileSet {:tree {"path" {:nested {:adding true}}}}) 36 | diff (#'tmpd/diff* before after [:nested])] 37 | (testing "Added" 38 | (is (has-path? (:added diff) "path")) 39 | (is (not (has-path? (:removed diff) "path"))) 40 | (is (not (has-path? (:changed diff) "path"))))) 41 | (let [before (tmpd/map->TmpFileSet {:tree {"path" {:nested {:removing true}}}}) 42 | after (tmpd/map->TmpFileSet {:tree {}}) 43 | diff (#'tmpd/diff* before after [:nested])] 44 | (testing "Removed" 45 | (is (has-path? (:removed diff) "path")) 46 | (is (not (has-path? (:added diff) "path"))) 47 | (is (not (has-path? (:changed diff) "path"))))) 48 | (let [before (tmpd/map->TmpFileSet {:tree {"path" {:nested {:changing true}}}}) 49 | after (tmpd/map->TmpFileSet {:tree {"path" {:nested {:changing false}}}}) 50 | diff (#'tmpd/diff* before after [:nested])] 51 | (testing "Changed (simple)" 52 | (is (has-path? (:changed diff) "path")) 53 | (is (not (has-path? (:added diff) "path"))) 54 | (is (not (has-path? (:removed diff) "path"))))) 55 | (let [before (tmpd/map->TmpFileSet {:tree {"path" {:nested {:staying true :changing true}}}}) 56 | after (tmpd/map->TmpFileSet {:tree {"path" {:nested {:staying true :changing false}}}}) 57 | diff (#'tmpd/diff* before after [:nested])] 58 | (testing "Changed (complex)" 59 | (is (has-path? (:changed diff) "path")) 60 | (is (not (has-path? (:added diff) "path"))) 61 | (is (not (has-path? (:removed diff) "path")))))) 62 | 63 | (deftest diff*-edge-test 64 | (let [before {} 65 | after {} 66 | diff (#'tmpd/diff* before after [:hash :time]) 67 | empty-fs {:tree {}}] 68 | (testing "Empty dicts" 69 | (is (= empty-fs (:added diff))) 70 | (is (= empty-fs (:removed diff))) 71 | (is (= empty-fs (:changed diff))))) 72 | (let [before nil 73 | after nil 74 | diff (#'tmpd/diff* before after [:hash :time]) 75 | empty-fs {:tree {}}] 76 | (testing "Nil" 77 | (is (= empty-fs (:added diff))) 78 | (is (= empty-fs (:removed diff))) 79 | (is (= empty-fs (:changed diff)))))) 80 | -------------------------------------------------------------------------------- /boot/core/src/boot/task_helpers/notify.clj: -------------------------------------------------------------------------------- 1 | (ns boot.task-helpers.notify 2 | (:require [clojure.java.io :as io] 3 | [boot.core :as core] 4 | [boot.pod :as pod] 5 | [boot.util :as util] 6 | [boot.from.io.aviso.ansi :as ansi])) 7 | 8 | (defn get-themefiles [theme tmp-dir] 9 | (let [resource #(vector %2 (format "boot/notify/%s_%s.mp3" %1 %2)) 10 | resources #(map resource (repeat %) ["success" "warning" "failure"])] 11 | (into {} 12 | (let [rs (when theme (resources theme))] 13 | (when (and (seq rs) (every? (comp io/resource second) rs)) 14 | (for [[x r] rs] 15 | (let [f (io/file tmp-dir (.getName (io/file r)))] 16 | (pod/copy-resource r f) 17 | [(keyword x) (.getPath f)]))))))) 18 | 19 | (defn ^{:boot/from :jeluard/boot-notify} boot-logo 20 | [] 21 | (let [d (core/tmp-dir!) 22 | f (io/file d "logo.png")] 23 | (io/copy (io/input-stream (io/resource "boot-logo-3.png")) f) 24 | (.getAbsolutePath f))) 25 | 26 | (defn- warn-ex-thrown [] 27 | (util/warn 28 | "An exception was thrown while trying to send a notification. To see more info, increase the verbosity of your build with e.g. \"boot -v\" or \"boot -vv\"\n")) 29 | 30 | (defn- sh-with-timeout [& args] 31 | (try 32 | (apply util/dosh-timed 1000 args) 33 | 0 34 | (catch Exception e 35 | (if (= 1 @util/*verbosity*) 36 | (warn-ex-thrown) 37 | (util/print-ex e)) 38 | 1))) 39 | 40 | (defn- warn-program-not-found [program-name] 41 | (util/warn "Could not find the '%s' program on PATH.\n" program-name) 42 | false) 43 | 44 | (defn- ^{:boot/from :jeluard/boot-notify} program-exists? 45 | [program-name] 46 | (or 47 | (= 0 (sh-with-timeout "sh" "-c" (format "command -v %s >/dev/null" program-name))) 48 | (warn-program-not-found program-name))) 49 | 50 | (defn- try-notify-with-shell-program [program-name & args] 51 | (and 52 | (program-exists? program-name) 53 | (= 0 54 | (apply sh-with-timeout program-name args)))) 55 | 56 | (defn- escape [s] 57 | (pr-str (str s))) 58 | 59 | (defn- notify-default [{:keys [message title]}] 60 | (util/info "%s%s %s \u2022 %s\n" 61 | ansi/reset-font 62 | (ansi/italic "notification:") 63 | (ansi/bold title) 64 | message)) 65 | 66 | (defmulti notify-method 67 | (fn [os _notification] 68 | os)) 69 | 70 | (defmethod notify-method :default 71 | [_ notification] 72 | (notify-default notification)) 73 | 74 | (defmethod notify-method "Mac OS X" 75 | [_ {:keys [message title icon uid] :as notification}] 76 | (or 77 | (try-notify-with-shell-program 78 | "terminal-notifier" 79 | "-message" (str message) 80 | "-title" (str title) 81 | "-contentImage" (str icon) 82 | "-group" (str uid)) 83 | 84 | (try-notify-with-shell-program 85 | "osascript" 86 | "-e" 87 | (str "display notification" 88 | (escape message) 89 | "with title" 90 | (escape title))) 91 | 92 | (notify-default notification))) 93 | 94 | (defmethod notify-method "Linux" 95 | [_ {:keys [message title icon] :as notification}] 96 | (or 97 | (try-notify-with-shell-program 98 | "notify-send" 99 | (str title) 100 | (str message) 101 | "--icon" 102 | (str icon)) 103 | (notify-default notification))) 104 | 105 | (defn ^{:boot/from :jeluard/boot-notify} visual-notify! 106 | [data] 107 | (notify-method (System/getProperty "os.name") data)) 108 | 109 | (defn audible-notify! 110 | [options] 111 | (pod/with-call-worker 112 | (boot.notify/notify! ~options))) 113 | -------------------------------------------------------------------------------- /boot/pod/src/boot/tools/deps.clj_: -------------------------------------------------------------------------------- 1 | (ns boot.tools.deps 2 | "Dependency management using tools.deps." 3 | {:boot/export-tasks true}) 4 | 5 | (deftask deps 6 | "Use tools.deps to read and resolve the specified deps.edn files. 7 | 8 | The dependencies read in are added to your Boot classpath. There are two 9 | options to update Boot's :dependencies if additional tasks in your pipeline 10 | rely on that: -B will completely overwrite the Boot :dependencies with the 11 | ones produced by tools.deps and should be used when you are creating uber 12 | jars; -Q will perform a quick merge of the dependencies from tools.deps into 13 | the Boot environment and may be needed for certain testing tools. 14 | 15 | As much as possible, the recommended approach is to avoid using the Boot 16 | :dependencies vector when using boot-tools-deps so that deps.edn represents 17 | the total dependencies for your project. 18 | 19 | Most of the arguments are intended to match the clj script usage 20 | (as passed to clojure.tools.deps.alpha.script.make-classpath/-main). 21 | 22 | In particular, the -c / --config-paths option is assumed to be the COMPLETE 23 | list of EDN files to read (and therefore overrides the default set of 24 | system deps, user deps, and local deps). 25 | 26 | The -r option is intended to be equivalent to the -Srepro option in 27 | tools.deps, which will exclude both the system deps and the user deps. 28 | 29 | The -D option is intended to be the equivalent to the -Sdeps option, which 30 | allows you to specify an additional deps.edn-like map of dependencies which 31 | are added to the set of deps.edn-derived dependencies (even when -r is 32 | given). 33 | 34 | The -A, -C, -M, and -R options mirror the clj script usage for aliases. 35 | 36 | The -x option will run clojure.main with any main-opts found by deps.edn. 37 | 38 | The -v option makes boot-tools-deps verbose, explaining which files it looked 39 | for, the dependencies it got back from tools.dep, and the changes it made to 40 | Boot's classpath, :resource-paths, and :source-path. If you specify it twice 41 | (-vv) then tools.deps will also be verbose about its work." 42 | 43 | [;; options that mirror tools.deps itself: 44 | c config-paths PATH [str] "the list of deps.edn files to read." 45 | r repeatable bool "Use only the specified deps.edn file for a repeatable build." 46 | D config-data EDN edn "is treated as a final deps.edn file." 47 | A aliases KW [kw] "the list of aliases (for -C, -M, and -R)." 48 | C classpath-aliases KW [kw] "the list of classpath aliases to use." 49 | M main-aliases KW [kw] "the list of main-opt aliases to use." 50 | R resolve-aliases KW [kw] "the list of resolve aliases to use." 51 | ;; options specific to boot-tools-deps 52 | B overwrite-boot-deps bool "Overwrite Boot's :dependencies." 53 | Q quick-merge bool "Merge into Boot's :dependencies." 54 | v verbose int "the verbosity level." 55 | x execute bool "Execute clojure.main with any main-opts found."] 56 | (let [{:keys [main-opts]} 57 | (load-deps {:config-paths config-paths 58 | :config-data config-data 59 | :classpath-aliases (into (vec aliases) classpath-aliases) 60 | :main-aliases (into (vec aliases) main-aliases) 61 | :resolve-aliases (into (vec aliases) resolve-aliases) 62 | :overwrite-boot-deps overwrite-boot-deps 63 | :quick-merge quick-merge 64 | :repeatable repeatable 65 | :verbose verbose})] 66 | (boot/with-pass-thru fs 67 | (when execute 68 | (when verbose 69 | (println "Executing clojure.main" (str/join " " main-opts))) 70 | (apply clojure.main/main main-opts))))) 71 | -------------------------------------------------------------------------------- /boot/worker/src/boot/xml.clj: -------------------------------------------------------------------------------- 1 | (ns boot.xml 2 | "DEPRECATED: Utility functions for working with XML." 3 | {:deprecated "2.0.0"} 4 | (:require 5 | [clojure.java.io :as io] 6 | [clojure.xml :as xml] 7 | [clojure.data.xml :as dxml] 8 | [alandipert.desiderata.invoke :as invoke]) 9 | (:import 10 | [java.io ByteArrayInputStream])) 11 | 12 | (def invalid-xml-chars 13 | "[^\u0009\r\n\u0020-\ud7ff\ue000-\ufffd\ud800\udc00-\udbfF\udfff]") 14 | 15 | (defn clean-xml [x] 16 | (when (string? x) (.replaceAll x invalid-xml-chars ""))) 17 | 18 | (defn ppxml [xml] 19 | (let [in (javax.xml.transform.stream.StreamSource. 20 | (java.io.StringReader. xml)) 21 | writer (java.io.StringWriter.) 22 | out (javax.xml.transform.stream.StreamResult. writer) 23 | transformer (.newTransformer 24 | (javax.xml.transform.TransformerFactory/newInstance))] 25 | (.setOutputProperty transformer 26 | javax.xml.transform.OutputKeys/INDENT "yes") 27 | (.setOutputProperty transformer 28 | "{http://xml.apache.org/xslt}indent-amount" "2") 29 | (.setOutputProperty transformer 30 | javax.xml.transform.OutputKeys/METHOD "xml") 31 | (.transform transformer in out) 32 | (-> out .getWriter .toString))) 33 | 34 | (defn- unsplice [kids] 35 | (let [spliced? #(or (vector? %) (seq? %))] 36 | (->> kids 37 | (mapcat #(cond (spliced? %) (unsplice %) (nil? %) [] :else [%]))))) 38 | 39 | ;;;; 40 | 41 | (defprotocol IHiccup 42 | (-hiccup [this])) 43 | 44 | (extend-protocol IHiccup 45 | java.lang.String 46 | (-hiccup [this] this) 47 | java.lang.Long 48 | (-hiccup [this] (str this)) 49 | java.lang.Double 50 | (-hiccup [this] (str this)) 51 | java.lang.Integer 52 | (-hiccup [this] (str this)) 53 | java.lang.Boolean 54 | (-hiccup [this] (str this)) 55 | clojure.lang.Keyword 56 | (-hiccup [this] (name this)) 57 | clojure.lang.Symbol 58 | (-hiccup [this] (name this))) 59 | 60 | (defn hiccup [this] 61 | (-hiccup this)) 62 | 63 | ;;;; 64 | 65 | (defn parse-elem-args [[head & tail :as args]] 66 | (let [kw1? (comp keyword? first) 67 | mkkw #(->> (partition 2 %) (take-while kw1?) (map vec)) 68 | drkw #(->> (partition 2 2 [] %) (drop-while kw1?) (mapcat identity))] 69 | (cond 70 | (map? head) [head (unsplice tail)] 71 | (keyword? head) [(into {} (mkkw args)) (unsplice (drkw args))] 72 | :else [{} (unsplice (concat () args))]))) 73 | 74 | (defmacro elem [bindings & body] 75 | `(fn [& args#] 76 | (let [~bindings (parse-elem-args args#)] 77 | ~@body))) 78 | 79 | (defmacro defelem [sym & args] 80 | `(def ~sym (elem ~@args))) 81 | 82 | (defmacro decelems [& symbols] 83 | `(doseq [sym# '~symbols] 84 | (intern (ns-name *ns*) sym# (elem [attrs# elems#] ((element (keyword sym#)) attrs# elems#))))) 85 | 86 | (invoke/deftypefn XMLElement 87 | [tag attrs elems] 88 | (fn [this & args] 89 | (let [[attrs' elems'] (parse-elem-args args) 90 | attrs'' (merge attrs attrs') 91 | elems'' (concat elems (unsplice elems')) 92 | hollow? #(or (and (coll? %) (empty? %)) (nil? %)) ] 93 | (XMLElement. tag attrs'' elems''))) 94 | IHiccup 95 | (-hiccup [this] 96 | (apply vector tag 97 | (into {} (map (fn [[k v]] [k (-hiccup v)]) attrs)) 98 | (map #(-hiccup %) elems)))) 99 | 100 | (defmethod print-method XMLElement 101 | [this ^java.io.Writer w] 102 | (.write w (-> this 103 | hiccup 104 | dxml/sexp-as-element 105 | dxml/indent-str 106 | (.replaceFirst ">" ">\n")))) 107 | 108 | (defn element [tag] 109 | (fn [& [attrs elems :as args]] 110 | (-> (XMLElement. tag {} ()) (apply args)))) 111 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/table/width.clj: -------------------------------------------------------------------------------- 1 | ;;; 2 | ;;; Taken from here: https://github.com/cldwalker/table 3 | ;;; 4 | ;;; The MIT LICENSE 5 | ;;; 6 | ;;; Copyright (c) 2012 Gabriel Horner 7 | ;;; 8 | ;;; Permission is hereby granted, free of charge, to any person obtaining 9 | ;;; a copy of this software and associated documentation files (the 10 | ;;; "Software"), to deal in the Software without restriction, including 11 | ;;; without limitation the rights to use, copy, modify, merge, publish, 12 | ;;; distribute, sublicense, and/or sell copies of the Software, and to 13 | ;;; permit persons to whom the Software is furnished to do so, subject to 14 | ;;; the following conditions: 15 | ;;; 16 | ;;; The above copyright notice and this permission notice shall be 17 | ;;; included in all copies or substantial portions of the Software. 18 | ;;; 19 | ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | ;;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | ;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | ;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | ;;; 27 | (ns boot.from.table.width 28 | {:boot/from :cldwalker/table} 29 | (:require clojure.java.shell clojure.java.io clojure.string)) 30 | 31 | (declare get-initial-widths max-width-per-field actual-width auto-resize-widths 32 | detect-terminal-width command-exists?) 33 | 34 | (def ^:dynamic *width* (delay (or (detect-terminal-width) 200))) 35 | ; TODO: calculate border lengths from styles 36 | ; " | " and "-+-" are inner borders 37 | (def inner-border-length 3) 38 | ; "+-" and "-+" are outer borders 39 | (def outer-border-length 2) 40 | 41 | (defn get-widths [all-rows] 42 | (-> all-rows get-initial-widths vec auto-resize-widths)) 43 | 44 | (defn auto-resize-widths [widths] 45 | (loop [new-widths [] widths widths field-count (count widths) max-width @*width*] 46 | (if (empty? widths) 47 | new-widths 48 | (let [width (first widths) 49 | width-per-field (max-width-per-field max-width field-count) 50 | new-width (if (< width width-per-field) width width-per-field)] 51 | (recur 52 | (conj new-widths new-width) 53 | (rest widths) 54 | (- field-count 1) 55 | (- max-width (+ new-width inner-border-length))))))) 56 | 57 | (defn get-initial-widths [all-rows] 58 | (map 59 | (fn [idx] 60 | (apply max (map #(count (str (nth % idx))) all-rows))) 61 | (range (count (first all-rows))))) 62 | 63 | (defn- max-width-per-field [current-width field-count] 64 | (quot (actual-width current-width field-count) field-count)) 65 | 66 | ; think of inner-borders as interposed between fields to understand why 67 | ; it's one less than the number of fields 68 | (defn- actual-width [current-width field-count] 69 | (- current-width (+ (* 2 outer-border-length) (* (dec field-count) inner-border-length)))) 70 | 71 | (defn ensure-valid-width [arg] 72 | (if (integer? arg) 73 | (if (> arg 0) arg 100) 74 | arg)) 75 | 76 | (defn- stty-detect [] 77 | (->> (clojure.java.shell/sh "/bin/sh" "-c" "stty -a < /dev/tty") 78 | :out 79 | (re-find #" (\d+) columns") 80 | vec 81 | second 82 | ((fn [_ two] (if two (Integer. two))) :not-used))) 83 | 84 | ; since Java doesn't recognize COLUMNS by default you need to `export COLUMNS` for it 85 | ; be recognized 86 | (defn- detect-terminal-width [] 87 | (ensure-valid-width 88 | (cond 89 | (System/getenv "COLUMNS") (Integer. (System/getenv "COLUMNS")) 90 | (command-exists? "stty") (stty-detect)))) 91 | 92 | (defn- command-exists? 93 | "Determines if command exists in $PATH" 94 | [cmd] 95 | (some 96 | #(-> (str % "/" cmd) clojure.java.io/file .isFile) 97 | (-> (System/getenv "PATH") (clojure.string/split #":")))) 98 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help deps install deploy test clean 2 | 3 | SHELL := /bin/bash 4 | export PATH := bin:$(PATH) 5 | export LEIN_SNAPSHOTS_IN_RELEASE := yes 6 | 7 | version = $(shell grep ^version version.properties |sed 's/.*=//') 8 | verfile = version.properties 9 | distjar = $(PWD)/bin/boot.jar 10 | bootjar = boot/boot/target/boot-$(version).jar 11 | podjar = boot/pod/target/pod-$(version).jar 12 | aetherjar = boot/aether/target/aether-$(version).jar 13 | aetheruber = aether.uber.jar 14 | workerjar = boot/worker/target/worker-$(version).jar 15 | corejar = boot/core/target/core-$(version).jar 16 | basejar = boot/base/target/base-$(version).jar 17 | baseuber = boot/base/target/base-$(version)-jar-with-dependencies.jar 18 | alljars = $(podjar) $(aetherjar) $(workerjar) $(corejar) $(baseuber) $(bootjar) 19 | java_version = $(shell java -version 2>&1 | awk -F '"' '/version/ {print $$2}' |awk -F. '{print $$1 "." $$2}') 20 | 21 | help: 22 | @echo "version =" $(version) 23 | @echo "Usage: make {help|deps|install|deploy|test|clean}" 1>&2 && false 24 | 25 | clean: 26 | (cd boot/base && mvn -q clean && rm -f src/main/resources/$(aetheruber)) 27 | (cd boot/core && lein clean) 28 | (cd boot/aether && lein clean) 29 | (cd boot/pod && lein clean) 30 | (cd boot/worker && lein clean) 31 | (rm -Rfv bin) 32 | (rm -fv .installed .deployed .tested) 33 | 34 | mkdirs: 35 | mkdir -p bin 36 | 37 | bin/lein: mkdirs 38 | wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O bin/lein 39 | chmod 755 bin/lein 40 | 41 | bin/boot: mkdirs 42 | curl -fsSLo bin/boot https://github.com/boot-clj/boot-bin/releases/download/latest/boot.sh 43 | chmod 755 bin/boot 44 | 45 | deps: bin/lein bin/boot 46 | 47 | $(bootjar): $(verfile) boot/boot/project.clj 48 | (cd boot/boot && lein install) 49 | 50 | boot/base/pom.xml: $(verfile) boot/base/pom.in.xml 51 | (cd boot/base && cat pom.in.xml |sed 's/__VERSION__/$(version)/' > pom.xml) 52 | 53 | $(basejar): boot/base/pom.xml $(shell find boot/base/src/main/java) 54 | (cd boot/base && mvn -q install) 55 | 56 | $(podjar): $(verfile) boot/pod/project.clj $(shell find boot/pod/src) 57 | (cd boot/pod && lein install) 58 | 59 | $(aetherjar): $(verfile) boot/aether/project.clj $(podjar) $(shell find boot/aether/src) 60 | (cd boot/aether && lein install && lein uberjar && \ 61 | mkdir -p ../base/src/main/resources && \ 62 | cp target/aether-$(version)-standalone.jar ../base/src/main/resources/$(aetheruber)) 63 | 64 | $(workerjar): $(verfile) boot/worker/project.clj $(shell find boot/worker/src) 65 | (cd boot/worker && lein install) 66 | 67 | $(corejar): $(verfile) boot/core/project.clj $(shell find boot/core/src) 68 | (cd boot/core && lein install) 69 | 70 | $(baseuber): boot/base/pom.xml $(shell find boot/base/src/main) 71 | (cd boot/base && mvn -q assembly:assembly -DdescriptorId=jar-with-dependencies) 72 | 73 | .installed: mkdirs $(basejar) $(alljars) 74 | cp $(baseuber) $(distjar) 75 | # FIXME: this is just for testing -- remove before release 76 | mkdir -p $$HOME/.boot/cache/bin/$(version) 77 | cp $(baseuber) $$HOME/.boot/cache/bin/$(version)/boot.jar 78 | # End testing code -- cut above. 79 | date > .installed 80 | 81 | install: .installed 82 | 83 | .deployed: .installed 84 | (cd boot/base && lein deploy clojars boot/base $(version) target/base-$(version).jar pom.xml) 85 | (cd boot/pod && lein deploy clojars) 86 | (cd boot/aether && lein deploy clojars) 87 | (cd boot/worker && lein deploy clojars) 88 | (cd boot/core && lein deploy clojars) 89 | (cd boot/boot && lein deploy clojars) 90 | date > .deployed 91 | 92 | deploy: .deployed 93 | 94 | .tested: bin/boot 95 | (export BOOT_VERSION=$(version) && export BOOT_EMIT_TARGET=no && cd boot/core && ../../bin/boot -x test) 96 | (export BOOT_VERSION=$(version) && export BOOT_EMIT_TARGET=no && cd boot/worker && ../../bin/boot -x test) 97 | (cd boot/pod && lein test) 98 | date > .tested 99 | 100 | test: .installed .tested 101 | -------------------------------------------------------------------------------- /boot/worker/test/boot/pom_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.pom-test 2 | (:require [boot.pom :as pom] 3 | [clojure.test :as test :refer [deftest is testing]] 4 | [clojure.zip :as zip] 5 | [clojure.data.xml :as dxml] 6 | [clojure.data.zip.xml :as dzxml])) 7 | 8 | (deftest pom-parent 9 | 10 | (testing "pom-xml-parse-string" 11 | (let [xml-str "\n 4.0.0\n \n \n org.codehaus.mojo\n my-parent\n 2.0\n ../my-parent\n \n \n my-project\n\n" 12 | {:keys [parent]} (pom/pom-xml-parse-string xml-str)] 13 | (is (= '[org.codehaus.mojo/my-parent "2.0"] (:dependency parent)) "The parent :dependency must exist and match the example") 14 | (is (= "../my-parent" (:relative-path parent)) "The parent :relative-path key must exist and match the example")) 15 | 16 | (let [xml-str "\n 4.0.0\n \n org.codehaus.mojo\n my-parent\n 2.0\n pom\n" 17 | {:keys [parent]} (pom/pom-xml-parse-string xml-str)] 18 | (is (nil? parent) "The parent tag must not exist if missing in the pom")) 19 | 20 | (let [xml-str "\n 4.0.0\n \n \n my-parent\n 2.0\n \n \n my-project\n\n" 21 | {:keys [parent]} (pom/pom-xml-parse-string xml-str)] 22 | (is (= '[my-parent "2.0"] (-> :dependency parent)) "The parent :dependency must exist and be just the artifactId of the example") 23 | (is (nil? (-> parent :dependency first namespace)) "The parent :dependency must exist but should not have the groupId as per example") 24 | (is (nil? (:relative-path parent)) "The parent :relative-path must be nil as it is not in the example")) 25 | 26 | ;; Edge case - parent tag is there but does not have artifactId 27 | (let [xml-str "\n 4.0.0\n \n \n org.codehaus.mojo\n \n \n my-project\n\n" 28 | {:keys [parent]} (pom/pom-xml-parse-string xml-str)] 29 | (is (nil? (-> :dependency parent)) "The parent :dependency should be nil if no artifactId is there"))) 30 | 31 | (testing "pom-xml :parent" 32 | (let [parent-loc (-> {:project 'group/my-plugin 33 | :version "1.2.0" 34 | :parent '[org.codehaus.mojo/my-parent "2.0"]} 35 | pom/pom-xml 36 | pr-str 37 | dxml/parse-str 38 | zip/xml-zip 39 | (dzxml/xml1-> :parent))] 40 | (is (not (nil? (dzxml/xml1-> parent-loc :groupId "org.codehaus.mojo"))) "I should contain a :groupId tag with correct content") 41 | (is (not (nil? (dzxml/xml1-> parent-loc :artifactId "my-parent"))) "It should contain a :artifactId tag with correct content") 42 | (is (not (nil? (dzxml/xml1-> parent-loc :version "2.0"))) "It should contain a :version tag with correct content")))) 43 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/StandardWatchEventKind.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | /** 29 | * Defines the standard event kinds. 30 | * 31 | * @since 1.7 32 | */ 33 | 34 | public final class StandardWatchEventKind { 35 | private StandardWatchEventKind() { } 36 | 37 | /** 38 | * A special event to indicate that events may have been lost or 39 | * discarded. 40 | * 41 | *

The {@link WatchEvent#context context} for this event is 42 | * implementation specific and may be {@code null}. The event {@link 43 | * WatchEvent#count count} may be greater than {@code 1}. 44 | * 45 | * @see WatchService 46 | */ 47 | public static final WatchEvent.Kind OVERFLOW = 48 | new StdWatchEventKind("OVERFLOW", Void.class); 49 | 50 | /** 51 | * Directory entry created. 52 | * 53 | *

When a directory is registered for this event then the {@link WatchKey} 54 | * is queued when it is observed that an entry is created in the directory 55 | * or renamed into the directory. The event {@link WatchEvent#count count} 56 | * for this event is always {@code 1}. 57 | */ 58 | public static final WatchEvent.Kind ENTRY_CREATE = 59 | new StdWatchEventKind("ENTRY_CREATE", WatchableFile.class); 60 | 61 | /** 62 | * Directory entry deleted. 63 | * 64 | *

When a directory is registered for this event then the {@link WatchKey} 65 | * is queued when it is observed that an entry is deleted or renamed out of 66 | * the directory. The event {@link WatchEvent#count count} for this event 67 | * is always {@code 1}. 68 | */ 69 | public static final WatchEvent.Kind ENTRY_DELETE = 70 | new StdWatchEventKind("ENTRY_DELETE", WatchableFile.class); 71 | 72 | /** 73 | * Directory entry modified. 74 | * 75 | *

When a directory is registered for this event then the {@link WatchKey} 76 | * is queued when it is observed that an entry in the directory has been 77 | * modified. The event {@link WatchEvent#count count} for this event is 78 | * {@code 1} or greater. 79 | */ 80 | public static final WatchEvent.Kind ENTRY_MODIFY = 81 | new StdWatchEventKind("ENTRY_MODIFY", WatchableFile.class); 82 | 83 | private static class StdWatchEventKind implements WatchEvent.Kind { 84 | private final String name; 85 | private final Class type; 86 | StdWatchEventKind(String name, Class type) { 87 | this.name = name; 88 | this.type = type; 89 | } 90 | @Override public String name() { return name; } 91 | @Override public Class type() { return type; } 92 | @Override public String toString() { return name; } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /boot/pod/src/boot/pod/deps.clj_: -------------------------------------------------------------------------------- 1 | (ns boot.pod.deps 2 | (:require [boot.core :as boot] 3 | [boot.pod :as pod])) 4 | 5 | (defn- make-pod 6 | "Make and return a Boot pod with tools.deps.alpha and a recent Clojure 7 | release (to ensure that tools.deps.alpha will run). The pod will also 8 | include Boot and boot-tools-deps (since they're both running), as well as 9 | any other 'runtime' dependencies (which is why it's best to avoid putting 10 | additional dependencies in build.boot when using this tool!)." 11 | [] 12 | (let [pod-env 13 | (-> (boot/get-env) 14 | ;; Pod class path needs to be bootstrapped independently of 15 | ;; the core Pod (build.boot context) so that, for example, 16 | ;; an older version of Clojure than 1.9 can be used in the 17 | ;; core Pod. 18 | (dissoc :boot-class-path :fake-class-path) 19 | ;; Clojure version in the core Pod (build.boot context) 20 | ;; is not guaranteed to be recent enough as Boot supports 21 | ;; 1.6.0 onwards. If it isn't recent enough, we replace it. 22 | ;; We also force tools.deps.alpha to a fixed version. 23 | (update :dependencies ensure-recent-clojure-tools-deps))] 24 | (pod/make-pod pod-env))) 25 | 26 | (defn build-environment-map 27 | "Run tools.deps to produce: 28 | * :resource-paths -- source code directories from :paths in deps.edn files 29 | * :source-paths -- additional directories from :extra-paths and classpath 30 | * :repositories -- any entries from :mvn/repos 31 | * :dependencies -- vector of Maven coordinates 32 | * :classpath -- JAR files to add to the classpath 33 | * :main-opts -- any main-opts pulled from tools.deps.alpha" 34 | [{:keys [config-data ; no config-paths 35 | classpath-aliases main-aliases resolve-aliases 36 | verbose ; no repeatable 37 | system-deps deps-files total] 38 | :as options}] 39 | (let [deps (reader/read-deps 40 | (into [] (comp (map io/file) 41 | (filter #(.exists %))) 42 | deps-files)) 43 | deps (if total 44 | (if config-data 45 | (reader/merge-deps [deps config-data]) 46 | deps) 47 | (reader/merge-deps 48 | (cond-> [system-deps deps] 49 | config-data (conj config-data)))) 50 | paths (set (or (seq (:paths deps)) [])) 51 | resolve-args (cond-> 52 | (deps/combine-aliases deps resolve-aliases) 53 | ;; handle both legacy boolean and new counter 54 | (and verbose 55 | (or (boolean? verbose) 56 | (< 1 verbose))) 57 | (assoc :verbose true)) 58 | libs (deps/resolve-deps deps resolve-args) 59 | cp-args (deps/combine-aliases deps classpath-aliases) 60 | cp (deps/make-classpath libs (:paths deps) cp-args) 61 | main-opts (:main-opts (deps/combine-aliases deps main-aliases)) 62 | cp-separator (re-pattern java.io.File/pathSeparator) 63 | [jars dirs] (reduce (fn [[jars dirs] item] 64 | (let [f (java.io.File. item)] 65 | (if (and (.exists f) 66 | (not (paths item))) 67 | (cond (.isFile f) 68 | [(conj jars item) dirs] 69 | (.isDirectory f) 70 | [jars (conj dirs item)] 71 | :else 72 | [jars dirs]) 73 | [jars dirs]))) 74 | [[] []] 75 | (str/split cp cp-separator))] 76 | {:resource-paths paths 77 | :source-paths (set dirs) 78 | :repositories (:mvn/repos deps) 79 | :dependencies libs 80 | :classpath jars 81 | :main-opts main-opts})) 82 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/WatchEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | /** 29 | * An event or a repeated event for an object that is registered with a {@link 30 | * WatchService}. 31 | * 32 | *

An event is classified by its {@link #kind() kind} and has a {@link 33 | * #count() count} to indicate the number of times that the event has been 34 | * observed. This allows for efficient representation of repeated events. The 35 | * {@link #context() context} method returns any context associated with 36 | * the event. In the case of a repeated event then the context is the same for 37 | * all events. 38 | * 39 | *

Watch events are immutable and safe for use by multiple concurrent 40 | * threads. 41 | * 42 | * @param The type of the context object associated with the event 43 | * 44 | * @since 1.7 45 | */ 46 | 47 | public abstract class WatchEvent { 48 | 49 | /** 50 | * An event kind, for the purposes of identification. 51 | * 52 | * @since 1.7 53 | * @see StandardWatchEventKind 54 | */ 55 | public static interface Kind { 56 | /** 57 | * Returns the name of the event kind. 58 | */ 59 | String name(); 60 | 61 | /** 62 | * Returns the type of the {@link WatchEvent#context context} value. 63 | */ 64 | Class type(); 65 | } 66 | 67 | /** 68 | * Initializes a new instance of this class. 69 | */ 70 | protected WatchEvent() { } 71 | 72 | /** 73 | * An event modifier that qualifies how a {@link Watchable} is registered 74 | * with a {@link WatchService}. 75 | * 76 | *

This release does not define any standard modifiers. 77 | * 78 | * @since 1.7 79 | * @see Watchable#register 80 | */ 81 | public static interface Modifier { 82 | /** 83 | * @return the name of the modifier. 84 | */ 85 | String name(); 86 | } 87 | 88 | /** 89 | * Returns the event kind. 90 | * 91 | * @return the event kind 92 | */ 93 | public abstract Kind kind(); 94 | 95 | /** 96 | * Returns the event count. If the event count is greater than {@code 1} 97 | * then this is a repeated event. 98 | * 99 | * @return the event count 100 | */ 101 | public abstract int count(); 102 | 103 | /** 104 | * Returns the context for the event. 105 | * 106 | *

In the case of {@link StandardWatchEventKind#ENTRY_CREATE ENTRY_CREATE}, 107 | * {@link StandardWatchEventKind#ENTRY_DELETE ENTRY_DELETE}, and {@link 108 | * StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} events the context is 109 | * a {@code File}. 110 | * 111 | * @return the event context; may be {@code null} 112 | */ 113 | public abstract T context(); 114 | } 115 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/io/aviso/ansi.clj: -------------------------------------------------------------------------------- 1 | (ns boot.from.io.aviso.ansi 2 | "Help with generating textual output that includes ANSI escape codes for formatting." 3 | {:boot/from :AvisoNovate/pretty:0.1.34} 4 | (:import 5 | [java.util.regex Pattern]) 6 | (:require 7 | [clojure.string :as str])) 8 | 9 | (def ^:const csi 10 | "The control sequence initiator: `ESC [`" 11 | "\u001b[") 12 | 13 | ;; select graphic rendition 14 | (def ^:const sgr 15 | "The Select Graphic Rendition suffix: m" 16 | "m") 17 | 18 | (def ^:const 19 | reset-font 20 | "Resets the font, clearing bold, italic, color, and background color." 21 | (str csi sgr)) 22 | 23 | (defmacro ^:private def-sgr-const 24 | "Utility for defining a font-modifying constant." 25 | [symbol-name color-name & codes] 26 | `(def ~(vary-meta (symbol symbol-name) assoc :const true) 27 | ~(format "Constant for ANSI code to enable %s text." color-name) 28 | (str csi ~(str/join ";" codes) sgr))) 29 | 30 | (defmacro ^:private def-sgr-fn 31 | "Utility for creating a function that enables some combination of SGR codes around some text, but resets 32 | the font after the text." 33 | [fn-name color-name & codes] 34 | (let [arg 'text] 35 | `(defn ~(symbol fn-name) 36 | ~(format "Wraps the provided text with ANSI codes to render as %s text." color-name) 37 | [~arg] 38 | (str csi ~(str/join ";" codes) sgr ~arg reset-font)))) 39 | 40 | ;;; Define functions and constants for each color. The functions accept a string 41 | ;;; and wrap it with the ANSI codes to set up a rendition before the text, 42 | ;;; and reset the rendition fully back to normal after. 43 | ;;; The constants enable the rendition, and require the reset-font value to 44 | ;;; return to normal. 45 | ;;; For each color C: 46 | ;;; - functions: 47 | ;;; - C: change text to that color (e.g., "green") 48 | ;;; - C-bg: change background to that color (e.g., "green-bg") 49 | ;;; - bold-C: change text to bold variation of color (e.g., "bold-green") 50 | ;;; - bold-C-bg: change background to bold variation of color (e.g., "bold-green-bg") 51 | ;;; - constants 52 | ;;; - C-font: enable text in that color (e.g., "green-font") 53 | ;;; - C-bg-font: enable background in that color (e.g., "green-bg-font") 54 | ;;; - bold-C-font; enable bold text in that color (e.g., "bold-green-font") 55 | ;;; - bold-C-bg-font; enable background in that bold color (e.g., "bold-green-bg-font") 56 | 57 | (defmacro ^:private define-colors 58 | [] 59 | `(do 60 | ~@(map-indexed 61 | (fn [index color-name] 62 | `(do 63 | (def-sgr-fn ~color-name ~color-name ~(+ 30 index)) 64 | (def-sgr-fn ~(str color-name "-bg") ~(str color-name " background") ~(+ 40 index)) 65 | (def-sgr-fn ~(str "bold-" color-name) ~(str "bold " color-name) 1 ~(+ 30 index)) 66 | (def-sgr-fn ~(str "bold-" color-name "-bg") ~(str "bold " color-name " background") 1 ~(+ 40 index)) 67 | (def-sgr-const ~(str color-name "-font") ~color-name ~(+ 30 index)) 68 | (def-sgr-const ~(str color-name "-bg-font") ~(str color-name " background") ~(+ 40 index)) 69 | (def-sgr-const ~(str "bold-" color-name "-font") ~(str "bold " color-name) 1 ~(+ 30 index)) 70 | (def-sgr-const ~(str "bold-" color-name "-bg-font") ~(str "bold " color-name " background") 1 ~(+ 40 index)))) 71 | ["black" "red" "green" "yellow" "blue" "magenta" "cyan" "white"]))) 72 | 73 | (define-colors) 74 | 75 | ;; ANSI defines quite a few more, but we're limiting to those that display properly in the 76 | ;; Cursive REPL. 77 | 78 | (defmacro ^:private define-fonts 79 | [] 80 | `(do 81 | ~@(for [[font-name code] [['bold 1] 82 | ['italic 3] 83 | ['inverse 7]]] 84 | `(do 85 | (def-sgr-fn ~font-name ~font-name ~code) 86 | (def-sgr-const ~(str font-name "-font") ~font-name ~code))))) 87 | 88 | (define-fonts) 89 | 90 | (def ^:const ^:private ansi-pattern (Pattern/compile "\\e\\[.*?m")) 91 | 92 | (defn ^String strip-ansi 93 | "Removes ANSI codes from a string, returning just the raw text." 94 | [string] 95 | (str/replace string ansi-pattern "")) 96 | 97 | (defn visual-length 98 | "Returns the length of the string, with ANSI codes stripped out." 99 | [string] 100 | (-> string strip-ansi .length)) 101 | -------------------------------------------------------------------------------- /boot/pod/test/boot/util_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.util-test 2 | (:require 3 | [clojure.test :refer :all] 4 | [boot.util :as util :refer :all])) 5 | 6 | (deftest dep-mgt-functions 7 | 8 | (let [project 'com.example/project 9 | version "1.2.3" 10 | scope "test" 11 | exclusions [['com.example/excl1 :extension "jar"] 12 | 'com.example/excl2]] 13 | 14 | (testing "simple dep-as-map conversions" 15 | (are [input expected] (= expected (dep-as-map input)) 16 | 17 | nil 18 | {:project nil 19 | :version nil 20 | :scope "compile"} 21 | 22 | [] 23 | {:project nil 24 | :version nil 25 | :scope "compile"} 26 | 27 | [project] 28 | {:project project 29 | :version nil 30 | :scope "compile"} 31 | 32 | [project version] 33 | {:project project 34 | :version version 35 | :scope "compile"} 36 | 37 | [project version :scope scope] 38 | {:project project 39 | :version version 40 | :scope scope} 41 | 42 | [project version :scope scope :exclusions exclusions] 43 | {:project project 44 | :version version 45 | :scope scope 46 | :exclusions exclusions} 47 | 48 | ;; checks that options with nil values are retained 49 | [project version :scope scope :exclusions exclusions :other nil] 50 | {:project project 51 | :version version 52 | :scope scope 53 | :exclusions exclusions 54 | :other nil} 55 | 56 | ;; checks that optional version with option works 57 | [project :scope scope] 58 | {:project project 59 | :version nil 60 | :scope scope})) 61 | 62 | (testing "simple map-as-dep conversions" 63 | (are [input expected] (= expected (map-as-dep input)) 64 | 65 | {} 66 | [] 67 | 68 | {:project project 69 | :version nil 70 | :scope "compile"} 71 | [project] 72 | 73 | {:project project 74 | :version version 75 | :scope "compile"} 76 | [project version] 77 | 78 | {:project project 79 | :version version 80 | :scope scope} 81 | [project version :scope scope] 82 | 83 | {:project project 84 | :version version 85 | :exclusions exclusions} 86 | [project version :exclusions exclusions] 87 | 88 | ;; checks that options with nil values are retained 89 | {:project project 90 | :version version 91 | :other nil} 92 | [project version :other nil] 93 | 94 | ;; checks that optional version with option works 95 | {:project project 96 | :version nil 97 | :scope scope} 98 | [project :scope scope])) 99 | 100 | (testing "roundtripping deps" 101 | 102 | (are [input] (= input (dep-as-map (map-as-dep input))) 103 | 104 | {:project project 105 | :version nil 106 | :scope "compile"} 107 | 108 | {:project project 109 | :version version 110 | :scope "compile"} 111 | 112 | {:project project 113 | :version version 114 | :scope scope} 115 | 116 | {:project project 117 | :version version 118 | :scope scope 119 | :exclusions exclusions} 120 | 121 | ;; checks that options with nil values are retained 122 | {:project project 123 | :version version 124 | :scope scope 125 | :exclusions exclusions 126 | :other nil} 127 | 128 | ;; checks that optional version with option works 129 | {:project project 130 | :version nil 131 | :scope scope})) 132 | 133 | (testing "check unusual arguments" 134 | (is (thrown? Exception (dep-as-map {}))) 135 | (is (= [] (map-as-dep nil))) 136 | (is (= [] (map-as-dep []))) 137 | (is (thrown? Exception (map-as-dep 3)))))) 138 | -------------------------------------------------------------------------------- /boot/pod/src/boot/gpg.clj: -------------------------------------------------------------------------------- 1 | (ns boot.gpg 2 | (:require 3 | [clojure.java.io :as io] 4 | [clojure.java.shell :as shell] 5 | [boot.pod :as pod] 6 | [boot.util :as util]) 7 | (:import [java.io StringReader File])) 8 | 9 | (defn ^{:boot/from :technomancy/leiningen} gpg-program 10 | "Lookup the gpg program to use, defaulting to 'gpg'" 11 | [] 12 | (or (boot.App/config "BOOT_GPG_COMMAND") "gpg")) 13 | 14 | (defn- ^{:boot/from :technomancy/leiningen} get-english-env [] 15 | "Returns environment variables as a map with clojure keywords and LANGUAGE set to 'en'" 16 | (let [env (System/getenv) 17 | keywords (map #(keyword %) (keys env))] 18 | (merge (zipmap keywords (vals env)) 19 | {:LANGUAGE "en"}))) 20 | 21 | (defn ^{:boot/from :technomancy/leiningen} gpg 22 | "Shells out to (gpg-program) with the given arguments" 23 | [& args] 24 | (let [env (get-english-env)] 25 | (try 26 | (shell/with-sh-env env 27 | (apply shell/sh (gpg-program) args)) 28 | (catch java.io.IOException e 29 | {:exit 1 :err (.getMessage e)})))) 30 | 31 | (defn ^{:boot/from :technomancy/leiningen} signing-args 32 | "Produce GPG arguments for signing a file." 33 | [file opts] 34 | (let [key-spec (if-let [key (:gpg-key opts)] 35 | ["--default-key" key]) 36 | passphrase-spec (if-let [pass (:gpg-passphrase opts)] 37 | ["--passphrase-fd" "0"]) 38 | passphrase-in-spec (if-let [pass (:gpg-passphrase opts)] 39 | [:in (StringReader. pass)])] 40 | `["--yes" "-ab" ~@key-spec ~@passphrase-spec "--" ~file ~@passphrase-in-spec])) 41 | 42 | (defn ^{:boot/from :technomancy/leiningen} sign 43 | "Create a detached signature and return the signature file name." 44 | [file opts] 45 | (let [{:keys [err exit]} (apply gpg (signing-args file opts))] 46 | (when-not (zero? exit) 47 | (util/fail (str "Could not sign " file "\n" err 48 | "\n\nIf you don't expect people to need to verify the " 49 | "authorship of your jar, don't set :gpg-sign option of push task to true.\n"))) 50 | (str file ".asc"))) 51 | 52 | (defn sign-it 53 | "Sign a java.io.File given the options." 54 | [f gpg-options] 55 | (slurp (sign (.getPath f) gpg-options))) 56 | 57 | (defn sign-pom 58 | "Materialize and sign the pom contained in jarfile. 59 | Returns an artifact-map entry - a map from partial coordinates to file 60 | path or File (see pomegranate/aether.clj for details). 61 | 62 | If you receive a \"Could not sign ... gpg: no default secret key: secret key 63 | not available\" error, make sure boot is using the right gpg executable. You 64 | can use the BOOT_GPG_COMMAND environment variable for that. 65 | 66 | In order to use gpg2, for instance, run: 67 | 68 | BOOT_GPG_COMMAND=gpg2 boot push --gpg-sign ... 69 | 70 | You rarely need to use this directly, use the push task instead." 71 | [outdir jarfile pompath gpg-options] 72 | (shell/with-sh-dir 73 | outdir 74 | (let [jarname (.getName jarfile) 75 | pomfile (doto (File/createTempFile "pom" ".xml") 76 | (.deleteOnExit) 77 | (spit (pod/pom-xml jarfile pompath))) 78 | pomout (io/file outdir (.replaceAll jarname "\\.jar$" ".pom.asc")) ] 79 | (spit pomout (sign-it pomfile gpg-options)) 80 | [[:extension "pom.asc"] (.getPath pomout)]))) 81 | 82 | (defn sign-jar 83 | "Sign a jar. 84 | 85 | Returns an artifact-map entry - a map from partial coordinates to file 86 | path or File (see pomegranate/aether.clj for details). 87 | 88 | If you receive a \"Could not sign ... gpg: no default secret key: secret key 89 | not available\" error, make sure boot is using the right gpg executable. You 90 | can use the BOOT_GPG_COMMAND environment variable for that. 91 | 92 | In order to use gpg2, for instance, run: 93 | 94 | BOOT_GPG_COMMAND=gpg2 boot push --gpg-sign ... 95 | 96 | You rarely need to use this directly, use the push task instead." 97 | [outdir jarfile gpg-options] 98 | (shell/with-sh-dir 99 | outdir 100 | (let [jarname (.getName jarfile) 101 | jarout (io/file outdir (str jarname ".asc"))] 102 | (spit jarout (sign-it jarfile gpg-options)) 103 | [[:extension "jar.asc"] (.getPath jarout)]))) 104 | 105 | (defn decrypt 106 | "Use gpg to decrypt a file -- returns string contents of file." 107 | [file] 108 | (let [path (.getPath (io/file file)) 109 | {:keys [out err exit]} (gpg "--quiet" "--batch" "--decrypt" "--" path)] 110 | (assert (zero? exit) err) 111 | out)) 112 | -------------------------------------------------------------------------------- /boot/aether/src/boot/ssl.clj: -------------------------------------------------------------------------------- 1 | (ns boot.ssl 2 | (:require 3 | [boot.util :as util] 4 | [cemerick.pomegranate.aether :as aether] 5 | [clojure.java.io :as io]) 6 | (:import 7 | java.security.KeyStore 8 | java.security.KeyStore$TrustedCertificateEntry 9 | java.security.Security 10 | java.security.cert.CertificateFactory 11 | javax.net.ssl.KeyManagerFactory 12 | javax.net.ssl.SSLContext 13 | javax.net.ssl.TrustManagerFactory 14 | javax.net.ssl.X509TrustManager 15 | java.io.FileInputStream 16 | org.apache.http.config.RegistryBuilder 17 | org.apache.http.conn.socket.PlainConnectionSocketFactory 18 | org.apache.http.conn.ssl.BrowserCompatHostnameVerifier 19 | org.apache.http.conn.ssl.SSLConnectionSocketFactory 20 | org.apache.http.impl.conn.PoolingHttpClientConnectionManager 21 | org.apache.maven.wagon.providers.http.HttpWagon)) 22 | 23 | (defn ^TrustManagerFactory trust-manager-factory [^KeyStore keystore] 24 | (doto (TrustManagerFactory/getInstance "PKIX") 25 | (.init keystore))) 26 | 27 | (defn ^{:boot/from :technomancy/leiningen} default-trust-managers [] 28 | (let [tmf (trust-manager-factory nil) 29 | tms (.getTrustManagers tmf)] 30 | (filter #(instance? X509TrustManager %) tms))) 31 | 32 | (defn key-manager-props [] 33 | (let [read #(java.lang.System/getProperty %)] 34 | (merge {:file (read "javax.net.ssl.keyStore") 35 | :type (read "javax.net.ssl.keyStoreType") 36 | :provider (read "javax.net.ssl.keyStoreProvider") 37 | :password (read "javax.net.ssl.keyStorePassword")} 38 | ;; TODO: support custom key-manager-properties 39 | {}))) 40 | 41 | (defn ^{:boot/from :technomancy/leiningen} key-manager-factory [{:keys [file type provider password]}] 42 | (let [type (or type (KeyStore/getDefaultType)) 43 | fis (if-not (empty? file) (FileInputStream. file)) 44 | pwd (and password (.toCharArray password)) 45 | store (if provider 46 | (KeyStore/getInstance type provider) 47 | (KeyStore/getInstance type))] 48 | (.load store fis pwd) 49 | (when fis (.close fis)) 50 | (doto (KeyManagerFactory/getInstance 51 | (KeyManagerFactory/getDefaultAlgorithm)) 52 | (.init store pwd)))) 53 | 54 | (defn ^{:boot/from :technomancy/leiningen} default-trusted-certs 55 | "Lists the CA certificates trusted by the JVM." 56 | [] 57 | (mapcat #(.getAcceptedIssuers %) (default-trust-managers))) 58 | 59 | (defn ^{:boot/from :technomancy/leiningen} read-certs 60 | "Read one or more X.509 certificates in DER or PEM format." 61 | [f] 62 | (try 63 | (let [cf (CertificateFactory/getInstance "X.509") 64 | in (io/input-stream (or (io/resource f) (io/file f)))] 65 | (.generateCertificates cf in)) 66 | (catch Exception _ 67 | (util/warn "Unable to read certificate: %s\n" f)))) 68 | 69 | (defn ^{:boot/from :technomancy/leiningen} make-keystore 70 | "Construct a KeyStore that trusts a collection of certificates." 71 | [certs] 72 | (let [ks (KeyStore/getInstance "jks")] 73 | (.load ks nil nil) 74 | (doseq [[i cert] (map vector (range) certs)] 75 | (.setEntry ks (str i) (KeyStore$TrustedCertificateEntry. cert) nil)) 76 | ks)) 77 | 78 | (defn ^{:boot/from :technomancy/leiningen} make-sslcontext 79 | "Construct an SSLContext that trusts a collection of certificates." 80 | [trusted-certs] 81 | (let [ks (make-keystore trusted-certs) 82 | kmf (key-manager-factory (key-manager-props)) 83 | tmf (trust-manager-factory ks)] 84 | (doto (SSLContext/getInstance "TLS") 85 | (.init (.getKeyManagers kmf) (.getTrustManagers tmf) nil)))) 86 | 87 | (alter-var-root #'make-sslcontext memoize) 88 | 89 | (defn ^{:boot/from :technomancy/leiningen} https-registry 90 | "Constructs a registry map that uses a given SSLContext for https." 91 | [context] 92 | (let [factory (SSLConnectionSocketFactory. context (BrowserCompatHostnameVerifier.))] 93 | {"https" factory 94 | "http" PlainConnectionSocketFactory/INSTANCE})) 95 | 96 | (defn- ^{:boot/from :technomancy/leiningen} map->registry 97 | "Creates a Registry based of the given map." 98 | [m] 99 | (let [rb (RegistryBuilder/create)] 100 | (doseq [[scheme conn-sock-factory] m] 101 | (.register rb scheme conn-sock-factory)) 102 | (.build rb))) 103 | 104 | (defn override-wagon-registry! 105 | "Override the registry scheme used by the HTTP Wagon's Connection 106 | manager (used for Aether)." 107 | [registry] 108 | (let [cm (PoolingHttpClientConnectionManager. (map->registry registry))] 109 | (HttpWagon/setPoolingHttpClientConnectionManager cm))) 110 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/io/aviso/repl.clj: -------------------------------------------------------------------------------- 1 | (ns boot.from.io.aviso.repl 2 | "Utilities to assist with REPL-oriented development" 3 | {:boot/from :AvisoNovate/pretty:0.1.34} 4 | (:require 5 | [boot.from.io.aviso.exception :as e] 6 | [clojure.pprint :refer [pprint write]] 7 | [clojure.main :as main] 8 | [clojure.repl :as repl] 9 | [clojure.stacktrace :as st] 10 | [clojure.edn :as edn] 11 | [boot.from.io.aviso.writer :as writer]) 12 | (:import 13 | (clojure.lang RT))) 14 | 15 | (defn- reset-var! 16 | [v override] 17 | (alter-var-root v (constantly override))) 18 | 19 | (defn- print-exception 20 | [e options] 21 | (print (e/format-exception e options)) 22 | (flush)) 23 | 24 | (defn pretty-repl-caught 25 | "A replacement for `clojure.main/repl-caught` that prints the exception to `*err*`, without a stack trace or properties." 26 | [e] 27 | (print-exception e {:frame-limit 0 :properties false})) 28 | 29 | (defn uncaught-exception-handler 30 | "Creates a reified UncaughtExceptionHandler that prints the formatted exception to `*err*`." 31 | {:added "0.1.18"} 32 | [] 33 | (reify Thread$UncaughtExceptionHandler 34 | (uncaughtException [_ _ t] 35 | (binding [*out* *err*] 36 | (printf "Uncaught exception in thread %s:%n" (-> (Thread/currentThread) .getName)) 37 | (e/write-exception t))))) 38 | 39 | 40 | (defn pretty-pst 41 | "Used as an override of `clojure.repl/pst` but uses pretty formatting." 42 | ([] (pretty-pst *e)) 43 | ([e-or-depth] 44 | (if (instance? Throwable e-or-depth) 45 | (print-exception e-or-depth nil) 46 | (pretty-pst *e e-or-depth))) 47 | ([e depth] (print-exception e {:frame-limit depth}))) 48 | 49 | (defn pretty-print-stack-trace 50 | "Replacement for `clojure.stacktrace/print-stack-trace` and `print-cause-trace`. These functions are used by `clojure.test`." 51 | ([tr] (pretty-print-stack-trace tr nil)) 52 | ([tr n] 53 | (println) 54 | (print-exception tr {:frame-limit n}))) 55 | 56 | (defn install-pretty-exceptions 57 | "Installs an override that outputs pretty exceptions when caught by the main REPL loop. Also, overrides 58 | `clojure.repl/pst`, `clojure.stacktrace/print-stack-trace`, `clojure.stacktrace/print-cause-trace`. 59 | 60 | In addition, installs an [[uncaught-exception-handler]] so that uncaught exceptions in non-REPL threads 61 | will be printed reasonably. See [[io.aviso.logging]] for a better handler, used when clojure.tools.logging 62 | is available. 63 | 64 | Caught exceptions do not print the stack trace; the pst replacement does." 65 | [] 66 | ;; TODO: Not exactly sure why this works, because clojure.main/repl should be resolving the var to its contained 67 | ;; function, so the override should not be visible. I'm missing something. 68 | (reset-var! #'main/repl-caught pretty-repl-caught) 69 | (reset-var! #'repl/pst pretty-pst) 70 | (reset-var! #'st/print-stack-trace pretty-print-stack-trace) 71 | (reset-var! #'st/print-cause-trace pretty-print-stack-trace) 72 | 73 | ;; This is necessary for Clojure 1.8 and above, due to direct linking 74 | ;; (from clojure.test to clojure.stacktrace). 75 | (RT/loadResourceScript "clojure/test.clj") 76 | 77 | (Thread/setDefaultUncaughtExceptionHandler (uncaught-exception-handler)) 78 | nil) 79 | 80 | (defn ^String copy 81 | "Copies the current contents of the Clipboard, returning its contents as a string. 82 | 83 | This makes use of AWT; it will throw java.awt.HeadlessException when AWT is not 84 | available, for example, when the JVM is launched with `-Djava.awt.headless=true`." 85 | {:added "0.1.32"} 86 | [] 87 | (require 'boot.from.io.aviso.clipboard) 88 | ((ns-resolve 'boot.from.io.aviso.clipboard 'copy))) 89 | 90 | (defn pretty-print 91 | "Pretty-prints the supplied object to a returned string. 92 | 93 | With no arguments, copies from the clipboard, parses as EDN, and prints the EDN data to `*out*`, 94 | returning nil." 95 | {:added "0.1.32"} 96 | ([] 97 | (-> (copy) edn/read-string pprint)) 98 | ([object] 99 | (write object 100 | :stream nil 101 | :pretty true))) 102 | 103 | (defn paste 104 | "Pastes a string in as the new content of the Clipboard. 105 | 106 | This can be helpful when, for example, pretty printing some EDN content from a log file 107 | before pasting it into some other editor." 108 | {:added "0.1.32"} 109 | [^String s] 110 | (require 'boot.from.io.aviso.clipboard) 111 | ((ns-resolve 'boot.from.io.aviso.clipboard 'paste) s)) 112 | 113 | (defn format-exception 114 | "Passed the standard exception text and formats it using [[parse-exception]] and 115 | [[write-exception]], returning the formatted exception text. 116 | 117 | With no arguments, parses the clipboard text and prints the formatted exception 118 | to `*out*` (returning nil)." 119 | {:added "0.1.32"} 120 | ([] 121 | (e/write-exception* *out* 122 | (-> (copy) 123 | (e/parse-exception nil)) 124 | nil)) 125 | ([text] 126 | (writer/into-string 127 | e/write-exception* (e/parse-exception text nil) nil))) 128 | -------------------------------------------------------------------------------- /boot/pod/src/boot/from/me/raynes/conch.clj: -------------------------------------------------------------------------------- 1 | ; (defproject me.raynes/conch "0.6.0" 2 | ; :license {:name "Eclipse Public License - v 1.0" 3 | ; :url "http://www.eclipse.org/legal/epl-v10.html"} 4 | ; :url "https://github.com/Raynes/conch" 5 | ; :description "A better shell-out library for Clojure.") 6 | 7 | (ns boot.from.me.raynes.conch 8 | "A simple but flexible library for shelling out from Clojure." 9 | {:boot/from :Raynes/conch} 10 | (:refer-clojure :exclude [flush read-line]) 11 | (:require [clojure.java.io :as io]) 12 | (:import (java.util.concurrent TimeUnit TimeoutException))) 13 | 14 | (defn proc 15 | "Spin off another process. Returns the process's input stream, 16 | output stream, and err stream as a map of :in, :out, and :err keys 17 | If passed the optional :dir and/or :env keyword options, the dir 18 | and enviroment will be set to what you specify. If you pass 19 | :verbose and it is true, commands will be printed. If it is set to 20 | :very, environment variables passed, dir, and the command will be 21 | printed. If passed the :clear-env keyword option, then the process 22 | will not inherit its environment from its parent process." 23 | [& args] 24 | (let [[cmd args] (split-with (complement keyword?) args) 25 | args (apply hash-map args) 26 | builder (ProcessBuilder. (into-array String cmd)) 27 | env (.environment builder)] 28 | (when (:clear-env args) 29 | (.clear env)) 30 | (doseq [[k v] (:env args)] 31 | (.put env k v)) 32 | (when-let [dir (:dir args)] 33 | (.directory builder (io/file dir))) 34 | (when (:verbose args) (apply println cmd)) 35 | (when (= :very (:verbose args)) 36 | (when-let [env (:env args)] (prn env)) 37 | (when-let [dir (:dir args)] (prn dir))) 38 | (when (:redirect-err args) 39 | (.redirectErrorStream builder true)) 40 | (let [process (.start builder)] 41 | {:out (.getInputStream process) 42 | :in (.getOutputStream process) 43 | :err (.getErrorStream process) 44 | :process process}))) 45 | 46 | (defn destroy 47 | "Destroy a process." 48 | [process] 49 | (.destroy (:process process))) 50 | 51 | ;; .waitFor returns the exit code. This makes this function useful for 52 | ;; both getting an exit code and stopping the thread until a process 53 | ;; terminates. 54 | (defn exit-code 55 | "Waits for the process to terminate (blocking the thread) and returns 56 | the exit code. If timeout is passed, it is assumed to be milliseconds 57 | to wait for the process to exit. If it does not exit in time, it is 58 | killed (with or without fire)." 59 | ([process] (.waitFor (:process process))) 60 | ([process timeout] 61 | (try 62 | (.get (future (.waitFor (:process process))) timeout TimeUnit/MILLISECONDS) 63 | (catch Exception e 64 | (if (or (instance? TimeoutException e) 65 | (instance? TimeoutException (.getCause e))) 66 | (do (destroy process) 67 | :timeout) 68 | (throw e)))))) 69 | 70 | (defn flush 71 | "Flush the output stream of a process." 72 | [process] 73 | (.flush (:in process))) 74 | 75 | (defn done 76 | "Close the process's output stream (sending EOF)." 77 | [proc] 78 | (-> proc :in .close)) 79 | 80 | (defn stream-to 81 | "Stream :out or :err from a process to an ouput stream. 82 | Options passed are fed to clojure.java.io/copy. They are :encoding to 83 | set the encoding and :buffer-size to set the size of the buffer. 84 | :encoding defaults to UTF-8 and :buffer-size to 1024." 85 | [process from to & args] 86 | (apply io/copy (process from) to args)) 87 | 88 | (defn feed-from 89 | "Feed to a process's input stream with optional. Options passed are 90 | fed to clojure.java.io/copy. They are :encoding to set the encoding 91 | and :buffer-size to set the size of the buffer. :encoding defaults to 92 | UTF-8 and :buffer-size to 1024. If :flush is specified and is false, 93 | the process will be flushed after writing." 94 | [process from & {flush? :flush :or {flush? true} :as all}] 95 | (apply io/copy from (:in process) all) 96 | (when flush? (flush process))) 97 | 98 | (defn stream-to-string 99 | "Streams the output of the process to a string and returns it." 100 | [process from & args] 101 | (with-open [writer (java.io.StringWriter.)] 102 | (apply stream-to process from writer args) 103 | (str writer))) 104 | 105 | ;; The writer that Clojure wraps System/out in for *out* seems to buffer 106 | ;; things instead of writing them immediately. This wont work if you 107 | ;; really want to stream stuff, so we'll just skip it and throw our data 108 | ;; directly at System/out. 109 | (defn stream-to-out 110 | "Streams the output of the process to System/out" 111 | [process from & args] 112 | (apply stream-to process from (System/out) args)) 113 | 114 | (defn feed-from-string 115 | "Feed the process some data from a string." 116 | [process s & args] 117 | (apply feed-from process (java.io.StringReader. s) args)) 118 | 119 | (defn read-line 120 | "Read a line from a process' :out or :err." 121 | [process from] 122 | (binding [*in* (io/reader (from process))] 123 | (clojure.core/read-line))) 124 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/AbstractWatchService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | import java.io.IOException; 29 | import java.util.concurrent.LinkedBlockingDeque; 30 | import java.util.concurrent.TimeUnit; 31 | 32 | /** 33 | * Base implementation class for watch services. 34 | */ 35 | 36 | abstract class AbstractWatchService extends WatchService { 37 | 38 | // signaled keys waiting to be dequeued 39 | private final LinkedBlockingDeque pendingKeys = 40 | new LinkedBlockingDeque(); 41 | 42 | // special key to indicate that watch service is closed 43 | private final WatchKey CLOSE_KEY = new AbstractWatchKey(null) { 44 | @Override 45 | public boolean isValid() { 46 | return true; 47 | } 48 | 49 | @Override 50 | public void cancel() { 51 | } 52 | }; 53 | 54 | // used when closing watch service 55 | private volatile boolean closed; 56 | private final Object closeLock = new Object(); 57 | 58 | protected AbstractWatchService() { 59 | } 60 | 61 | /** 62 | * Register the given object with this watch service 63 | */ 64 | abstract WatchKey register(WatchableFile watchableFile, 65 | WatchEvent.Kind[] events, 66 | WatchEvent.Modifier... modifers) 67 | throws IOException; 68 | 69 | // used by AbstractWatchKey to enqueue key 70 | final void enqueueKey(WatchKey key) { 71 | pendingKeys.offer(key); 72 | } 73 | 74 | /** 75 | * Throws ClosedWatchServiceException if watch service is closed 76 | */ 77 | private void checkOpen() { 78 | if (closed) 79 | throw new ClosedWatchServiceException(); 80 | } 81 | 82 | /** 83 | * Checks the key isn't the special CLOSE_KEY used to unblock threads when 84 | * the watch service is closed. 85 | */ 86 | private void checkKey(WatchKey key) { 87 | if (key == CLOSE_KEY) { 88 | // re-queue in case there are other threads blocked in take/poll 89 | enqueueKey(key); 90 | } 91 | checkOpen(); 92 | } 93 | 94 | @Override 95 | public final WatchKey poll() { 96 | checkOpen(); 97 | WatchKey key = pendingKeys.poll(); 98 | checkKey(key); 99 | return key; 100 | } 101 | 102 | @Override 103 | public final WatchKey poll(long timeout, TimeUnit unit) 104 | throws InterruptedException { 105 | checkOpen(); 106 | WatchKey key = pendingKeys.poll(timeout, unit); 107 | checkKey(key); 108 | return key; 109 | } 110 | 111 | @Override 112 | public final WatchKey take() 113 | throws InterruptedException { 114 | checkOpen(); 115 | WatchKey key = pendingKeys.take(); 116 | checkKey(key); 117 | return key; 118 | } 119 | 120 | /** 121 | * Tells whether or not this watch service is open. 122 | */ 123 | final boolean isOpen() { 124 | return !closed; 125 | } 126 | 127 | /** 128 | * Retrieves the object upon which the close method synchronizes. 129 | */ 130 | final Object closeLock() { 131 | return closeLock; 132 | } 133 | 134 | /** 135 | * Closes this watch service. This method is invoked by the close 136 | * method to perform the actual work of closing the watch service. 137 | */ 138 | abstract void implClose() throws IOException; 139 | 140 | @Override 141 | public final void close() 142 | throws IOException { 143 | synchronized (closeLock) { 144 | // nothing to do if already closed 145 | if (closed) 146 | return; 147 | closed = true; 148 | 149 | implClose(); 150 | 151 | // clear pending keys and queue special key to ensure that any 152 | // threads blocked in take/poll wakeup 153 | pendingKeys.clear(); 154 | pendingKeys.offer(CLOSE_KEY); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /boot/worker/src/boot/watcher.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2013 Google Inc. 2 | ; 3 | ; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ; you may not use this file except in compliance with the License. 5 | ; You may obtain a copy of the License at 6 | ; 7 | ; http://www.apache.org/licenses/LICENSE-2.0 8 | ; 9 | ; Unless required by applicable law or agreed to in writing, software 10 | ; distributed under the License is distributed on an "AS IS" BASIS, 11 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ; See the License for the specific language governing permissions and 13 | ; limitations under the License. 14 | 15 | (ns boot.watcher 16 | {:boot/from :google/hesokuri 17 | :doc "This file was modified by micha.niskin@gmail.com."} 18 | (:import 19 | [java.nio.file FileSystems Path Paths StandardWatchEventKinds] 20 | [com.barbarysoftware.watchservice StandardWatchEventKind WatchableFile]) 21 | (:require 22 | [clojure.java.io :as io] 23 | [boot.util :as util])) 24 | 25 | (defprotocol IRegister 26 | (register [this path events]) 27 | (enum->kw [this x])) 28 | 29 | (extend-type java.nio.file.WatchService 30 | IRegister 31 | (register [service path events] 32 | (let [path (Paths/get (str path) (into-array String [])) 33 | events (into-array (map {:create StandardWatchEventKinds/ENTRY_CREATE 34 | :modify StandardWatchEventKinds/ENTRY_MODIFY 35 | :delete StandardWatchEventKinds/ENTRY_DELETE} 36 | events))] 37 | (.register path service events))) 38 | (enum->kw [this x] 39 | (-> {StandardWatchEventKinds/ENTRY_CREATE :create 40 | StandardWatchEventKinds/ENTRY_MODIFY :modify 41 | StandardWatchEventKinds/ENTRY_DELETE :delete} 42 | (get x)))) 43 | 44 | (extend-type com.barbarysoftware.watchservice.WatchService 45 | IRegister 46 | (register [service path events] 47 | (let [path (WatchableFile. (io/file path)) 48 | events (into-array (map {:create StandardWatchEventKind/ENTRY_CREATE 49 | :modify StandardWatchEventKind/ENTRY_MODIFY 50 | :delete StandardWatchEventKind/ENTRY_DELETE} 51 | events))] 52 | (.register path service events))) 53 | (enum->kw [this x] 54 | (-> {StandardWatchEventKind/ENTRY_CREATE :create 55 | StandardWatchEventKind/ENTRY_MODIFY :modify 56 | StandardWatchEventKind/ENTRY_DELETE :delete} 57 | (get x)))) 58 | 59 | (defn- register-recursive 60 | [service path events ignore-patterns] 61 | (when (and @util/*watchers?* 62 | (not-any? #(re-find % (str path)) ignore-patterns)) 63 | (util/dbug* "registering %s %s\n" path events) 64 | (register service path events) 65 | (doseq [dir (.listFiles (io/file path))] 66 | (when (.isDirectory dir) 67 | (register-recursive service dir events ignore-patterns))))) 68 | 69 | (defn- new-watch-service [] 70 | (if (= "Mac OS X" (System/getProperty "os.name")) 71 | ;; Use barbarywatchservice library for Mac OS X so we can avoid polling. 72 | (com.barbarysoftware.watchservice.WatchService/newWatchService) 73 | 74 | ;; Use java.nio file system watcher 75 | (.newWatchService (FileSystems/getDefault)))) 76 | 77 | (defn- take-watch-key [service] 78 | (try 79 | (.take service) 80 | (catch java.nio.file.ClosedWatchServiceException _ 81 | (util/dbug* "watch service closed\n")) 82 | (catch com.barbarysoftware.watchservice.ClosedWatchServiceException _ 83 | (util/dbug* "watch service closed\n")))) 84 | 85 | (defn- send-it! 86 | [queue] 87 | ;; It doesn't matter what we send because the information in the watch keys 88 | ;; is completely unreliable and useless, so we send the sentinel "changed!". 89 | (util/dbug* "sending change event\n") 90 | (.offer queue "changed!")) 91 | 92 | (defn- service 93 | [queue paths ignore-patterns] 94 | (let [service (new-watch-service) 95 | doreg #(register-recursive %1 %2 [:create :modify :delete] ignore-patterns)] 96 | (doseq [path paths] (doreg service (io/file path))) 97 | (-> #(let [watch-key (take-watch-key service)] 98 | (when-let [path (and watch-key (or (.watchable watch-key) ""))] 99 | (if-not (.isValid watch-key) 100 | (util/dbug* "invalid watch key %s\n" (.watchable watch-key)) 101 | (do (doseq [event (.pollEvents watch-key)] 102 | (let [dir (.toFile path) 103 | changed (io/file dir (str (.context event))) 104 | etype (enum->kw service (.kind event)) 105 | dir? (.isDirectory changed)] 106 | (util/dbug* "event: %s %s %s\n" etype dir? path) 107 | (when (and dir? (= :create etype)) 108 | (try (doreg service changed) 109 | (catch Throwable t 110 | (util/dbug* "error registering %s: %s\n" path t)))))) 111 | (when-not (.reset watch-key) 112 | (util/dbug* "failed to reset watch key %s\n" path)))) 113 | (send-it! queue) 114 | (recur))) 115 | Thread. .start) 116 | service)) 117 | 118 | (def ^:private watchers (atom {})) 119 | 120 | (defn stop-watcher 121 | [k] 122 | (when-let [w (@watchers k)] (.close w))) 123 | 124 | (defn make-watcher 125 | [queue paths & {:keys [ignore]}] 126 | (let [k (str (gensym)) 127 | s (service queue paths ignore)] 128 | (swap! watchers assoc k s) 129 | (send-it! queue) 130 | k)) 131 | -------------------------------------------------------------------------------- /boot/pod/src/boot/xform.clj: -------------------------------------------------------------------------------- 1 | (ns boot.xform 2 | (:require 3 | [boot.util :as util]) 4 | (:import 5 | [java.lang.reflect Modifier])) 6 | 7 | (def ^:dynamic *for-eval* nil) 8 | (def ^:dynamic *from-pod* nil) 9 | (def ^:dynamic *to-pod* nil) 10 | 11 | (declare ->clj*) 12 | 13 | (defn- log-unhandled-type 14 | "Use to debug strange new types that aren't transformed correctly." 15 | [x] 16 | (util/dbug* "Xform: unhandled type: %s\n" (.. x getClass getName))) 17 | 18 | (defn- static-field? 19 | "Is this Field static?" 20 | [x] 21 | (pos? (bit-and Modifier/STATIC (.getModifiers x)))) 22 | 23 | (defn- reflect-record? 24 | "Is this object a Clojure record from another pod?" 25 | [x] 26 | (->> x .getClass .getInterfaces (some #(= "clojure.lang.IRecord" (.getName %))))) 27 | 28 | (defn- reflect-fn? 29 | "Is this object a Clojure function from another pod?" 30 | [x] 31 | (#{"clojure.lang.AFunction" "clojure.lang.RestFn"} (.. x getClass getSuperclass getName))) 32 | 33 | (defn- reflect-record-args 34 | "Extract the constructor args for this Clojure record from another pod and 35 | translate them into data compatible with this pod." 36 | [x] 37 | (->> x .getClass .getDeclaredFields 38 | (reduce #(if (static-field? %2) %1 (conj %1 (->clj* (.get %2 x)))) []))) 39 | 40 | (defn- reflect-impl-class 41 | "Returns Class x or the first superclass of x that implements the interface 42 | named iface-name, or nil if the interface is not implemented by x or any of 43 | its superclasses." 44 | [x iface-name] 45 | (loop [c (.getClass x)] 46 | (when c 47 | (let [ifs (map #(.getName %) (.getInterfaces c))] 48 | (if ((set ifs) iface-name) c (recur (.getSuperclass c))))))) 49 | 50 | (defn- meta->clj 51 | "Extract the metadata on x and translate it to be compatible with this pod." 52 | [x] 53 | (->clj* (-> (reflect-impl-class x "clojure.lang.IObj") 54 | (.getMethod "meta" (into-array Class [])) 55 | (.invoke x (into-array Object []))))) 56 | 57 | (defn- record->clj 58 | "Create a new record in this pod that is equivalent to x from another pod." 59 | [x] 60 | (eval (list* (-> x .getClass .getName (str ".") symbol) (reflect-record-args x)))) 61 | 62 | (defn- <-clj 63 | "Perform a reverse translation, translating data compatible with this pod to 64 | data compatible with another pod. Must be called in a future if there is any 65 | chance that *from-pod* is the pod in which this code is run." 66 | [x] 67 | (-> *from-pod* .get (.invoke "boot.xform/->clj" *to-pod* *from-pod* x))) 68 | 69 | (defn- fn->clj 70 | "Wrap the function x from another pod in a function from this pod that will 71 | do all necessary translation of arguments and use reflection to call the 72 | original function implementation. The result is translated to be compatible 73 | with this pod." 74 | [x] 75 | (bound-fn [& args] 76 | (let [param (into-array Class (repeat (count args) Object)) 77 | args (into-array Object @(future (<-clj args)))] 78 | (-> x .getClass (.getMethod "invoke" param) (.invoke x args) ->clj*)))) 79 | 80 | (defn- ->clj* 81 | "Translate x to data compatible with this pod. Assumes the following dynamic 82 | vars are correctly bound: *from-pod*, *to-pod*, and *for-eval*." 83 | [x] 84 | (when-not (nil? x) 85 | (case (.. x getClass getName) 86 | ;; EDN types (can be passed to eval) 87 | "clojure.lang.MapEntry" 88 | (into [] (map ->clj* x)) 89 | "clojure.lang.PersistentVector" 90 | (with-meta (into [] (map ->clj* x)) (meta->clj x)) 91 | ("clojure.lang.PersistentHashMap" 92 | "clojure.lang.PersistentArrayMap") 93 | (with-meta (into {} (map ->clj* x)) (meta->clj x)) 94 | ("clojure.lang.Cons" 95 | "clojure.lang.LazySeq" 96 | "clojure.lang.ArraySeq" 97 | "clojure.lang.ChunkedCons" 98 | "clojure.lang.PersistentList" 99 | "clojure.lang.APersistentMap$KeySeq") 100 | (with-meta (doall (map ->clj* x)) (meta->clj x)) 101 | "clojure.lang.PersistentList$EmptyList" 102 | (with-meta () (meta->clj x)) 103 | "clojure.lang.PersistentHashSet" 104 | (with-meta (into #{} (map ->clj* x)) (meta->clj x)) 105 | "clojure.lang.Keyword" 106 | (-> x str (subs 1) keyword) 107 | "clojure.lang.Symbol" 108 | (with-meta (-> x str symbol) (meta->clj x)) 109 | "clojure.lang.Ratio" 110 | (let [c (.getClass x) 111 | n (.. c (getDeclaredField "numerator") (get x)) 112 | d (.. c (getDeclaredField "denominator") (get x))] 113 | (clojure.lang.Ratio. n d)) 114 | "clojure.lang.BigInt" 115 | (let [c (.getClass x) 116 | l (.. c (getDeclaredField "lpart") (get x)) 117 | b (.. c (getDeclaredField "bipart") (get x)) 118 | C (-> c .getDeclaredConstructors (aget 0) (doto (.setAccessible true)))] 119 | (.newInstance C (into-array Object [l b]))) 120 | ("java.lang.Boolean" 121 | "java.lang.String" 122 | "java.lang.Long" 123 | "java.lang.Double" 124 | "java.lang.Integer" 125 | "java.lang.Character" 126 | "java.util.regex.Pattern") 127 | x 128 | ;; Non-EDN types (cannot be passed to eval without stashing) 129 | (let [x (cond (reflect-fn? x) (with-meta (fn->clj x) (meta->clj x)) 130 | (reflect-record? x) (record->clj x) 131 | :else (doto x (log-unhandled-type)))] 132 | ;; Stash if result will be sent to eval 133 | (if-not *for-eval* x `(boot.App/getStash ~(boot.App/setStash x))))))) 134 | 135 | (defn ->clj 136 | [from-pod to-pod x & {:keys [for-eval]}] 137 | (binding [*from-pod* from-pod 138 | *to-pod* to-pod 139 | *for-eval* for-eval] 140 | (->clj* x))) 141 | 142 | -------------------------------------------------------------------------------- /boot/worker/src/boot/pom.clj: -------------------------------------------------------------------------------- 1 | (ns boot.pom 2 | (:refer-clojure :exclude [name]) 3 | (:require 4 | [clojure.java.io :as io] 5 | [boot.pod :as pod] 6 | [boot.file :as file] 7 | [boot.util :as util] 8 | [boot.xml :as xml] 9 | [clojure.xml :refer [parse]] 10 | [clojure.zip :refer [xml-zip]] 11 | [clojure.data.zip.xml :refer [attr text xml-> xml1->]]) 12 | (:import 13 | [java.util Properties] 14 | [java.io ByteArrayInputStream] 15 | [java.util.jar JarEntry JarOutputStream])) 16 | 17 | ;;; elements ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | 19 | (xml/decelems 20 | artifactId connection description dependencies dependency exclusion 21 | exclusions developerConnection enabled groupId id license licenses 22 | modelVersion name email project scope tag url scm version comments 23 | developer developers packaging classifier parent relativePath) 24 | 25 | ;;; private ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 26 | 27 | (defn pom-parent-parse [z] 28 | (let [gid (util/guard (xml1-> z :groupId text)) 29 | aid (util/guard (xml1-> z :artifactId text)) 30 | v (util/guard (xml1-> z :version text)) 31 | dep (when aid 32 | (if (= gid aid) 33 | [(symbol aid) v] 34 | [(symbol gid aid) v])) 35 | rp (util/guard (xml1-> z :relativePath text))] 36 | {:dependency dep 37 | :relative-path rp})) 38 | 39 | (defn pom-xml-parse-string [xml-str] 40 | (let [z (-> xml-str .getBytes ByteArrayInputStream. parse xml-zip) 41 | gid (util/guard (xml1-> z :groupId text)) 42 | aid (util/guard (xml1-> z :artifactId text)) 43 | parent-z (util/guard (xml1-> z :parent))] 44 | {:project (util/guard (if (= gid aid) (symbol aid) (symbol gid aid))) 45 | :version (util/guard (xml1-> z :version text)) 46 | :description (util/guard (xml1-> z :description text)) 47 | :classifier (util/guard (xml1-> z :classifier text)) 48 | :url (util/guard (xml1-> z :url text)) 49 | :parent (when parent-z (pom-parent-parse parent-z)) 50 | :scm {:url (util/guard (xml1-> z :scm :url text)) 51 | :tag (util/guard (xml1-> z :scm :tag text))}})) 52 | 53 | (defn pom-xml-parse 54 | ([jarpath] 55 | (pom-xml-parse jarpath nil)) 56 | ([jarpath pompath] 57 | (pom-xml-parse-string (pod/pom-xml jarpath pompath)))) 58 | 59 | (defn pom-xml [{p :project 60 | v :version 61 | d :description 62 | pkg :packaging 63 | l :license 64 | {su :url 65 | st :tag 66 | sc :connection 67 | sd :developerConnection} :scm 68 | ds :developers 69 | u :url 70 | c :classifier 71 | deps :dependencies 72 | prnt :parent 73 | :as env}] 74 | (let [[g a] (util/extract-ids p) 75 | ls (map (fn [[name url]] {:name name :url url}) l)] 76 | (project 77 | :xmlns "http://maven.apache.org/POM/4.0.0" 78 | :xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance" 79 | :xsi:schemaLocation "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" 80 | (modelVersion "4.0.0") 81 | (when prnt 82 | (let [[p v & {rp :relative-path}] prnt 83 | [g a] (util/extract-ids p)] 84 | (parent 85 | (groupId g) 86 | (artifactId a) 87 | (version v) 88 | (when rp 89 | (relativePath rp))))) 90 | (groupId g) 91 | (artifactId a) 92 | (version v) 93 | (name a) 94 | (description d) 95 | (url u) 96 | (licenses 97 | (for [{ln :name lu :url lc :comments} ls] 98 | (license 99 | (url lu) 100 | (name ln) 101 | (comments lc)))) 102 | (when pkg 103 | (packaging pkg)) 104 | (when c 105 | (classifier c)) 106 | (when (or su st sc sd) 107 | (scm 108 | (when sc (connection sc)) 109 | (when sd (developerConnection sd)) 110 | (when su (url su)) 111 | (when st (tag st)))) 112 | (when-let [ds (seq ds)] 113 | (developers 114 | (for [[n e] ds] 115 | (developer 116 | (name n) 117 | (email e))))) 118 | (dependencies 119 | (for [[p v & {es :exclusions s :scope}] deps 120 | :let [[g a] (util/extract-ids p)]] 121 | (dependency 122 | (groupId g) 123 | (artifactId a) 124 | (version v) 125 | (scope (or s "compile")) 126 | (exclusions 127 | (for [p es :let [[g a] (util/extract-ids p)]] 128 | (exclusion 129 | (groupId g) 130 | (artifactId a)))))))))) 131 | 132 | ;;; public ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 133 | 134 | (defn spit-pom! [xmlpath proppath {:keys [project version] :as env}] 135 | (let [[gid aid] (util/extract-ids project) 136 | prop (doto (Properties.) 137 | (.setProperty "groupId" gid) 138 | (.setProperty "artifactId" aid) 139 | (.setProperty "version" version)) 140 | xmlfile (doto (io/file xmlpath) io/make-parents) 141 | propfile (doto (io/file proppath) io/make-parents)] 142 | (spit xmlfile (pr-str (pom-xml env))) 143 | (with-open [s (io/output-stream propfile)] 144 | (.store prop s (str gid "/" aid " " version " property file"))))) 145 | -------------------------------------------------------------------------------- /boot/core/test/boot/task/built_in_test.clj: -------------------------------------------------------------------------------- 1 | (ns boot.task.built-in-test 2 | (:require [clojure.pprint :refer [pprint]] 3 | [clojure.test :refer :all] 4 | [boot.core :refer :all] 5 | [boot.task.built-in :refer :all] 6 | [boot.test :as boot-test :refer [deftesttask]] 7 | [boot.pod :as pod])) 8 | 9 | ;;;;;;;;;;;;;;;;;;;;;;;;; 10 | ;;; sift --with-meta ;;; 11 | ;;;;;;;;;;;;;;;;;;;;;;;;; 12 | 13 | (deftask ^:private with-meta-tests [] 14 | (with-pass-thru fileset 15 | (let [tmpfiles (output-files fileset) 16 | tmpfiles-with-meta (filter :boot-test-tag tmpfiles) 17 | tmpfiles-clj (by-re [#".clj$"] tmpfiles)] 18 | (is (= tmpfiles-with-meta tmpfiles-clj) "only .clj files should result from sift :with-meta #{boot-test-tag}")) 19 | fileset)) 20 | 21 | (deftesttask sift-with-meta-tests [] 22 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"}) ;; populate 23 | (sift :add-meta {#".clj$" :boot-test-tag}) 24 | (sift :with-meta #{:boot-test-tag}) 25 | (with-meta-tests))) 26 | 27 | (deftask ^:private with-meta-invert-tests [] 28 | (with-pass-thru fileset 29 | (let [tmpfiles (output-files fileset) 30 | tmpfiles-without-meta (remove :boot-test-tag tmpfiles) 31 | tmpfiles-clj (by-re [#".clj$"] tmpfiles)] 32 | (is (not (= tmpfiles-without-meta tmpfiles-clj)) "only non .clj files should result from sift :with-meta #{boot-test-tag} invert")) 33 | fileset)) 34 | 35 | (deftesttask sift-with-meta-invert-tests [] 36 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"}) ;; populate 37 | (sift :add-meta {#".clj$" :boot-test-tag}) 38 | (sift :with-meta #{:boot-test-tag} :invert true) 39 | (with-meta-invert-tests))) 40 | 41 | ;;;;;;;;;;;;;;;;;;;;;;; 42 | ;;; sift --include ;;; 43 | ;;;;;;;;;;;;;;;;;;;;;;; 44 | 45 | (deftask ^:private include-tests [] 46 | (with-pass-thru fileset 47 | (let [tmpfiles (output-files fileset) 48 | tmpfiles-clj-mf (by-re [#".clj$" #".MF$"] tmpfiles) 49 | tmpfiles-others (not-by-re [#".clj$" #".MF$"] tmpfiles)] 50 | (is (not (empty? tmpfiles-clj-mf)) ".clj and .MD files should be in output") 51 | (is (empty? tmpfiles-others) "Output files (no .clj and .MD) should be empty")) 52 | fileset)) 53 | 54 | (deftesttask sift-include-tests [] 55 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"}) ;; populate 56 | (sift :include #{#".clj$" #".MD$"}) 57 | (include-tests))) 58 | 59 | (deftask ^:private include-invert-tests [] 60 | (with-pass-thru fileset 61 | (let [tmpfiles (output-files fileset) 62 | tmpfiles-clj-mf (by-re [#".clj$" #".MF$"] tmpfiles) 63 | tmpfiles-others (not-by-re [#".clj$" #".MF$"] tmpfiles)] 64 | (is (empty? tmpfiles-clj-mf) ".clj and .MD files should not be in output") 65 | (is (not (empty? tmpfiles-others)) "Output files (no .clj and .MD) should not be empty")))) 66 | 67 | (deftesttask sift-include-invert-tests [] 68 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"}) ;; populate 69 | (sift :include #{#"\.clj$" #"\.MF$"} :invert true) 70 | (include-invert-tests))) 71 | 72 | ;;;;;;;;;;;;;;;;;;;;;;;; 73 | ;;; sift --to-asset ;;; 74 | ;;;;;;;;;;;;;;;;;;;;;;;; 75 | 76 | ;; AR - adding this in order to test sift-mv 77 | 78 | (deftask ^:private to-asset-tests [] 79 | (with-pass-thru fileset 80 | (let [mf-input-files (by-re [#".*\.MF$"] (input-files fileset)) 81 | mf-output-files (by-re [#".*\.MF$"] (output-files fileset))] 82 | (is (empty? mf-input-files) "The .MF files should not have input role") 83 | (is (not (empty? mf-output-files)) "The .MF files should have output role")))) 84 | 85 | (deftesttask sift-to-asset-tests [] 86 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"} ;; populate 87 | :to-asset #{#".*\.MF$"}) 88 | (to-asset-tests))) 89 | 90 | (deftask ^:private to-asset-invert-tests [] 91 | (with-pass-thru fileset 92 | (let [non-mf-input-files (not-by-re [#".*\.MF$"] (input-files fileset)) 93 | non-mf-output-files (not-by-re [#".*\.MF$"] (output-files fileset))] 94 | (is (empty? non-mf-input-files) "The .MF files should not have input role") 95 | (is (not (empty? non-mf-output-files)) "The .MF files should have output role")))) 96 | 97 | (deftesttask sift-to-asset-invert-tests [] 98 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"} ;; populate 99 | :to-asset #{#".*\.MF$"} 100 | :invert true) 101 | (to-asset-invert-tests))) 102 | 103 | ;;;;;;;;;;;;;;;;;;;;;;;; 104 | ;;; sift --add-meta ;;; 105 | ;;;;;;;;;;;;;;;;;;;;;;;; 106 | 107 | (deftask ^:private add-meta-tests [] 108 | (with-pass-thru fileset 109 | (let [tmpfiles (output-files fileset) 110 | tmpfiles-with-meta (filter :boot-test-tag tmpfiles)] 111 | (is (empty? (not-by-re [#".clj$"] tmpfiles-with-meta)) "non .clj files should not have :boot-test-tag metadata") 112 | (is (seq (by-re [#".clj$"] tmpfiles-with-meta)) "only .clj files should have :boot-test-tag metadata")))) 113 | 114 | (deftesttask sift-add-meta-tests [] 115 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"}) ;; populate 116 | (sift :add-meta {#".clj$" :boot-test-tag}) 117 | (add-meta-tests))) 118 | 119 | (deftask ^:private add-meta-invert-tests [] 120 | (with-pass-thru fileset 121 | (let [tmpfiles (output-files fileset) 122 | tmpfiles-with-meta (filter :boot-test-tag tmpfiles)] 123 | (is (empty? (by-re [#".clj$"] tmpfiles-with-meta)) ".clj files should not have :boot-test-tag metadata") 124 | (is (seq (not-by-re [#".clj$"] tmpfiles-with-meta)) "only non .clj files should have :boot-test-tag metadata")))) 125 | 126 | (deftesttask sift-add-meta-invert-tests [] 127 | (comp (sift :add-jar {'org.clojure/tools.reader #".*"}) ;; populate 128 | (sift :add-meta {#".clj$" :boot-test-tag} :invert true) 129 | (add-meta-invert-tests))) 130 | -------------------------------------------------------------------------------- /boot/core/src/boot/task_helpers.clj: -------------------------------------------------------------------------------- 1 | (ns boot.task-helpers 2 | (:require 3 | [clojure.java.io :as io] 4 | [clojure.set :as set] 5 | [clojure.string :as string] 6 | [clojure.stacktrace :as trace] 7 | [boot.from.io.aviso.ansi :as ansi] 8 | [boot.from.digest :as digest] 9 | [boot.pod :as pod] 10 | [boot.core :as core] 11 | [boot.file :as file] 12 | [boot.util :as util] 13 | [boot.tmpdir :as tmpd])) 14 | 15 | 16 | (defn- first-line [s] (when s (first (string/split s #"\n")))) 17 | 18 | (defn- tasks-table [tasks] 19 | (let [get-task #(-> % :name str) 20 | get-desc #(-> % :doc first-line) 21 | built-in {nil (get tasks 'boot.task.built-in)}] 22 | (->> (dissoc tasks 'boot.task.built-in) 23 | (concat built-in) (interpose nil) 24 | (mapcat (fn [[_ xs]] (or xs [{:name "" :doc ""}]))) 25 | (mapv (fn [x] ["" (get-task x) (get-desc x)]))))) 26 | 27 | (defn- set-title [[[_ & xs] & zs] title] (into [(into [title] xs)] zs)) 28 | 29 | (defn- available-tasks [sym] 30 | (let [base {nil (the-ns sym)} 31 | task? #(:boot.core/task %) 32 | nssym #(->> % meta :ns ns-name) 33 | addrf #(if-not (seq %1) %2 (symbol %1 (str %2))) 34 | proc (fn [a [k v]] (assoc (meta v) :ns* (nssym v) :name (addrf a k) :var v)) 35 | pubs (fn [[k v]] (map proc (repeat (str k)) (ns-publics v)))] 36 | (->> 37 | (concat 38 | (->> sym ns-refers (map proc (repeat nil))) 39 | (->> sym ns-aliases (into base) (mapcat pubs))) 40 | (filter task?) (sort-by :name) (group-by :ns*) (into (sorted-map))))) 41 | 42 | (defn read-pass 43 | [prompt] 44 | (String/valueOf (.readPassword (System/console) prompt nil))) 45 | 46 | (defn print-fileset 47 | [fileset] 48 | (letfn [(tree [xs] 49 | (when-let [xs (seq (remove nil? xs))] 50 | (->> (group-by first xs) 51 | (reduce-kv #(let [t (->> %3 (map (comp seq rest)) tree)] 52 | (assoc %1 (if (map? t) (ansi/bold-blue %2) %2) t)) 53 | (sorted-map-by #(->> %& (map ansi/strip-ansi) (apply compare)))))))] 54 | (let [tmpfiles (core/ls fileset) 55 | split-paths (map (comp file/split-path core/tmp-path) tmpfiles)] 56 | (util/print-tree [["" (into #{} (tree split-paths))]])))) 57 | 58 | ;; sift helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 59 | 60 | (defn- sift-match 61 | [invert? regexes] 62 | (fn [path tmpfile] 63 | ((if-not invert? identity not) 64 | (some #(re-find % path) regexes)))) 65 | 66 | (defn- sift-meta 67 | [invert? kws] 68 | (fn [path tmpfile] 69 | (some (comp (if-not invert? identity not) 70 | (partial contains? kws)) (keys tmpfile)))) 71 | 72 | (defn- sift-mv 73 | [rolekey invert? optargs] 74 | (fn [fileset] 75 | (let [match? (sift-match invert? optargs) 76 | dir (#'core/get-add-dir fileset #{rolekey}) 77 | reducer (fn [xs k v] 78 | (->> (if-not (match? k v) v (assoc v :dir dir)) 79 | (assoc xs k)))] 80 | (->> (partial reduce-kv reducer {}) 81 | (update-in fileset [:tree]))))) 82 | 83 | (defn- sift-add 84 | [rolekey optargs] 85 | (fn [fileset] 86 | (let [dir (#'core/get-add-dir fileset #{rolekey})] 87 | (->> (map io/file optargs) 88 | (reduce #(tmpd/add %1 dir %2 nil) fileset))))) 89 | 90 | (defn- sift-filter 91 | "Similar to filter, where match? is a predicate with signature [path tmpfile]." 92 | [match?] 93 | (let [reducer (fn [xs k v] (if-not (match? k v) xs (assoc xs k v)))] 94 | (fn [fileset] (->> (partial reduce-kv reducer {}) 95 | (update-in fileset [:tree]))))) 96 | 97 | (defn- jar-path 98 | [sym] 99 | (let [env (core/get-env)] 100 | (->> env 101 | pod/resolve-dependencies 102 | (map :dep) 103 | (filter #(= sym (first %))) 104 | first 105 | (pod/resolve-dependency-jar env)))) 106 | 107 | (defmulti sift-action (fn [invert? opkey optargs] opkey)) 108 | (defmethod sift-action :to-asset [v? _ args] (sift-mv :asset v? args)) 109 | (defmethod sift-action :to-resource [v? _ args] (sift-mv :resource v? args)) 110 | (defmethod sift-action :to-source [v? _ args] (sift-mv :source v? args)) 111 | (defmethod sift-action :add-asset [_ _ args] (sift-add :asset args)) 112 | (defmethod sift-action :add-resource [_ _ args] (sift-add :resource args)) 113 | (defmethod sift-action :add-source [_ _ args] (sift-add :source args)) 114 | (defmethod sift-action :include [v? _ args] (sift-filter (sift-match v? args))) 115 | (defmethod sift-action :with-meta [v? _ args] (sift-filter (sift-meta v? args))) 116 | 117 | (defmethod sift-action :move 118 | [_ _ args] 119 | (let [proc #(reduce-kv string/replace % args) 120 | reducer (fn [xs k v] 121 | (let [k (proc k)] 122 | (assoc xs k (assoc v :path k))))] 123 | (fn [fileset] 124 | (->> (partial reduce-kv reducer {}) 125 | (update-in fileset [:tree]))))) 126 | 127 | (defmethod sift-action :add-jar 128 | [v? _ args] 129 | (fn [fileset] 130 | (-> (fn [fs [sym regex]] 131 | (let [incl (when-not v? [regex]) 132 | excl (when v? [regex]) 133 | jar (jar-path sym)] 134 | (core/add-cached-resource 135 | fs (digest/md5 (io/file jar)) (partial pod/unpack-jar jar) 136 | :include incl :exclude excl :mergers pod/standard-jar-mergers))) 137 | (reduce fileset args)))) 138 | 139 | (defmethod sift-action :add-meta 140 | [v? _ args] 141 | (fn [fileset] 142 | (let [[regex kw] (first args) 143 | file-paths (filter (comp (if v? not identity) 144 | (partial re-find regex)) (keys (:tree fileset)))] 145 | (core/add-meta fileset (zipmap file-paths 146 | (repeat {kw true})))))) 147 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/Watchable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | import java.io.IOException; 29 | 30 | /** 31 | * An object that may be registered with a watch service so that it can be 32 | * watched for changes and events. 33 | * 34 | *

This interface defines the {@link #register register} method to register 35 | * the object with a {@link WatchService} returning a {@link WatchKey} to 36 | * represent the registration. An object may be registered with more than one 37 | * watch service. Registration with a watch service is cancelled by invoking the 38 | * key's {@link WatchKey#cancel cancel} method. 39 | * 40 | * @since 1.7 41 | * 42 | * @see WatchableFile#register 43 | */ 44 | 45 | public interface Watchable { 46 | 47 | /** 48 | * Registers an object with a watch service. 49 | * 50 | *

If the file system object identified by this object is currently 51 | * registered with the watch service then the watch key, representing that 52 | * registration, is returned after changing the event set or modifiers to 53 | * those specified by the {@code events} and {@code modifiers} parameters. 54 | * Changing the event set does not cause pending events for the object to be 55 | * discarded. Objects are automatically registered for the {@link 56 | * StandardWatchEventKind#OVERFLOW OVERFLOW} event. This event is not 57 | * required to be present in the array of events. 58 | * 59 | *

Otherwise the file system object has not yet been registered with the 60 | * given watch service, so it is registered and the resulting new key is 61 | * returned. 62 | * 63 | *

Implementations of this interface should specify the events they 64 | * support. 65 | * 66 | * @param watcher 67 | * the watch service to which this object is to be registered 68 | * @param events 69 | * the events for which this object should be registered 70 | * @param modifiers 71 | * the modifiers, if any, that modify how the object is registered 72 | * 73 | * @return a key representing the registration of this object with the 74 | * given watch service 75 | * 76 | * @throws UnsupportedOperationException 77 | * if unsupported events or modifiers are specified 78 | * @throws IllegalArgumentException 79 | * if an invalid of combination of events are modifiers are specified 80 | * @throws ClosedWatchServiceException 81 | * if the watch service is closed 82 | * @throws IOException 83 | * if an I/O error occurs 84 | * @throws SecurityException 85 | * if a security manager is installed and it denies an unspecified 86 | * permission required to monitor this object. Implementations of 87 | * this interface should specify the permission checks. 88 | */ 89 | WatchKey register(WatchService watcher, 90 | WatchEvent.Kind[] events, 91 | WatchEvent.Modifier... modifiers) 92 | throws IOException; 93 | 94 | 95 | /** 96 | * Registers an object with a watch service. 97 | * 98 | *

An invocation of this method behaves in exactly the same way as the 99 | * invocation 100 | *

101 |      *     watchable.{@link #register(WatchService, com.barbarysoftware.watchservice.WatchEvent.Kind[], com.barbarysoftware.watchservice.WatchEvent.Modifier...)}  register}(watcher, events, new WatchEvent.Modifier[0]);
102 |      * 
103 | * 104 | * @param watcher 105 | * the watch service to which this object is to be registered 106 | * @param events 107 | * the events for which this object should be registered 108 | * 109 | * @return a key representing the registration of this object with the 110 | * given watch service 111 | * 112 | * @throws UnsupportedOperationException 113 | * if unsupported events are specified 114 | * @throws IllegalArgumentException 115 | * if an invalid of combination of events are specified 116 | * @throws ClosedWatchServiceException 117 | * if the watch service is closed 118 | * @throws IOException 119 | * if an I/O error occurs 120 | * @throws SecurityException 121 | * if a security manager is installed and it denies an unspecified 122 | * permission required to monitor this object. Implementations of 123 | * this interface should specify the permission checks. 124 | */ 125 | WatchKey register(WatchService watcher, WatchEvent.Kind... events) 126 | throws IOException; 127 | } 128 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/AbstractWatchKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | /** 32 | * Base implementation class for watch keys. 33 | */ 34 | 35 | abstract class AbstractWatchKey extends WatchKey { 36 | 37 | /** 38 | * Maximum size of event list (in the future this may be tunable) 39 | */ 40 | static final int MAX_EVENT_LIST_SIZE = 512; 41 | 42 | /** 43 | * Special event to signal overflow 44 | */ 45 | static final Event OVERFLOW_EVENT = 46 | new Event(StandardWatchEventKind.OVERFLOW, null); 47 | 48 | /** 49 | * Possible key states 50 | */ 51 | private static enum State { 52 | READY, SIGNALLED 53 | } 54 | 55 | // reference to watcher 56 | private final AbstractWatchService watcher; 57 | 58 | // key state 59 | private State state; 60 | 61 | // pending events 62 | private List> events; 63 | 64 | protected AbstractWatchKey(AbstractWatchService watcher) { 65 | this.watcher = watcher; 66 | this.state = State.READY; 67 | this.events = new ArrayList>(); 68 | } 69 | 70 | final AbstractWatchService watcher() { 71 | return watcher; 72 | } 73 | 74 | /** 75 | * Enqueues this key to the watch service 76 | */ 77 | final void signal() { 78 | synchronized (this) { 79 | if (state == State.READY) { 80 | state = State.SIGNALLED; 81 | watcher.enqueueKey(this); 82 | } 83 | } 84 | } 85 | 86 | /** 87 | * Adds the event to this key and signals it. 88 | * @param kind event kind 89 | * @param context context 90 | */ 91 | @SuppressWarnings("unchecked") 92 | final void signalEvent(WatchEvent.Kind kind, Object context) { 93 | synchronized (this) { 94 | int size = events.size(); 95 | if (size > 1) { 96 | // don't let list get too big 97 | if (size >= MAX_EVENT_LIST_SIZE) { 98 | kind = StandardWatchEventKind.OVERFLOW; 99 | context = null; 100 | } 101 | 102 | // repeated event 103 | WatchEvent prev = events.get(size - 1); 104 | if (kind == prev.kind()) { 105 | boolean isRepeat; 106 | if (context == null) { 107 | isRepeat = (prev.context() == null); 108 | } else { 109 | isRepeat = context.equals(prev.context()); 110 | } 111 | if (isRepeat) { 112 | ((Event) prev).increment(); 113 | return; 114 | } 115 | } 116 | } 117 | 118 | // non-repeated event 119 | events.add(new Event((WatchEvent.Kind) kind, context)); 120 | signal(); 121 | } 122 | } 123 | 124 | @Override 125 | public final List> pollEvents() { 126 | synchronized (this) { 127 | List> result = events; 128 | events = new ArrayList>(); 129 | return result; 130 | } 131 | } 132 | 133 | @Override 134 | public final boolean reset() { 135 | synchronized (this) { 136 | if (state == State.SIGNALLED && isValid()) { 137 | if (events.isEmpty()) { 138 | state = State.READY; 139 | } else { 140 | // pending events so re-queue key 141 | watcher.enqueueKey(this); 142 | } 143 | } 144 | return isValid(); 145 | } 146 | } 147 | 148 | /** 149 | * WatchEvent implementation 150 | */ 151 | private static class Event extends WatchEvent { 152 | private final WatchEvent.Kind kind; 153 | private final T context; 154 | 155 | // synchronize on watch key to access/increment count 156 | private int count; 157 | 158 | Event(WatchEvent.Kind type, T context) { 159 | this.kind = type; 160 | this.context = context; 161 | this.count = 1; 162 | } 163 | 164 | @Override 165 | public WatchEvent.Kind kind() { 166 | return kind; 167 | } 168 | 169 | @Override 170 | public T context() { 171 | return context; 172 | } 173 | 174 | @Override 175 | public int count() { 176 | return count; 177 | } 178 | 179 | // for repeated events 180 | void increment() { 181 | count++; 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /boot/worker/third_party/barbarywatchservice/src/com/barbarysoftware/watchservice/WatchKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Sun designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Sun in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 | * CA 95054 USA or visit www.sun.com if you need additional information or 23 | * have any questions. 24 | */ 25 | 26 | package com.barbarysoftware.watchservice; 27 | 28 | import java.util.List; 29 | 30 | /** 31 | * A token representing the registration of a {@link Watchable watchable} object 32 | * with a {@link WatchService}. 33 | * 34 | *

A watch key is created when a watchable object is registered with a watch 35 | * service. The key remains {@link #isValid valid} until: 36 | *

    37 | *
  1. It is cancelled, explicitly, by invoking its {@link #cancel cancel} 38 | * method, or
  2. 39 | *
  3. Cancelled implicitly, because the object is no longer accessible, 40 | * or
  4. 41 | *
  5. By {@link WatchService#close closing} the watch service.
  6. 42 | *
43 | * 44 | *

A watch key has a state. When initially created the key is said to be 45 | * ready. When an event is detected then the key is signalled 46 | * and queued so that it can be retrieved by invoking the watch service's {@link 47 | * WatchService#poll() poll} or {@link WatchService#take() take} methods. Once 48 | * signalled, a key remains in this state until its {@link #reset reset} method 49 | * is invoked to return the key to the ready state. Events detected while the 50 | * key is in the signalled state are queued but do not cause the key to be 51 | * re-queued for retrieval from the watch service. Events are retrieved by 52 | * invoking the key's {@link #pollEvents pollEvents} method. This method 53 | * retrieves and removes all events accumulated for the object. When initially 54 | * created, a watch key has no pending events. Typically events are retrieved 55 | * when the key is in the signalled state leading to the following idiom: 56 | * 57 | *

 58 |  *     for (;;) {
 59 |  *         // retrieve key
 60 |  *         WatchKey key = watcher.take();
 61 |  *
 62 |  *         // process events
 63 |  *         for (WatchEvent<?> event: key.pollEvents()) {
 64 |  *             :
 65 |  *         }
 66 |  *
 67 |  *         // reset the key
 68 |  *         boolean valid = key.reset();
 69 |  *         if (!valid) {
 70 |  *             // object no longer registered
 71 |  *         }
 72 |  *     }
 73 |  * 
74 | * 75 | *

Watch keys are safe for use by multiple concurrent threads. Where there 76 | * are several threads retrieving signalled keys from a watch service then care 77 | * should be taken to ensure that the {@code reset} method is only invoked after 78 | * the events for the object have been processed. This ensures that one thread 79 | * is processing the events for an object at any time. 80 | * 81 | * @since 1.7 82 | */ 83 | 84 | public abstract class WatchKey { 85 | /** 86 | * Initializes a new instance of this class. 87 | */ 88 | protected WatchKey() { } 89 | 90 | /** 91 | * Tells whether or not this watch key is valid. 92 | * 93 | *

A watch key is valid upon creation and remains until it is cancelled, 94 | * or its watch service is closed. 95 | * 96 | * @return {@code true} if, and only if, this watch key is valid 97 | */ 98 | public abstract boolean isValid(); 99 | 100 | /** 101 | * Retrieves and removes all pending events for this watch key, returning 102 | * a {@code List} of the events that were retrieved. 103 | * 104 | *

Note that this method does not wait if there are no events pending. 105 | * 106 | * @return the list of the events retrieved; may be empty 107 | */ 108 | public abstract List> pollEvents(); 109 | 110 | /** 111 | * Resets this watch key. 112 | * 113 | *

If this watch key has been cancelled or this watch key is already in 114 | * the ready state then invoking this method has no effect. Otherwise 115 | * if there are pending events for the object then this watch key is 116 | * immediately re-queued to the watch service. If there are no pending 117 | * events then the watch key is put into the ready state and will remain in 118 | * that state until an event is detected or the watch key is cancelled. 119 | * 120 | * @return {@code true} if the watch key is valid and has been reset, and 121 | * {@code false} if the watch key could not be reset because it is 122 | * no longer {@link #isValid valid} 123 | */ 124 | public abstract boolean reset(); 125 | 126 | /** 127 | * Cancels the registration with the watch service. Upon return the watch key 128 | * will be invalid. If the watch key is enqueued, waiting to be retrieved 129 | * from the watch service, then it will remain in the queue until it is 130 | * removed. Pending events, if any, remain pending and may be retrieved by 131 | * invoking the {@link #pollEvents pollEvents} method after the key is 132 | * cancelled. 133 | * 134 | *

If this watch key has already been cancelled then invoking this 135 | * method has no effect. Once cancelled, a watch key remains forever invalid. 136 | */ 137 | public abstract void cancel(); 138 | } 139 | -------------------------------------------------------------------------------- /mkdocs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env boot 2 | 3 | ;; vim: set ft=clojure: 4 | 5 | (set-env! 6 | :dependencies '[[adzerk/clj-github-docs "0.1.1"]]) 7 | 8 | (require 9 | '[adzerk.clj-github-docs :refer :all]) 10 | 11 | (defn -main [& _] 12 | 13 | (write-docs 14 | :ns boot.task.built-in 15 | :tag *boot-version* 16 | :src "boot/core/src" 17 | :doc "Boot built-in tasks." 18 | 19 | (section 20 | "Info" 21 | help show) 22 | 23 | (section 24 | "Develop" 25 | notify repl speak wait watch) 26 | 27 | (section 28 | "Fileset" 29 | add-repo sift uber) 30 | 31 | (section 32 | "Build" 33 | aot javac) 34 | 35 | (section 36 | "Package" 37 | pom jar web war zip) 38 | 39 | (section 40 | "Deploy" 41 | install push target) 42 | 43 | (section 44 | "Deprecated" 45 | checkout)) 46 | 47 | (write-docs 48 | :ns boot.util 49 | :tag *boot-version* 50 | :src "boot/pod/src" 51 | :doc "Namespace containing various utility functions and macros to make 52 | life easier in Boot scripts." 53 | 54 | (section 55 | "Settings (read-only)" 56 | *colorize?* *verbosity* colorize?-system-default) 57 | 58 | (section 59 | "Shell" 60 | dosh sh *sh-dir*) 61 | 62 | (section 63 | "Exit" 64 | exit-ok exit-error) 65 | 66 | (section 67 | "Logging" 68 | dbug dbug* info warn fail warn-deprecated) 69 | 70 | (section 71 | "Useful Macros" 72 | guard while-let with-err-str with-let with-resolve with-rethrow 73 | without-exiting dotoseq do-while-let extends-protocol) 74 | 75 | (section 76 | "Printing" 77 | pp* pp-str print-ex print-tree) 78 | 79 | (section 80 | "Miscellaneous" 81 | extract-ids auto-flush bind-syms dep-as-map map-as-dep let-assert-keys 82 | index-of jarname path->ns read-string-all with-semaphore with-semaphore-noblock)) 83 | 84 | (write-docs 85 | :ns boot.pod 86 | :tag *boot-version* 87 | :src "boot/pod/src" 88 | :doc "Namespace containing functions and vars related to pods, dependencies, 89 | jar files, and classloaders." 90 | 91 | (section 92 | "Settings (read-only)" 93 | env data pods pod-id worker-pod shutdown-hooks) 94 | 95 | (section 96 | "Pods" 97 | get-pods call-in* with-call-in with-call-worker eval-in* with-eval-in 98 | with-eval-worker eval-fn-call get-pods make-pod require-in send! 99 | destroy-pod pod-pool pod-name this-pod with-invoke-in with-invoke-worker) 100 | 101 | (section 102 | "Classpath" 103 | add-classpath add-dependencies add-dependencies-in add-dependencies-worker 104 | dependency-loaded? get-classpath modifiable-classloader? resources 105 | seal-app-classloader classloader-hierarchy classloader-resources 106 | copy-resource resource-last-modified) 107 | 108 | (section 109 | "Dependencies" 110 | resolve-release-versions 111 | resolve-dependencies resolve-dependency-jar resolve-dependency-jars 112 | resolve-nontransitive-dependencies apply-exclusions apply-global-exclusions 113 | canonical-coord copy-dependency-jar-entries default-dependencies 114 | dependency-pom-properties dependency-pom-properties-map outdated 115 | extract-ids jars-dep-graph jars-in-dep-order coord->map map->coord) 116 | 117 | (section 118 | "Jars" 119 | copy-url jar-entries jar-entries* jar-entries-memoized* pom-properties 120 | pom-properties-map pom-xml pom-xml-map unpack-jar) 121 | 122 | (section 123 | "Jar Exclusions & Mergers" 124 | concat-merger first-wins-merger into-merger standard-jar-mergers 125 | standard-jar-exclusions) 126 | 127 | (section 128 | "Misc. Utility" 129 | lifecycle-pool add-shutdown-hook! caller-namespace non-caching-url-input-stream) 130 | 131 | (section 132 | "Deprecated / Internal" 133 | eval-in-caller eval-in-callee with-pod with-worker 134 | set-pods! set-data! set-pod-id! set-worker-pod! set-this-pod!)) 135 | 136 | (write-docs 137 | :ns boot.core 138 | :tag *boot-version* 139 | :src "boot/core/src" 140 | :doc "The Boot core namespace, containing most of Boot's public API." 141 | 142 | (section 143 | "Settings (read-only)" 144 | *app-version* *boot-script* *boot-version* *boot-opts* *warnings* 145 | new-build-at last-file-change bootignore) 146 | 147 | (section 148 | "Configuration Helpers" 149 | load-data-readers! configure-repositories!) 150 | 151 | (section 152 | "Boot Environment" 153 | get-checkouts 154 | get-env set-env! merge-env! get-sys-env set-sys-env! pre-env! post-env!) 155 | 156 | (section 157 | "Define Tasks" 158 | deftask cleanup reset-build! reset-fileset with-pre-wrap with-pass-thru 159 | with-post-wrap) 160 | 161 | (section 162 | "Manipulate Task Options" 163 | task-options! replace-task! disable-task!) 164 | 165 | (section 166 | "REPL Integration" 167 | boot rebuild! launch-nrepl) 168 | 169 | (section 170 | "Create Temp Directories" 171 | tmp-dir! cache-dir!) 172 | 173 | (section 174 | "TmpFile API" 175 | tmp-path tmp-dir tmp-file tmp-time) 176 | 177 | (section 178 | "Query Fileset For TmpFiles" 179 | tmp-get user-files input-files output-files) 180 | 181 | (section 182 | "Filter Sequences Of TmpFiles" 183 | file-filter by-ext by-name by-path by-re not-by-ext not-by-name 184 | not-by-path not-by-re by-meta not-by-meta) 185 | 186 | (section 187 | "Other Fileset Queries" 188 | ls fileset-namespaces input-fileset output-fileset user-dirs input-dirs 189 | output-dirs checkout-dirs) 190 | 191 | (section 192 | "Manipulate Fileset" 193 | new-fileset commit! rm mv cp add-meta add-asset add-cached-asset add-source 194 | add-cached-source add-resource add-cached-resource mv-asset mv-source mv-resource) 195 | 196 | (section 197 | "Fileset Diffs" 198 | fileset-diff fileset-added fileset-removed fileset-changed) 199 | 200 | (section 201 | "Misc. Helpers" 202 | gpg-decrypt json-generate json-parse yaml-generate yaml-parse touch 203 | git-files empty-dir! sync! patch! watch-dirs template) 204 | 205 | (section 206 | "Deprecated / Internal" 207 | tmppath tmpdir tmpget tmpfile tmptime temp-dir! fileset-reduce init!))) 208 | --------------------------------------------------------------------------------