From a77ac6f2cf0dab035a316e33ef264f86a05492a0 Mon Sep 17 00:00:00 2001
From: rubo77 <github@r.z11.de>
Date: Mon, 24 Dec 2018 00:13:27 +0100
Subject: [PATCH] add ci files for gitlab

---
 .gitlab-ci.yml                        |  74 ++++++
 .gitlab-ci/build-container/Dockerfile |  39 +++
 .gitlab-ci/build.sh                   | 360 ++++++++++++++++++++++++++
 .gitlab-ci/update-git.sh              |  46 ++++
 release                               |   1 +
 5 files changed, 520 insertions(+)
 create mode 100644 .gitlab-ci.yml
 create mode 100644 .gitlab-ci/build-container/Dockerfile
 create mode 100755 .gitlab-ci/build.sh
 create mode 100755 .gitlab-ci/update-git.sh
 create mode 100644 release

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..ea09e9d
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,74 @@
+variables:
+  GIT_SUBMODULE_STRATEGY: recursive
+  GIT_SSL_CAPATH: /etc/ssl/certs/
+  CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/build
+  GLUON_GIT: https://github.com/freifunk-gluon/gluon.git/
+  GLUON_BRANCH: master
+  BROKEN: BROKEN=1
+
+cache:
+  key: $CI_COMMIT_REF_SLUG-$GLUON_GIT-$GLUON_BRANCH
+  paths:
+    - gluon
+
+stages:
+  - prepare
+  - build
+  - upload
+
+# Preparation
+
+prepare:
+  stage: prepare
+  image: docker:latest
+  services:
+    - docker:dind
+  script:
+    - docker info
+    - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
+    - docker pull $CONTAINER_IMAGE:latest || true
+    - docker build --cache-from $CONTAINER_IMAGE:latest -t $CONTAINER_IMAGE:$CI_COMMIT_SHA -t $CONTAINER_IMAGE:latest .gitlab-ci/build-container
+    - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA
+    - docker push $CONTAINER_IMAGE:latest
+  cache: {}
+
+# Actual building
+build:
+  stage: build
+  image: $CI_REGISTRY_IMAGE/build
+  script:
+    - export FORCE_UNSAFE_CONFIGURE=1
+      # former clone step
+    - ./.gitlab-ci/update-git.sh | tee -a debug.log
+    - ./.gitlab-ci/build.sh -c update -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log
+      # We should never need this, should we?
+    - ./.gitlab-ci/build.sh -c clean -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log
+      # In the past this build step repeatedly broke
+    # - ./.gitlab-ci/build.sh -c download -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) V=s" | tee -a debug.log
+    - ./.gitlab-ci/build.sh -c build -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log
+      # Bring gluon repo to cacheable state
+    - ./.gitlab-ci/build.sh -c clean -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log
+      # Sign
+    - echo $SIGNING_KEY > signing_key
+    - ./.gitlab-ci/build.sh -c sign -b $CI_COMMIT_REF_NAME -s $(pwd)/signing_key
+  artifacts:
+    untracked: false
+    paths:
+      - debug.log
+      - output
+    expire_in: 1 day
+    when: always
+  dependencies: []
+
+upload:
+  stage: upload
+  image: $CI_REGISTRY_IMAGE/build
+  script:
+    - eval $(ssh-agent -s)
+    - ssh-add <(echo "$SSH_KEY")
+      # create fake gluon dir to satisfy build script
+    - mkdir -p gluon
+    - ./.gitlab-ci/build.sh -c upload -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID
+  dependencies:
+    - build
+  cache: {}
diff --git a/.gitlab-ci/build-container/Dockerfile b/.gitlab-ci/build-container/Dockerfile
new file mode 100644
index 0000000..bec64bd
--- /dev/null
+++ b/.gitlab-ci/build-container/Dockerfile
@@ -0,0 +1,39 @@
+FROM debian:stretch
+
+RUN apt-get update && apt-get install -y \
+    git \
+    subversion \
+    python \
+    build-essential \
+    gawk \
+    unzip \
+    time \
+    libncurses5-dev \
+    zlib1g-dev \
+    libssl1.0-dev \
+    wget \
+    curl \
+    openssh-client
+RUN apt-get update && apt-get install -y \
+    cmake \
+    make \
+    pkg-config && \
+    cd ~ && \
+    git clone http://git.universe-factory.net/libuecc && \
+    cd libuecc && \
+    cmake ./ && \
+    make && \
+    make install && \
+    ldconfig && \
+    cd ~ && \
+    git clone https://github.com/tcatm/ecdsautils.git && \
+    cd ecdsautils && \
+    git checkout tags/v0.3.2 && \
+    mkdir build && \
+    cd build/ && \
+    cmake ../ && \
+    make && \
+    make install && \
+    cd ~ && \
+    rm -rf ~/libuecc && \
+    rm -rf ~/ecdsautils
diff --git a/.gitlab-ci/build.sh b/.gitlab-ci/build.sh
new file mode 100755
index 0000000..9a3bdfd
--- /dev/null
+++ b/.gitlab-ci/build.sh
@@ -0,0 +1,360 @@
+#!/bin/bash -e
+# =====================================================================
+# Build script for Freifunk Nord firmware
+#
+# Source: 
+# Contact: 
+# Web: 
+#
+# Credits:
+#   - Freifunk Darmstadt for your great support
+#   - Freifunk Fulda for the base of the gitlab-ci support
+# =====================================================================
+
+# Default make options
+MAKEOPTS="V=s -j 4"
+
+# Default to build all Gluon targets if parameter -t is not set
+TARGETS="ar71xx-tiny ar71xx-generic x86-64 ar71xx-nand x86-generic x86-64"
+TARGETS=$TARGETS" mpc85xx-generic" # (tp-link-tl-wdr4900-v1)
+
+# BROKEN:
+TARGETS=$TARGETS" ramips-mt76x8" # BROKEN: unstable WiFi (tp-link 841 v13 und archer c50)
+TARGETS=$TARGETS" ar71xx-mikrotik" # BROKEN: no sysupgrade support (mikrotik-nand)
+TARGETS=$TARGETS" brcm2708-bcm2710" # BROKEN: Untested (raspberry-pi-3)
+TARGETS=$TARGETS" ipq806x" # BROKEN: unstable wifi drivers (tp-link-archer-c2600)
+TARGETS=$TARGETS" mvebu-cortexa9" # BROKEN: No AP+IBSS or 11s support (linksys-wrt1200ac)
+
+# Default is set to use current work directory
+SITEDIR="$(pwd)"
+
+# Default build identifier set to snapshot
+BUILD="snapshot"
+
+# Specify deployment server and user
+DEPLOYMENT_SERVER="10.116.250.1"
+DEPLOYMENT_USER="rsync"
+DEPLOYMENT_PATH="/opt/firmware/nord"
+
+# Path to signing key
+SIGNKEY=""
+
+# Error codes
+E_ILLEGAL_ARGS=126
+
+# Help function used in error messages and -h option
+usage() {
+  echo ""
+  echo "Build script for Freifunk-Fulda gluon firmware."
+  echo ""
+  echo "-b: Firmware branch name (e.g. development)"
+  echo "    Default: current git branch"
+  echo "-c: Build command: update | clean | download | build | sign | upload | prepare"
+  echo "-d: Enable bash debug output"
+  echo "-h: Show this help"
+  echo "-m: Setting for make options (optional)"
+  echo "    Default: \"${MAKEOPTS}\""
+  echo "-n: Build identifier (optional)"
+  echo "    Default: \"${BUILD}\""
+  echo "-t: Gluon targets architectures to build"
+  echo "    Default: \"${TARGETS}\""
+  echo "-r: Release number (optional)"
+  echo "    Default: fetched from release file"
+  echo "-w: Path to site directory"
+  echo "    Default: current working directory"
+  echo "-s: Path to signing key"
+  echo "    Default: empty"
+}
+
+# Evaluate arguments for build script.
+if [[ "${#}" == 0 ]]; then
+  usage
+  exit ${E_ILLEGAL_ARGS}
+fi
+
+# Evaluate arguments for build script.
+while getopts b:c:dhm:n:t:w:s: flag; do
+  case ${flag} in
+    b)
+        BRANCH="${OPTARG}"
+        ;;
+    c)
+      case "${OPTARG}" in
+        update)
+          COMMAND="${OPTARG}"
+          ;;
+        clean)
+          COMMAND="${OPTARG}"
+          ;;
+        download)
+          COMMAND="${OPTARG}"
+          ;;
+        build)
+          COMMAND="${OPTARG}"
+          ;;
+        sign)
+          COMMAND="${OPTARG}"
+          ;;
+        upload)
+          COMMAND="${OPTARG}"
+          ;;
+        prepare)
+          COMMAND="${OPTARG}"
+          ;;
+        *)
+          echo "Error: Invalid build command set."
+          usage
+          exit ${E_ILLEGAL_ARGS}
+          ;;
+      esac
+      ;;
+    d)
+      set -x
+      ;;
+    h)
+      usage
+      exit
+      ;;
+    m)
+      MAKEOPTS="${OPTARG}"
+      ;;
+    n)
+      BUILD="${OPTARG}"
+      ;;
+    t)
+      TARGETS="${OPTARG}"
+      ;;
+    r)
+      RELEASE="${OPTARG}"
+      ;;
+    w)
+      # Use the root project as site-config for make commands below
+      SITEDIR="${OPTARG}"
+      ;;
+    s)
+      SIGNKEY="${OPTARG}"
+      ;;
+    *)
+      usage
+      exit ${E_ILLEGAL_ARGS}
+      ;;
+  esac
+done
+
+# Strip of all remaining arguments
+shift $((OPTIND - 1));
+
+# Check if there are remaining arguments
+if [[ "${#}" > 0 ]]; then
+  echo "Error: To many arguments: ${*}"
+  usage
+  exit ${E_ILLEGAL_ARGS}
+fi
+
+# Set branch name
+if [[ -z "${BRANCH}" ]]; then
+  BRANCH=$(git symbolic-ref -q HEAD)
+  BRANCH=${BRANCH##refs/heads/}
+  BRANCH=${BRANCH:-HEAD}
+fi
+
+# Set command
+if [[ -z "${COMMAND}" ]]; then
+  echo "Error: Build command missing."
+  usage
+  exit ${E_ILLEGAL_ARGS}
+fi
+
+# Set release number
+if [[ -z "${RELEASE}" ]]; then
+  RELEASE=$(cat "${SITEDIR}/release")
+fi
+
+# Normalize the branch name
+BRANCH="${BRANCH#origin/}" # Use the current git branch as autoupdate branch
+BRANCH="${BRANCH//\//-}"   # Replace all slashes with dashes
+
+# Get the GIT commit description
+COMMIT="$(git describe --always --dirty)"
+
+# Number of days that may pass between releasing an updating
+PRIORITY=1
+
+update() {
+  echo "--- Update Gluon Dependencies"
+  make ${MAKEOPTS} \
+       GLUON_SITEDIR="${SITEDIR}" \
+       GLUON_OUTPUTDIR="${SITEDIR}/output" \
+       GLUON_RELEASE="${RELEASE}-${BUILD}" \
+       GLUON_BRANCH="${BRANCH}" \
+       GLUON_PRIORITY="${PRIORITY}" \
+       update
+}
+
+clean() {
+  for TARGET in ${TARGETS}; do
+    echo "--- Clean Gluon Build Artifacts for target: ${TARGET}"
+    make ${MAKEOPTS} \
+         GLUON_SITEDIR="${SITEDIR}" \
+         GLUON_OUTPUTDIR="${SITEDIR}/output" \
+         GLUON_RELEASE="${RELEASE}-${BUILD}" \
+         GLUON_BRANCH="${BRANCH}" \
+         GLUON_PRIORITY="${PRIORITY}" \
+         GLUON_TARGET="${TARGET}" \
+         clean
+  done
+}
+
+download() {
+  for TARGET in ${TARGETS}; do
+    echo "--- Download Gluon Dependencies for target: ${TARGET}"
+    make ${MAKEOPTS} \
+         GLUON_SITEDIR="${SITEDIR}" \
+         GLUON_OUTPUTDIR="${SITEDIR}/output" \
+         GLUON_RELEASE="${RELEASE}-${BUILD}" \
+         GLUON_BRANCH="${BRANCH}" \
+         GLUON_PRIORITY="${PRIORITY}" \
+         GLUON_TARGET="${TARGET}" \
+         download
+  done
+}
+
+build() {
+  for TARGET in ${TARGETS}; do
+    echo "--- Build Gluon Images for target: ${TARGET}"
+    case "${BRANCH}" in
+      stable| \
+      testing| \
+      development)
+        make ${MAKEOPTS} \
+             GLUON_SITEDIR="${SITEDIR}" \
+             GLUON_OUTPUTDIR="${SITEDIR}/output" \
+             GLUON_RELEASE="${RELEASE}-${BUILD}" \
+             GLUON_BRANCH="${BRANCH}" \
+             GLUON_PRIORITY="${PRIORITY}" \
+             GLUON_TARGET="${TARGET}"
+        ;;
+
+      *)
+        make ${MAKEOPTS} \
+             GLUON_SITEDIR="${SITEDIR}" \
+             GLUON_OUTPUTDIR="${SITEDIR}/output" \
+             GLUON_RELEASE="${RELEASE}-${BUILD}" \
+             GLUON_BRANCH="${BRANCH}" \
+             GLUON_TARGET="${TARGET}"
+      ;;
+    esac
+  done
+
+  echo "--- Build Gluon Manifest"
+  make ${MAKEOPTS} \
+       GLUON_SITEDIR="${SITEDIR}" \
+       GLUON_OUTPUTDIR="${SITEDIR}/output" \
+       GLUON_RELEASE="${RELEASE}-${BUILD}" \
+       GLUON_BRANCH="${BRANCH}" \
+       GLUON_PRIORITY="${PRIORITY}" \
+       manifest
+
+  echo "--- Write Build file"
+  cat > "${SITEDIR}/output/images/build" <<EOF
+DATE=$(date '+%Y-%m-%d %H:%M:%S')
+VERSION=$(cat "${SITEDIR}/release")
+RELEASE=${RELEASE}
+BUILD=${BUILD}
+BRANCH=${BRANCH}
+COMMIT=${COMMIT}
+HOST=$(uname -n)
+EOF
+}
+
+sign() {
+  echo "--- Sign Gluon Firmware Build"
+
+  # Add the signature to the local manifest
+  contrib/sign.sh \
+      "${SIGNKEY}" \
+      "${SITEDIR}/output/images/sysupgrade/${BRANCH}.manifest"
+}
+
+upload() {
+  echo "--- Upload Gluon Firmware Images and Manifest"
+
+  # Build the ssh command to use
+  SSH="ssh"
+  SSH="${SSH} -o stricthostkeychecking=no -v"
+
+  # Determine upload target prefix
+  TARGET="${BRANCH}"
+
+  # Create the target directory on server
+  ${SSH} \
+      ${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER} \
+      -- \
+      mkdir \
+          --parents \
+          --verbose \
+          "${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}"
+
+  # Add site metadata
+  tar -czf "${SITEDIR}/output/images/site.tgz" --exclude='gluon' --exclude='output' "${SITEDIR}"
+
+  # Copy images to server
+  rsync \
+      --verbose \
+      --recursive \
+      --compress \
+      --progress \
+      --links \
+      --chmod=ugo=rwX \
+      --rsh="${SSH}" \
+      "${SITEDIR}/output/images/" \
+      "${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER}:${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}"
+  ${SSH} \
+      ${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER} \
+      -- \
+      ln -sf \
+          "${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}/sysupgrade" \
+          "${DEPLOYMENT_PATH}/${TARGET}/"
+  ${SSH} \
+      ${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER} \
+      -- \
+      ln -sf \
+          "${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}/factory" \
+          "${DEPLOYMENT_PATH}/${TARGET}/"
+}
+
+prepare() {
+  echo "--- Prepare directory for upload"
+
+  # Determine upload target prefix
+  TARGET="${BRANCH}"
+
+  # Create the target directory on server
+  mkdir \
+    --parents \
+    --verbose \
+    "${SITEDIR}/output/firmware/${TARGET}"
+
+  # Copy images to directory
+  mv \
+    --verbose \
+    "${SITEDIR}/output/images" \
+    "${SITEDIR}/output/firmware/${TARGET}/${RELEASE}-${BUILD}"
+
+  # Link latest upload in target to 'current'
+  cd "${SITEDIR}/output"
+  ln \
+      --symbolic \
+      --force \
+      --no-target-directory \
+      "${RELEASE}-${BUILD}" \
+      "firmware/${TARGET}/current"
+}
+
+(
+  # Change working directory to gluon tree
+  cd "${SITEDIR}/gluon"
+
+  # Execute the selected command
+  ${COMMAND}
+)
diff --git a/.gitlab-ci/update-git.sh b/.gitlab-ci/update-git.sh
new file mode 100755
index 0000000..48a78f8
--- /dev/null
+++ b/.gitlab-ci/update-git.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail
+
+function update() {
+	# Try ff first
+	git -C gluon fetch --all && git -C gluon checkout "$GLUON_BRANCH" && git -C gluon pull --ff-only || {
+		# Kill it with fire
+		echo "Fast-Forward failed, killing it with fire"
+		rm -rf gluon
+		git clone "$GLUON_GIT" -b "$GLUON_BRANCH" gluon
+	}
+}
+
+(
+	if ! [[ -e gluon ]]; then
+		echo "gluon dir nonexistent, updating"
+		update
+		exit 0
+	fi
+
+	REMOTE_REFS="$(git ls-remote -qht "$GLUON_GIT" | grep "$GLUON_BRANCH" | cut -f1)"
+
+	set +e
+	LOCAL_REF=$(git -C gluon rev-parse HEAD)
+	GIT_EXIT=$?
+	set -e
+
+	if [[ $GIT_EXIT -ne 0 ]]; then
+		echo "Local repo damaged, forcing update"
+		update
+		exit 0
+	fi
+
+	# There can be multiple objects describing the same state, we need to check them all
+	for ref in $REMOTE_REFS; do
+		echo "Checking $ref == $LOCAL_REF"
+		if [[ "$ref" == "$LOCAL_REF" ]]; then
+			echo "Local repo is up to date"
+			exit 0
+		fi
+	done
+
+	echo "Local state does not reflect latest remote state, updating"
+	update
+)
diff --git a/release b/release
new file mode 100644
index 0000000..1ba54c6
--- /dev/null
+++ b/release
@@ -0,0 +1 @@
+2018.2.0.0~exp
-- 
GitLab