Thursday, April 09, 2009

Pre-commitment issues

I've been doing a bit of Subversion hackery recently, and thought I'd briefly cover some of the major moving parts here for future reference.

First things first - Subversion hooks go into the /hooks directory of your repository and are executed by Subversion at various stages of the Subversion process. I'm working on a pre-commit hook, which will be executed by Subversion before each check-in is committed to the repository. Any non-zero return code from the hook will cause Subversion to deny the check-in.

If your Subversion repository is hosted on Unix, all you need to do is to name your pre-commit script "pre-commit" (note no extension), and make sure it is executable and has the appropriate hashbang at the top.

If your repository is hosted on Windows (like my test-repo is), you'll need to create a pre-commit.bat file and call through to your script, like this -

@rem PRE-COMMIT.BAT
@rem
@rem Pre-commit script for Subversion running on Windows.
@rem Calls a pre-commit python script in the current folder.

pre-commit.py %*


(I'm obviously relying on the .py extension being correctly associated with the Python interpreter here, but you could also invoke the interpreter directly if you wanted to.)

Now you have the basics in place, every check-in to the repo will cause the pre-commit.bat to be executed. However, this leaves you with a problem when it comes to debugging - the only way to execute your script is by attempting to make a commit to the repo and wait for Subversion to call the script.

Enter this cunning little trick from Thomas Guest - executing your hook script from the command-line with a past revision:

#!/usr/local/bin/python

"""
Pre-commit code goes here. Non-zero return code indicates
failure.
"""
def preCommit( repo, transaction, useRevision=False ):
# put your pre-commit code here

return 0

"""
Main control logic. Parses the command-line and invokes the
preCommit() method with the appropriate parameters.
"""
def main():
usage = """usage: %prog [options] REPO TXN

Run pre-commit checks on a repository transaction.

For debugging, try "%prog -r /path/to/repo 123" to check revision 123
"""
from optparse import OptionParser
parser = OptionParser(usage=usage)
parser.add_option(
"-r", "--revision",
help="Test mode. TXN actually refers to a revision.",
action="store_true", default=False)

try:
(opts, (repo, transaction)) = parser.parse_args()
except:
parser.print_help()
return 1

return preCommit( repo, transaction, opts.revision )

if __name__ == "__main__":
import sys
sys.exit(main())


When Subversion invokes the hook, it will call it with the repository-location as the first parameter, and a transaction id as the second. By allowing the command-line to treat the 2nd parameter as a revision instead, it allows us to test and debug the hook without going through Subversion all the time:

pre-commit.py -r /path/to/repo 123


Thanks to Thomas for the idea, and apologies for reimplementing it badly.

Stay tuned for more Subversion hackery and a more comprehensive example showing how to link Subversion and Maven 2.

Tuesday, July 29, 2008

iPhone unable to log in to iTunes Store

I ran into an unexpected problem this morning after my iPhone 3G informed me that updates were available for my current favourite time-waster, Aurora Feint. While I downloaded the game through iTunes on my PC and sync'ed it over to the iPhone, the updates are downloaded over the air, so to get them I had to log into my iTunes account on the iPhone for the first time.

First attempt failed. Now, I'm still not quite up to speed on typing on the iPhone keyboard, so I figured I'd got it wrong and tried again. Still wrong password, even though I made sure I got it right. I even double-checked that I had the right password by logging into my account from my PC.

Then I had an idea - being Norwegian, my password contains "funny" characters. Could the iPhone be messing up the input of special characters, even though it properly displays them and makes them available for input?

I changed my iTunes password to "safe" characters only, and tried logging in from the iPhone again. Success first time - my hypothesis was strengthened.

To confirm my findings, I went back to my account page in iTunes and tried changing the password back to my original one.

Password contains an invalid character. Only letters, without accents, numbers, and simple punctuation may be used. Your password contained unacceptable characters.

Hmmm. But this is my OLD password that was perfectly fine all along? (Except not being able to log in from my iPhone, obviously ...)

So - a couple of problems with this approach, Apple:
  • Limiting passwords to 7-bit ASCII characters is a Bad Thing.
  • Not realising that TWOTUS(*) has more than 26 "letters, without accents" is a Bad Thing.
  • Changing the set of allowable characters in the passwords after making your service 'live' is a Bad Thing.
  • Not detecting existing passwords with newly outlawed characters and informing your users is a Bad Thing. (**)
  • Reducing your server security to accommodate "inferior" clients is a Bad Thing. (Assuming this is iPhone/iPod-touch related, that is. I can't think why else you'd do it, though.)

Not impressed. Must do better.

(*) TWOTUS: The World Outside The United States.

(**) Note on password security:
You should NOT be able to scan your database of existing accounts to find the offending passwords, but it should be trivial to hook into the validation process at log-in to discover accounts with newly-invalidated passwords.

Sunday, July 20, 2008

Subversion: In-url revision browsing

I use Subversion for revision control, and while most Svn tools (like Subclipse, TortoiseSVN, and even the svn command-line client) offer decent log- and diff-tools, sometimes I find it easier to quickly pull up an Svn resource in a browser to look at it.

Let's use the Google Code 'svn merge fairy' project for our guinea pig. Their current trunk is at http://svn-merge-fairy.googlecode.com/svn/trunk/ (revision 8 at the time of writing).

Now, to easily browse an earlier revision of the tree, simply edit the URL and insert "/!svn/bc/<revision number>/" after the Svn root: http://svn-merge-fairy.googlecode.com/svn/!svn/bc/1/trunk/

Here you can see that the first version (revision 1) of the project contained no files.

(I'll come back to branch-management using svn merge fairy in a future post.)