diff options
Diffstat (limited to '')
-rwxr-xr-x | scripts/build-in-obs.sh | 29 | ||||
-rwxr-xr-x | scripts/coverage_c_combine.sh | 24 | ||||
-rwxr-xr-x | scripts/coverage_env.sh | 40 | ||||
-rwxr-xr-x | scripts/embed-lua.sh | 10 | ||||
-rwxr-xr-x | scripts/gen-cdefs.sh | 72 | ||||
-rwxr-xr-x | scripts/kresd-host.lua | 114 | ||||
-rwxr-xr-x | scripts/kresd-query.lua | 64 | ||||
-rw-r--r-- | scripts/kresd.apparmor | 29 | ||||
-rwxr-xr-x | scripts/launch-test-instance.sh | 26 | ||||
-rwxr-xr-x | scripts/luacov_gen_empty.sh | 17 | ||||
-rwxr-xr-x | scripts/luacov_to_info.lua | 56 | ||||
-rwxr-xr-x | scripts/make-archive.sh | 15 | ||||
-rwxr-xr-x | scripts/make-distrofiles.sh | 53 | ||||
-rwxr-xr-x | scripts/make-srpm.sh | 13 | ||||
-rwxr-xr-x | scripts/map_install_src.lua | 167 | ||||
-rwxr-xr-x | scripts/obs-testbuild.sh | 38 |
16 files changed, 767 insertions, 0 deletions
diff --git a/scripts/build-in-obs.sh b/scripts/build-in-obs.sh new file mode 100755 index 0000000..7aea0d3 --- /dev/null +++ b/scripts/build-in-obs.sh @@ -0,0 +1,29 @@ +#!/bin/bash -e + +# Example usage: +# 1. place tarball to be released in git root dir +# 2. scripts/make-distrofiles.sh -s +# 3. scripts/build-in-obs.sh knot-resolver-latest + +project=home:CZ-NIC:$1 +package=knot-resolver + +if ! [[ "$1" == *-devel || "$1" == *-testing ]]; then + read -p "Pushing to '$project', are you sure? [y/N]: " yn + case $yn in + [Yy]* ) + ;; + * ) + exit 1 + esac +fi + +osc co "${project}" "${package}" +pushd "${project}/${package}" +osc del * ||: +cp -L ../../*.orig.tar.xz ../../*.debian.tar.xz ../../*.dsc ./ +cp -rL ../../distro/rpm/* ./ +cp -rL ../../distro/arch/* ./ +osc addremove +osc ci -n +popd diff --git a/scripts/coverage_c_combine.sh b/scripts/coverage_c_combine.sh new file mode 100755 index 0000000..23006c1 --- /dev/null +++ b/scripts/coverage_c_combine.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# $1 = top source directory +# $2 = coverage data directory path +# $3 = output directory for *.info files + +set -o errexit -o nounset +shopt -s nullglob +IFS=$'\n' + +TOPSRCDIR="$1" +DATAROOT="$2" +OUTDIR="$3" + +cd "${TOPSRCDIR}" +for COVNAME in $(find "${DATAROOT}" -name .topdir_kresd_coverage) +do + find "${DATAROOT}" -name '*.gcda' -not -path "${DATAROOT}/*" -delete + COVDIR="$(dirname "${COVNAME}")" + COVDATA_FILENAMES=("${COVDIR}"/*) # filenames in BASH array + (( ${#COVDATA_FILENAMES[*]} )) || continue # skip empty dirs + + cp -r -t ${TOPSRCDIR} "${COVDIR}"/* + ${LCOV} -q --no-external --capture -d lib -d daemon -d modules -o "$(mktemp -p "${OUTDIR}" -t XXXXXXXX.c.info)" > /dev/null +done diff --git a/scripts/coverage_env.sh b/scripts/coverage_env.sh new file mode 100755 index 0000000..bb85649 --- /dev/null +++ b/scripts/coverage_env.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# generate variables for coverage testing +# $1 = top source directory +# $2 = coverage data directory path +# $3 = name of test/new subdirectory name +# $4 = [optional] --export to generate export commands + +set -o errexit -o nounset +shopt -s nullglob + +test -z "${COVERAGE:-}" && exit 0 # not enabled, do nothing +test ! -z "${V:-}" && set -o xtrace # verbose mode + +EXPORT="" +test "${4:-}" == "--export" && EXPORT="export " +TOPSRCDIR="$1" +DATAROOT="$2" +OUTPATH="$2/$3" + +# check that output directory is empty +# beware: Makefile will always call coverage_env.sh for all targets +# so directories get created but not populated +# i.e. test -d is not sufficient check +OUTPATH_FILENAMES=("${OUTPATH}"/*) # filenames in BASH array +(( ${#OUTPATH_FILENAMES[*]} )) && echo "false" && >&2 echo "fatal: output directory ${OUTPATH} must be empty (or non-existent)" && exit 1 + +mkdir -p "${OUTPATH}" +# convert paths to absolute +pushd "${OUTPATH}" &> /dev/null +touch .topdir_kresd_coverage +OUTPATH="$(pwd -P)" +popd &> /dev/null + +# determine GCOV_PREFIX_STRIP value for current source directory +TOPSRCDIR_SLASHES="${TOPSRCDIR//[^\/]/}" # remove everything except / +GCOV_PREFIX_STRIP="${#TOPSRCDIR_SLASHES}" # numer of / == number of components + +KRESD_COVERAGE_STATS="${OUTPATH}/luacov.stats.out" +GCOV_PREFIX="${OUTPATH}" +echo "${EXPORT}KRESD_COVERAGE_STATS=\"${KRESD_COVERAGE_STATS}\" ${EXPORT}GCOV_PREFIX=\"${GCOV_PREFIX}\" ${EXPORT}GCOV_PREFIX_STRIP=\"${GCOV_PREFIX_STRIP}\"" diff --git a/scripts/embed-lua.sh b/scripts/embed-lua.sh new file mode 100755 index 0000000..80f6cba --- /dev/null +++ b/scripts/embed-lua.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -e +# Clean unnecessary stuff from the lua file; note the significant tabulator. +alias strip="sed -e 's/^[ ]*//g; s/ */ /g; /^--/d; /^$/d'" +if command -v xxd > /dev/null 2>&1; then + strip < "$1" | xxd -i - +else + strip < "$1" | hexdump -v -e '/1 "0x%02X, " " "' +fi +exit $? diff --git a/scripts/gen-cdefs.sh b/scripts/gen-cdefs.sh new file mode 100755 index 0000000..0627fa4 --- /dev/null +++ b/scripts/gen-cdefs.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -o pipefail -o errexit + +if [ "$2" != types ] && [ "$2" != functions ]; then + echo "Usage: $0 libkres (types|functions)" >&2 + echo " and input identifiers, one per line." >&2 + echo " You need debug symbols in the library." >&2 + exit 1 +fi + +if ! command -v gdb >/dev/null; then + echo "Failed to find gdb" >&2 + exit 1 +fi + +if ! command -v sed >/dev/null; then + echo "Failed to find GNU sed" >&2 + exit 1 +fi + +if ! sed --version | head -1 | grep -q "GNU sed"; then + echo "GNU sed required to run this script" >&2 +fi + +# be very precise with the directories for libraries to not pick wrong library +case "$1" in + libknot) library="$(PATH="$(pkg-config libknot --variable=libdir)" command -v "$1.so")" ;; + libzscanner) library="$(PATH="$(pkg-config libzscanner --variable=libdir)" command -v "$1.so")" ;; + *) library="$(PATH="$(pwd)/lib" command -v "$1.so")" +esac + +if [ -z "$library" ]; then + echo "$1 not found. Note: only .so platforms work currently." >&2 + exit 1 +fi + +# Let's use an array to hold command-line arguments, to simplify quoting. +GDB=(gdb) +GDB+=(-n -quiet -batch "-symbols=$library") +GDB+=(-iex "set width unlimited" -iex "set max-value-size unlimited") + +grep -v '^#\|^$' | while read -r ident; do + if [ "$2" = functions ]; then + output="$("${GDB[@]}" --ex "info functions ^$ident\$" \ + | sed '0,/^All functions/ d; /^File .*:$/ d')" + else # types + case "$ident" in + struct\ *|union\ *|enum\ *) + output="$("${GDB[@]}" --ex "ptype $ident" \ + | sed '0,/^type = /s/^type = /\n/; $ s/$/;/')" + ;; + *) + output="$("${GDB[@]}" --ex "info types ^$ident\$" \ + | sed -e '0,/^File .*:$/ d' -e '/^File .*:$/,$ d')" + # we need to stop early to remove ^^ multiple matches + ;; + esac + fi + # LuaJIT FFI blows up on "uint" type + output="$(echo "$output" | sed 's/\buint\b/unsigned int/g')" + # GDB 8.2+ added source line prefix to output + output="$(echo "$output" | sed 's/^[0-9]\+:[[:space:]]*//g')" + + # abort on empty output + if [ -z "$(echo "$output" | tr -d "\n;")" ]; then + echo "Failed to find cdef of $ident" >&2 + exit 1 + fi + echo "$output" | grep -v '^$' +done + +exit 0 diff --git a/scripts/kresd-host.lua b/scripts/kresd-host.lua new file mode 100755 index 0000000..9348716 --- /dev/null +++ b/scripts/kresd-host.lua @@ -0,0 +1,114 @@ +#!/usr/bin/env luajit +-- Work around OS X stripping dyld variables +cli_bin = 'luajit scripts/kresd-query.lua' +libdir = os.getenv('DYLD_LIBRARY_PATH') +if libdir then + cli_bin = string.format('DYLD_LIBRARY_PATH="%s" %s', libdir, cli_bin) +end +-- Parse CLI arguments +local function help(rc) + print(string.format([[ +Usage: %s [-vdh46D] [-c class] [-t type] + [-f keyfile] hostname + Queries the DNS for information. + The hostname is looked up for IP4, IP6 and mail. + Use the -v option to see DNSSEC security information. + -t type what type to look for. + -c class what class to look for, if not class IN. + -C confstr additional kresd-style configuration. + -D DNSSEC enable with default root anchor + -f keyfile read trust anchors from file, with lines as -y. + -v be more verbose, shows nodata and security. + -d debug, traces the action, -d -d shows more. + -4 use ipv4 network, avoid ipv6. + -6 use ipv6 network, avoid ipv4. + -h show this usage help.]], + arg[0])) + return rc +end + +-- Parse CLI arguments +if #arg < 1 then + return help(1) +end +local qtypes, qclass, qname = {}, 'IN', nil +local verbose, config = false, {} +k = 1 while k <= #arg do + local v = arg[k] + if v == '-h' or v == '--help' then + return help(0) + elseif v == '-C' then + k = k + 1 + table.insert(config, arg[k]) + elseif v == '-D' then + table.insert(config, 'trust_anchors.file = "root.keys"') + elseif v == '-f' then + k = k + 1 + table.insert(config, string.format('trust_anchors.file = "%s"', arg[k])) + elseif v == '-v' then + verbose = true + elseif v == '-d' then + verbose = true + table.insert(config, 'verbose(true)') + elseif v == '-4' then + table.insert(config, 'net.ipv6 = false') + elseif v == '-6' then + table.insert(config, 'net.ipv4 = false') + elseif v == '-c' then + k = k + 1 + qclass = arg[k]:upper() + elseif v == '-t' then + k = k + 1 + table.insert(qtypes, arg[k]:upper()) + elseif v:byte() == string.byte('-') then + return help(1) + else + qname = v + -- Check if name is an IP addresses + -- @TODO: convert to domain name and make a PTR lookup + end + k = k + 1 +end +if not qname then + return help(1) +end +if #qtypes == 0 then + qtypes = {'A', 'AAAA', 'MX'} +end +-- Assemble config/query +for _, qtype in ipairs(qtypes) do + query = string.format('-t %s -c %s %s', qtype, qclass, qname) + capture = string.format([[ + local qname = "%s" + local qtype = "%s" + local qverbose = %s]], qname, qtype, tostring(verbose))..[[ + local qry = req:resolved() + local section = pkt:rrsets(kres.section.ANSWER) + for i = 1, #section do + local rr = section[i] + for k = 1, rr.rrs.count do + local rdata = rr:tostring(k - 1) + local owner = kres.dname2str(rr:owner()) + if qverbose then + if not qry.flags.DNSSEC_WANT or qry.flags.DNSSEC_INSECURE then + rdata = rdata .. " (insecure)" + else + rdata = rdata .. " (secure)" + end + end + if rr.type == kres.type.A then + print(string.format("%s has address %s", owner, rdata)) + elseif rr.type == kres.type.AAAA then + print(string.format("%s has IPv6 address %s", owner, rdata)) + elseif rr.type == kres.type.MX then + print(string.format("%s mail is handled by %s", owner, rdata)) + elseif rr.type == kres.type.CNAME then + print(string.format("%s is an alias for %s", owner, rdata)) + else + print(string.format("%s has %s record %s", owner, qtype, rdata)) + end + end + end + ]] + os.execute(string.format('%s -C \'%s\' %s \'%s\'', cli_bin, table.concat(config, ' '), query, capture)) +end diff --git a/scripts/kresd-query.lua b/scripts/kresd-query.lua new file mode 100755 index 0000000..c2d5468 --- /dev/null +++ b/scripts/kresd-query.lua @@ -0,0 +1,64 @@ +#!/usr/bin/env luajit +cli_bin = 'kresd -q -c -' +-- Work around OS X stripping dyld variables +libdir = os.getenv('DYLD_LIBRARY_PATH') +if libdir then + cli_bin = string.format('DYLD_LIBRARY_PATH="%s" %s', libdir, cli_bin) +end +cli_cmd = [[echo ' +option("ALWAYS_CUT", true) +%s +return resolve("%s", kres.type.%s, kres.class.%s, 0, +function (pkt, req) + pkt = kres.pkt_t(pkt) + req = kres.request_t(req) + local ok, err = pcall(function () %s end) + if not ok then + print(err) + end + quit() +end)']] +-- Parse CLI arguments +local function help() + name = 'kresd-query.lua' + print(string.format('Usage: %s [-t type] [-c class] [-C config] <name> <script>', name)) + print('Execute a single-shot query and run a script on the result.') + print('There are two variables available: pkt (kres.pkt_t), req (kres.request_t)') + print('See modules README to learn about their APIs.') + print('') + print('Options:') + print('\t-h,--help ... print this help') + print('\t-t TYPE ... query for given type (default: A)') + print('\t-c CLASS ... query in given class (default: IN)') + print('\t-C config_str ... kresd-style config (default: -)') + print('Examples:') + print('\t'..name..' -t SOA cz "print(pkt:qname())" ... print response QNAME') +end +-- Parse CLI arguments +if #arg < 2 then help() return 1 end +local qtype, qclass, qname = 'A', 'IN', nil +local config, scripts = '', {} +k = 1 while k <= #arg do + local v = arg[k] + if v == '-h' or v == '--help' then + return help() + elseif v == '-C' then + k = k + 1 + config = arg[k] + elseif v == '-c' then + k = k + 1 + qclass = arg[k]:upper() + elseif v == '-t' then + k = k + 1 + qtype = arg[k]:upper() + elseif v:byte() == string.byte('-') then + return help() + elseif not qname then + qname = v + else + table.insert(scripts, v) + end + k = k + 1 +end +cli_cmd = string.format(cli_cmd, config, qname, qtype, qclass, table.concat(scripts, ' ')) +return os.execute(cli_cmd..' | '..cli_bin) diff --git a/scripts/kresd.apparmor b/scripts/kresd.apparmor new file mode 100644 index 0000000..ad6f911 --- /dev/null +++ b/scripts/kresd.apparmor @@ -0,0 +1,29 @@ +#include <tunables/global> + +/usr/sbin/kresd { + #include <abstractions/base> + #include <abstractions/p11-kit> + #include <abstractions/nameservice> + capability net_bind_service, + capability setgid, + capability setuid, + # seems to be needed during start to read /var/lib/knot-resolver + # while we still run as root. + capability dac_override, + + network tcp, + network udp, + + /proc/sys/net/core/somaxconn r, + /etc/knot-resolver/* r, + /var/lib/knot-resolver/ r, + /var/lib/knot-resolver/** rwlk, + + # modules + /usr/lib{,64}/kdns_modules/*.lua r, + /usr/lib{,64}/kdns_modules/*.so rm, + + # Site-specific additions and overrides. See local/README for details. + #include <local/usr.sbin.kresd> +} + diff --git a/scripts/launch-test-instance.sh b/scripts/launch-test-instance.sh new file mode 100755 index 0000000..8a93328 --- /dev/null +++ b/scripts/launch-test-instance.sh @@ -0,0 +1,26 @@ +#!/bin/sh -e +export PATH="/usr/lib/ccache:$PATH" + +PORT=${1:-$((32767+$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -d' ' -f1) % 32768))} + +JOBS=$(cat /proc/cpuinfo | grep processor | wc -l) + +WORKDIR=${2:-$(mktemp -d /tmp/knot-resolver.XXXXXX)} + +PREFIX=${PREFIX:-$WORKDIR} make clean + +CFLAGS=${CFLAGS:-"-O2 -g3"} PREFIX=${PREFIX:-$WORKDIR} make -j ${JOBS} V=1 + +PREFIX=${PREFIX:-$WORKDIR} make install + +install -d -m 0700 ${WORKDIR}/run/kresd + +echo "Launching Knot Resolver on port: ${PORT}" +echo "To debug, use:" +echo "dig +dnssec +multi +time=60 +retry=1 -p ${PORT} @::1" + +LD_LIBRARY_PATH=${WORKDIR}/lib ${WORKDIR}/sbin/kresd -a 127.0.0.1#${PORT} -a ::1#${PORT} -v -k ${ROOT_KEY:-/usr/share/dns/root.key} ${WORKDIR}/run/kresd + +if [ "${WORKDIR}" != "${2}" -a "${KEEP_WORKDIR}" != "yes" ]; then + rm -r ${WORKDIR} +fi diff --git a/scripts/luacov_gen_empty.sh b/scripts/luacov_gen_empty.sh new file mode 100755 index 0000000..a224081 --- /dev/null +++ b/scripts/luacov_gen_empty.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Generate stats file in luacov format indicating that files named on stdin +# were not processed. +# +# Normally luacov does not know about files which were not loaded so +# without this manual addition the files are missing in coverage report. + +# Usage: +# $ luacov_gen_empty.sh < list_of_lua_files > luacov.empty_stats.out + +set -o errexit -o nounset +IFS=$'\n' + +while read FILENAME +do + echo -e "0:${FILENAME}\n " +done diff --git a/scripts/luacov_to_info.lua b/scripts/luacov_to_info.lua new file mode 100755 index 0000000..372f5c0 --- /dev/null +++ b/scripts/luacov_to_info.lua @@ -0,0 +1,56 @@ +#!/usr/bin/env luajit + +local luacov = require('luacov') +local ReporterBase = require('luacov.reporter').ReporterBase +local LcovReporter = setmetatable({}, ReporterBase) +LcovReporter.__index = LcovReporter + +function LcovReporter:on_new_file(filename) + self.finfo = self.current_files[filename] or {name=filename, coverage={}} +end + +function LcovReporter:on_mis_line(_, lineno, _) + self.finfo.coverage[lineno] = self.finfo.coverage[lineno] or 0 +end + +function LcovReporter:on_hit_line(_, lineno, _, hits) + self.finfo.coverage[lineno] = (self.finfo.coverage[lineno] or 0) + hits +end + +function LcovReporter:on_end_file() + self.current_files[self.finfo.name] = self.finfo + self.finfo = nil +end + +-- Write out results in lcov format +local function write_lcov_info(files) + for fname, finfo in pairs(files) do + local instrumented, nonzero = 0, 0 + print('TN:') + print(string.format('SF:%s', fname)) + for i, hits in pairs(finfo.coverage) do + print(string.format('DA:%d,%d', i, hits)) + instrumented = instrumented + 1 + if hits > 0 then + nonzero = nonzero + 1 + end + end + print(string.format('LH:%d', nonzero)) + print(string.format('LF:%d', instrumented)) + print('end_of_record') + end +end + +-- Accumulate total coverage +local all_files = {} +for _, fname in ipairs(arg) do + local conf = luacov.load_config() + conf.statsfile = fname + local reporter = assert(LcovReporter:new(conf)) + reporter.current_files = all_files + reporter:run() + reporter:close() +end + +-- Write results +write_lcov_info(all_files) diff --git a/scripts/make-archive.sh b/scripts/make-archive.sh new file mode 100755 index 0000000..e3b1a97 --- /dev/null +++ b/scripts/make-archive.sh @@ -0,0 +1,15 @@ +#!/bin/sh -e +# Create a distribution tarball, like 'make dist' from autotools. +cd "$(git rev-parse --show-toplevel)" +ver=$(git describe | sed 's/^v//' | sed 's/-/\./g') +test 0 -ne $(git status --porcelain | wc -l) && \ + echo "Git working tree is dirty, make it clean first" && \ + exit 1 +git submodule status --recursive | grep -q '^[^ ]' && \ + echo "Git submodules are dirty, run: git submodule update --recursive --init" && \ + exit 2 + +# 'git ls-files --recurse-submodules' works only if modules are initialized +name="knot-resolver-$ver" +tar caf "$name.tar.xz" -h --no-recursion --transform "s|^|$name/|" -- $(git ls-files --recurse-submodules) +echo "$name.tar.xz" diff --git a/scripts/make-distrofiles.sh b/scripts/make-distrofiles.sh new file mode 100755 index 0000000..957c067 --- /dev/null +++ b/scripts/make-distrofiles.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -o errexit -o nounset -o xtrace + +# Run with -s to include *.symbols files. + +package=knot-resolver +withsymbols=false + +while getopts "s" o; do + case "${o}" in + s) + withsymbols=true + ;; + *) + ;; + esac +done +shift $((OPTIND-1)) + + +cd "$(git rev-parse --show-toplevel)" +version=$(ls ${package}*.tar.xz | sed "s/${package}-\(.*\).tar.xz/\1/") + +# Check version for invalid characters +if [[ $(echo "${version}" | grep '^[[:alnum:].]$') -ne 0 ]]; then + echo "Invalid version number: may contain only alphanumeric characters and dots" + exit 1 +fi + +# Fill in VERSION field in distribution specific files +files="distro/rpm/${package}.spec distro/deb/changelog distro/arch/PKGBUILD" +for file in ${files}; do + sed -i "s/__VERSION__/${version}/g" "${file}" +done + +# Rename archive to debian format +pkgname="${package}-${version}" +debname="${package}_${version}.orig" +mv "${pkgname}.tar.xz" "${debname}.tar.xz" + +# Prepare clean debian-specific directory +tar -xf "${debname}.tar.xz" +pushd "${pkgname}" > /dev/null +cp -arL ../distro/deb debian + +# Optionally remove symbols file +if [ "$withsymbols" = false ]; then + rm -f debian/*.symbols +fi + +# Create debian archive and dsc +dpkg-source -b . +popd > /dev/null diff --git a/scripts/make-srpm.sh b/scripts/make-srpm.sh new file mode 100755 index 0000000..29fc8b3 --- /dev/null +++ b/scripts/make-srpm.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -o errexit -o nounset -o xtrace + +# Create a source rpm for Fedora/EPEL + +cd "$(git rev-parse --show-toplevel)" +scripts/make-archive.sh +scripts/make-distrofiles.sh +mv knot-resolver_*.orig.tar.xz distro/rpm/ +cd distro/rpm +rpkg srpm --outdir . +mv *.src.rpm ../../ +mv *.tar.xz ../../ diff --git a/scripts/map_install_src.lua b/scripts/map_install_src.lua new file mode 100755 index 0000000..f4f0ed3 --- /dev/null +++ b/scripts/map_install_src.lua @@ -0,0 +1,167 @@ +#!/usr/bin/env luajit + +-- parse install commands from stdin +-- input: PREFIX=... make install --dry-run --always-make +-- output: <install path> <source path> +-- (or sed commands if --sed was specified) + +output = 'list' +if #arg > 1 or arg[1] == '-h' or arg[1] == '--help' then + print(string.format([[ +Read install commands and map install paths to paths in source directory. + +Usage: +$ PREFIX=... make install --dry-run --always-make | %s + +Example output: +/kresd/git/.local/lib/kdns_modules/policy.lua modules/policy/policy.lua + +Option --sed will produce output suitable as input suitable for sed.]], + arg[0])) + os.exit(1) +elseif #arg == 0 then + output = 'list' +elseif arg[1] == '--sed' then + output = 'sed' +else + print('Invalid arguments. See --help.') + os.exit(2) +end + +-- remove double // from paths and remove trailing / +function normalize_path(path) + assert(path) + repeat + path, changes = path:gsub('//', '/') + until changes == 0 + return path:gsub('/$', '') +end + +function is_opt(word) + return word:match('^-') +end + +-- opts requiring additional argument to be skipped +local ignored_opts_with_arg = { + ['--backup'] = true, + ['-g'] = true, + ['--group'] = true, + ['-m'] = true, + ['--mode'] = true, + ['-o'] = true, + ['--owner'] = true, + ['--strip-program'] = true, + ['--suffix'] = true, +} + +-- state machine junctions caused by --opts +-- returns: new state (expect, mode) and target name if any +function parse_opts(word, expect, mode) + if word == '--' then + return 'names', mode, nil -- no options anymore + elseif word == '-d' or word == '--directory' then + return 'opt_or_name', 'newdir', nil + elseif word == '-t' or word == '--target-directory' then + return 'targetdir', mode, nil + elseif word:match('^--target-directory=') then + return 'opt_or_name', mode, string.sub(word, 20) + elseif ignored_opts_with_arg[word] then + return 'ignore', mode, nil -- ignore next word + else + return expect, mode, nil -- unhandled opt + end +end + + +-- cmd: complete install command line: install -m 0644 -t dest src1 src2 +-- dirs: names known to be directories: name => true +-- returns: updated dirs +function process_cmd(cmd, dirs) + -- print('# ' .. cmd) + sanity_check(cmd) + local expect = 'install' + local mode = 'copy' -- copy or newdir + local target -- last argument or argument for install -t + local names = {} -- non-option arguments + + for word in cmd:gmatch('%S+') do + if expect == 'install' then -- parsing 'install' + assert(word == 'install') + expect = 'opt_or_name' + elseif expect == 'opt_or_name' then + if is_opt(word) then + expect, mode, newtarget = parse_opts(word, expect, mode) + target = newtarget or target + else + if mode == 'copy' then + table.insert(names, word) + elseif mode == 'newdir' then + local path = normalize_path(word) + dirs[path] = true + else + assert(false, 'bad mode') + end + end + elseif expect == 'targetdir' then + local path = normalize_path(word) + dirs[path] = true + target = word + expect = 'opt_or_name' + elseif expect == 'names' then + table.insert(names, word) + elseif expect == 'ignore' then + expect = 'opt_or_name' + else + assert(false, 'bad expect') + end + end + if mode == 'newdir' then + -- no mapping to print, this cmd just created directory + return dirs + end + + if not target then -- last argument is the target + target = table.remove(names) + end + assert(target, 'fatal: no target in install cmd') + target = normalize_path(target) + + for _, name in pairs(names) do + basename = string.gsub(name, "(.*/)(.*)", "%2") + if not dirs[target] then + print('fatal: target directory "' .. target .. '" was not created yet!') + os.exit(2) + end + -- mapping installed name -> source name + if output == 'list' then + print(target .. '/' .. basename, name) + elseif output == 'sed' then + print(string.format([[s`%s`%s`g]], + target .. '/' .. basename, name)) + else + assert(false, 'unsupported output') + end + end + return dirs +end + +function sanity_check(cmd) + -- shell quotation is not supported + assert(not cmd:match('"'), 'quotes " are not supported') + assert(not cmd:match("'"), "quotes ' are not supported") + assert(not cmd:match('\\'), "escapes like \\ are not supported") + assert(cmd:match('^install%s'), 'not an install command') +end + +-- remember directories created by install -d so we can expand relative paths +local dirs = {} +while true do + local cmd = io.read("*line") + if not cmd then + break + end + local isinstall = cmd:match('^install%s') + if isinstall then + dirs = process_cmd(cmd, dirs) + end +end diff --git a/scripts/obs-testbuild.sh b/scripts/obs-testbuild.sh new file mode 100755 index 0000000..f44cecc --- /dev/null +++ b/scripts/obs-testbuild.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# +# Builds the checked out version in knot-dns-testing OBS repository + +set -o errexit -o nounset -o xtrace + +force=false + +# Read options +while getopts "f" o; do + case "${o}" in + f) + force=true + ;; + *) + ;; + esac +done +shift $((OPTIND-1)) + +# Clean working tree +if [[ $(git status --porcelain | wc -l) -ne 0 ]]; then + if [ "$force" = false ]; then + echo "working tree dirty. force clean with '-f'" + exit 1 + fi + git clean -dfx + git reset --hard +fi + +# Create tarball +scripts/make-archive.sh + +# Submit to OBS +scripts/make-distrofiles.sh -s +scripts/build-in-obs.sh knot-resolver-testing + +echo "Check results at https://build.opensuse.org/package/show/home:CZ-NIC:knot-resolver-testing/knot-resolver" |