Skip to content

Instantly share code, notes, and snippets.

@timjstewart
Created March 10, 2016 20:30
Show Gist options
  • Select an option

  • Save timjstewart/180dbff04d61774e7074 to your computer and use it in GitHub Desktop.

Select an option

Save timjstewart/180dbff04d61774e7074 to your computer and use it in GitHub Desktop.
a script that makes creating quick Java projects and experiments easy.
#! /bin/bash
# A script to make it very easy to try things in Java.
#
# Pros:
#
# * Create Java project quickly
# * Create unit test files quickly
# * Create source code files quickly
# * Run unit tests easily
# * Run Java main methods easily
# * Project files compatible with Maven directory structure.
#
# Cons:
#
# * Doesn't download jar dependencies like mvn, gradle
# * No ${EDITOR} integration.
# * Not compatible with IDEs
# * No debugging support
# The path to the pom.xml file (it may not exist)
POM_FILE=./pom.xml
# The directory where source files (not including tests) go.
SRC_DIR=./src/main/java
# The directory where test source code goes
TEST_DIR=./src/test/java
# The directory that contains all Jar files
JARS_DIR=./jars
# The directory that contains all compiled class files (from both the
# src and test directories).
OUTPUT_DIR=./target/classes
# Hidden config file (empty at the moment).
CONFIG_FILE=./.jconfig
# The base URL for downloading Jar files.
MAVEN_REPO="https://repo1.maven.org/maven2"
function usage()
{
if [ "$#" == "1" ] ; then
>&2 echo "command usage: $1"
else
>&2 echo "usage: j <command> [<param>...]"
>&2 echo
>&2 echo " Commands:"
>&2 echo
>&2 echo " build builds all source code (not tests)"
>&2 echo " clean deletes all compiled class files"
>&2 echo " cp print classpath"
>&2 echo " disasm disassemble a class file"
>&2 echo " jars list jars"
>&2 echo " create creates a project"
>&2 echo " get-jar creates a project"
>&2 echo " new creates a new class or test or one of each"
>&2 echo " pom creates a pom.xml file"
>&2 echo " run runs a specific class' main function."
>&2 echo " test runs a specific test"
>&2 echo " tests runs all tests"
>&2 echo
fi
}
function disassemble()
{
in_project_or_die
local FQN=$1
if [ -z ${FQN} ] ; then
usage "specify a fully qualified class name"
exit 1
fi
javap -c -cp $(get_class_path) ${FQN}
}
function get_class_name()
{
local fqn=$1
echo ${fqn##*.}
}
function get_package_name()
{
local fqn=$1
pkg=${fqn%.*}
if [ "${pkg}" == "${fqn}" ] ; then
echo
else
echo "${pkg}"
fi
}
function get_file_name()
{
local fqn=$1
echo $(echo "$fqn" | tr '.' '/').java
}
function source_files()
{
find "${SRC_DIR}" -iname '*.java'
}
function test_files()
{
find "${TEST_DIR}" -iname '*Test.java'
}
function test_class_files()
{
find "${OUTPUT_DIR}" -iname '*Test.class'
}
function in_project()
{
if [ -e "${CONFIG_FILE}" ] ; then
return 0
else
return 1
fi
}
function die()
{
if [ ! -z "$1" ] ; then
>&2 echo "error: $1"
else
>&2 echo "error: unknown"
fi
exit 1
}
function in_project_or_die()
{
in_project || die "must be in project to run that command."
}
function list_test_classes()
{
in_project_or_die
for test in $(find "${TEST_DIR}" -iname '*Test.java') ; do
local test_name=$(echo ${test#${TEST_DIR}/} | tr '/' '.')
local test_name=${test_name%.java}
>&2 echo " - ${test_name}"
done
}
function list_jars()
{
in_project_or_die
for jar in $(find ${JARS_DIR} -iname '*.jar') ; do
>&2 echo " $(basename ${jar%.*})"
done | sort
}
function get_jar()
{
in_project_or_die
if [ "$#" != "3" ] ; then
usage "get-jar GROUP_ID ARTIFACT_ID VERSION"
return 1
fi
in_project_or_die
local GROUP_ID=$1
local GROUP_DIR=$(echo $GROUP_ID | tr '.' '/')
local ARTIFACT_ID=$2
local VERSION=$3
local JAR_FILE="${JARS_DIR}/${GROUP_ID}/${ARTIFACT_ID}-${VERSION}.jar"
mkdir -p $(dirname $JAR_FILE)
if [ -e "${JAR_FILE}" ] ; then
return 0
fi
local JAR_URL="${MAVEN_REPO}/${GROUP_DIR}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.jar"
>&2 echo -n "downloading jar: ${GROUP_DIR}:${ARTIFACT_ID}:${VERSION} ..."
if ! wget -q "${JAR_URL}" -P "$(dirname $JAR_FILE)" ; then
>&2 echo
>&2 echo " error: could not download jar:"
>&2 echo " Group: ${GROUP_ID}"
>&2 echo " Artifact: ${ARTIFACT_ID}"
>&2 echo " Version: ${VERSION}"
>&2 echo " From: ${JAR_URL}"
return 1
fi > /dev/null
>&2 echo " SUCCEEDED."
return 0
}
function jar_file_exists()
{
in_project_or_die
local ARTIFACT_ID=$1
local VERSION=$2
if [ -e "${JARS_DIR}/${ARTIFACT_ID}-${VERSION}.jar" ] ; then
return 0
else
return 1
fi
}
function clean()
{
in_project_or_die
rm -rf "${OUTPUT_DIR}"
}
function ensure_test_jars()
{
in_project_or_die
mkdir -p "${JARS_DIR}"
local HAMCREST_VERSION=1.3
local JUNIT_VERSION=4.12
get_jar "org.hamcrest" "hamcrest-core" ${HAMCREST_VERSION}
get_jar "junit" "junit" ${JUNIT_VERSION}
}
function get_class_path()
{
local jar_globs=$(find jars -type d -exec echo "{}/*:" \;)
local jar_globs=$(echo $jar_globs | tr -d ' ')
echo "./:${jar_globs}:${OUTPUT_DIR}"
}
function print_classpath()
{
echo $(get_class_path)
}
function get_target_vm()
{
echo "1.8"
}
function get_source_version()
{
echo "1.8"
}
function ensure_output_dir()
{
in_project_or_die
mkdir -p "${OUTPUT_DIR}"
}
function build()
{
in_project_or_die
>&2 echo "building source..."
if [ ! -d "${SRC_DIR}" ] ; then
>&2 echo "error: no src directory"
exit 2
fi
ensure_output_dir
if ! javac \
-source $(get_source_version) \
-target $(get_target_vm) \
-cp "$(get_class_path)" \
-d "${OUTPUT_DIR}" \
$(source_files)
then
exit 1
fi
}
function build_tests()
{
in_project_or_die
>&2 echo "building tests..."
ensure_test_jars
ensure_output_dir
if [ ! -d "${TEST_DIR}" ] ; then
>&2 echo "error: no test directory"
exit 2
fi
if ! javac \
-source $(get_source_version) \
-target $(get_target_vm) \
-cp "$(get_class_path)" \
-d "${OUTPUT_DIR}" \
$(test_files)
then
exit 1
fi
}
function run()
{
in_project_or_die
local MAIN_CLASS=$1
if [ -z "${MAIN_CLASS}" ] ; then
usage "run CLASS"
return 1
fi
>&2 echo "running ${MAIN_CLASS} ..."
java -cp "$(get_class_path)" \
${MAIN_CLASS}
}
function run_test()
{
in_project_or_die
if [ "$#" == "0" ] ; then
usage "test TEST_CLASS..."
>&2 echo
list_test_classes
>&2 echo
exit 1
fi
build || exit 1
ensure_test_jars || exit 1
build_tests || exit 1
for test_class in $@ ; do
>&2 echo "running test: ${test_class} ..."
java -cp "${OUTPUT_DIR}:$(get_class_path)" \
org.junit.runner.JUnitCore \
${test_class}
done
}
function run_tests()
{
in_project_or_die
build || exit 1
ensure_test_jars || exit 1
build_tests || exit 1
>&2 echo "running all tests..."
for test in $(test_class_files)
do
local test_name=$(echo ${test#$OUTPUT_DIR/} | tr '/' '.')
local test_name=${test_name%.class}
>&2 echo "running test: ${test_name} ..."
java -cp "${OUTPUT_DIR}:$(get_class_path)" \
org.junit.runner.JUnitCore \
${test_name}
done
}
function create_source_file()
{
in_project_or_die
if [ "$#" == "0" ] ; then
usage "new class CLASS_NAME..."
return 1
fi
for arg in $@ ; do
local class_name=$(get_class_name "${arg}")
local package_name=$(get_package_name "${arg}")
local file_name="${SRC_DIR}/$(get_file_name ${arg})"
mkdir -p $(dirname "${file_name}")
if [ -e "${file_name}" ] ; then
>&2 echo "warning: file exists: ${file_name}"
continue
fi
if [ ! -z "${package_name}" ] ; then
cat <<EOF > "${file_name}"
package ${package_name};
EOF
fi
cat <<EOF >> "${file_name}"
import java.io.*; // For file I/O
import java.net.*; // For networking
import java.util.*; // For collections
import java.util.concurrent.*; // For concurrency
import java.util.regex.*; // For matching text
import java.util.stream.*; // For handling streams
public class ${class_name}
{
public static void main(final String[] args)
{
System.out.println("${class_name} says, 'Hello, World!'");
}
}
EOF
>&2 echo "created: ${file_name}"
done
}
function create_test_file()
{
in_project_or_die
if [ "$#" == "0" ] ; then
usage "new test CLASS_NAME..."
return 1
fi
mkdir -p "${TEST_DIR}"
for arg in $@ ; do
local class_name=$(get_class_name "${arg}")Test
local package_name=$(get_package_name "${arg}")
local file_name="${TEST_DIR}/$(get_file_name ${arg}Test)"
mkdir -p $(dirname "${file_name}")
if [ -e "${file_name}" ] ; then
>&2 echo "warning: file exists: ${file_name}"
continue
fi
if [ ! -z "${package_name}" ] ; then
cat <<EOF > "${file_name}"
package ${package_name};
EOF
fi
cat <<EOF >> "${file_name}"
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matcher.*;
import static org.hamcrest.core.Is.*;
public class ${class_name}
{
@Before
public void setUp()
{
}
@After
public void tearDown()
{
}
@Test
public void test()
{
assertTrue(true);
}
@Test(expected=Exception.class)
public void testExpected() throws Exception
{
throw new Exception("Catch me!");
}
@Test
public void testMatcher()
{
final String name = "Tim";
assertThat(name, is("Tim"));
}
}
EOF
>&2 echo "created: ${file_name}"
done
}
function create_project()
{
in_project && die "already in a project"
local NAME=$1
if [ -z "${NAME}" ] ; then
usage "create PROJECT_NAME"
return 1
fi
if [ -d "./${NAME}" ] ; then
>&2 echo "error: project ${NAME} exists"
return 1
fi
mkdir -p ./${NAME}/jars
touch "./${NAME}/${CONFIG_FILE}"
pushd "${NAME}" > /dev/null
>&2 echo "in directory: ${NAME}"
>&2 echo
create_source_file Main
create_test_file Main
popd > /dev/null
>&2 echo
>&2 echo "project ${NAME} created."
}
function create_pom()
{
in_project_or_die
if [ -e "${POM_FILE}" ] ; then
die "pom.xml file already exists"
fi
local name=$(pwd)
local name=$(basename $name)
cat <<EOF > "${POM_FILE}"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>${name}</name>
<groupId>${name}</groupId>
<artifactId>${name}</artifactId>
<version>0.1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
EOF
for jar in $(find "${JARS_DIR}" -iname '*.jar') ; do
jar=${jar#${JARS_DIR}/}
jar=${jar%.jar}
local pair=${jar%-*}
local group=${pair%/*}
local artifact=${pair#*/}
local version=${jar##*-}
cat <<EOF >> "${POM_FILE}"
<dependency>
<groupId>${group}</groupId>
<artifactId>${artifact}</artifactId>
<version>${version}</version>
</dependency>
EOF
done
cat <<EOF >> "${POM_FILE}"
</dependencies>
</project>
EOF
}
function create_new()
{
in_project_or_die
if [ "$#" == "0" ] ; then
usage "new class|test|pair NAME"
exit 1
else
case "$1" in
class)
shift
create_source_file $@
;;
test)
shift
create_test_file $@
;;
pair)
shift
create_source_file $@
create_test_file $@
;;
*)
>&2 echo "error: don't know how to create a new '$1'."
;;
esac
fi
}
function main()
{
if [ "$#" == "0" ] ; then
usage
exit 1
else
case "$1" in
build)
shift
build $@
;;
run)
shift
build
run $@
;;
clean)
shift
clean $@
;;
test)
shift
run_test $@
;;
jars)
shift
list_jars $@
;;
get-jar)
shift
get_jar $@
;;
tests)
shift
run_tests $@
;;
create)
shift
create_project $@
;;
cp|classpath)
shift
print_classpath $@
;;
pom)
shift
create_pom $@
;;
disasm)
shift
disassemble $@
;;
new)
shift
create_new $@
;;
*|help|--help|-h)
shift
usage $@
;;
esac
fi
}
main $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment