-
Notifications
You must be signed in to change notification settings - Fork 0
/
jargo
executable file
·667 lines (562 loc) · 16.8 KB
/
jargo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
#!/bin/bash
# Jargo - Java Project Manager
#
# A simple script to manage a Java project
#
# Author: Daniel Hammer
# Date: 2021-04-21
#
# Exit codes:
# 0 - Program success
# 1 - Insufficient usage
# 2 - Unknown command passed to Jargo
# 3 - No name supplied during project creation
# 4 - Supplied invalid name during project creation
# 5 - Supplied invalid argument during project creation/initialization
########## GLOBAL VARIABLES ###########
# Project configuration file
CONFIG="jargo.cfg"
# Project name
name=""
# Name of package where driver resides
package=""
# Name of driver file
driver=""
# Name of primary module file
MODULE="module-info.java"
# ANSI text colors
RESET="\e[0m"
YELLOW="\e[1;33m"
#######################################
# Initialize globals
if [ -r "$CONFIG" ]; then
name=$(awk -F: '/name/ { print $2 }' $CONFIG)
package=$(awk -F: '/package/ { print $2 }' $CONFIG)
driver=$(awk -F: '/driver/ { print $2 }' $CONFIG)
else
name="$USERJavaProject"
package="App"
driver="Main"
fi
################################################################################
# Displays usage message.
#
# Outputs:
# A usage message.
################################################################################
usage() {
echo "Simple Java Project Manager
USAGE:
usage: jargo [OPTIONS] [COMMANDS]
OPTIONS:
-h, --help Display this menu
--list List all commands
COMMANDS:
new, n Create a new Java project
init Initialize an existing project as a Jargo project
build, b Builds project, compiling classes if updates were made
run, r Runs the driver for this project
clean Cleans working directory of *.class files
doc Generate documentation files
add Add a dependency (only javafx is support currently)
See \`jargo help <COMMAND>\` for command-specific information"
}
################################################################################
# Handles graceful cleanup and shutdown.
#
# Arguments:
# $1: Error code to exit with.
# ${@}: List of files to remove.
#
# Outputs:
# A message displaying what files are being removed.
################################################################################
shutdown() {
# Debug printing
#echo "Exiting with error code $exit_status"
# Store exit code and shift to next arg
exit_status=$1
shift
# Remove all files in the remaining arguments
for arg in "${@}"; do
echo "Cleaning up: Removing $arg"
rm -rf $arg
done
# Exit with saved status
exit $exit_status
}
################################################################################
# Handles creation of new project.
#
# Globals:
# name: Project directory name.
# package: Package name where the driver resides.
# driver: Name of the driver file.
#
# Outputs:
# A message displaying that the project was created.
#
# Arguments:
# $1: Name of project to create.
################################################################################
new() {
# Initialize default configuration variables
name=$1
git=1
# Ensure a project name was passed in
if [ -z "$name" ]; then
echo "usage: jargo new <NAME> [OPTIONS]"
shutdown 3
fi
# If the directory already exists, throw an error
if [ -d "$name" ]; then
echo "Error: $name already exists"
shutdown 4
fi
shift # Consume project name and begin scanning flags
while (($#)); do
case $1 in
"-n") # Change primary package name
shift
package=$1
;;
"-d") # Change driver filename
shift
driver=$1
;;
"--no-git") # Do not initialize a git repository
shift
git=0
;;
*) # Unknown argument
echo "Error: Unknown argument \`$1\`"
shutdown 5
;;
esac
shift # Continue looping through arguments
done
# Set up directory structure
mkdir -p $name/src/$package
mkdir -p $name/bin
# Create configuration file
echo "# Configuration file for Jargo Project Manager (https://github.com/HammerAPI/jargo)
name:$name
package:$package
driver:$driver" > $name/$CONFIG
# Get current system time
local time=$(date +"%Y-%m-%d %T")
# Set up Main class
echo "package $package;
/**
* Driver Class.
*
* @author $USER
* @version $time
*/
public class $driver {
/**
* Main
*
* @param args List of arguments supplied by executor.
*/
public static void main(String[] args) {
System.out.println(\"Hello, world!\");
}
}" > $name/src/$package/$driver.java
# Create module file
echo "/**
* Default module.
*/
module $name {
}" > $name/src/$MODULE
# Set up README.md
echo "# $name " > $name/README.md
# Initialize Git repository (if not disabled)
if [ $git -eq 1 ]; then
git init $name/ > /dev/null
echo "*.class" > $name/.gitignore
echo "bin/" >> $name/.gitignore
echo "docs/" >> $name/.gitignore
fi
# End
echo -e "\t${YELLOW}CREATED${RESET} new Java project: \"$name\""
}
################################################################################
# Handles compilation of a project.
#
# Arguments:
# ${@}: All compilation arguments.
#
# Outputs:
# Possible output of an "already up to date" message.
#
# Returns:
# 0 if compilation was successful, else a non-zero error code.
################################################################################
build() {
# Ensure command was run from project root
if [ $(in_root) -ne 1 ]; then
echo "Error: \"${PWD##*/}\" not a project root."
return 1
fi
# Only recompile if needed
if [ $(needs_rebuild) -eq 1 ]; then
# Parse the args and shift
args=$(arg_parser ${@})
shift $?
compile ${args[@]}
return=$?
else
echo "Project binaries are up to date."
return 0
fi
}
################################################################################
# Handles execution of application.
#
# Globals:
# name: Project directory name.
# package: Package name where the driver resides.
# driver: Name of the driver file.
#
# Outputs:
# A message displaying that the project was ran.
#
# Arguments:
# ${@}: All command line arguments passed by the user, to be sent to `main()`.
################################################################################
run() {
# Ensure command was run from project root
if [ $(in_root) -ne 1 ]; then
echo "Error: \"${PWD##*/}\" not a project root."
return
fi
# By default, status is OK to run
local status=0
# Parse the args and shift
args=$(arg_parser ${@})
local shift_amt=$?
shift $shift_amt
# If the project needs to be recompiled, do so.
if [ $(needs_rebuild) -eq 1 ]; then
compile ${args[@]}
status=$?
fi
# Only execute if compilation was successful
if [ $status -eq 0 ]; then
if [ ${#args[@]} -gt 0 ]; then
echo -e "\t${YELLOW}EXECUTING${RESET} $name with args: ${args[@]} ${@}"
else
echo -e "\t${YELLOW}EXECUTING${RESET} $name"
fi
# Execute driver with supplied args
java ${args[@]} -cp bin/ $package.$driver ${@}
fi
}
################################################################################
# Cleans project directory of class files
#
# Outputs:
# A message displaying that the project was cleaned.
#
# Arguments:
# ${@}: Flags to clean additional directories.
################################################################################
clean() {
# Ensure command was run from project root
if [ $(in_root) -ne 1 ]; then
echo "Error: \"${PWD##*/}\" not a project root."
return
fi
# Handle optional arguments
for arg in "${@}"; do
# Delete docs, if requested
if [ "$arg" = "--doc" ] || [ "$arg" = "-d" ]; then
rm -rf docs/*
fi
done
# Recursively delete all *.class files in bin/
find bin/ -name "*.class" -delete
echo -e "\t${YELLOW}CLEANED${RESET} project binaries."
}
################################################################################
# Generates documentation for the project.
#
# Globals:
# name: Project root name.
#
# Outputs:
# A message stating that documentation was created.
################################################################################
doc() {
# Ensure command was run from project root
if [ $(in_root) -ne 1 ]; then
echo "Error: \"${PWD##*/}\" not a project root."
return
fi
# Need to pass in special args for JavaFX?
args=$(arg_parser ${@})
shift $?
# Mute output when documenting, but display errors
find src/ -name "*.java" -print | xargs javadoc ${args[@]} -d docs > /dev/null
echo -e "\t${YELLOW}GENERATED${RESET} docs for project under \`$name/docs/\`"
}
################################################################################
# Adds dependencies to the project
#
# Globals:
# name: Project root name.
# MODULE: Project module file.
#
# Arguments:
# ${@}: Dependencies and flags to add.
#
# Outputs:
# A message declaring that a dependency was added
################################################################################
add() {
# Ensure command was run from project root
if [ $(in_root) -ne 1 ]; then
echo "Error: \"${PWD##*/}\" not a project root."
return
fi
if [ ${#@} -lt 1 ]; then
echo "usage: jargo add <dependency>"
return
fi
# Keep track of number of dependencies added
local added=0
# Add each dependency
for arg in "${@}"; do
case "$arg" in
"jfx" | "javafx") # Add JavaFX support
sed -i "/module $name/a requires javafx.controls;" src/$MODULE
added=$((added + 1))
;;
*)
echo "Unsupported dependency \`$arg\`. Not yet implemented"
;;
esac
done
if [ $added -ne 0 ]; then
echo -e "\t${YELLOW}ADDED${RESET} $added dependencies for project under \`$name/src/$MODULE\`"
fi
}
################################################################################
# Initializes an existing project to be a Jargo project.
#
# Globals:
# name: Project root name.
# driver: Driver file name.
# package: Package name containing driver file.
# MODULE: Project module file.
#
# Arguments:
# ${@}: Initialization flags.
#
# Outputs:
# A message declaring that the project was initialized.
################################################################################
init() {
# Ensure command was not run from project root
if [ $(in_root) -eq 1 ]; then
echo "Error: \"${PWD##*/}\" is already a project root."
return
fi
# Default to initializing a git repository
local git=1
# Get name of current directory
name=$(basename $(pwd))
# Get name of the driver (where main is located)
driver=$(grep -lr "public static void main" src/ | xargs basename -s ".java")
# Get name of the package containing driver
package=$(grep -lr "public static void main" src/ | xargs dirname | xargs basename)
for arg in "${@}"; do
case $arg in
"--no-git") # Do not initialize a git repository
shift
git=0
;;
*) # Unknown argument
echo "Error: Unknown argument \`$arg\`"
shutdown 5
;;
esac
done
# Create configuration file
echo "# Configuration file for Jargo Project Manager (https://github.com/HammerAPI/jargo)
name:$name
package:$package
driver:$driver" > $CONFIG
# Set up README.md
echo "# $name " > README.md
# Initialize Git repository (if not disabled)
if [ $git -eq 1 ]; then
git init > /dev/null
echo "*.class" > .gitignore
echo "bin/" >> .gitignore
echo "docs/" >> .gitignore
fi
echo -e "\t${YELLOW}INITIALIZED${RESET} Project under \`$name/src/$MODULE\`"
}
################################################################################
# Checks if the project needs to be recompiled.
#
# Returns
# 1 if project must be recompiled, else 0.
################################################################################
needs_rebuild() {
local retval=0
# Fetch arrays of all files in `bin/` and `src/`
bins=($(find bin -type f -exec echo {} \;))
srcs=($(find src -type f -exec echo {} \;))
# If there are fewer binaries than source files, compile
if [ ${#bins[@]} -lt ${#srcs[@]} ]; then
retval=1
fi
# Loop over both arrays
for ((i=0; i<${#bins[@]}; i++)); do
# If any source file is newer, recompile
if [ "${srcs[i]}" -nt "${bins[i]}" ]; then
retval=1
fi
done
echo $retval
}
################################################################################
# Actually compiles the project.
#
# Globals:
# name: Project root name.
#
# Outputs:
# A message displaying a successful compilation.
#
# Arguments:
# ${@}: List of arguments to compile with.
#
# Returns:
# 0 If program was compiled successfully.
################################################################################
compile () {
# Compile with new args
find src/ -name "*.java" -print | xargs javac ${@} -d bin/
local retval=$?
# Display compilation message if no errors occurred
if [ $retval -eq 0 ]; then
# Display appropriate compilation message
if [ ${#@} -gt 0 ]; then
echo -e "\t${YELLOW}COMPILED${RESET} $name with args: ${@}"
else
echo -e "\t${YELLOW}COMPILED${RESET} $name"
fi
fi
return $retval
}
################################################################################
# Determines if `jargo` was run from a project's root.
#
# Globals:
# name: Ensure this command is being run from the project root.
#
# Returns
# 1 if ran from project root, else 0.
################################################################################
in_root() {
local retval=0
# If the working directory is the same as the project's name
if [ "${PWD##*/}" == "$name" ]; then
retval=1
fi
echo $retval
}
################################################################################
# Parses arguments supplied for the `java` and `javac` commands.
#
# Arguments:
# ${@}: List of arguments to be parsed.
#
# Returns
# A list of parsed arguments.
# The number of arguments parsed.
################################################################################
arg_parser() {
# Local variables for args and shifting
local shift_amt=0
local args=()
# Loop over every arg provided
for arg in ${@}; do
# If the arg is empty, ignore it
if [ -z "$arg" ]; then
continue
fi
# Parse the args
case "$arg" in
"--jfx" | "--fx") # Add JFX support
# Increase shift amount
shift_amt=$((shift_amt + 1))
args+=("--module-path $PATH_TO_FX --add-modules javafx.controls")
;;
*) # No parsing needed
;;
esac
done
echo "${args[@]}"
return $shift_amt
}
################################################################################
# Project Main Method.
#
# Arguments:
# ${@}: All command line arguments supplied by the user.
################################################################################
main () {
# Check minimum args
if [ $# -lt 1 ]; then
usage
shutdown 1
fi
# Launch appropriate command
case $(echo $1 | tr '[:upper:]' '[:lower:]') in
"new" | "n") # Create new project
shift
new ${@}
;;
"build" | "b") # Compile project
shift
build ${@}
;;
"run" | "r") # Run project
shift
run ${@}
;;
"clean") # Clean project
shift
clean ${@}
;;
"doc") # Generate documentation for project
shift
doc ${@}
;;
"add") # Adds dependencies to the project
shift
add ${@}
;;
"init") # Initializes an existing project as a Jargo project
shift
init ${@}
;;
"--help" | "-h") # Display help menu
shift
usage
;;
*) # Unknown arg
echo "Error: Unknown command \`$1\`"
shutdown 2
;;
esac
}
# Execute main and exit with appropriate error code
main ${@}
# Program success
exit $?