Merge branch 'ckuehl_python_package'
This commit is contained in:
commit
6f6814e91b
17 changed files with 328 additions and 124 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
dumb-init
|
dumb-init
|
||||||
dist/
|
dist/
|
||||||
*.deb
|
*.deb
|
||||||
|
*.egg-info
|
||||||
|
.tox
|
||||||
|
|
26
.pre-commit-config.yaml
Normal file
26
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks.git
|
||||||
|
sha: 003e43251aea1da33f2072f2365ec8b9ceaae070
|
||||||
|
hooks:
|
||||||
|
- id: autopep8-wrapper
|
||||||
|
- id: check-added-large-files
|
||||||
|
- id: check-docstring-first
|
||||||
|
- id: check-json
|
||||||
|
- id: check-merge-conflict
|
||||||
|
- id: check-xml
|
||||||
|
- id: check-yaml
|
||||||
|
- id: debug-statements
|
||||||
|
- id: detect-private-key
|
||||||
|
- id: double-quote-string-fixer
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: flake8
|
||||||
|
- id: name-tests-test
|
||||||
|
- id: requirements-txt-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/asottile/reorder_python_imports.git
|
||||||
|
sha: 3d86483455ab5bd06cc1069fdd5ac57be5463f10
|
||||||
|
hooks:
|
||||||
|
- id: reorder-python-imports
|
||||||
|
- repo: https://github.com/Lucas-C/pre-commit-hooks.git
|
||||||
|
sha: 181a63c511691da58116fa19a7241956018660bc
|
||||||
|
hooks:
|
||||||
|
- id: remove-tabs
|
|
@ -2,9 +2,9 @@ FROM debian:jessie
|
||||||
|
|
||||||
MAINTAINER Chris Kuehl <ckuehl@yelp.com>
|
MAINTAINER Chris Kuehl <ckuehl@yelp.com>
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
build-essential devscripts equivs && \
|
build-essential devscripts equivs && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
WORKDIR /mnt
|
WORKDIR /mnt
|
||||||
|
|
||||||
ENTRYPOINT mk-build-deps -i && make builddeb
|
ENTRYPOINT mk-build-deps -i && make builddeb
|
||||||
|
|
1
MANIFEST.in
Normal file
1
MANIFEST.in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include dumb-init.c
|
59
Makefile
59
Makefile
|
@ -1,13 +1,31 @@
|
||||||
DOCKER_TEST := sh -c 'dpkg -i /mnt/dist/*.deb && cd /mnt && ./test'
|
DOCKER_RUN_TEST := docker run -v $(PWD):/mnt:ro
|
||||||
|
DOCKER_DEB_TEST := sh -euxc ' \
|
||||||
|
apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends procps \
|
||||||
|
&& dpkg -i /mnt/dist/*.deb \
|
||||||
|
&& cd /mnt \
|
||||||
|
&& ./test \
|
||||||
|
'
|
||||||
|
DOCKER_PYTHON_TEST := sh -uexc ' \
|
||||||
|
apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends python-pip build-essential procps \
|
||||||
|
&& pip install -vv /mnt \
|
||||||
|
&& cd /mnt \
|
||||||
|
&& ./test \
|
||||||
|
'
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
$(CC) -static -Wall -Werror -o dumb-init dumb-init.c
|
$(CC) -static -Wall -Werror -o dumb-init dumb-init.c
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean: clean-tox
|
||||||
rm -rf dumb-init dist/ *.deb
|
rm -rf dumb-init dist/ *.deb
|
||||||
|
|
||||||
|
.PHONY: clean-tox
|
||||||
|
clean-tox:
|
||||||
|
rm -rf .tox
|
||||||
|
|
||||||
.PHONY: builddeb
|
.PHONY: builddeb
|
||||||
builddeb:
|
builddeb:
|
||||||
debuild -us -uc -b
|
debuild -us -uc -b
|
||||||
|
@ -22,24 +40,31 @@ builddeb-docker: docker-image
|
||||||
docker-image:
|
docker-image:
|
||||||
docker build -t dumb-init-build .
|
docker build -t dumb-init-build .
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
tox
|
||||||
|
|
||||||
|
.PHONY: install-hooks
|
||||||
|
install-hooks:
|
||||||
|
tox -e pre-commit -- install -f --install-hooks
|
||||||
|
|
||||||
.PHONY: itest itest_lucid itest_precise itest_trusty itest_wheezy itest_jessie itest_stretch
|
.PHONY: itest itest_lucid itest_precise itest_trusty itest_wheezy itest_jessie itest_stretch
|
||||||
itest: itest_lucid itest_precise itest_trusty itest_wheezy itest_jessie itest_stretch
|
itest: itest_lucid itest_precise itest_trusty itest_wheezy itest_jessie itest_stretch
|
||||||
|
|
||||||
itest_lucid: builddeb-docker
|
itest_lucid: _itest-ubuntu-lucid
|
||||||
docker run -v $(PWD):/mnt:ro ubuntu:lucid \
|
itest_precise: _itest-ubuntu-precise
|
||||||
sh -ec "apt-get -y install timeout; $(DOCKER_TEST)"
|
itest_trusty: _itest-ubuntu-trusty
|
||||||
|
itest_wheezy: _itest-debian-wheezy
|
||||||
|
itest_jessie: _itest-debian-jessie
|
||||||
|
itest_stretch: _itest-debian-stretch
|
||||||
|
|
||||||
itest_precise: builddeb-docker
|
_itest-%: _itest_deb-% _itest_python-%
|
||||||
docker run -v $(PWD):/mnt:ro ubuntu:precise $(DOCKER_TEST)
|
@true
|
||||||
|
|
||||||
itest_trusty: builddeb-docker
|
_itest_python-%:
|
||||||
docker run -v $(PWD):/mnt:ro ubuntu:trusty $(DOCKER_TEST)
|
$(eval DOCKER_IMG := $(shell echo $@ | cut -d- -f2 | sed 's/-/:/'))
|
||||||
|
$(DOCKER_RUN_TEST) $(DOCKER_IMG) $(DOCKER_PYTHON_TEST)
|
||||||
|
|
||||||
itest_wheezy: builddeb-docker
|
_itest_deb-%:
|
||||||
docker run -v $(PWD):/mnt:ro debian:wheezy $(DOCKER_TEST)
|
$(eval DOCKER_IMG := $(shell echo $@ | cut -d- -f2 | sed 's/-/:/'))
|
||||||
|
$(DOCKER_RUN_TEST) $(DOCKER_IMG) $(DOCKER_DEB_TEST)
|
||||||
itest_jessie: builddeb-docker
|
|
||||||
docker run -v $(PWD):/mnt:ro debian:jessie $(DOCKER_TEST)
|
|
||||||
|
|
||||||
itest_stretch: builddeb-docker
|
|
||||||
docker run -v $(PWD):/mnt:ro debian:stretch $(DOCKER_TEST)
|
|
||||||
|
|
|
@ -60,6 +60,14 @@ If you don't have an internal apt server, you can use `dpkg -i` to install the
|
||||||
(mounting a directory or `wget`-ing it are some options).
|
(mounting a directory or `wget`-ing it are some options).
|
||||||
|
|
||||||
|
|
||||||
|
### Option 3: Installing from PyPI
|
||||||
|
|
||||||
|
dumb-init can be installed [from PyPI](https://pypi.python.org/pypi/dumb-init)
|
||||||
|
using pip. Since dumb-init is written in C, you'll want to first install gcc
|
||||||
|
(on Debian/Ubuntu, `apt-get install gcc` is sufficient), then just `pip install
|
||||||
|
dumb-init`.
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Once installed inside your Docker container, simply prefix your commands with
|
Once installed inside your Docker container, simply prefix your commands with
|
||||||
|
|
2
debian/control
vendored
2
debian/control
vendored
|
@ -2,7 +2,7 @@ Source: dumb-init
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Chris Kuehl <ckuehl@yelp.com>
|
Maintainer: Chris Kuehl <ckuehl@yelp.com>
|
||||||
Build-Depends: debhelper (>= 7), gcc, fakeroot
|
Build-Depends: debhelper (>= 7), gcc, fakeroot, procps
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.6
|
||||||
|
|
||||||
Package: dumb-init
|
Package: dumb-init
|
||||||
|
|
3
debian/rules
vendored
3
debian/rules
vendored
|
@ -4,3 +4,6 @@
|
||||||
|
|
||||||
override_dh_builddeb:
|
override_dh_builddeb:
|
||||||
dh_builddeb -- -Zgzip
|
dh_builddeb -- -Zgzip
|
||||||
|
|
||||||
|
override_dh_auto_test:
|
||||||
|
./test ./dumb-init
|
||||||
|
|
126
dumb-init.c
126
dumb-init.c
|
@ -20,87 +20,87 @@ pid_t child = -1;
|
||||||
char debug = 0;
|
char debug = 0;
|
||||||
|
|
||||||
void signal_handler(int signum) {
|
void signal_handler(int signum) {
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf(stderr, "Received signal %d.\n", signum);
|
fprintf(stderr, "Received signal %d.\n", signum);
|
||||||
|
|
||||||
if (child > 0) {
|
if (child > 0) {
|
||||||
kill(child, signum);
|
kill(child, signum);
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf(stderr, "Forwarded signal to child.\n");
|
fprintf(stderr, "Forwarded signal to child.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_help(char *argv[]) {
|
void print_help(char *argv[]) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s COMMAND [[ARG] ...]\n"
|
"Usage: %s COMMAND [[ARG] ...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Docker runs your processes as PID1. The kernel doesn't apply default signal\n"
|
"Docker runs your processes as PID1. The kernel doesn't apply default signal\n"
|
||||||
"handling to PID1 processes, so if your process doesn't register a custom\n"
|
"handling to PID1 processes, so if your process doesn't register a custom\n"
|
||||||
"signal handler, signals like TERM will just bounce off your process.\n"
|
"signal handler, signals like TERM will just bounce off your process.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This can result in cases where sending signals to a `docker run` process\n"
|
"This can result in cases where sending signals to a `docker run` process\n"
|
||||||
"results in the run process exiting, but the container continuing in the\n"
|
"results in the run process exiting, but the container continuing in the\n"
|
||||||
"background.\n"
|
"background.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"A workaround is to wrap your script in this proxy, which runs as PID1. Your\n"
|
"A workaround is to wrap your script in this proxy, which runs as PID1. Your\n"
|
||||||
"process then runs as some other PID, and the kernel won't treat the signals\n"
|
"process then runs as some other PID, and the kernel won't treat the signals\n"
|
||||||
"that are proxied to them specially.\n"
|
"that are proxied to them specially.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The proxy dies when your process dies, so it must not double-fork or do other\n"
|
"The proxy dies when your process dies, so it must not double-fork or do other\n"
|
||||||
"weird things (this is basically a requirement for doing things sanely in\n"
|
"weird things (this is basically a requirement for doing things sanely in\n"
|
||||||
"Docker anyway).\n",
|
"Docker anyway).\n",
|
||||||
argv[0]
|
argv[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int signum, exit_status, status = 0;
|
int signum, exit_status, status = 0;
|
||||||
char *debug_env;
|
char *debug_env;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
print_help(argv);
|
print_help(argv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_env = getenv("DUMB_INIT_DEBUG");
|
debug_env = getenv("DUMB_INIT_DEBUG");
|
||||||
if (debug_env && strcmp(debug_env, "1") == 0)
|
if (debug_env && strcmp(debug_env, "1") == 0)
|
||||||
debug = 1;
|
debug = 1;
|
||||||
|
|
||||||
|
|
||||||
/* register signal handlers */
|
/* register signal handlers */
|
||||||
for (signum = 1; signum < 32; signum++) {
|
for (signum = 1; signum < 32; signum++) {
|
||||||
if (signum == SIGKILL || signum == SIGSTOP || signum == SIGCHLD)
|
if (signum == SIGKILL || signum == SIGSTOP || signum == SIGCHLD)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (signal(signum, signal_handler) == SIG_ERR) {
|
if (signal(signum, signal_handler) == SIG_ERR) {
|
||||||
fprintf(stderr, "Error: Couldn't register signal handler for signal `%d`. Exiting.\n", signum);
|
fprintf(stderr, "Error: Couldn't register signal handler for signal `%d`. Exiting.\n", signum);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* launch our process */
|
/* launch our process */
|
||||||
child = fork();
|
child = fork();
|
||||||
|
|
||||||
if (child < 0) {
|
if (child < 0) {
|
||||||
fprintf(stderr, "Unable to fork. Exiting.\n");
|
fprintf(stderr, "Unable to fork. Exiting.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child == 0) {
|
if (child == 0) {
|
||||||
execvp(argv[1], &argv[1]);
|
execvp(argv[1], &argv[1]);
|
||||||
} else {
|
} else {
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf(stderr, "Child spawned with PID %d.\n", child);
|
fprintf(stderr, "Child spawned with PID %d.\n", child);
|
||||||
|
|
||||||
waitpid(child, &status, 0);
|
waitpid(child, &status, 0);
|
||||||
exit_status = WEXITSTATUS(status);
|
exit_status = WEXITSTATUS(status);
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf(stderr, "Child exited with status %d, goodbye.\n", exit_status);
|
fprintf(stderr, "Child exited with status %d, goodbye.\n", exit_status);
|
||||||
|
|
||||||
return exit_status;
|
return exit_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
107
setup.py
Normal file
107
setup.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import os.path
|
||||||
|
from distutils.command.build import build as orig_build
|
||||||
|
from distutils.core import Command
|
||||||
|
|
||||||
|
from setuptools import Distribution
|
||||||
|
from setuptools import Extension
|
||||||
|
from setuptools import setup
|
||||||
|
from setuptools.command.install import install as orig_install
|
||||||
|
|
||||||
|
|
||||||
|
class ExeDistribution(Distribution):
|
||||||
|
c_executables = ()
|
||||||
|
|
||||||
|
|
||||||
|
class build(orig_build):
|
||||||
|
sub_commands = orig_build.sub_commands + [
|
||||||
|
('build_cexe', None),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class install(orig_install):
|
||||||
|
sub_commands = orig_install.sub_commands + [
|
||||||
|
('install_cexe', None),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class install_cexe(Command):
|
||||||
|
description = 'install C executables'
|
||||||
|
outfiles = ()
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
self.build_dir = self.install_dir = None
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
# this initializes attributes based on other commands' attributes
|
||||||
|
self.set_undefined_options('build', ('build_scripts', 'build_dir'))
|
||||||
|
self.set_undefined_options(
|
||||||
|
'install', ('install_scripts', 'install_dir'))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
||||||
|
|
||||||
|
def get_outputs(self):
|
||||||
|
return self.outfiles
|
||||||
|
|
||||||
|
|
||||||
|
class build_cexe(Command):
|
||||||
|
description = 'build C executables'
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
self.build_scripts = None
|
||||||
|
self.build_temp = None
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
self.set_undefined_options(
|
||||||
|
'build',
|
||||||
|
('build_scripts', 'build_scripts'),
|
||||||
|
('build_temp', 'build_temp'),
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# stolen and simplified from distutils.command.build_ext
|
||||||
|
from distutils.ccompiler import new_compiler
|
||||||
|
|
||||||
|
compiler = new_compiler(verbose=True)
|
||||||
|
|
||||||
|
for exe in self.distribution.c_executables:
|
||||||
|
objects = compiler.compile(
|
||||||
|
exe.sources,
|
||||||
|
output_dir=self.build_temp,
|
||||||
|
)
|
||||||
|
compiler.link_executable(
|
||||||
|
objects,
|
||||||
|
exe.name,
|
||||||
|
output_dir=self.build_scripts,
|
||||||
|
extra_postargs=exe.extra_link_args,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_outputs(self):
|
||||||
|
return [
|
||||||
|
os.path.join(self.build_scripts, exe.name)
|
||||||
|
for exe in self.distribution.c_executables
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='dumb-init',
|
||||||
|
description='Simple wrapper script which proxies signals to a child',
|
||||||
|
version='0.0.2',
|
||||||
|
author='Yelp',
|
||||||
|
platforms='linux',
|
||||||
|
|
||||||
|
c_executables=[
|
||||||
|
Extension(
|
||||||
|
'dumb-init',
|
||||||
|
['dumb-init.c'],
|
||||||
|
extra_link_args=['-static'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
cmdclass={
|
||||||
|
'build': build,
|
||||||
|
'build_cexe': build_cexe,
|
||||||
|
'install': install,
|
||||||
|
'install_cexe': install_cexe,
|
||||||
|
},
|
||||||
|
distclass=ExeDistribution,
|
||||||
|
)
|
19
test
19
test
|
@ -1,8 +1,19 @@
|
||||||
#!/bin/sh -eux
|
#!/bin/bash -eux
|
||||||
|
if [ "$#" -eq 1 ]; then
|
||||||
|
dumb_init_bin=$(readlink -f "$1")
|
||||||
|
else
|
||||||
|
dumb_init_bin=$(which dumb-init) || {
|
||||||
|
echo "Couldn't find dumb-init on your path, exiting."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running with dumb-init at '$dumb_init_bin'"
|
||||||
|
|
||||||
run_tests() {
|
run_tests() {
|
||||||
./test-proxies-signals
|
./test-proxies-signals "$dumb_init_bin"
|
||||||
./test-exit-status
|
./test-exit-status "$dumb_init_bin"
|
||||||
./test-help-message
|
./test-help-message "$dumb_init_bin"
|
||||||
}
|
}
|
||||||
|
|
||||||
cd tests
|
cd tests
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
#!/bin/sh -eu
|
#!/bin/bash -eux
|
||||||
# Print received signals into a file, one per line
|
# Print received signals into a file, one per line
|
||||||
file="$1"
|
file="$1"
|
||||||
|
|
||||||
. ./lib/testlib.sh
|
. ./lib/testlib.sh
|
||||||
|
|
||||||
for i in $(catchable_signals); do
|
for i in $(catchable_signals); do
|
||||||
trap "echo $i > \"$file\"" "$i"
|
trap "echo $i > \"$file\"" "$i"
|
||||||
done
|
done
|
||||||
|
|
||||||
echo 'ready' > "$file"
|
echo 'ready' > "$file"
|
||||||
|
|
||||||
# loop forever
|
echo 'loop forever...'
|
||||||
|
set +x
|
||||||
while :; do true; done
|
while :; do true; done
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
catchable_signals() {
|
catchable_signals() {
|
||||||
# We can't handle the signals SIGKILL=9, SIGCHLD=17, SIGSTOP=19
|
# We can't handle the signals SIGKILL=9, SIGCHLD=17, SIGSTOP=19
|
||||||
seq 1 31 | grep -vE '^(9|17|19)$'
|
seq 1 31 | grep -vE '^(9|17|19)$'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#!/bin/sh -u
|
#!/bin/bash -eux
|
||||||
|
dumb_init="$1"
|
||||||
|
|
||||||
# dumb-init should exit with the same exit status as the process it launches.
|
# dumb-init should exit with the same exit status as the process it launches.
|
||||||
for i in $(seq 0 255); do
|
for i in $(seq 0 255); do
|
||||||
status=$(dumb-init sh -c "exit $i"; echo $?)
|
status=$($dumb_init sh -c "exit $i"; echo $?)
|
||||||
|
|
||||||
if [ "$status" -ne "$i" ]; then
|
if [ "$status" -ne "$i" ]; then
|
||||||
echo "Error: Expected exit status $i, got $status."
|
echo "Error: Expected exit status $i, got $status."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
#!/bin/sh -u
|
#!/bin/bash -eux
|
||||||
# dumb-init should say something useful when called with no arguments, and exit
|
# dumb-init should say something useful when called with no arguments, and exit
|
||||||
# nonzero.
|
# nonzero.
|
||||||
|
|
||||||
status=$(dumb-init > /dev/null 2>&1; echo $?)
|
dumb_init="$1"
|
||||||
|
|
||||||
|
status=$($dumb_init > /dev/null 2>&1; echo $?)
|
||||||
|
|
||||||
if [ "$status" -ne 0 ]; then
|
if [ "$status" -ne 0 ]; then
|
||||||
msg=$(dumb-init 2>&1 || true)
|
msg=$($dumb_init 2>&1 || true)
|
||||||
msg_len=${#msg}
|
msg_len=${#msg}
|
||||||
|
|
||||||
if [ "$msg_len" -le 50 ]; then
|
if [ "$msg_len" -le 50 ]; then
|
||||||
echo "Error: Expected dumb-init with no arguments to print a useful message, but it was only ${msg_len} chars long."
|
echo "Error: Expected dumb-init with no arguments to print a useful message, but it was only ${msg_len} chars long."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Error: Expected dumb-init with no arguments to return nonzero, but it returned ${status}."
|
echo "Error: Expected dumb-init with no arguments to return nonzero, but it returned ${status}."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/bin/sh -eum
|
#!/bin/bash -euxm
|
||||||
# dumb-init should proxy all possible signals to the child process.
|
# dumb-init should proxy all possible signals to the child process.
|
||||||
|
dumb_init="$1"
|
||||||
|
|
||||||
# Try sending all signals via dumb-init to our `print-signals` script, ensure
|
# Try sending all signals via dumb-init to our `print-signals` script, ensure
|
||||||
# they were all received.
|
# they were all received.
|
||||||
|
@ -11,31 +12,35 @@ fifo=$(mktemp -u)
|
||||||
mkfifo -m 600 "$fifo"
|
mkfifo -m 600 "$fifo"
|
||||||
read_cmd="timeout 1 head -n1 $fifo"
|
read_cmd="timeout 1 head -n1 $fifo"
|
||||||
|
|
||||||
dumb-init ./lib/print-signals "$fifo" &
|
$dumb_init ./lib/print-signals "$fifo" &
|
||||||
pid="$!"
|
pid="$!"
|
||||||
|
|
||||||
# Wait for `print-signals` to indicate it's ready.
|
# Wait for `print-signals` to indicate it's ready.
|
||||||
$read_cmd > /dev/null
|
$read_cmd > /dev/null
|
||||||
|
|
||||||
for expected in $(catchable_signals); do
|
for expected in $(catchable_signals); do
|
||||||
kill -s "$expected" "$pid"
|
kill -s "$expected" "$pid"
|
||||||
echo -n "Sent signal ${expected}... "
|
echo -n "Sent signal ${expected}... "
|
||||||
received=$($read_cmd) || {
|
received=$($read_cmd) || {
|
||||||
echo
|
echo
|
||||||
echo "Error: Didn't receive signal within 1 second."
|
echo "Error: Didn't receive signal within 1 second."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "received signal ${received}."
|
echo "received signal ${received}."
|
||||||
|
|
||||||
if [ "$expected" -ne "$received" ]; then
|
if [ "$expected" -ne "$received" ]; then
|
||||||
echo "Error: Received signal $received, but expected signal $expected."
|
echo "Error: Received signal $received, but expected signal $expected."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Turn off job monitoring so we don't get a spurious "[1] + Killed" printed
|
# Turn off job monitoring so we don't get a spurious "[1] + Killed" printed
|
||||||
set +m
|
set +m
|
||||||
|
|
||||||
kill -9 "$pid"
|
# $pid is the PID of the dumb-init process. Since print-signals ignores all
|
||||||
|
# signals, we need to `kill -9` it. If we just `kill -9` the dumb-init process,
|
||||||
|
# `print-signals` will still be running. So we instead kill children of the
|
||||||
|
# dumb-init process.
|
||||||
|
pkill -9 -P "$pid"
|
||||||
rm "$fifo"
|
rm "$fifo"
|
||||||
|
|
11
tox.ini
Normal file
11
tox.ini
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[tox]
|
||||||
|
envlist = py27,py34
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps = pre-commit>=0.5.0
|
||||||
|
commands =
|
||||||
|
./test
|
||||||
|
pre-commit run --all-files
|
||||||
|
|
||||||
|
[testenv:pre-commit]
|
||||||
|
commands = pre-commit {posargs}
|
Loading…
Reference in a new issue