Nightly WebKit auto-updater

Filed under: Uncategorized — 2005-10-17 @ 21:14:20

Ever since I heard about the WebKit Nightly Builds I wanted a way to automatically update so that I would always be running the latest version of webkit. Well, here ya go.
Requires CURL and ( PHP_Compat or PHP 5 ).
It *should* "just work". But (indemnification coming) i'm not responsible if it erases your hard drive, makes you a peanut butter and jelly sandwich without jelly (or with some crappy skippy peanut butter) or sends insulting messages to random people on your IM buddy list.

<?
$target="http://nightly.webkit.org/builds/Latest-WebKit+SVG-CVS.dmg";
$state_file="/tmp/webkit_cache";
$tmp="/tmp";
$hdiutil="/usr/bin/hdiutil";
$rsync="/usr/bin/rsync";
$name="WebKit+SVG.app";
$applications="/Applications";
$debug=false;

$version="0.3.0";
$ref_url="http://blog.adamjacobmuller.com/"
	."2005/10/17/nightly-webkit-auto-updater/";
require_once 'PEAR.php';
require_once 'PHP/Compat.php';
PHP_Compat::loadFunction('file_get_contents');
PHP_Compat::loadFunction('file_put_contents');

$url=parse_url($target);
$sh=fsockopen($url['host'],80);
fwrite($sh,"HEAD ".$url['path']." HTTP/1.1\r\n".
	"Connection: Close\r\n".
	"User-Agent: WebKit auto-updater $version ($ref_url)\r\n".
	"Host: ".$url['host']."\r\n\r\n");
while(!feof($sh)) {
	$headers.=fread($sh,1024);
}
preg_match_all("#(.*?): (.*?)\r\n#",$headers,$matches);
$headers=array();
foreach($matches[1] as $idx=>$match) {
	$headers[$match]=$matches[2][$idx];
}
$headers['ETag']=trim($headers['ETag'],'"');
$headers['Last-Modified']=strtotime($headers['Last-Modified']);
$headers['Date']=strtotime($headers['Date']);

if (file_exists($state_file)) {
	$data=file_get_contents($state_file);
	$data=unserialize($data);
} else {
	$data['last']['ETag']="";
	$data['last']['Last-Modified']=0;
	$data=array();
}

if (
	($data['last']['headers']['ETag']<>$headers['ETag'])
	&&($data['last']['headers']['Last-Modified']<$headers['Last-Modified'])
	) {
	$tmp=tempnam($tmp,"webkit_");
	unlink($tmp);
	mkdir($tmp,0700);
	$dmg=$tmp.".dmg";
	if ($debug) {
		$res=link("Latest-WebKit+SVG-CVS.dmg",$dmg);
	} else {
		$ch = curl_init($target);
		$fp = fopen($dmg, "w");
		curl_setopt($ch, CURLOPT_FILE, $fp);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_USERAGENT,
			"WebKit auto-updater $version ($ref_url)");
		$res=curl_exec($ch);
		$curl_info=curl_getinfo($ch);
		curl_close($ch);
		fclose($fp);
	}
	if ($res) {
		$cmd=$hdiutil." attach -mountpoint ".$tmp." ".$dmg;
		$cmd['attach']=$cmd."\n";
		$output['attach']=`$cmd`;
		
		$src=$tmp."/".$name."/";
		$dst=$applications."/".$name;
		$cmd=$rsync." -aHv --stats ".$src." ".$dst;
		$cmd['rsync']=$cmd."\n";
		$output['rsync']=`$cmd 2>&1`;

		$cmd=$hdiutil." detach $tmp";
		$cmd['detach']=$cmd."\n";
		$output['detach']=`$cmd`;
		$this=array(
			"output"=>$output,
			"headers"=>$headers,
			"curl"=>$curl_info
		);
		$data['historical'][$this['headers']['Last-Modified']]=$this;
		$data['last']=&$data['historical'][$this['headers']['Last-Modified']];
		$data=serialize($data);
		file_put_contents($state_file,$data);
	} else {
		print "failed $tmp\n\n";
	}
	unlink($dmg);
	rmdir($tmp);
}

You can download it here.
It's pretty robust, it only downloads/upgrades if it has changed, based on the last-modified and ETag headers so you can probably do something like this in cron without pissing anyone off:

0 * * * * /path/to/webkit.php

Kudos to the WebKit people for making their Nightly Builds stable enough to use on a daily basis and for making such a great browser and inspiring technical innovation in a field that is generally satisfied with "good enough".

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

(required)

(required)