[cowdancer] 02/06: qemubuilder: Add support for hooks
James Clarke
jrtc27-guest at moszumanska.debian.org
Sun May 1 18:33:34 UTC 2016
This is an automated email from the git hooks/post-receive script.
jrtc27-guest pushed a commit to branch master
in repository cowdancer.
commit 4a68e51ebc6d71b0db7269ff48a112424da3db65
Author: James Clarke <jrtc27 at jrtc27.com>
Date: Sat Apr 30 01:51:50 2016 +0100
qemubuilder: Add support for hooks
Hooks of type A-H will be run inside qemu. Hook of type I cannot
currently be supported, as the build result is copied once qemu has
exited, but hooks expect to run within the chroot (or qemu system in
this case). The PBUILDER_OPERATION and DISTRIBUTION environment
variables are also currently unavailable to hooks.
Closes: #819803
Thanks: Reiner Herrmann for the initial concept patch.
---
parameter.c | 14 ++++++
parameter.h | 1 +
qemubuilder.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 156 insertions(+), 14 deletions(-)
diff --git a/parameter.c b/parameter.c
index 33dd41e..409c8ae 100644
--- a/parameter.c
+++ b/parameter.c
@@ -170,6 +170,10 @@ int load_config_file(const char* config, pbuilderconfig* pc)
{
pc->smp=strdup_strip_quote(delim);
}
+ else if (!strcmp(buf, "HOOKDIR"))
+ {
+ pc->hookdir=strdup_strip_quote(delim);
+ }
else if (!strcmp(buf, "DEBBUILDOPTS"))
{
pc->debbuildopts=strdup_strip_quote(delim);
@@ -251,6 +255,7 @@ int cpbuilder_dumpconfig(pbuilderconfig* pc)
DUMPSTR(components);
DUMPSTR(othermirror);
DUMPSTR(smp);
+ DUMPSTR(hookdir);
DUMPSTR(debbuildopts);
DUMPINT(binary_arch);
DUMPINT(binary_indep);
@@ -305,6 +310,7 @@ int parse_parameter(int ac, char** av,
{"extrapackages", required_argument, 0, 0},
{"othermirror", required_argument, 0, 0},
{"smp", required_argument, 0, 0},
+ {"hookdir", required_argument, 0, 0},
{"debbuildopts", required_argument, 0, 0},
{"binary-arch", no_argument, 0, 0},
{"binary-indep", no_argument, 0, 0},
@@ -532,6 +538,14 @@ int parse_parameter(int ac, char** av,
/* pass it for cowbuilder */
PASS_TO_PBUILDER_WITH_PARAM
}
+ else if (!strcmp(long_options[index_point].name,"hookdir"))
+ {
+ /* this is for qemubuilder */
+ pc.hookdir=strdup(optarg);
+
+ /* pass it for cowbuilder */
+ PASS_TO_PBUILDER_WITH_PARAM
+ }
else if (!strcmp(long_options[index_point].name,"debbuildopts"))
{
/* this is for qemubuilder */
diff --git a/parameter.h b/parameter.h
index 768a383..2f27391 100644
--- a/parameter.h
+++ b/parameter.h
@@ -39,6 +39,7 @@ typedef struct pbuilderconfig
char* components;
char* extrapackages;
char* othermirror;
+ char* hookdir;
char* debbuildopts;
int binary_arch;
int binary_indep;
diff --git a/qemubuilder.c b/qemubuilder.c
index 2140231..4c9bdd8 100755
--- a/qemubuilder.c
+++ b/qemubuilder.c
@@ -27,6 +27,8 @@
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
#include <getopt.h>
#include <stdarg.h>
#include <assert.h>
@@ -38,6 +40,42 @@
#include "qemuarch.h"
#include "file.h"
+#define BUILDDIR "/tmp/buildd"
+
+#define CHROOT_HOOKDIR BUILDDIR"/hooks"
+
+#define EXECUTE_HOOKS_INDENT(indent, prefix) \
+indent"if [ -d \""CHROOT_HOOKDIR"\" ]; then\n" \
+indent" for fn in \""CHROOT_HOOKDIR"/"prefix"\"[0-9][0-9]* ; do\n" \
+indent" case \"$fn\" in\n" \
+indent" \""CHROOT_HOOKDIR"/"prefix"\"'[0-9][0-9]*')\n" \
+indent" echo \"W: no hooks of type "prefix" found -- ignoring\"\n" \
+indent" ;;\n" \
+indent" *~)\n" \
+indent" echo \"W: skipping an editor backup file $fn\"\n" \
+indent" ;;\n" \
+indent" *)\n" \
+indent" if [ -x \"$fn\" ]; then\n" \
+indent" echo \"I: user script $fn starting\"\n" \
+indent" BUILDDIR=\""BUILDDIR"\" \\\n" \
+indent" \""CHROOT_HOOKDIR"/$(basename \"$fn\")\"\n" \
+indent" echo \"I: user script $fn finished\"\n" \
+indent" else\n" \
+indent" if [ -f \"$fn\" ]; then\n" \
+indent" filetype=$(basename \"fn\")\n" \
+indent" echo \"W: execute priv not set on file $filetype, not executing.\"\n" \
+indent" else\n" \
+indent" # Should it reach here ? This case should be caught in the above case.\n" \
+indent" echo \"W: no hooks of type ${prefix} found -- internal error in logic\"\n" \
+indent" fi\n" \
+indent" fi\n" \
+indent" ;;\n" \
+indent" esac\n" \
+indent" done\n" \
+indent"fi\n"
+
+#define EXECUTE_HOOKS(prefix) EXECUTE_HOOKS_INDENT("", prefix)
+
/*
* example exit codes:
*
@@ -174,13 +212,82 @@ static int copy_file_contents_through_temp(FILE* f,
fprintf(f,
"echo \"I: copying %s/%s from temporary location\"\n"
+ "mkdir -p %s\n"
"cp $PBUILDER_MOUNTPOINT/%s %s/%s || echo \"E: Copy failed\"\n",
targetdir, file_basename,
+ targetdir,
file_basename,
targetdir, file_basename);
return ret;
}
+static int copy_hookdir(FILE *f, const char *hookdir, const char *tmp)
+{
+ int ret = 0;
+ struct dirent *dirp;
+ DIR *hd = opendir(hookdir);
+
+ if (hd == NULL)
+ {
+ fprintf(stderr,
+ "Error copying hooks from '%s': %s\n",
+ hookdir,
+ strerror(errno));
+ ret = 1;
+ goto out;
+ }
+
+ while ((dirp = readdir(hd)) != NULL)
+ {
+ struct stat st;
+ char *src = NULL;
+
+ if (0>asprintf(&src,
+ "%s/%s",
+ hookdir,
+ dirp->d_name))
+ {
+ fprintf(stderr,
+ "Error allocating string for '%s/%s': %s\n",
+ hookdir,
+ dirp->d_name,
+ strerror(errno));
+ ret = 1;
+ goto out;
+ }
+ if (0>stat(src, &st))
+ {
+ fprintf(stderr,
+ "Error calling stat '%s': %s\n",
+ src,
+ strerror(errno));
+ free(src);
+ ret = 1;
+ goto out;
+ }
+
+ if ((st.st_mode & S_IFMT) != S_IFREG)
+ {
+ // Not a regular file
+ free(src);
+ continue;
+ }
+
+ copy_file_contents_through_temp(f, src, tmp, CHROOT_HOOKDIR);
+ fprintf(f,
+ "chmod 0755 \""CHROOT_HOOKDIR"/%s\"\n",
+ dirp->d_name);
+ free(src);
+ }
+
+out:
+ if (hd != NULL)
+ {
+ closedir(hd);
+ }
+ return ret;
+}
+
static const char* format_for_image(const char* file)
{
static const char *formats[][2] = {
@@ -506,7 +613,6 @@ static int run_second_stage_script
/* main code */
"echo \n"
"echo ' -> qemu-pbuilder second-stage' \n"
- //TODO: copy hook scripts
//"mount -n /proc /proc -t proc\n" // this is done in first stage.
"echo ' -> setting time to %s' \n"
"date --set=\"%s\"\n"
@@ -514,16 +620,17 @@ static int run_second_stage_script
"ifconfig -a\n"
"export IFNAME=`/sbin/ifconfig -a | grep eth | head -n1 | awk '{print $1}'`\n"
"dhclient $IFNAME\n"
- "mkdir -p /tmp/buildd\n"
+ "mkdir -p \""BUILDDIR"\"\n"
+ "%s\n"
"$PBUILDER_MOUNTPOINT/run-copyfiles\n"
"hostname pbuilder-$(cat /etc/hostname)\n"
- //TODO: run G hook
"%s\n"
//TODO: I can mount /var/cache/apt/archives from some scratch space to not need this:
"apt-get clean || true\n"
"exit_from_qemu 0\n",
timestring,
timestring,
+ pc->hookdir && pc->hookdir[0] ? "mkdir -p \""CHROOT_HOOKDIR"\"" : "",
commandline);
fclose(f);
@@ -534,12 +641,15 @@ static int run_second_stage_script
/* copy inputfile */
for (i=0; pc->inputfile[i]; ++i)
{
- copy_file_contents_through_temp(f, pc->inputfile[i], pc->buildplace, "/tmp/buildd");
+ copy_file_contents_through_temp(f, pc->inputfile[i], pc->buildplace, BUILDDIR);
+ }
+ if (pc->hookdir != NULL && pc->hookdir[0])
+ {
+ copy_hookdir(f, pc->hookdir, pc->buildplace);
}
fclose(f);
/* do I not need to copy /etc/pbuilderrc, and ~/.pbuilderrc to inside chroot? */
- /* TODO: hooks probably need copying here. */
/* TODO: recover aptcache */
if(hostcommand1)
@@ -808,17 +918,17 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
"rm /etc/udev/disabled\n" // work-around for #520742
"echo deb %s %s %s > /etc/apt/sources.list \n"
"echo 'APT::Install-Recommends \"false\"; ' > /etc/apt/apt.conf.d/15pbuilder\n"
- //TODO: copy hook scripts
"mount -n proc /proc -t proc\n"
"mount -n sysfs /sys -t sysfs\n"
"mkdir /dev/pts\n"
"mount -n devpts /dev/pts -t devpts\n"
"dhclient eth0\n"
+ "%s\n"
"$PBUILDER_MOUNTPOINT/run-copyfiles\n"
"hostname pbuilder-$(cat /etc/hostname)\n"
//TODO: installaptlines
"echo '%s' > /etc/apt/sources.list.d/other.list\n"
- //TODO: run G hook
+ EXECUTE_HOOKS("G")
"apt-get update || exit_from_qemu 1\n"
//TODO: "dpkg --purge $REMOVEPACKAGES\n"
//recover aptcache
@@ -826,7 +936,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
"apt-get install %s -y build-essential dpkg-dev apt aptitude pbuilder %s || exit_from_qemu 1\n"
//TODO: save aptcache
//optionally autoclean aptcache
- //run E hook
+ EXECUTE_HOOKS("E")
//TODO: I can mount /var/cache/apt/archives from some scratch space to not need this:
"apt-get clean || true\n"
"exit_from_qemu $RET\n"
@@ -834,6 +944,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
timestring,
timestring,
t=sanitize_mirror(pc->mirror), pc->distribution, pc->components,
+ pc->hookdir && pc->hookdir[0] ? "mkdir -p \""CHROOT_HOOKDIR"\"" : "",
pc->othermirror?pc->othermirror:"",
pc->allow_untrusted?"--force-yes":"",
pc->allow_untrusted?"--force-yes":"",
@@ -849,10 +960,13 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
f = create_script(pc->buildplace, "run-copyfiles");
copy_file_contents_through_temp(f, "/etc/hosts", pc->buildplace, "/etc");
copy_file_contents_through_temp(f, "/etc/hostname", pc->buildplace, "/etc");
+ if (pc->hookdir != NULL && pc->hookdir[0])
+ {
+ copy_hookdir(f, pc->hookdir, pc->buildplace);
+ }
fclose(f);
/* do I not need to copy /etc/pbuilderrc, and ~/.pbuilderrc to inside chroot? */
- /* TODO: hooks probably need copying here. */
/* TODO: recover aptcache */
loop_umount(pc->buildplace);
@@ -906,13 +1020,20 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile)
hoststr=copy_dscfile(dscfile, pc->buildplace);
asprintf(&commandline,
- /* TODO: executehooks D: */
+ EXECUTE_HOOKS("D")
"ALLOWUNTRUSTED=%s /usr/lib/pbuilder/pbuilder-satisfydepends --control $PBUILDER_MOUNTPOINT/*.dsc --internal-chrootexec 'chroot . ' %s \n"
"apt-get install %s -y %s\n"
"cd $PBUILDER_MOUNTPOINT; /usr/bin/dpkg-source -x $(basename %s) \n"
"echo ' -> Building the package'\n"
- /* TODO: executehooks A: */
- "cd $PBUILDER_MOUNTPOINT/*-*/; dpkg-buildpackage -us -uc %s\n",
+ EXECUTE_HOOKS("A")
+ "if ! (\n"
+ " cd $PBUILDER_MOUNTPOINT/*-*/\n"
+ " dpkg-buildpackage -us -uc %s\n"
+ "); then\n"
+ EXECUTE_HOOKS_INDENT(" ", "C")
+ " exit_from_qemu 1\n"
+ "fi\n"
+ EXECUTE_HOOKS("B"),
pc->allow_untrusted?"yes":"no",
buildopt,
pc->allow_untrusted?"--force-yes":"",
@@ -943,6 +1064,8 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile)
int cpbuilder_login(const struct pbuilderconfig* pc)
{
return run_second_stage_script(pc->save_after_login,
+ EXECUTE_HOOKS("H")
+ EXECUTE_HOOKS("F")
"bash",
pc,
NULL,
@@ -962,7 +1085,10 @@ int cpbuilder_execute(const struct pbuilderconfig* pc, char** av)
asprintf(&hostcommand, "cp %s %s/runscript\n", av[0], pc->buildplace);
/* TODO: add options too */
- asprintf(&runcommandline, "sh $PBUILDER_MOUNTPOINT/runscript");
+ asprintf(&runcommandline,
+ EXECUTE_HOOKS("H")
+ EXECUTE_HOOKS("F")
+ "sh $PBUILDER_MOUNTPOINT/runscript");
ret=run_second_stage_script(pc->save_after_login, runcommandline, pc,
hostcommand, NULL);
free(hostcommand);
@@ -982,6 +1108,7 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
*/
char *script;
if (0>asprintf(&script,
+ EXECUTE_HOOKS("H")
//TODO: installaptlines if required.
//TODO: "dpkg --purge $REMOVEPACKAGES\n"
//TODO: add error code handling.
@@ -989,7 +1116,7 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
"apt-get -y %s -o DPkg::Options::=--force-confnew dist-upgrade\n"
"apt-get install %s -y build-essential dpkg-dev apt aptitude pbuilder %s\n"
//TODO: optionally autoclean aptcache
- //run E hook
+ EXECUTE_HOOKS("E")
, pc->allow_untrusted?"--force-yes":""
, pc->allow_untrusted?"--force-yes":""
, pc->extrapackages?pc->extrapackages:""))
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pbuilder/cowdancer.git
More information about the Pbuilder-maint
mailing list