Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default command to cqfd run, remove command and automatically init when needed #106

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@ Just follow these steps:
* Go into your project's directory
* Create a .cqfdrc file
* Put a Dockerfile and save it as .cqfd/docker/Dockerfile
* Run ``cqfd init``

Examples are available in the samples/ directory.

cqfd will use the provided Dockerfile to create a normalized runtime
build environment for your project.

Warning: Running cqfd init creates and names a new Docker image each
Warning: Running cqfd --init creates and names a new Docker image each
time the Dockerfile is modified, which may lead to a large number of
unused images that cannot be automatically purged. Currently, cqfd
does not have a systematic clean-up system in place.
Expand All @@ -45,8 +44,8 @@ default build command as configured in .cqfdrc, use:
Alternatively, you may want to specify a custom build command to be
executed from inside the build container.

$ cqfd run make clean
$ cqfd run "make linux-dirclean && make foobar-dirclean"
$ cqfd make clean
$ cqfd "make linux-dirclean && make foobar-dirclean"

When ``cqfd`` is running, the current directory is mounted by Docker
as a volume. As a result, all the build artefacts generated inside the
Expand All @@ -59,7 +58,7 @@ The release command behaves exactly like run, but creates a release
tarball for your project additionally. The release files (as specified
in your ``.cqfdrc``) will be included inside the release archive.

$ cqfd release
$ cqfd --release

The resulting release file is then called according to the archive
template, which defaults to ``%Po-%Pn.tar.xz``.
Expand Down
130 changes: 86 additions & 44 deletions cqfd
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ Options:
-h or --help Show this help text.

Commands:
init Initialize project build container
flavors List flavors from config file to stdout
run Run argument(s) inside build container
release Run argument(s) and release software
help Show this help text
--init Initialize project build container
--flavors List flavors from config file to stdout
--release Run argument(s) and release software
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these 3 now be in the Options: section?


By default, run is assumed, and the run command is the one
configured in .cqfdrc.
Expand Down Expand Up @@ -111,13 +109,66 @@ die() {
exit 1
}

# loading_throbber() - Loading throbber process for Docker build initialization
loading_throbber() {
pid=$1
delay=0.1
spinstr='-\|/'

while kill -0 "$pid" 2>/dev/null
do
temp=${spinstr#?}
state=$(awk '$2 ~ /(\[[0-9]+\/[0-9]+)\]/ { print $2 }' "$TEMP_OUTPUT" | sed 's/^.\(.*\).$/\1/' | tail -n 1)
# if not using buildx, use previous format
[ "$state" ] || state=$(awk '$1 == "Step" { print $2 }' "$TEMP_OUTPUT" | tail -n 1)
spinstr=$temp${spinstr%"$temp"}
# Getting the last line of the output of the long command
if [ "$state" ]; then
printf '\r[%c] %s: Initialization of the environment (%s)' "$spinstr" "$PROGNAME" "$state"
line_length=$((46 + ${#state}))
else
printf '\r[%c] %s: Initialization of the environment' "$spinstr" "$PROGNAME"
fi
sleep $delay
done
}

# docker_build() - Initialize build container
docker_build() {
export BUILDKIT_PROGRESS=plain
TEMP_OUTPUT=$(mktemp -u)
line_length=46

if [ -z "$project_build_context" ]; then
docker build ${quiet:+-q} $CQFD_EXTRA_BUILD_ARGS -t "$docker_img_name" "$(dirname "$dockerfile")"
docker build ${quiet:+-q} $CQFD_EXTRA_BUILD_ARGS -t "$docker_img_name" "$(dirname "$dockerfile")" > "$TEMP_OUTPUT" 2>&1 &
else
docker build ${quiet:+-q} $CQFD_EXTRA_BUILD_ARGS -t "$docker_img_name" "${project_build_context}" -f "$dockerfile"
docker build ${quiet:+-q} $CQFD_EXTRA_BUILD_ARGS -t "$docker_img_name" "${project_build_context}" -f "$dockerfile" > "$TEMP_OUTPUT" 2>&1 &
fi
container_init_command_pid=$!

if [ "$quiet" ]; then
# If quiet mode is enabled, we don't display the throbber
# and we wait for the docker build to finish
wait $container_init_command_pid
cat "$TEMP_OUTPUT"
rm "$TEMP_OUTPUT"
return 0
fi

# Start the throbber
loading_throbber $container_init_command_pid

# Wait for the docker build to finish
if ! wait $container_init_command_pid; then
printf "\r%${line_length}s\r"
cat "$TEMP_OUTPUT" 1>&2
rm "$TEMP_OUTPUT"
die 'Initialization of environment failed'
fi

# Clean up the output file and the console
printf "\r%${line_length}s\r"
rm "$TEMP_OUTPUT"
}

# docker_run() - run command in configured container
Expand All @@ -136,9 +187,8 @@ docker_build() {
# arg$1: the command string to execute as $cqfd_user
#
docker_run() {

if ! docker image inspect $docker_img_name &> /dev/null; then
die "The docker image doesn't exist, launch 'cqfd init' to create it"
docker_build
fi

local interactive_options
Expand Down Expand Up @@ -456,20 +506,22 @@ has_custom_cqfdrc=false
has_to_release=false
while [ $# -gt 0 ]; do
case "$1" in
help|-h|"--help")
-h|"--help")
usage
exit 0
;;
version|-v|"--version")
-v|"--version")
echo $VERSION
exit 0
;;
init)
"--init")
config_load $flavor
docker_build
exit $?
ret=$?
[ "$quiet" ] || echo "$PROGNAME: Initialization of environment successful"
exit $ret
;;
flavors)
"--flavors")
config_load
echo $build_flavors
exit 0
Expand All @@ -494,43 +546,33 @@ while [ $# -gt 0 ]; do
-q)
quiet=true
;;
run|release)
if [ "$1" = "release" ]; then
has_to_release=true
fi

shift

# No more args? run default command
[ "$#" -eq 0 ] && break

# -c appends following args to the default command
if [ "$1" = "-c" ]; then
if [ $# -lt 2 ]; then
die "option -c requires arguments"
fi

shift
build_cmd_append="$*"
break
fi

# Run alternate command
build_cmd_alt="$@"
break
;;
?*)
echo "Unknown command: $1"
usage
exit 1
"--release")
has_to_release=true
;;
*)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be out of scope, but can we support -- signifying the end of the options? Right now, cqfd -- ls doesn't work (shows the help message).

# empty or no argument case
# run a command
break
;;
esac
shift
done

# No more args? run default command
if [ "$#" -ne 0 ]; then
# -c appends following args to the default command
if [ "$1" = "-c" ]; then
if [ $# -lt 2 ]; then
die "option -c requires arguments"
fi

shift
build_cmd_append="$*"
else
# Run alternate command
build_cmd_alt="$@"
fi
fi

config_load $flavor

if [ -n "$build_cmd_alt" ]; then
Expand Down
16 changes: 8 additions & 8 deletions tests/00-setup
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,31 @@ cp -a test_data/. $TDIR/.
cd $TDIR/

################################################################################
# running 'cqfd init' should fail, as there's no proper config
# running 'cqfd --init' should fail, as there's no proper config
################################################################################
if $TDIR/.cqfd/cqfd init; then
if $TDIR/.cqfd/cqfd --init; then
jtest_result fail
else
jtest_result pass
fi

################################################################################
# running 'cqfd init' should fail, as there's an empty config
# running 'cqfd --init' should fail, as there's an empty config
################################################################################
jtest_prepare "cqfd init complains with an empty .cqfdrc"
jtest_prepare "cqfd --init complains with an empty .cqfdrc"
touch $TDIR/.cqfdrc
if $TDIR/.cqfd/cqfd init; then
if $TDIR/.cqfd/cqfd --init; then
jtest_result fail
else
jtest_result pass
fi

################################################################################
# running 'cqfd init' should fail, as there's an incomplete config
# running 'cqfd --init' should fail, as there's an incomplete config
################################################################################
jtest_prepare "cqfd init complains with an incomplete .cqfdrc"
jtest_prepare "cqfd --init complains with an incomplete .cqfdrc"
echo '[project]' >$TDIR/.cqfdrc
if $TDIR/.cqfd/cqfd init; then
if $TDIR/.cqfd/cqfd --init; then
jtest_result fail
else
jtest_result pass
Expand Down
26 changes: 13 additions & 13 deletions tests/01-cqfd_init
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,36 @@
cd $TDIR/

################################################################################
# 'cqfd init' with a proper .cqfdrc should pass
# 'cqfd --init' with a proper .cqfdrc should pass
################################################################################
jtest_prepare "run cqfd init"
if $TDIR/.cqfd/cqfd init; then
jtest_prepare "run cqfd --init"
if $TDIR/.cqfd/cqfd --init; then
jtest_result pass
else
jtest_result fail
fi


################################################################################
# 'cqfd init' with a nonexistent Dockerfile should fail
# 'cqfd --init' with a nonexistent Dockerfile should fail
################################################################################
cqfdrc_old=$(mktemp)
jtest_prepare "init with a nonexisting dockerfile shall fail"
cp -f .cqfdrc $cqfdrc_old
sed -i -e "s/\[build\]/[build]\ndistro='thisshouldfail'/" .cqfdrc
if $TDIR/.cqfd/cqfd init; then
if $TDIR/.cqfd/cqfd --init; then
jtest_result fail
else
jtest_result pass
fi


################################################################################
# 'cqfd init' with a proper Dockerfile should pass
# 'cqfd --init' with a proper Dockerfile should pass
################################################################################
jtest_prepare "run cqfd init with an other Dockerfile"
jtest_prepare "run cqfd --init with an other Dockerfile"
sed -i -e "s/thisshouldfail/centos/" .cqfdrc
if $TDIR/.cqfd/cqfd init; then
if $TDIR/.cqfd/cqfd --init; then
jtest_result pass
else
jtest_result fail
Expand All @@ -44,25 +44,25 @@ mv -f $cqfdrc_old .cqfdrc


################################################################################
# 'cqfd init' with same uid/gid dummy user should pass
# 'cqfd --init' with same uid/gid dummy user should pass
################################################################################
jtest_prepare "add dummy user and dummy group with same uid/gid"
cat <<EOF >>.cqfd/docker/Dockerfile
RUN groupadd -og $GROUPS -f dummy && \
useradd -s /bin/bash -ou $UID -g $GROUPS dummy
EOF
if $TDIR/.cqfd/cqfd init; then
if $TDIR/.cqfd/cqfd --init; then
jtest_result pass
else
jtest_result fail
fi


################################################################################
# 'cqfd init' in quiet mode should be quiet
# 'cqfd --init' in quiet mode should be quiet
################################################################################
jtest_prepare "cqfd -q init should remain quiet"
if ! $TDIR/.cqfd/cqfd -q init | grep -E "^sha256:"; then
jtest_prepare "cqfd -q --init should remain quiet"
if ! $TDIR/.cqfd/cqfd -q --init | grep -E "^sha256:"; then
jtest_result fail
else
jtest_result pass
Expand Down
4 changes: 2 additions & 2 deletions tests/03-cqfd_error
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ fi
################################################################################
# Running cqfd without a .cqfdrc file in the current directory shall fail
################################################################################
jtest_prepare "'cqfd run' with no config file shall fail"
jtest_prepare "'cqfd' with no config file shall fail"

empty_dir=$(mktemp -d)
pushd "$empty_dir" >/dev/null || exit 1

if "$cqfd" run true; then
if "$cqfd" true; then
jtest_result fail
else
jtest_result pass
Expand Down
10 changes: 5 additions & 5 deletions tests/03-cqfd_help
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
. "$(dirname $0)"/jtest.inc "$1"

################################################################################
# 'cqfd help' shall be an accepted command
# 'cqfd --help' shall be an accepted command
################################################################################
jtest_prepare "cqfd help shall exit normally"
jtest_prepare "cqfd --help shall exit normally"
TEST=$(mktemp)

if ! $TDIR/.cqfd/cqfd help >$TEST; then
if ! $TDIR/.cqfd/cqfd --help >$TEST; then
jtest_result fail
rm -f $TEST
else
Expand All @@ -17,9 +17,9 @@ fi


################################################################################
# 'cqfd help' shall produce a useful help message
# 'cqfd --help' shall produce a useful help message
################################################################################
jtest_prepare "cqfd help shall produce an help message"
jtest_prepare "cqfd --help shall produce an help message"
# Those words shall be present in the output
for word in Usage Options Commands; do
if ! grep -q "^$word:" $TEST; then
Expand Down
Loading