/BuildTools.java Secret
Last active
January 19, 2022 03:22
Star
You must be signed in to star a gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A set of utilities for building java projects. | |
*/ | |
public final class BuildTools { | |
private BuildTools() {} | |
/** | |
* Project root path, defaults to current directory. | |
* Use `resolve-path` to resolve relative paths in terms of the *project-root*. | |
* Use BuildTools#setProjectRoot to override the default for all tasks. | |
*/ | |
public static String projectRoot() { | |
return (String) DEREF.invoke(API_PROJECT_ROOT); | |
} | |
/** | |
* Sets the project root in the given scope. | |
*/ | |
@SuppressWarnings("unchecked") | |
public static <T> T withProjectRoot(String projectRoot, Supplier<T> callable) { | |
var sym = GENSYM.invoke(); | |
var code = LIST.invoke( | |
SYMBOL.invoke("fn"), | |
VECTOR.invoke(sym), | |
LIST.invoke( | |
SYMBOL.invoke("clojure.core", "binding"), | |
VECTOR.invoke( | |
SYMBOL.invoke("clojure.tools.build.api", "*project-root*"), | |
projectRoot | |
), | |
LIST.invoke(SYMBOL.invoke(".get"), sym) | |
) | |
); | |
return (T) ((IFn) EVAL.invoke(code)).invoke(callable); | |
} | |
/** | |
* Copy the contents of the src-dirs to the target-dir, optionally do text replacement. | |
* @param targetDir dir to write files, will be created if it doesn't exist | |
* @param srcDirs coll of dirs to copy from | |
*/ | |
public static void copyDir(String targetDir, List<String> srcDirs) { | |
copyDir(targetDir, srcDirs, CopyDirOptions.builder().build()); | |
} | |
/** | |
* Copy the contents of the src-dirs to the target-dir, optionally do text replacement. | |
* @param targetDir dir to write files, will be created if it doesn't exist | |
* @param srcDirs coll of dirs to copy from | |
* @param options options | |
*/ | |
public static void copyDir(String targetDir, List<String> srcDirs, CopyDirOptions options) { | |
Objects.requireNonNull(targetDir); | |
Objects.requireNonNull(srcDirs); | |
var args = HASH_MAP.invoke( | |
Clojure.read(":target-dir"), targetDir, | |
Clojure.read(":src-dirs"), SEQ.invoke(srcDirs) | |
); | |
if (options.include != null) { | |
args = ASSOC.invoke(args, Clojure.read(":include"), options.include); | |
} | |
if (options.ignores != null) { | |
args = ASSOC.invoke(args, Clojure.read(":ignores"), SEQ.invoke(options.ignores)); | |
} | |
if (options.replace != null) { | |
args = ASSOC.invoke(args, Clojure.read(":replace"), INTO.invoke(Clojure.read("{}"), options.replace)); | |
} | |
if (options.nonReplacedExts != null) { | |
args = ASSOC.invoke(args, Clojure.read(":non-replaced-exts"), SEQ.invoke(options.nonReplacedExts)); | |
} | |
API_COPY_DIR.invoke(args); | |
} | |
/** | |
* Copy one file from source to target, creating target dirs if needed. | |
* @param src Source path | |
* @param target Target path | |
*/ | |
public static void copyFile(String src, String target) { | |
API_COPY_FILE.invoke( | |
HASH_MAP.invoke( | |
Clojure.read(":src"), src, | |
Clojure.read(":target"), target | |
) | |
); | |
} | |
public static Basis createBasis() { | |
return new Basis(API_CREATE_BASIS.invoke()); | |
} | |
public static Basis createBasis(CreateBasisOptions options) { | |
Objects.requireNonNull(options); | |
Function<DepSource, Object> toClojure = depSource -> { | |
if (depSource instanceof DepSource.Standard __) { | |
return Clojure.read(":standard"); | |
} | |
else { | |
return ((DepSource.Path) depSource).path(); | |
} | |
}; | |
var args = Clojure.read("{}"); | |
if (options.root != null) { | |
args = ASSOC.invoke(args, Clojure.read(":include"), toClojure.apply(options.root)); | |
} | |
if (options.user != null) { | |
args = ASSOC.invoke(args, Clojure.read(":user"), toClojure.apply(options.user)); | |
} | |
if (options.project != null) { | |
args = ASSOC.invoke(args, Clojure.read(":project"), toClojure.apply(options.project)); | |
} | |
if (options.extra != null) { | |
args = ASSOC.invoke(args, Clojure.read(":extra"), toClojure.apply(options.extra)); | |
} | |
if (options.aliases != null) { | |
args = ASSOC.invoke(args, Clojure.read(":aliases"), VEC.invoke(options.aliases | |
.stream() | |
.map(alias -> { | |
if (alias.startsWith(":")) { | |
return KEYWORD.invoke(alias.substring(1)); | |
} | |
else { | |
return KEYWORD.invoke(alias); | |
} | |
}) | |
.toList()) | |
); | |
} | |
return new Basis(API_CREATE_BASIS.invoke(args)); | |
} | |
/** | |
* Delete file or directory recursively, if it exists. | |
*/ | |
public static void delete(String path) { | |
API_DELETE.invoke(HASH_MAP.invoke(Clojure.read(":path"), path)); | |
} | |
/** | |
* Shells out to git and returns count of commits on this branch: | |
* git rev-list HEAD --count | |
*/ | |
public static Long gitCountRevs(GitCountRevsOptions options) { | |
Objects.requireNonNull(options); | |
Object args = Clojure.read("{}"); | |
if (options.dir != null) { | |
args = ASSOC.invoke(args, Clojure.read(":include"), options.dir); | |
} | |
if (options.gitCommand != null) { | |
args = ASSOC.invoke(args, Clojure.read(":git-command"), options.gitCommand); | |
} | |
if (options.path != null) { | |
args = ASSOC.invoke(args, Clojure.read(":path"), options.path); | |
} | |
Object revs = API_GIT_COUNT_REVS.invoke(args); | |
if (revs == null) { | |
return null; | |
} | |
else if (revs instanceof Number n) { | |
return n.longValue(); | |
} | |
else { | |
return Long.parseLong((String) revs); | |
} | |
} | |
/** | |
* Shells out to git and returns count of commits on this branch: | |
* git rev-list HEAD --count | |
*/ | |
public static Long gitCountRevs() { | |
return gitCountRevs(GitCountRevsOptions.builder().build()); | |
} | |
public static String gitProcess(List<String> gitArgs) { | |
return gitProcess(gitArgs, GitProcessOptions.builder().build()); | |
} | |
/** | |
* Run git process in the specified dir using git-command with git-args (which should not | |
* start with "git"). By default, stdout is captured, trimmed, and returned. | |
*/ | |
public static String gitProcess(List<String> gitArgs, GitProcessOptions options) { | |
Object args = HASH_MAP.invoke( | |
Clojure.read(":git-args"), VEC.invoke(gitArgs) | |
); | |
if (options.capture != null) { | |
args = ASSOC.invoke(args, Clojure.read(":capture"), switch (options.capture) { | |
case OUT -> Clojure.read(":out"); | |
case ERR -> Clojure.read(":err"); | |
case NOTHING -> null; | |
}); | |
} | |
if (options.dir != null) { | |
args = ASSOC.invoke(args, Clojure.read(":dir"), options.dir); | |
} | |
if (options.gitCommand != null) { | |
args = ASSOC.invoke(args, Clojure.read(":git-command"), options.gitCommand); | |
} | |
return (String) API_GIT_PROCESS.invoke(args); | |
} | |
public static void install(InstallOptions options) { | |
API_INSTALL.invoke(); | |
} | |
public static void jar(String classDir, String jarFile) { | |
jar(classDir, jarFile, JarOptions.builder().build()); | |
} | |
public static void jar(String classDir, String jarFile, JarOptions options) { | |
Objects.requireNonNull(classDir); | |
Objects.requireNonNull(jarFile); | |
Objects.requireNonNull(options); | |
Object args = HASH_MAP.invoke( | |
Clojure.read(":class-dir"), classDir, | |
Clojure.read(":jar-file"), jarFile | |
); | |
if (options.main != null) { | |
args = ASSOC.invoke(args, Clojure.read(":main"), SYMBOL.invoke(options.main)); | |
} | |
API_JAR.invoke(args); | |
} | |
public static List<String> javaCommand(String main) { | |
return javaCommand(main, JavaCommandOptions.builder().build()); | |
} | |
@SuppressWarnings("unchecked") | |
public static List<String> javaCommand(String main, JavaCommandOptions options) { | |
Objects.requireNonNull(main); | |
Objects.requireNonNull(options); | |
var result = API_JAVA_COMMAND.invoke( | |
ASSOC.invoke(options.toClojure(), Clojure.read(":main"), SYMBOL.invoke(main)) | |
); | |
return (List<String>) ((IFn) Clojure.read(":command-args")).invoke(result); | |
} | |
public static void javac( | |
List<Path> srcDirs, | |
String classDir, | |
List<String> javacOpts, | |
Basis basis | |
) { | |
Objects.requireNonNull(srcDirs); | |
Objects.requireNonNull(classDir); | |
var args = HASH_MAP.invoke( | |
Clojure.read(":src-dirs"), SEQ.invoke(srcDirs.stream().map(Path::toString).toList()), | |
Clojure.read(":class-dir"), classDir | |
); | |
if (basis != null) { | |
args = ASSOC.invoke(args, Clojure.read(":basis"), basis.rawBasisObject); | |
} | |
if (javacOpts != null) { | |
args = ASSOC.invoke(args, Clojure.read(":javac-opts"), SEQ.invoke(javacOpts)); | |
} | |
API_JAVAC.invoke(args); | |
} | |
public static void setProjectRoot(String newProjectRoot) { | |
API_SET_PROJECT_ROOT.invoke(newProjectRoot); | |
} | |
public static <ConflictHandlerState> void uber( | |
UberOptions<ConflictHandlerState> options | |
) { | |
API_UBER.invoke(options.toClojure()); | |
} | |
/** | |
* Create zip file containing contents of src dirs. | |
* | |
* @param srcDirs coll of source directories to include in zip | |
* @param zipFile zip file to create | |
*/ | |
public static void zip(List<String> srcDirs, String zipFile) { | |
API_ZIP.invoke(HASH_MAP.invoke( | |
Clojure.read(":src-dirs"), SEQ.invoke(srcDirs), | |
Clojure.read(":zip-file"), zipFile | |
)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* All the clojure vars required by this library. | |
*/ | |
final class Requires { | |
static final IFn DEREF; | |
static final IFn SEQ; | |
static final IFn VEC; | |
static final IFn INTO; | |
static final IFn ASSOC; | |
static final IFn KEYWORD; | |
static final IFn SYMBOL; | |
static final IFn HASH_MAP; | |
static final IFn VECTOR; | |
static final IFn LIST; | |
static final IFn GENSYM; | |
static final IFn EVAL; | |
static final IFn API_PROJECT_ROOT; | |
static final IFn API_COPY_DIR; | |
static final IFn API_COPY_FILE; | |
static final IFn API_CREATE_BASIS; | |
static final IFn API_DELETE; | |
static final IFn API_GIT_COUNT_REVS; | |
static final IFn API_GIT_PROCESS; | |
static final IFn API_INSTALL; | |
static final IFn API_JAR; | |
static final IFn API_JAVA_COMMAND; | |
static final IFn API_JAVAC; | |
static final IFn API_POM_PATH; | |
static final IFn API_PROCESS; | |
static final IFn API_RESOLVE_PATH; | |
static final IFn API_SET_PROJECT_ROOT; | |
static final IFn API_UBER; | |
static final IFn API_UNZIP; | |
static final IFn API_WRITE_FILE; | |
static final IFn API_WRITE_POM; | |
static final IFn API_ZIP; | |
static { | |
DEREF = Clojure.var("clojure.core","deref"); | |
SEQ = Clojure.var("clojure.core","seq"); | |
VEC = Clojure.var("clojure.core", "vec"); | |
INTO = Clojure.var("clojure.core","into"); | |
ASSOC = Clojure.var("clojure.core","assoc"); | |
KEYWORD = Clojure.var("clojure.core", "keyword"); | |
SYMBOL = Clojure.var("clojure.core", "symbol"); | |
HASH_MAP = Clojure.var("clojure.core", "hash-map"); | |
VECTOR = Clojure.var("clojure.core", "vector"); | |
LIST = Clojure.var("clojure.core", "list"); | |
GENSYM = Clojure.var("clojure.core", "gensym"); | |
EVAL = Clojure.var("clojure.core", "eval"); | |
IFn REQUIRE = Clojure.var("clojure.core", "require"); | |
String api = "clojure.tools.build.api"; | |
REQUIRE.invoke(Clojure.read(api)); | |
API_PROJECT_ROOT = Clojure.var(api, "*project-root*"); | |
API_COPY_DIR = Clojure.var(api, "copy-dir"); | |
API_COPY_FILE = Clojure.var(api, "copy-file"); | |
API_CREATE_BASIS = Clojure.var(api, "create-basis"); | |
API_DELETE = Clojure.var(api, "delete"); | |
API_GIT_COUNT_REVS = Clojure.var(api, "git-count-revs"); | |
API_GIT_PROCESS = Clojure.var(api, "git-process"); | |
API_INSTALL = Clojure.var(api, "install"); | |
API_JAR = Clojure.var(api, "jar"); | |
API_JAVA_COMMAND = Clojure.var(api, "java-command"); | |
API_JAVAC = Clojure.var(api, "javac"); | |
API_POM_PATH = Clojure.var(api, "pom-path"); | |
API_PROCESS = Clojure.var(api, "process"); | |
API_RESOLVE_PATH = Clojure.var(api, "resolve-path"); | |
API_SET_PROJECT_ROOT = Clojure.var(api, "set-project-root!"); | |
API_UBER = Clojure.var(api, "uber"); | |
API_UNZIP = Clojure.var(api, "unzip"); | |
API_WRITE_FILE = Clojure.var(api, "write-file"); | |
API_WRITE_POM = Clojure.var(api, "write-pom"); | |
API_ZIP = Clojure.var(api, "zip"); | |
} | |
private Requires() {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment