Android ant and bash scripting - android

I've had 0 exposure to BASH scripting and this is something I would love to learn. I can't figure out how to run a conditional statement based on the output of ant debug on an Android build.
I would like to essentially say something like
if(`ant debug` == SUCCESS) {
// EXECUTE THESE COMMANDS
} else {
// EXECUTE THESE COMMANDS
}
How can I determine if the ant debug has passed or failed in shell script?
SOLUTION
Okay here is what I have:
ant clean
if ant debug; then
echo "success"
else
echo "failure"
fi

I'll give a quick summary for you.
In Bash, conditionals are based around the exit codes of programs. An exit code of 0 is accepted as true, while everything else is accepted as false.
For example, the true program always exits with an exit code of 0, which means that something like this is possible:
if true;
echo "It is true"
fi
Most commands honor this system, but not every program does. The first thing to check is what exit code ant returns on success and failure. You can check the exit code of the previous command with $?.
Here is an example:
$ true
$ echo $?
0
$ false
$ echo $?
1
If ant does honor the exit code system properly, then something like the following should be possible:
if ant debug; then
echo success
else
echo failure
fi

I know nothing about Ant debugging, but there are two approaches to doing what you want to do in Bash. The first is to test output like you've shown:
if test $(ant debug) == 'SUCCESS'; then
# do stuff
else
# do other stuff
fi
You can make your shell script portable to other variants on the Bourne shell by using backticks instead of $(.....) like you wrote in your question, but that starts to become a hassle if your commands later involve nested quotes.
The second way, which is a little more robust, is to test the exit value of the commands instead of their output. This depends on Ant (or whatever) having exit codes that are documented and stable, but it means that if the output of the commands changes, your scripts will continue to work. For example, the POSIX standard says that if a programs succeeds in doing whatever it's supposed to do, it should exit() with a value of zero:
ant debug > /dev/null
ant_exit_code=$?
# other commands can safely go here now that $? is captured
if test $ant_exit_code -eq 0; then
# do stuff
else
# do other stuff
fi
And yes, Bourne shell really does end an if block with "fi". :-)

A quick man ant shows that ant debug invokes Ant with the debug task. Ant's tasks are kinda of user-defined XML scripts, and by default Ant searches a build.xml file in the current directory. You can generate the file with the android tools, however a template is kept in android-sdk/tools/ant and you can view it online (line 1005 defines the debug target).
So ant debug isn't really a command, and should not be put in a script toolchain. However, if you find your output to be stable and feel brave, you can always compare string. This is the definitve guide.
if [ `ant debug` = $SOMETHING ]; then
echo Success
else
echo Failure
fi

Related

How to make Android Studio/Gradle build from an updated source file?

In my previous Windows/Eclipse/ant project development method I had a means of producing a time-limited release apk from the command line. I would like to reproduce this functionality with my new Ubuntu/Android Studio/Gradle setup.
This is how the old system worked:
I had a .bat file which ran a runnable jar which I wrote (and can also create on my new machine). That jar takes two arguments expiry date and where to put the output file. The jar's output is called Timekey.java and it looks like:
package uk.co.myname.timekey;
public final class Timekey{
public static final String EXPIRY_DATE =
"the encrypted string";
public String getExpiryDate() {
return EXPIRY_DATE;
}
}
// Plain date : 2020-01-01.00_00_00
I have my build.xml checking for the presence of this file
<target name="-check-timekey">
<echo>"${timelimit_src}/Timekey.java"</echo>
<available file="${timelimit_src}/Timekey.java" property="timekey.present" />
</target>
and if present it sets the src
<if condition="${timekey.present}">
<src path="${timelimit_src}" />
Thus I can produce an apk which will only run up to the date entered as a parameter to the batch file. The encryption is not military grade but good enough to defeat amateurs and should stop the de-obfuscation fiends.
Any ideas on how to implement this with gradle will be most welcome. I know how to run the jar from a bash script but swapping source directories, just for command line release builds has me stumped
I did manage to solve this in the end. I created the build type 'release' which was not previously necessary,as 'main' sufficed. I also reated the build type 'timelimited'. Timekey.java was removed from main and placed in debug, release and timelimited's src/java folders (including the class stucture hierarchical folders).
This script completed the process
#!/bin/bash
# Script to build time limited apk NBT 2nd March 2016
# Must be run from one leve below AndroidStudioProjects folder
# Must have one argument of expiry date in YYYY-MM-DD format
CURRENT_DIR=`pwd`
case "$CURRENT_DIR" in
*AndroidStudioProjects/*) ;;
*) echo "Quitting because of wrong starting directory name"
echo "You must be one folder below ~/AndroidStudioProjects to run this script"
exit 1 ;;
esac
OUTDIR_SUFFIX=/app/src/timelimited/java/uk/co/myname/timekey/
OUTDIR=$CURRENT_DIR$OUTDIR_SUFFIX
echo "Directory to write in: "$OUTDIR
if [ -z "$1" ]
then
echo "argument 1 required, as expiry date in YYYY-MM-DD format, so quitting"
exit 1
fi
EXDATE=$1
case "$EXDATE" in
????-??-??) ;;
*) echo "Quitting because of bad date format on parameter 1"
exit 1 ;;
esac
# the encrypt5.jar requires these two arguments
java -jar ~/runnablejars/encrypt5.jar $EXDATE $OUTDIR
echo " "
echo " "
gradlew assembleTimelimited
cat $OUTDIR/Timekey.java
echo " "
echo "All done, now IF you saw Timekey.java printed out, then"
echo "the time limited apk is built. Run gradlew InstallTimelimited"
echo "to install it on a running device"
while true; do
read -p "Do you wish to install this apk on running device y/n [enter]? " yn
case $yn in
[Yy]* ) gradlew InstallTimelimited; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
I hope this might prove useful. There are probably less convoluted ways of doing it but I don't know one.

Why does gradle not run my shell script?

I'm almost certain i am overlooking something.
I have an android gradle project with a build.gradle file. Inside here, I specify the task:
task doSomething(type: Exec) {
println("okay clearly you have got to be getting in here")
commandLine 'sh /Users/dzt/Desktop/create_a_file_on_desktop.sh'
}
and that doesn't run at all. the shell file just literally does:
#!/bin/sh
echo "hi" > /Users/dzt/Desktop/i_am_a_byproduct.txt
and i ran chmod u+x on it so it is executable (i double checked on regular bash shell).
I also tried to use the groovy command:
"cd ../ && sh /Users/dzt/Desktop/create_a_file_on_desktop.sh".execute()
which does not work either. I'm a little stumped. i do NOT see the output file. however, i do see my print statement in the gradle console.
What is going on here?
** EDIT **
okay, i drilled it down more ->
cd ../ does not work at all. why is this? i need to use a relative path, at least relative to this directory
The call must be
commandLine 'sh', '/Users/dzt/Desktop/create_a_file_on_desktop.sh'
or else this is considered one command. But you want to start the sh with the script as param. On the other hand, since you have set the execute-bit, you can as well just call the shell script directly.
See http://gradle.org/docs/current/dsl/org.gradle.api.tasks.Exec.html
Running cd like you want with cd ../ && sh script does also not work like this, since && is a shell script command. If you want to run like this, you have to run the shell and make it run as a command. E.g.
commandLine 'sh', '-c', 'cd ~/scripts && sh myscript.sh'
Gradle does not allow cd command for some reason. some commands just do NOT work using groovy.
instead, i used cd inside my shell script. that seems to work just fine.
First, you have to put in the root level gradle.build file. The you need to write it like this, to actually be able to execute the task.
task doSomething << {
group 'yourGroupName'
description 'Runs your bash script'
exec {
workingDir "$projectDir/../pathto/"
commandLine 'bash', '-c', './bashscript.sh'
}
}
Then you can execute with: ./gradlew -q doSomething. In this case I used bash, but you can use any supported scripting shell, like sh, perl, python etc.

How to return 0 if a pattern is matched from a file?

I have a binary that repacks android kernel (not mkbootimg).
I'm making a script to automate the process.
I don't want any output on the screen. So I have redirected the output to a file named foo.log.
My current working folder is data/local/working/.
The command is - kernel_make "$zImage" "$ramdisk" "$cmdline" "$image" &> data/local/working/foo.log
What I've to do is, if the last line of the output (foo.log) is this -
"targed file $1 is patched sucesfully, enjoy new kernel"
Then return 0 and exit. Else return 1 and exit.
I'm trying to do with grep, but as I'm new to command line, do don't have any idea of doing it the right way.
Please be free to ask if anything more is required..
a common usage for that would be grep -q 'pattern', it doesn't generate any output, but you can check the return value of the command to decide if the pattern was found. See this example:
kent$ echo "foo"|grep -q bar
kent$ echo $?
1
kent$ echo "bar"|grep -q bar
kent$ echo $?
0
hope this is what you are looking for.
To extract the last line, you can use tail command.
In fact, you can also do it with awk in one shot:
..cmd with..output|awk 'END{if (!/pattern/)exit 1}'
then you can check the $?

Why is nohup still causing a process being run in a shell script to terminate?

I am logging the data coming from top and putting it into a circular set of files. I am not executing top for one set of data and then rerunning for the next set, but instead using a read time out to specify when to go from one log file to the next. This is primarily done this way to remove the startup CPU load cost every time top is executed. The shell script file's name is toplog.sh and looks similar to this:
#!/data/data/com.spartacusrex.spartacuside/files/system/bin/bash
date
echo " Logging started."
fileCmp()
{
test `ls -lc "$1" | sed -n 's/\([^ ]* *\)\{4\}\([0-9]*\).*$/\2/;p'` $2 $3
}
oldest()
{
ls -rc $1 2> /dev/null |head -1
}
file=`oldest /mnt/sdcard/toplog.\*.gz`
echo " Oldest file is $file"
if [ -z "$file" ]; then
x=0
else
file=${file%%.gz}
file=${file##*.}
x=$file
fi
echo " x=$x"
top -d 20 -b | \
while true; do
file=/mnt/sdcard/toplog.$x.gz
while read -t 5 line; do
echo "$line"
done | gzip -c > $file
if fileCmp "$file" -le 300; then
date
echo " Failure to write to file '$file'."
exit
fi
x=$((($x+1)%10))
sleep 14
done
I execute this using nohup so that when the shell dies, this process still runs, like so:
$ nohup ./toplog.sh
But there's a problem. top terminates when I exit the shell session that executed that command, and I'm not exactly sure why. Any ideas?
To clarify, I'm logging on a Android phone. The tools are limited in functionality (i.e. lack some of these switches) and is why I am using top as it contains the output I want.
Version of busybox I'm using is:
BusyBox 1.19.2 (2011-12-12 12:59:36 GMT)
Installed when I installed Terminal IDE.
BTW, this phone is not rooted. I'm trying to track down a failure when my phone responds as if the CPU has spiked and won't go down.
Edit:
Well, I found a workaround. But the reason is a bit hazy. I think it has to do with process management and smells of a bug in the busybox ver that I'm using that was missed during regression testing.
The workaround is to wrap top with a useless loop structure like this: while true; do top; done. Through testing, top never gets killed and never gets respawned, but by wrapping it up, it isn't killed.
Any insights on this?
going to sound stupid, but change your startup command from
nohup ./toplog.sh
to
nohup ./toplog.sh &
the & makes it run as a background process further removing it from the terminal stack.
Running the bash internal command "disown" on your script's process before logging off may prevent it from being signaled.

Time cannot run brunch?

I'm having an issue with the time command.
I use /usr/bin/time so i can use the -f and -o modifiers.
My script is:
make clean
repo sync -j5
. ./platform_manifest/manual_add_kernel_manifest.sh \
&& . build/envsetup.sh \
&& /usr/bin/time -o log$day$month.log -f "Buildtime: %E" brunch aokp_mako-eng
The script is part of an automated build system for an android ROM.
When it gets to the time part, i get:
/usr/bin/time: cannot run brunch: No such file or directory
Command exited with non-zero status 127
Buildtime: 0:00.00
Brunch works fine with the regular time command, but I cannot route its output to a file, which is why I am using /usr/bin/time in the first place. If there is a way to do this, that is fine for me as I can trim off the real: header with | awk '{ print $2 }'.
Any help is appreciated!
Ubuntu 12.04, all updates installed
I don't know what brunch is, but the most likely reason that a non-builtin time program can't find it, even when the built-in time can, is that it's a shell function or a Bash alias.
Whether or not that's the case . . .
[…] I cannot route [the regular time command's] output to a file […]
You can write:
{ time brunch aokp_mako-eng ; } 2>"log$day$month.log"
to wrap time (and everything else) into a command-list whose STDERR has already been redirected to the file.

Categories

Resources