Power of bash

February 27, 20170

  We all tend to do our work faster because time costs money. I realized that we lose a lot of time waiting for IDE to start. In our company, we use Netbeans IDE and all our work is related to it. For Java modules, we use Maven and, of course, we have some custom goals. Some goals are pure Java, though we have some goals that use SVN for committing, logging, reverting and so on. And some of them are related to our RDBMS as we load a DB.

  But the main problem is that we can do all of this only when Netbeans IDE finishes its class path scanning and other indexing background processes. This, depending on your hardware, could sometimes take up to 3-5 minutes. I didn’t like it, so I decided to make this process a bit faster.

  I defined the following main features we use, which I could improve:

  • Load database;
  • SonarQube scanning;
  • Clean and build;
  • Pull the source code aka Git but this is for SVN;
  • Push the source code aka Git but this is for SVN;
  • SVN reset;
  • SVN log;
  • Java Deploy.

2016-09-19-14_46_26-inther-core-demo-setup-netbeans-ide-8-1

Fig. 1 Default Maven actions set up for a project

  All these features are related to Maven, therefore, we can write Maven commands. Here is where the BASH comes in! We all know that bash is a very popular and flexible scripting language used by many people around the world. I decided to install and use it instead of the default CMD from Windows. However, it is really hard to remember and write a command like:

mvn clean install inther:loaddb inther:execmodule inther:migratedb inther:activemq -Pdevelopment -Dactivemq.purgeAllQueues=true

  I could have used some plugins from GitHub that provide some features, like fast running a command. But, since I am not a Bash person, I decided to write my own bash scripts. This would introduce me to the Bash world and give me a brief view of its commands. As starting point I installed GIT that provides, by default, the Bash terminal and its environment.

Bash aliases

  Bash terminal can be configured to load a file at startup. This file is called .bash_profile. You can create it in the %USER_PROFILE% directory. In this file, you can write your own bash scripts and they will be available in the terminal at runtime. I added some aliases that are bound to some functions I could run. Example:

alias r='r_registerCurrentDirectoryWithAnAllias'
alias j='j_jumpToADirectory'
alias m="maven_command"

  Each alias value is a Bash function that is responsible for doing something. Taking in consideration that all commands are Maven based, I defined three aliases I would need:

  • M – Run a maven command based on a pom.xml file;
  • R – Stands for register. I use it to add a directory with a directory alias, list them or remove one;
  • J – Jump to a directory using a directory alias.

Core and customer structure

  Before we go through the implementation, I have to explain why I defined these specific aliases. Internally, we build a product for clients that hold warehouses. More or less, they all have mostly the same functionality, so we have divided our product in 2 parts:

  • The Core (common functionality);
  • The Client (customer specific functionality).

  Because of this, we have different versions for these components. The Core is based on branches and tags like 1.0-SNAPSHOT or 1.0.1.

  The Client component is based on environments:

  • Development-SNAPSHOT, where it may have a dependency on 1.0-SNAPSHOT;
  • Acceptance-SNAPSHOT;
  • Production-SNAPSHOT.

  This structure creates some patterns for accessing specific project folder, like:

D:ProjectAbranches1.0-SNAPSHOT
D:ProjectBtags1.0.2
D:ProjectCenvironmentdevelopment
D:ProjectCenvironmentacceptance
D:ProjectCenvironmentproduction

Commands

  R – Register

  Now let’s see what was optimized by using Bash. Using the above mentioned aliases, I can run the commands. As I mentioned ‘r’ stands for register, which holds different aliases for different paths. Using “r” I can run:

  • a – add alias;
  • ls – list aliases;
  • r – remove an alias.

  Main function:

 
function r_registerCurrentDirectoryWithAnAllias()
 {
  command=$1
  alias=$2
  r_processCommand $command $alias
 }

  Delegated function:

 
function r_processCommand()
{
command=$1
alias=$2
validateParameter $command
local isCommandValid=$?

if [ $isCommandValid == 0 ]
then
case $command in
"a" )
validateParameter $alias
local isAlliasValid=$?
if [ $isAlliasValid == 0 ]
then
add $alias
else
echo "Missing alias"
fi 
;;
"ls" ) 
initFile out_pathDir
pathDir=$out_pathDir
fileLines $pathDir 0
;;
"r" ) 
validateParameter $alias
local isAlliasValid=$?
if [ $isAlliasValid == 0 ]
then
remove $alias
else
echo "Missing alias"
fi 
;;
esac
else
echo "Missing command"
fi

}

  Now I go to the pom.xml file of the project and run: r a test – which means: register add for the current path the alias ‘test’;

a1

function add()
{
initFile out_pathDir
pathDir=$out_pathDir

alias=$1
currentDir=$(pwd)

fileLines $pathDir 1
file_lines_array_size=${#fileLines_lines[@]} 

if [ $file_lines_array_size == 0 ]
then
echo "$alias=$currentDir" >> $pathDir
else
array_of_lines=${fileLines_lines[@]}
for line in $array_of_lines
do
lineKeyValue $line out_key out_value
if [ $out_value == $currentDir ]
then
echo "Such directory already exists on $line"
break
else
echo "$alias=$currentDir" >> $pathDir
break
fi
done
fi
}

  This command creates in background a file “.pathDir” which will be used as a storage for all the aliases. Now I have an alias inside it.

  In order to see what other aliases I have, I can write: r ls – this command will display all the aliases I have in the “.pathDir”.

s2

  And of course, I can remove an alias by writing: r r test – which means: register remove the alias ‘test’ linked to any path. Now I can use ‘test’ for any other path from the system.

s3

function remove()
{
initFile out_pathDir
pathDir=$out_pathDir

alias=$1
currentDir=$(pwd)
sed "/$alias=/d" $pathDir >> "$pathDir tmp" && mv "$pathDir tmp" $pathDir
}

  J – Jump

  After we added an alias for a path, we can now directly jump to that directory by typing: j iut – it’s a simple cd to the referenced path.

s4

  Main function:

function j_jumpToADirectory
 {
  alias=$1
  branch=$2
  j_jump $alias $branch
 }

  However, this does not bring you a lot of magic since we might have tags, branches and environments for a project. Well, jump supports additional parameters to the command, like: j iut 1.0.2 – this way we can jump specifically inside the needed folder. But in this case ‘iut’ alias should be linked to ‘D:ProjectA’ , because this will be the root folder of the project. We can also jump to a tag or an environment if it exists, by writing the following command: j iut 1.0.2 or j iut d where d stands for development environment.

s5

function j_jump
{
local alias=$1
local branch=$2
validateParameter $alias
local isAliasValid=$?
if [ $isAliasValid == 0 ]
then
initFile out_pathDir
pathDir=$out_pathDir
fileLines $pathDir 1
file_lines_array_size=${#fileLines_lines[@]}

if [ $file_lines_array_size != 0 ]
then
array_of_lines=${fileLines_lines[@]}
local isFound=1 
for line in $array_of_lines
do
lineKeyValue $line out_key out_value
if [ $out_key == $alias ]
then
isFound=0
local path=$out_value
validateParameter $branch
local isBranchValid=$?
if [ $isBranchValid != 0 ]
then
cd $path
break
else
cd $path
j_process_branch $branch out_path
local fullpath="$path/$out_path"
cd $fullpath
break
fi
fi
done
if [ $isFound == 1 ]
then
echo "No such alias found"
fi
else
echo "No aliases found"
fi
else
echo "Missing parameter"
fi
}

function j_process_branch
{
local branch=$1
local pth=$2
isMajorMinorFunc $branch
local isMajorMinor=$?
isTagFunc $branch
local isTag=$?
isPrivateNumberFunc $branch
local isPrivateBranch=$?

if [ $isMajorMinor == 0 ]
then
eval $pth="branches/$branch-SNAPSHOT"
elif [ $isTag == 0 ]
then
eval $pth="tags/$branch"
elif [ $isPrivateBranch == 0 ]
then
eval $pth="branches//private-$branch"
else
case $branch in
"t" )
eval $pth="branches/TRUNK-SNAPSHOT"
;;
"d" )
eval $pth="environment/development"
;;
"a" )
eval $pth="environment/acceptance"
;;
"p" )
eval $pth="environment/production"
;;
esac

fi
}

  M – Maven

  Now, when we are able to jump faster from one project to another, we can run maven goals over the pom.xml files, like this:

  • m ldb – loads database;
  • m pull – SVN update goal;
  • m push – SVN commit goal;
  • m reset – SVN revert goal;
  • m log – SVN log goal;
  • m deploy – deploy;
  • m sonar – sonar goal.

s6

 

function maven_command
{
local command=$1
validateParameter $command
local isCommandValid=$?
if [ $isCommandValid == 0 ]
then
case $command in
"sonar" )
mvn clean install sonar:sonar -Dsonar.host.url="https://md-dev01:9000"
;;
"ldb" )
local setup=$(find -regex ".*setup$" | head -1)
cd "$setup"
mvn clean install inther:loaddb inther:execmodule inther:migratedb inther:activemq -Pdevelopment -Dactivemq.purgeAllQueues=true
;;
"ci" )
mvn clean install
;;
"pull" )
mvn inther:ts-update -N
;;
"push" )
mvn inther:ts-commit -N
;;
"reset" )
mvn inther:ts-revert -N
;;
"log" )
mvn inther:ts-log -N
;;
"deploy" )
mvn clean source:jar javadoc:jar deploy -Pjavadocprof
;;

*)
mvn $@
;;
esac
else
echo "Missing command"
fi
}

Conclusion

  Having all of this configured, we can run the load the database or any command over a pom.xml file without even having to start the Netbeans IDE. The .bash_profile can be customized per developer, so everyone can add commands of their own. The most important thing is that using Bash we can gain a lot of power due to its internal commands that Windows does not have. We save a lot of time. And while Netbeans starts, you could already have 3-4 terminals working:

  • One loading the DB;
  • Another loading logs;
  • Third updating another project.

Leave a Reply

Your email address will not be published.

https://isd-soft.com/wp-content/uploads/2022/08/whitelogo150.png
Connect with us
Bulgara Street 33/1, Chisinau MD-2001, Moldova
+ 373 22 996 170
info@isd-soft.com
De Amfoor 15, 5807 GW Venray-Oostrum, The Netherlands
+ 31 478 502944

Subscribe to our newsletter today to receive updates on the latest news, releases and special offers.

Copyright ©2022, ISD. All rights reserved | Cookies Policy | Privacy Policy