425 lines
13 KiB
Bash
Executable File
425 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
if [ ! -f "$1" ]
|
|
then
|
|
echo "Please supply the path to an existing zip binary as the first argument"
|
|
exit 1
|
|
fi
|
|
|
|
GITHUB_TOKEN_FILE="${HOME}/.config/github-api-token"
|
|
GPG_KEYFILE="${HOME}/.config/signkeys/Duplicati/updater-gpgkey.key"
|
|
AUTHENTICODE_PFXFILE="${HOME}/.config/signkeys/Duplicati/authenticode.pfx"
|
|
AUTHENTICODE_PASSWORD="${HOME}/.config/signkeys/Duplicati/authenticode.key"
|
|
MONO=/Library/Frameworks/Mono.framework/Commands/mono
|
|
|
|
GPG=/usr/local/bin/gpg2
|
|
|
|
FEDORA_INSTANCE_ID=i-deef5352
|
|
FEDORA_PUBKEY=AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM3OWpUJOqoh9hq/k48g/FFLqnxUHxecVZM/jRD69Y/cn0OygsSyi3E5X/PVgtfyoced/HV788f9rDpLbY08jXg=
|
|
|
|
DEBIAN_INSTANCE_ID=i-f237887e
|
|
DEBIAN_PUBKEY=AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJUDOPM7lBBOUtRbAZ8DUP7hHN88CvSvKzWQ15uXcOhdMgtqlznSQiLNfagD/AlqnPsOXWCnNN0fM+QAeMuMBEY=
|
|
|
|
WINDOWS_INSTANCE_ID=i-be348b32
|
|
WINDOWS_PUBKEY=AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK5MD6Jg+p6rJmJfx8lWqIY+ZLDEYcGIwcf+eGzPSz4QKuOgxtDo0xgg3/OrxJibyk7sBWkT0f9RHD1qN9Nz/o8=
|
|
|
|
ZIPFILE=`basename "$1"`
|
|
VERSION=`echo "${ZIPFILE}" | cut -d "-" -f 2 | cut -d "_" -f 1`
|
|
BUILDTYPE=`echo "${ZIPFILE}" | cut -d "-" -f 2 | cut -d "_" -f 2`
|
|
BUILDTAG_RAW=`echo "${ZIPFILE}" | cut -d "." -f 1-4 | cut -d "-" -f 2-4`
|
|
BUILDTAG="${BUILDTAG_RAW//-}"
|
|
|
|
RPMNAME="duplicati-${VERSION}-${BUILDTAG}.noarch.rpm"
|
|
DEBNAME="duplicati_${VERSION}-1_all.deb"
|
|
MSI64NAME="duplicati-${BUILDTAG_RAW}-x64.msi"
|
|
MSI32NAME="duplicati-${BUILDTAG_RAW}-x86.msi"
|
|
DMGNAME="duplicati-${BUILDTAG_RAW}.dmg"
|
|
PKGNAME="duplicati-${BUILDTAG_RAW}.pkg"
|
|
SPKNAME="duplicati-${BUILDTAG_RAW}.spk"
|
|
|
|
UPDATE_TARGET="Updates/build/${BUILDTYPE}_target-${VERSION}"
|
|
|
|
KEYFILE=~/.ssh/duplicati-build-machines-key.pem
|
|
SSH_OPTIONS="-i ${KEYFILE} -o UserKnownHostsFile=./tmp/known_hosts"
|
|
|
|
echo "Filename: ${ZIPFILE}"
|
|
echo "Version: ${VERSION}"
|
|
echo "Buildtype: ${BUILDTYPE}"
|
|
echo "Buildtag: ${BUILDTAG}"
|
|
echo "RPMName: ${RPMNAME}"
|
|
echo "DEBName: ${DEBNAME}"
|
|
echo "SPKName: ${SPKNAME}"
|
|
|
|
start_aws_instance() {
|
|
|
|
local STATE=`aws ec2 describe-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["Reservations"][0]["Instances"][0]["State"]["Name"]'`
|
|
|
|
if [ "${STATE}" == "stopping" ]; then
|
|
echo -n "Instance has state '${STATE}', waiting .."
|
|
while [ "${STATE}" == "stopping" ]; do
|
|
echo -n "."
|
|
sleep 5
|
|
local STATE=`aws ec2 describe-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["Reservations"][0]["Instances"][0]["State"]["Name"]'`
|
|
done
|
|
echo ""
|
|
fi
|
|
|
|
local STATE=`aws ec2 start-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["StartingInstances"][0]["CurrentState"]["Name"]'`
|
|
|
|
if [ "${STATE}" != "running" ]; then
|
|
echo -n "Instance has state '${STATE}', waiting .."
|
|
|
|
while [ "${STATE}" != "running" ]; do
|
|
echo -n "."
|
|
sleep 5
|
|
local STATE=`aws ec2 describe-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["Reservations"][0]["Instances"][0]["State"]["Name"]'`
|
|
done
|
|
|
|
echo ""
|
|
fi
|
|
|
|
}
|
|
|
|
stop_aws_instance() {
|
|
local STATE=`aws ec2 stop-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["StoppingInstances"][0]["CurrentState"]["Name"]'`
|
|
echo "Instance state is now: ${STATE}"
|
|
}
|
|
|
|
ssh_connect_to_instance() {
|
|
local DNSNAME=`aws ec2 describe-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["Reservations"][0]["Instances"][0]["PublicDnsName"]'`
|
|
local IPADDR=`aws ec2 describe-instances --profile=duplicati-builder --instance-ids $1 | python -c 'import sys, json; print json.load(sys.stdin)["Reservations"][0]["Instances"][0]["PublicIpAddress"]'`
|
|
|
|
if [ -d "./tmp" ]; then
|
|
rm -rf "./tmp"
|
|
fi
|
|
|
|
mkdir "./tmp"
|
|
|
|
echo "${DNSNAME},${IPADDR} ecdsa-sha2-nistp256 $3" > "./tmp/known_hosts"
|
|
|
|
SSH_HOST="$2@${DNSNAME}"
|
|
|
|
ssh ${SSH_OPTIONS} "${SSH_HOST}" "cd" > /dev/null
|
|
local EXITCODE=$?
|
|
|
|
if [ ! "${EXITCODE}" -eq 0 ]; then
|
|
echo -n "Server did not allow login, waiting .."
|
|
while [ ! "${EXITCODE}" -eq 0 ]; do
|
|
echo -n "."
|
|
sleep 5
|
|
|
|
ssh ${SSH_OPTIONS} "${SSH_HOST}" "cd" > /dev/null
|
|
local EXITCODE=$?
|
|
done
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
ssh_upload_file() {
|
|
scp ${SSH_OPTIONS} "$1" "${SSH_HOST}:"
|
|
}
|
|
|
|
ssh_run_commands() {
|
|
cat "$1" | ssh ${SSH_OPTIONS} "${SSH_HOST}"
|
|
}
|
|
|
|
build_file_signatures() {
|
|
if [ "z${GPGID}" != "z" ]; then
|
|
echo "$GPGKEY" | "${GPG}" "--passphrase-fd" "0" "--batch" "--yes" "--default-key=${GPGID}" "--output" "$2.sig" "--detach-sig" "$1"
|
|
echo "$GPGKEY" | "${GPG}" "--passphrase-fd" "0" "--batch" "--yes" "--default-key=${GPGID}" "--armor" "--output" "$2.sig.asc" "--detach-sig" "$1"
|
|
fi
|
|
|
|
md5 "$1" | awk -F ' ' '{print $NF}' > "$2.md5"
|
|
shasum -a 1 "$1" | awk -F ' ' '{print $1}' > "$2.sha1"
|
|
shasum -a 256 "$1" | awk -F ' ' '{print $1}' > "$2.sha256"
|
|
}
|
|
|
|
if [ -f "${GPG_KEYFILE}" ]; then
|
|
if [ "z${KEYFILE_PASSWORD}" == "z" ]; then
|
|
echo -n "Enter keyfile password: "
|
|
read -s KEYFILE_PASSWORD
|
|
echo
|
|
fi
|
|
|
|
GPGDATA=`"${MONO}" "BuildTools/AutoUpdateBuilder/bin/Debug/SharpAESCrypt.exe" d "${KEYFILE_PASSWORD}" "${GPG_KEYFILE}"`
|
|
if [ ! $? -eq 0 ]; then
|
|
echo "Decrypting GPG keyfile failed"
|
|
exit 1
|
|
fi
|
|
GPGID=`echo "${GPGDATA}" | head -n 1`
|
|
GPGKEY=`echo "${GPGDATA}" | head -n 2 | tail -n 1`
|
|
else
|
|
echo "No GPG keyfile found, skipping gpg signatures"
|
|
fi
|
|
|
|
# Pre-boot instances to keep the waiting to a minimun
|
|
|
|
aws ec2 start-instances --profile=duplicati-builder --instance-ids "${DEBIAN_INSTANCE_ID}" &> /dev/null
|
|
aws ec2 start-instances --profile=duplicati-builder --instance-ids "${FEDORA_INSTANCE_ID}" &> /dev/null
|
|
aws ec2 start-instances --profile=duplicati-builder --instance-ids "${WINDOWS_INSTANCE_ID}" &> /dev/null
|
|
|
|
# Then do the local build to mask the waiting a little more
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "Building OSX package locally ..."
|
|
echo ""
|
|
echo "Enter local sudo password..."
|
|
|
|
cd Installer/OSX
|
|
bash "make-dmg.sh" "../../$1"
|
|
mv "Duplicati.dmg" "../../${UPDATE_TARGET}/${DMGNAME}"
|
|
mv "Duplicati.pkg" "../../${UPDATE_TARGET}/${PKGNAME}"
|
|
cd ../..
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "Building Synology package locally ..."
|
|
|
|
cd Installer/Synology
|
|
bash "make-binary-package.sh" "../../$1"
|
|
mv "${SPKNAME}" "../../${UPDATE_TARGET}/"
|
|
cd ../..
|
|
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "Starting Debian build instance"
|
|
|
|
start_aws_instance "${DEBIAN_INSTANCE_ID}"
|
|
|
|
ssh_connect_to_instance "${DEBIAN_INSTANCE_ID}" "ubuntu" "${DEBIAN_PUBKEY}"
|
|
|
|
echo "Instance has started, uploading binary package ..."
|
|
|
|
ssh_upload_file "$1"
|
|
|
|
echo "Running build script on server ..."
|
|
|
|
cat > "./tmp/debian-commands.sh" <<EOF
|
|
cd duplicati/Installer/debian
|
|
git pull
|
|
bash make-binary-package.sh "../../../${ZIPFILE}"
|
|
rm -rf "../../../${ZIPFILE}"
|
|
EOF
|
|
|
|
ssh_run_commands "./tmp/debian-commands.sh"
|
|
|
|
echo "Downloading binary package ..."
|
|
|
|
scp ${SSH_OPTIONS} "${SSH_HOST}:duplicati/Installer/debian/${DEBNAME}" "./tmp"
|
|
ssh ${SSH_OPTIONS} "${SSH_HOST}" "rm -rf duplicati/Installer/debian/duplicati_${VERSION}-*"
|
|
|
|
echo "Done, stopping instance ..."
|
|
|
|
stop_aws_instance "${DEBIAN_INSTANCE_ID}"
|
|
|
|
mv "./tmp/${DEBNAME}" "${UPDATE_TARGET}/"
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "Starting Fedora build instance ..."
|
|
|
|
start_aws_instance "${FEDORA_INSTANCE_ID}"
|
|
|
|
ssh_connect_to_instance "${FEDORA_INSTANCE_ID}" "ec2-user" "${FEDORA_PUBKEY}"
|
|
|
|
echo "Instance has started, uploading binary package ..."
|
|
|
|
ssh_upload_file "$1"
|
|
|
|
echo "Running build script on server ..."
|
|
|
|
cat > "./tmp/fedora-commands.sh" <<EOF
|
|
rm -rf ~/rpmbuild
|
|
rpmdev-setuptree
|
|
cd duplicati/Installer/fedora
|
|
git pull
|
|
bash make-binary-package.sh "../../../${ZIPFILE}"
|
|
rm -rf "../../../${ZIPFILE}"
|
|
EOF
|
|
|
|
ssh_run_commands "./tmp/fedora-commands.sh"
|
|
|
|
echo "Downloading binary package ..."
|
|
|
|
scp ${SSH_OPTIONS} "${SSH_HOST}:rpmbuild/RPMS/noarch/${RPMNAME}" "./tmp"
|
|
|
|
echo "Done, stopping instance ..."
|
|
|
|
stop_aws_instance "${FEDORA_INSTANCE_ID}"
|
|
|
|
mv "./tmp/${RPMNAME}" "${UPDATE_TARGET}/"
|
|
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "Starting Windows build instance"
|
|
|
|
start_aws_instance "${WINDOWS_INSTANCE_ID}"
|
|
|
|
ssh_connect_to_instance "${WINDOWS_INSTANCE_ID}" "ec2-user" "${WINDOWS_PUBKEY}"
|
|
|
|
echo "Instance has started, uploading binary package ..."
|
|
|
|
ssh_upload_file "$1"
|
|
|
|
echo "Running build script on server ..."
|
|
|
|
cat > "./tmp/windows-commands.sh" <<EOF
|
|
SET VS120COMNTOOLS=%VS140COMNTOOLS%
|
|
cd duplicati\\Installer\\Windows
|
|
git pull
|
|
build-msi.bat "..\\..\\..\\${ZIPFILE}"
|
|
del /q "..\\..\\..\\${ZIPFILE}"
|
|
EOF
|
|
|
|
ssh_run_commands "./tmp/windows-commands.sh"
|
|
|
|
echo "Downloading binary packages ..."
|
|
|
|
scp ${SSH_OPTIONS} "${SSH_HOST}:duplicati/Installer/Windows/Duplicati.msi" "./tmp"
|
|
scp ${SSH_OPTIONS} "${SSH_HOST}:duplicati/Installer/Windows/Duplicati-32bit.msi" "./tmp"
|
|
|
|
echo "Done, stopping instance ..."
|
|
|
|
stop_aws_instance "${WINDOWS_INSTANCE_ID}"
|
|
|
|
mv "./tmp/Duplicati.msi" "${UPDATE_TARGET}/${MSI64NAME}"
|
|
mv "./tmp/Duplicati-32bit.msi" "${UPDATE_TARGET}/${MSI32NAME}"
|
|
|
|
if [ -f "${AUTHENTICODE_PFXFILE}" ] && [ -f "${AUTHENTICODE_PASSWORD}" ]; then
|
|
echo "Performing authenticode signing of installers"
|
|
|
|
if [ "z${KEYFILE_PASSWORD}" == "z" ]; then
|
|
echo -n "Enter keyfile password: "
|
|
read -s KEYFILE_PASSWORD
|
|
echo
|
|
fi
|
|
|
|
authenticode_sign() {
|
|
NEST=""
|
|
for hashalg in sha1 sha256; do
|
|
SIGN_MSG=`osslsigncode sign -pkcs12 "${AUTHENTICODE_PFXFILE}" -pass "${PFX_PASS}" -n "Duplicati" -i "http://www.duplicati.com" -h "${hashalg}" ${NEST} -t "http://timestamp.verisign.com/scripts/timstamp.dll" -in "$1" -out tmpfile`
|
|
if [ "${SIGN_MSG}" != "Succeeded" ]; then echo "${SIGN_MSG}"; fi
|
|
mv tmpfile "$1"
|
|
NEST="-nest"
|
|
done
|
|
}
|
|
|
|
PFX_PASS=`"${MONO}" "BuildTools/AutoUpdateBuilder/bin/Debug/SharpAESCrypt.exe" d "${KEYFILE_PASSWORD}" "${AUTHENTICODE_PASSWORD}"`
|
|
|
|
DECRYPT_STATUS=$?
|
|
if [ "${DECRYPT_STATUS}" -ne 0 ]; then
|
|
echo "Failed to decrypt, SharpAESCrypt gave status ${DECRYPT_STATUS}, exiting"
|
|
exit 4
|
|
fi
|
|
|
|
if [ "x${PFX_PASS}" == "x" ]; then
|
|
echo "Failed to decrypt, SharpAESCrypt gave empty password, exiting"
|
|
exit 4
|
|
fi
|
|
|
|
authenticode_sign "${UPDATE_TARGET}/${MSI64NAME}"
|
|
authenticode_sign "${UPDATE_TARGET}/${MSI32NAME}"
|
|
|
|
else
|
|
echo "Skipped authenticode signing as files are missing"
|
|
fi
|
|
|
|
echo ""
|
|
echo ""
|
|
echo "Done building, uploading installers ..."
|
|
|
|
echo "{" > "./tmp/latest-installers.json"
|
|
|
|
process_installer() {
|
|
if [ "$2" != "zip" ]; then
|
|
aws --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/$1" "s3://updates.duplicati.com/${BUILDTYPE}/$1"
|
|
fi
|
|
|
|
local MD5=`md5 ${UPDATE_TARGET}/$1 | awk -F ' ' '{print $NF}'`
|
|
local SHA1=`shasum -a 1 ${UPDATE_TARGET}/$1 | awk -F ' ' '{print $1}'`
|
|
local SHA256=`shasum -a 256 ${UPDATE_TARGET}/$1 | awk -F ' ' '{print $1}'`
|
|
|
|
cat >> "./tmp/latest-installers.json" <<EOF
|
|
"$2": {
|
|
"name": "$1",
|
|
"url": "http://updates.duplicati.com/${BUILDTYPE}/$1",
|
|
"md5": "${MD5}",
|
|
"sha1": "${SHA1}",
|
|
"sha256": "${SHA256}"
|
|
},
|
|
EOF
|
|
|
|
}
|
|
|
|
process_installer "${ZIPFILE}" "zip"
|
|
process_installer "${SPKNAME}" "spk"
|
|
process_installer "${RPMNAME}" "rpm"
|
|
process_installer "${DEBNAME}" "deb"
|
|
process_installer "${DMGNAME}" "dmg"
|
|
process_installer "${PKGNAME}" "pkg"
|
|
process_installer "${MSI32NAME}" "msi86"
|
|
process_installer "${MSI64NAME}" "msi64"
|
|
|
|
cat >> "./tmp/latest-installers.json" <<EOF
|
|
"done": true
|
|
}
|
|
EOF
|
|
|
|
aws --profile=duplicati-upload s3 cp "./tmp/latest-installers.json" "s3://updates.duplicati.com/${BUILDTYPE}/latest-installers.json"
|
|
|
|
if [ -d "./tmp" ]; then
|
|
rm -rf "./tmp"
|
|
fi
|
|
|
|
mkdir tmp
|
|
mkdir "./tmp/duplicati-${BUILDTAG_RAW}-signatures"
|
|
|
|
for FILE in "${SPKNAME}" "${RPMNAME}" "${DEBNAME}" "${DMGNAME}" "${PKGNAME}" "${MSI32NAME}" "${MSI64NAME}" "${ZIPFILE}"; do
|
|
build_file_signatures "${UPDATE_TARGET}/${FILE}" "./tmp/duplicati-${BUILDTAG_RAW}-signatures/${FILE}"
|
|
done
|
|
|
|
if [ "z${GPGID}" != "z" ]; then
|
|
echo "${GPGID}" > "./tmp/duplicati-${BUILDTAG_RAW}-signatures/sign-key.txt"
|
|
echo "https://pgp.mit.edu/pks/lookup?op=get&search=${GPGID}" >> "./tmp/duplicati-${BUILDTAG_RAW}-signatures/sign-key.txt"
|
|
fi
|
|
|
|
cd tmp
|
|
zip -r9 "./duplicati-${BUILDTAG_RAW}-signatures.zip" "./duplicati-${BUILDTAG_RAW}-signatures/"
|
|
cd ..
|
|
|
|
rm -rf "./tmp/duplicati-${BUILDTAG_RAW}-signatures"
|
|
|
|
aws --profile=duplicati-upload s3 cp "./tmp/duplicati-${BUILDTAG_RAW}-signatures.zip" "s3://updates.duplicati.com/${BUILDTYPE}/duplicati-${BUILDTAG_RAW}-signatures.zip"
|
|
|
|
GITHUB_TOKEN=`cat "${GITHUB_TOKEN_FILE}"`
|
|
|
|
if [ "x${GITHUB_TOKEN}" == "x" ]; then
|
|
echo "No GITHUB_TOKEN found in environment, you can manually upload the binaries"
|
|
else
|
|
github-release upload \
|
|
--tag "v${VERSION}-${BUILDTAG_RAW}" \
|
|
--name "duplicati-${BUILDTAG_RAW}-signatures.zip" \
|
|
--repo "duplicati" \
|
|
--user "duplicati" \
|
|
--security-token "${GITHUB_TOKEN}" \
|
|
--file "./tmp/duplicati-${BUILDTAG_RAW}-signatures.zip"
|
|
|
|
for FILE in "${SPKNAME}" "${RPMNAME}" "${DEBNAME}" "${DMGNAME}" "${PKGNAME}" "${MSI32NAME}" "${MSI64NAME}"; do
|
|
github-release upload \
|
|
--tag "v${VERSION}-${BUILDTAG_RAW}" \
|
|
--name "${FILE}" \
|
|
--repo "duplicati" \
|
|
--user "duplicati" \
|
|
--security-token "${GITHUB_TOKEN}" \
|
|
--file "${UPDATE_TARGET}/${FILE}"
|
|
done
|
|
fi
|
|
|
|
rm -rf "./tmp"
|