Late night coding

While avoiding the new learning series I dreamt up I've been doing some reading and playing with postfix and ldap. The first topic came about because of some stuff at work (had to set up postfix with authentication, turned out to be much more complex than one would expect) and I wanted to make sure I knew how to do it in the future. The second part came about because my server setup is too messy - I want to deal with the hosting in a proper fashion where adding, updating, etc. is easy. Hence ldap came to mind: I want to run an ldap server in one of the containers on the server, so all the other containers can authenticate against it as needed and grab other info from there as well.

So to make sure I don't forget these things after I've done them I've got a library of files containing notes on how to do things. On top of that, I've also got Trac running on my server. I installed it mainly to keep track of hosting info (such as server details, bugs and other things I needed to take care of, projects from clients, etc) but I discovered it would also be useful to migrate my library of notes onto Trac. Or rather, I haven't migrated it, I've just copied it over to trac while keeping (and working on) the local copy. Hence the need to sync everything. Locally, I keep the notes in git, making for easy syncing across the network - but I don't have anything like that setup for trac. Hence, a bit of late night coding and hey presto! git hooks. I still need to work a bit on the pre-commit hook but the post-commit hook is done. Just a very simple script to update trac after I've committed changes to my notes locally. It looks like this:

// script residing in the main repo folder

#!/usr/bin/php
<?php
define('TRAC_AUTH', 'username:password');
define('COOKIEFILE', tempnam('/tmp', 'cookies_'));

$self = array('web_hook.php', 'web_update.php');

if (empty($_SERVER['argv'][1])) {
    echo "Call with name of file" . PHP_EOL;
    exit(1);
}

if (in_array($_SERVER['argv'][1], $self)) {
    exit(0);
}

$url_base   = 'http://path/to/server/wiki/';
$url_suffix = '?action=edit';

$url_array = array(
    'server.txt'      => 'Server',
    'development.txt' => 'Development',
    'email.txt'       => 'Email',
    'git.txt'         => 'Git',
);

if (!isset($url_array[$_SERVER['argv'][1]])) {
    echo "No such file set: " . $_SERVER['argv'][1] . PHP_EOL;
    exit(1);
}

$url_part = $url_array[$_SERVER['argv'][1]];

$data = fetch_data($url_base . $url_part . $url_suffix);
if (!$data) {
    echo "Could not fetch data" . PHP_EOL;
    exit(1);
}

if (!put_data($data, $_SERVER['argv'][1], $url_base . $url_part)) {
    echo "Could not update trac" . PHP_EOL;
    exit(1);
}

/**
 * posts data to the proper
 * page, updating trac info
 *
 * @param string $data
 * @param string $filename
 * @param string $url
 *
 * @return string
 */
function put_data($data, $filename, $url) {
    $dom = new DOMDocument();
    $dom->loadHTML($data);

    $xpath = new DOMXPath($dom);

    $form_token  = $xpath->query('//form[@id="edit"]//input[@name="__FORM_TOKEN"]')->item(0)->getAttribute('value');
    $version     = $xpath->query('//form[@id="edit"]//input[@name="version"]')->item(0)->getAttribute('value');
    $action      = $xpath->query('//form[@id="edit"]//input[@name="action"]')->item(0)->getAttribute('value');
    $from_editor = $xpath->query('//form[@id="edit"]//input[@name="from_editor"]')->item(0)->getAttribute('value');

    $comment = "Saved from git hook";
    $text    = file_get_contents($filename);
    if (empty($text)) {
        echo "No text to save";
        exit(1);
    }

    $post_data = array(
        '__FORM_TOKEN'  => $form_token,
        'version'       => $version,
        'action'        => $action,
        'from_editor'   => $from_editor,
        'text'          => $text,
        'comment'       => $comment,
    );

    $curl_handle = curl_init();
    curl_setopt($curl_handle, CURLOPT_URL, $url);
    curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl_handle, CURLOPT_USERPWD, TRAC_AUTH);
    curl_setopt($curl_handle, CURLOPT_POST, true);
    curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($curl_handle, CURLOPT_COOKIEFILE, COOKIEFILE);

    return curl_exec($curl_handle);
}

/**
 * fetches the data from trac
 *
 * @param string $url
 *
 * @return string
 */
function fetch_data($url) {
    $curl_handle = curl_init();
    curl_setopt($curl_handle, CURLOPT_URL, $url);
    curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl_handle, CURLOPT_USERPWD, TRAC_AUTH);
    curl_setopt($curl_handle, CURLOPT_COOKIEJAR, COOKIEFILE);

    return curl_exec($curl_handle);
}

// this is the post-commit file in .git/hooks/
for LINE in `git log --oneline --name-only -1 HEAD | awk '{if ($2 == "") print $1}'`
do
    if ! ./web_update.php $LINE
    then
        echo "Failed to update trac with changes"
    fi
done

It should be fairly easy to figure out what's going on. The post-commit hook checks all the lines from the log for the last commit and filters the output, passing it to the update script as needed. The update script fetches the edit page from trac for the given file, scrapes out the needed variables to post back to trac, then sends a post request to trac, thus updating the trac wiki.

Now, I'm sure there are better ways (most likely some sort of trac plugin or api) to update trac remotely ... but the point is, this is just a bit of late night coding and done deal: I'm now updating my trac wiki whenever I commit my notes locally.

social