[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