diff options
-rw-r--r-- | tools/client-updates/.gitignore | 3 | ||||
-rw-r--r-- | tools/client-updates/README | 69 | ||||
-rw-r--r-- | tools/client-updates/release/news.txt | 0 | ||||
-rw-r--r-- | tools/client-updates/release/resources.xml | 3 | ||||
-rw-r--r-- | tools/client-updates/release/resources2.txt | 0 | ||||
-rw-r--r-- | tools/client-updates/src/adler32.c | 68 | ||||
-rwxr-xr-x | tools/client-updates/src/client-updates-gen | 68 | ||||
-rwxr-xr-x | tools/client-updates/src/client-updates-inspect | 20 | ||||
-rwxr-xr-x | tools/client-updates/src/client-updates-news | 14 | ||||
-rwxr-xr-x | tools/client-updates/src/client-updates-push | 8 | ||||
-rw-r--r-- | tools/client-updates/src/client-updates.conf.example | 15 | ||||
-rw-r--r-- | tools/client-updates/src/makefile | 9 |
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 |