12 Jan 2012

Update AndroidManifest.xml version code and name for builds programmatically

After far too long of putting it off I have gone through and automated some of our Android build processes. We increment our version code for every release build and set the version code to be version number . date code. So our AndroidManifest.xml looks something like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="schema"
      package="packagename" android:versionCode="96" android:versionName="0.9.201201011255">

The following simple Bash script to pull these values (the 96 and 0.9.201201011255) and increment the version code and change the date code on the version to be the current date / time.
Despite using Linux for many years I've never gotten comfortable with Bash, so there might be a significantly better way to do this:
#!/bin/bash

MANIFEST_FILE='AndroidManifest.xml'
VERSIONCODE=`grep versionCode $MANIFEST_FILE | sed 's/.*versionCode="//;s/".*//'`
VERSIONNAME=`grep versionName $MANIFEST_FILE | sed 's/.*versionName="//;s/\.[0-9]*".*//'`

NEWCODE=$((1+$VERSIONCODE))
NEWNAME=$VERSIONNAME.$(date +'%Y%m%d%H%M')

echo "Updating Android build information. New version code: $NEWCODE - New version name: $NEWNAME";

sed -i 's/versionCode *= *"'$VERSIONCODE'"/versionCode="'$NEWCODE'"/; s/versionName *= *"[^"]*"/'$NEWNAME'/' $MANIFEST_FILE
I can then run an automatic build, copy the filename to the VERSIONNAME specified and do whatever I need to from there.

 

5 Dec 2011

Gnome3 - Adding custom applications (Linux Mint)

Linux Mint 12 doesn't ship with the application to edit the "Main Menu" by default. Since Gnome3 relies heavily on typing in application names, you need to be able to add new applications to the menu list.

Luckily you can just create per-user .desktop files that will be quickly picked up by the Gnome3 launcher.

The folder location is ~/.local/share/applications/

Just add the .desktop files, as desired. For example:

~/.local/share/applications/Eclipse.desktop

[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=Eclipse
Categories=;
Comment=Eclipse
Comment[en_CA]=Eclipse Development Environment
Exec=/opt/eclipse/eclipse
Icon=/opt/eclipse/eclipse-reflective.png
Hidden=false
Terminal=false
Type=Application
GenericName[en_CA]=

New_app

31 Aug 2011

Using a VPS and SSH to expose your local machine's ports

When working with certain APIs it can be necessary to expose certain ports on your local machine to the world. In this case, I need to expose port 80, but most consumer ISPs (and work firewalls) block port 80 incoming.

Enter SSH port forwarding (and Amazon's free micro instance tier, although any VPS would work).

Once your machine is set up (the default configuration of Ubuntu Server is what I used, but most Linux machines should be fairly similarly configured), you need to do the following:

Enable SSH access for root.

 In my case, I did this by setting up the public/private key for SSH so that I can connect root in but still disallow password SSH access. Root is needed to be able to SSH in since port 80 is a privileged port. If you don't need to forward port 80, then you don't need to connect as root.

Enable "GatewayPorts" in your /etc/ssh/sshd_config file.

Without this setting, sshd will not allow you to set up a port forward on anything but the loopback adapter, meaning you'll never be able to connect to your forwarded port from external IP addresses. This is the most important step to making this work, because without this it will fail silently.

# grep Gateway /etc/ssh/sshd_config
GatewayPorts yes
#

Run a service on your local machine on any port.

My development laptop has port 80 running apache2. This could be any port.

Connect to the remote machine with SSH and port forwarding.

This makes the magic happen - just run a simple SSH command:

ssh -R*:VPS_PORT:127.0.0.1:LOCAL_PORT root@yourVPS

Since I have my VPS set up in my ~/.ssh/config file, I can simply run this command:

ssh -R*:80:127.0.0.1:80 root@micro

From left to right, these parameters mean:

  • -R - use remote port forwarding (remote machine port to local machine port)
  • * - bind on all interfaces (this allows remote connections, not just local connections on the server)
  • 80 - bind to port 80 on the REMOTE machine
  • 127.0.0.1 - forward to the LOCAL machine's IP
  • 80 - forward to the LOCAL machine's port 80

Test the configuration.

From another machine enter in your SERVER's ip address into a web browser (or some other method for testing) and you should see output from your LOCAL machine.

This is all very straightforward. 

The only gotcha here is enabling GatewayPorts. This is mentioned in the docs, but had been holding me up in the past when I tried to make this configuration work.

21 Jun 2011

Compiling BlackBerry Compatible Libraries In Eclipse in Linux

I'm currently working on a project with a shared library between Android and BlackBerry. For the most part this works well, but it's very easy to forget myself and write code that will not compile for BlackBerry. Since BlackBerry only ships development tools for Windows, you need to configure Eclipse to only allow code that will compile for BlackBerry. Simply setting the compliance level is not sufficient.

What you can do, however, is set up an Execution Environment from the BlackBerry JDK. This does not involve running and Windows executables, and is not enough to develop BlackBerry applications under Linux. It will, however, give you enough to at least write code that will compile (no more forgetting and trying to use HashMap!).

First, find the execution environment folder on a Windows machine that has the BlackBerry environment installed. The folder is named in the form net.rim.ejde.componentpack5.0.0_5.0.0.25/ (the exact name will vary). This folder contains the following:

about.html  about.ini  about.mappings  about.properties  BlackBerryJDE.gif  components  META-INF  plugin.properties  plugin.xml

Copy these to your Linux machine.

In Eclipse, go to Windows -> Preferences..., Java -> Installed JREs, and click "Add":

20110621_133458_001_selection

Choose "Execution Environment Description" and click "Next".

For the "Definition File", find the BlackBerry.ee file and click "Ok".

20110621_133637_001_selection

In the resulting window, choose "Add External JARs", and browse for net_rim_api.jar:

20110621_133824_001_selection

Once you've done that, your new Exectuion Environment should look something like this:

20110621_133948_001_selection
Click "Finish", and change one of your projects to point to this library:

20110621_134116_001_selection

Now enjoy the limited API BlackBerry developers have to deal with, all from the comfort of Linux.

20110621_134309_001_selection

14 Jun 2011

Splitting a sub-module out of a git repository

I recently had a need to split a single folder out of a repository into a new repository. When I was finished I wanted that folder to be in its own git repository and to be removed from the old. Splitting out the new repository is simple:

git clone --no-hardlinks --bare file:///opt/git/original_repository.git/
cd original_repository.git/
git filter-branch  --prune-empty --subdirectory-filter FOLDER/PATH/TO/REMOVE/ -- --all
cd ..
git clone --no-hardlinks original_repository.git/ repository_subset.git
cd repository_subset.git
git gc --aggressive
git prune

This will result in everything under the path FOLDER/PATH/TO/REMOVE being at the root of the new repository. Unlike a "git rm -rf" on the unwanted folders, the new repository has only the history associated with the kept files (making for a smaller overall repository and less baggage to push around). And removing it from the original has two options - remove it entirely (rewrite history):

git clone --no-hardlinks --bare file:///opt/git/original_repository.git/
cd original_repository.git/
git filter-branch --tree-filter "rm -rf FOLDER/PATH/TO/REMOVE/" --prune-empty
cd ..
git clone --no-hardlinks original_repository.git filtered_repository.git
cd filtered_repository.git
git gc --aggressive
git prune

Or just remove and commit the remove:

git rm -rf FOLDER/PATH/TO/REMOVE
git commit -m 'split off FOLDER/PATH/TO/REMOVE into its own repository'

I opted the for the latter for minimal impact on others using that repository. Many thanks to Paul's answer on Stackoverflow: http://stackoverflow.com/questions/359424/detach-subdirectory-into-separate-g...

9 Mar 2011

Two-Legged OAuth in Java (using Scribe) to Access SimpleGeo

There's surprisingly little clear information on how to implement a two-legged OAuth client in Java. I needed to do just that to interface with the SimpleGeo geo-information service. They provide a lot of valuable geospatial information for free. The only hurdle was accessing it.

The key with 2-legged OAuth, which is exactly the same as three-legged OAuth, is that you're simply skipping the authorization step. You don't need the special authorization key granted by the user - on the provider's website. Other than that, everything behaves exactly the same, and you can fool most OAuth APIs, even ones that don't directly support 2-legged OAuth into performing it anyway.

The secret is hinted at in the SimpleGeo blog post on Two-Legged OAuth, althoug hthey don't go into any specifics.

For this project I used Scribe-java. It was the most light-weight OAuth client I found in my quick search, and the amount of code to accomplish what I needed was astoundingly simple.

First, I needed to set the Api class for Scribe-java. This technically shouldn't be needed, but the Scribe-java API insists that this be done, so done it is. The return values don't matter, since none of these methods never get called.

public static class TwoLeggedOAuth extends DefaultApi10a {
                @Override
                public String getAccessTokenEndpoint ()       { return ""; };
                @Override
                public String getRequestTokenEndpoint()       { return ""; };
                @Override
                public String getAuthorizationUrl(Token arg0) { return ""; };
        }

Then I call the code to set up the OAuth request and get back a response.

String OPENGEO_API_KEY    = "key here";
    String OPENGEO_API_SECRET = "secret here";
    String OPENGEO_CONTEXT_URL = "http://api.simplegeo.com/1.0/context/#LAT#,#LON#.json";
    OAuthService service = new ServiceBuilder()
                             .provider(TwoLeggedOAuth.class)
                             .apiKey(OPENGEO_API_KEY)
                             .apiSecret(OPENGEO_API_SECRET)
                             .build();          

    // for 3-legged you would need to request the authorization token         
    // OpenGeo is a two-legged OAuth server, so the token is empty         
    Token token = new Token("", "");            

    OAuthRequest request = new OAuthRequest(Verb.GET, OPENGEO_CONTEXT_URL);         
    service.signRequest(token, request);         
    Response response = request.send();            

    System.out.println("Response: " + response.getBody());

And that's it. A very simple set of code to interface with the OpenGeo API. This should work with pretty much any two-legged OAuth provider.

3 Aug 2010

Exporting XML Nodes Matching an XPath Search

This is a work in progress, but it's the culmination of a bunch of various ideas pulled together.

The desired result is to return all of the records which match a specific XPath search, but instead of returning all of the XML for those records, I only want to return the nodes that matched the XPath.

This is actually really simple - just use TABLE(xmlsequence(extract)) like so:

SQL> l
  1  select m.doc_name,
  2             extractValue(value(t), '//procdate') value
  3             from fgdc m, TABLE(xmlsequence(extract(m.xml, '/metadata/dataqual/lineage/procstep'))) t
  4             where existsNode(m.xml,  '/metadata/dataqual/lineage/procstep/procdate[. >= 20100800 and . <= 20110000]') = 1
  5*             and existsNode(value(t), '//procdate >= 20100800') = 1
SQL> /

DOC_NAME                                                          VALUE
----------------------------------------------------------------- ------------------------------
Test                                                                  20100803
Test                                                                  20100803

SQL>


But this is actually really more work than is necessary. You can simply put the criteria in the original selection xpath and you end up with:

 
SQL> l
  1  select m.doc_name,
  2             extractValue(value(t), '//procdate') value
  3*             from fgdc m, TABLE(xmlsequence(extract(m.xml, '/metadata/dataqual/lineage/procstep[procdate >= 20100800 and procdate <= 20110000]'))) t
SQL> /

DOC_NAME                                                          VALUE
----------------------------------------------------------------- ------------------------------
Test                                                                  20100803
Test                                                                  20100803

SQL>

This, of course, works for text queries as well - combining contains() and a date comparison:

SQL> l
  1  select m.doc_name,
  2             extractValue(value(t), '//procdesc') procdesc,
  3             extractValue(value(t), '//procdate') procdate
  4*             from fgdc m, TABLE(xmlsequence(extract(m.xml, '/metadata/dataqual/lineage/procstep[contains(procdesc, "Test") > 0 and procdate >= 20100800]'))) t
SQL> /

DOC_NAME   PROCDESC                                              PROCDATE
---------- -------------------------------------------------- ----------
Test           Testing XML value1                                       20100803
Test           Testing XML value2                                       20100803

SQL>

The table is defined as:

SQL> desc fgdc
 Name                                                       Null?        Type
 ----------------------------------------------------- -------- ------------------------------------
 DOC_NAME                                                        VARCHAR2(65)
 XML                                                                SYS.XMLTYPE(XMLSchema "fgdc-std-001-
                                                                1998-all.xsd" Element "metadata") ST
                                                                ORAGE Object-relational TYPE "FGDC_M
                                                                ETADATA_T"

SQL>

26 Jun 2010

Eclipse Helios - Improved code lint

Given that the majority of my day is spent interacting with Eclipse, any chance that it might be improved gets me excited. So with the release of Helios I was quick to download and give it a try.

It wasn't the revolutionary change I would have liked (it's still feels big and slow, and context assist seems to drag even more than before), I did find one improvement that I don't think was in previous versions. The code lint picked up some dead code - and actually helped save me from a NullPointerException in future code.

This is a simplified example, obviously, but it illustrates what Eclipse noticed:

Eclipse_helios_lint

It makes perfect sense - if s is null, s.equals will NPE and the null check will never be called. It's also exactly what I rely on lint type operations to do - checking for that honest mistake that could lead to all sorts of problems down the line.

Thanks, Eclipse.