summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/client-updates/.gitignore3
-rw-r--r--tools/client-updates/README69
-rw-r--r--tools/client-updates/release/news.txt0
-rw-r--r--tools/client-updates/release/resources.xml3
-rw-r--r--tools/client-updates/release/resources2.txt0
-rw-r--r--tools/client-updates/src/adler32.c68
-rwxr-xr-xtools/client-updates/src/client-updates-gen68
-rwxr-xr-xtools/client-updates/src/client-updates-inspect20
-rwxr-xr-xtools/client-updates/src/client-updates-news14
-rwxr-xr-xtools/client-updates/src/client-updates-push8
-rw-r--r--tools/client-updates/src/client-updates.conf.example15
-rw-r--r--tools/client-updates/src/makefile9
12 files changed, 277 insertions, 0 deletions
diff --git a/tools/client-updates/.gitignore b/tools/client-updates/.gitignore
new file mode 100644
index 00000000..c369c66c
--- /dev/null
+++ b/tools/client-updates/.gitignore
@@ -0,0 +1,3 @@
+/src/adler32
+/src/client-updates.conf
+
diff --git a/tools/client-updates/README b/tools/client-updates/README
new file mode 100644
index 00000000..56026b85
--- /dev/null
+++ b/tools/client-updates/README
@@ -0,0 +1,69 @@
+########################################
+# How to use the client updates system #
+########################################
+
+# Initial setup
+
+1. compile adler32: Run 'make' in the src directory.
+2. Copy example config and edit it to your needs:
+ $ cp client-updates.conf.example client-updates.conf
+3. Optionally, put the client-update-{gen,news,inspect,push} in your PATH
+4. Init a git repository for the client-updates dir, as zip updates will be committed.
+ $ git init
+ $ git add .
+ $ git commit -m 'Initial scripts'
+
+Now we have to generate the base update.
+If you have already base zip files, you can include them in the release/ directory.
+Fill properly the resources.xml and resources2.xml files.
+Otherwise, run client-updates-gen with proper arguments.
+1st arg is base commit, 2nd arg is final commit (HEAD if omitted).
+
+# Overview
+The process to manage client updates is as follows:
+
+1. a developer needs to include new client data.
+2. if not done already, he/she will set up a personal branch in the tmwa-client-data repo
+ and pull what is necessary.
+3. the tmwa-client-data repo has a "testing" branch which is the reference for generating the updates.
+ there is also the "master" branch which is in sync with mainline.
+ the developer will perform a merge in the "testing" branch, and if necessary resolve the conflicts.
+4. $ client-updates-gen
+ will generate if necessary a new zip and display its contents.
+5. optionally, you can check the contents of the updates is correct:
+ $ client-updates-inspect
+ This will list the contents of all updates in a pager, from most recent to oldest.
+6. $ client-updates-push
+ will sync the client updates to the local webserver directory
+
+As a general rule, never break the history of the "$CLIENT_DATA_BRANCH" branch of the tmwa-client-data repository.
+
+# Handling news -- only useful if not using the news of the server-data.
+
+1. $ client-updates-news
+ will open the news.txt for editing.
+2. Publish these changes.
+ $ client-updates-push
+
+# Details on the client-updates-gen script
+
+This script analyses the client data repo and generates
+a zip file with the files changed / added between 2 revisions.
+
+The script will check the differences between HEAD and the latest reference commit.
+The reference commit is determined by the latest entry in $UPDATES_DIR/resources2.src.txt
+
+# Config file (client-updates.conf)
+
+Several variables for finding the UPDATES_DIR, the client data repository,
+and ftp credentials.
+Find it next to client-updates-* scripts.
+
+# Client updates repository
+
+A local git repository is used for managing these scripts.
+This repository has 2 branches: master and updates
+The repository should always be left on the branch "updates": most scripts will write commits
+when updates are issued or when news.txt is updated.
+When you need to change things in the core scripts, change to master, commit, then rebase the "updates" branch.
+
diff --git a/tools/client-updates/release/news.txt b/tools/client-updates/release/news.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tools/client-updates/release/news.txt
diff --git a/tools/client-updates/release/resources.xml b/tools/client-updates/release/resources.xml
new file mode 100644
index 00000000..faab9811
--- /dev/null
+++ b/tools/client-updates/release/resources.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<updates>
+</updates>
diff --git a/tools/client-updates/release/resources2.txt b/tools/client-updates/release/resources2.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tools/client-updates/release/resources2.txt
diff --git a/tools/client-updates/src/adler32.c b/tools/client-updates/src/adler32.c
new file mode 100644
index 00000000..5dd7e4c1
--- /dev/null
+++ b/tools/client-updates/src/adler32.c
@@ -0,0 +1,68 @@
+/*
+ * adler32.c (c) 2006 Bjorn Lindeijer
+ * License: GPL, v2 or later
+ *
+ * Calculates Adler-32 checksums for all files passed as argument.
+ *
+ * Usage: adler32 [file]...
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <zlib.h>
+
+/**
+ * Calculates the Adler-32 checksum for the given file.
+ */
+unsigned long fadler32(FILE *file)
+{
+ // Obtain file size
+ fseek(file, 0, SEEK_END);
+ long fileSize = ftell(file);
+ rewind(file);
+
+ // Calculate Adler-32 checksum
+ char *buffer = (char*) malloc(fileSize);
+ fread(buffer, 1, fileSize, file);
+ unsigned long adler = adler32(0L, Z_NULL, 0);
+ adler = adler32(adler, (Bytef*) buffer, fileSize);
+ free(buffer);
+
+ return adler;
+}
+
+/**
+ * Prints out usage and exists.
+ */
+void print_usage()
+{
+ printf("Usage: adler32 [file]...\n");
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ int i; /**< Loops through arguments. */
+
+ if (argc == 1)
+ {
+ print_usage();
+ }
+
+ for (i = 1; i < argc; ++i)
+ {
+ FILE *file = fopen(argv[i], "r");
+
+ if (!file)
+ {
+ printf("Error while opening '%s' for reading!\n", argv[i]);
+ exit(1);
+ }
+
+ unsigned long adler = fadler32(file);
+ printf("%s %lx\n", argv[i], adler);
+ fclose(file);
+ }
+
+ return 0;
+}
diff --git a/tools/client-updates/src/client-updates-gen b/tools/client-updates/src/client-updates-gen
new file mode 100755
index 00000000..76c0ed34
--- /dev/null
+++ b/tools/client-updates/src/client-updates-gen
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+# config
+SRC=$(dirname $(readlink -f "$0"))
+
+. ${SRC}/client-updates.conf
+
+# Check we are on the $CLIENT_DATA_BRANCH branch
+git --git-dir "${CLIENT_DATA_DIR}/.git" branch | grep -q "^* $CLIENT_DATA_BRANCH" || { echo "The client-data repository is not on $CLIENT_DATA_BRANCH branch. Exiting"; exit 2; }
+
+# Unless specified on 1st argument, we'll use the latest revision that was
+# included in updates, as starting revision.
+# If this is the initial generation, this argument is mandatory.
+if [ $# -gt 0 ]; then
+ OLD_CLIENT_DATA_HEAD="$1"
+else
+ # Get the last commit sha where we generated an update
+ # This assumes the generated zip names follow the pattern: update-SHA1..SHA2.zip
+ OLD_CLIENT_DATA_HEAD=$(tail -n 1 ${UPDATES_DIR}/release/resources2.txt | cut -d . -f 3)
+fi
+
+# Unless specified on 2nd argument, we'll use the HEAD as final revision.
+if [ $# -gt 1 ]; then
+ NEW_CLIENT_DATA_HEAD="$2"
+else
+ # get the commit SHA from the client data repo
+ NEW_CLIENT_DATA_HEAD=$(git --git-dir "${CLIENT_DATA_DIR}/.git" rev-parse HEAD | cut -c 1-7)
+fi
+
+if [ "$OLD_CLIENT_DATA_HEAD" = "$NEW_CLIENT_DATA_HEAD" ]; then
+ echo "Everything is up-to-date."
+ exit 0
+fi
+
+update_basename="update-${OLD_CLIENT_DATA_HEAD}..${NEW_CLIENT_DATA_HEAD}"
+
+# generate a diff of files to package
+cd ${CLIENT_DATA_DIR}
+git --git-dir "${CLIENT_DATA_DIR}/.git" log --name-status ${OLD_CLIENT_DATA_HEAD}..${NEW_CLIENT_DATA_HEAD} | awk '/^(A|M)\t/ {print $2}' | sort | uniq | xargs zip -9 -r "${UPDATES_DIR}/${update_basename}.zip" > /dev/null
+cd - > /dev/null
+
+if [ ! -f "${UPDATES_DIR}/${update_basename}.zip" ];then
+ echo "Error while generating ${update_basename}.zip. Exiting." > /dev/stderr
+ exit 1
+fi
+
+# package update
+cd "${UPDATES_DIR}"
+mkdir -p "release"
+${SRC}/adler32 "${update_basename}.zip" >> "release/resources2.txt"
+hash=$(tail -n 1 "release/resources2.txt" | awk '{ print $2; }')
+# populate resources.xml as well
+xmlentry="<update type=\"data\" file=\"${update_basename}.zip\" hash=\"${hash}\" />"
+
+sed -i '$d' 'release/resources.xml'
+echo " $xmlentry" >> 'release/resources.xml'
+echo '</updates>' >> 'release/resources.xml'
+
+echo "Adding ${update_basename}.zip:"
+# Display the contents of the update
+unzip -l ${update_basename}.zip
+mv "${update_basename}.zip" "release/"
+# Copy resources
+git add 'release'
+git commit -m "Updating resources to ${NEW_CLIENT_DATA_HEAD}" > /dev/null
+cd - > /dev/null
+
+exit 0
diff --git a/tools/client-updates/src/client-updates-inspect b/tools/client-updates/src/client-updates-inspect
new file mode 100755
index 00000000..03ae2d65
--- /dev/null
+++ b/tools/client-updates/src/client-updates-inspect
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+#config
+SRC=$(dirname $(readlink -f "$0"))
+
+. ${SRC}/client-updates.conf
+
+DIRECTORY="${UPDATES_DIR}/release"
+listing=$(mktemp)
+IFS='
+'
+for f in $(tac $DIRECTORY/resources2.txt); do
+ file=$(awk '{ print $1; }' <<< $f)
+ unzip -l "$DIRECTORY/$file" >> $listing
+done
+
+if [ -f "$listing" ]; then
+ less "$listing"
+fi
+rm -f "$listing"
diff --git a/tools/client-updates/src/client-updates-news b/tools/client-updates/src/client-updates-news
new file mode 100755
index 00000000..bc78e4ef
--- /dev/null
+++ b/tools/client-updates/src/client-updates-news
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# config
+SRC=$(dirname $(readlink -f "$0"))
+
+. ${SRC}/client-updates.conf
+
+# Edit news.txt
+nano "${UPDATES_DIR}"/release/news.txt
+
+# Commit if changed
+cd "${UPDATES_DIR}"
+git status | grep -q 'news.txt' && { git add release/news.txt; git commit -m 'Updating news.txt' > /dev/null; }
+cd - > /dev/null
diff --git a/tools/client-updates/src/client-updates-push b/tools/client-updates/src/client-updates-push
new file mode 100755
index 00000000..edeae490
--- /dev/null
+++ b/tools/client-updates/src/client-updates-push
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# config
+SRC=$(dirname $(readlink -f "$0"))
+
+. ${SRC}/client-updates.conf
+
+rsync -av --delete "$UPDATES_DIR/release/" "$UPDATES_PUBLISH_DIR"
diff --git a/tools/client-updates/src/client-updates.conf.example b/tools/client-updates/src/client-updates.conf.example
new file mode 100644
index 00000000..8bdce432
--- /dev/null
+++ b/tools/client-updates/src/client-updates.conf.example
@@ -0,0 +1,15 @@
+# The client-data directory
+CLIENT_DATA_DIR="$HOME/tmwa-client-data"
+
+# The updates working directory
+UPDATES_DIR="$HOME/client-updates"
+
+# The git branch used for generating the updates
+# This allows for more complex setups, where e.g a branch is used for merging
+# from various other branches. It's used on the testing server
+# Defaults to master
+CLIENT_DATA_BRANCH=master
+
+# Local directory served by the web server,
+# where the update files will be copied
+UPDATES_PUBLISH_DIR="$HOME/www/tmwupdate"
diff --git a/tools/client-updates/src/makefile b/tools/client-updates/src/makefile
new file mode 100644
index 00000000..00acaf0d
--- /dev/null
+++ b/tools/client-updates/src/makefile
@@ -0,0 +1,9 @@
+all: adler32
+
+adler32: adler32.c
+ gcc -lz -o $@ $<
+
+clean:
+ rm -f adler32
+
+.PHONY: clean