Benabik Alvar (benabik) wrote,
Benabik Alvar
benabik

  • Mood:
  • Music:

Programmers put effort into being lazy

It's true. It really is. I just spent an hour writing an Applescript to keep me from having to do the same set of commands over and over and over again.

The Problem: I have seven pieces of software that I like to keep up to date with the bleeding edge. To do so I have to do the following:

  1. Open a new Terminal.app tab
  2. Type in "cd <directory>"
  3. Remember if it's a git or svn repository
  4. Type in either "git pull" or "git svn rebase"
  5. Once the update is complete, notice if there are any updates. If not, stop.
  6. If there have been, optionally push those changes to a mirror with "git push"
  7. List the changes using "git changes" (an alias I've set up in my ~/.gitconfig)

The Solution: A new AppleScript application:

#!/usr/bin/osascript

global win
set win to missing value

to update of directory given pull:pullCommand, push:remote
	tell application "Terminal"
		tell application "System Events" to set process "Terminal"'s frontmost to true
		set t to missing value
		if win is missing value then
			tell application "System Events" to ¬
				tell process "Terminal" to ¬
					keystroke "n" using command down
			set win to the front window
		else
			set win's frontmost to true
			tell application "System Events" to ¬
				tell process "Terminal" to ¬
					keystroke "t" using command down
		end if
		set t to win's selected tab

The above hack is brought to you by the fact that the obvious AppleScript "set win to make new window" doesn't work. Terminal.app doesn't know how to "make new window" or "make new tab". APPLE FAIL.

		set command to "clear && echo " & directory & " && cd ~/dev/" & directory ¬
			& " && i=\"$(git rev-parse HEAD)\" &&" & pullCommand ¬
			& "&& [ \"$i\" != \"$(git rev-parse HEAD)\" ]"
		
		if remote is true then
			set command to command & "&& git push"
		else if remote is not false then
			set command to command & "&& git push " & remote
		end if
		set command to command & " && git changes"
		do script command in t
	end tell
end update

The above essentially boils down to the following shell commands (concatenated with "&&" so it stops at the first command that fails):

clear
Clears the screen
echo <directory>
Shows me which directory we're working in. Usually this is repeated in the title bar, but I put this in just for safety.
cd ~/dev/<directory>
I keep all my development work in "~/dev", which a directory per project.
i="$(git rev-parse HEAD)"
Keep around the current value of HEAD, which is git's current state. Lets me check later to see if we got any changes.
<pull command>
This will be either "git pull" or "git svn rebase" based on how this is called.
[ "$i" != "$(git rev-parse HEAD)" ]
Aforementioned checking for changes. Because of the &&s if this is not true (i.e. HEAD before pull is the same as HEAD after), nothing after this will run if it didn't download any changes.
git push <remote>
This is only added if a remote is passed in. If the remote is true, this is just "git push" which pushes to the default remote for the branch.
git changes
This is a custom alias that does "git log --reverse --no-merges ORIG_HEAD..HEAD | tig". This prints all non-merge commits (since those shouldn't have functional changes) between ORIG_HEAD (state before pulling) and HEAD in chronological order (default is newest first, so --reverse is oldest first). tig is a pager designed for git, which lets me show patches for commits, etc etc.

to git at directory
	update of directory without push given pull:"git pull"
end git

to svn of directory given push:remote
	update of directory given pull:"git svn rebase", push:remote
end svn

These two handlers make it quicker to define git and SVN (technically git-svn) based downloads. I only really maintain git mirrors of SVN repos, so all git repos skip the push step. This makes it really easy to add new repositories here...

activate application "Terminal"

git at "git"
git at "tig"
svn of "pugs" with push
svn of "parrot" with push
git at "nqp-rx"
git at "rakudo"
svn of "heritage" given push:"silver"

tell application "Terminal" to set win's selected tab to win's first tab

Each of those lines opens a new tab in Terminal and runs the commands to update a given repository. pugs and parrot are mirrored to their default locations while heritage (a stalled personal project I want to keep up-to-date against the upstream) mirrors to my server instead.

That's a lot of work, but will let me just double-click an application to update seven programs. In the long run, it takes less time. Honest.

Tags: applescript, mac, programming, stupid programmer tricks
Subscribe
  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 4 comments