michaelrsweet / epm

Software packaging tool.
https://www.msweet.org/epm
GNU General Public License v2.0
22 stars 33 forks source link

Add a %literal tag to tweak packages #5

Closed michaelrsweet closed 16 years ago

michaelrsweet commented 17 years ago

Version: -feature Original reporter: Michael Sweet

Hello,

I've been writing an epm based installer for TWiki (perl based), and have gotten to the point where rpmbuild is making a mess that I need to prevent.

when I hard code in the magic rpm defines to add a custom provides and requires script as per the following url's

http://fedoraproject.org/wiki/PackagingDrafts/FilteringAutomaticDependencies http://fedoraproject.org/wiki/Packaging/Perl

my package does not get dependencies on things like perl(further) due to redhat's rather nasty magical dependency code.

SO I was thinking to solve this by: adding a way for EPM list files to contain literal strings into whatever output files are made (presumably re-using the %format qualifier).

the syntax i'm thinking, would just be to have lines that start with '%literal' be appended to each other, and then inserted into the native package's file.

so in my case i'd add something like

%format rpm %literal %define __perl_provides $prefix/perl.prov %literal %define __perl_requires $prefix/perl.req %format all

thus adding %define __perl_provides "/var/www/twiki/perl.prov" %define __perl_requires "/var/www/twiki/perl.req"

to the spec file

I will need help with the platforms i don't have access to (like HP/UX).

Is there a better way to achieve this? or should i just code it up, and hand it over to you guys?

Cheers

Sven

michaelrsweet commented 17 years ago

Original reporter: Michael Sweet

Sven Dowideit wrote:

... Is there a better way to achieve this? or should i just code it up, and hand it over to you guys?

Yeah, that kind of stuff gets tricky since you quickly fall into the issue of format differences, e.g. not all formats allow for that, and some things can interfere with the normal packaging with the stuff we automatically generate.

If you just need to %define stuff, then we can probably add support for that specifically and map it to other formats as possible/ necessary.

michaelrsweet commented 17 years ago

Original reporter: Michael Sweet

I was thinking that the %literal would be an advanced directive, that would enable format specific hacks only - maybe there's a way to dissallow them for 'format all'

this way, instead of EPM being forced to choose between supporting all the oddities and less used parts of the platforms, there would be a general fallback.

after implementing just the rpm and parser portion, I started to think about the debian version, and realised that more will be required - perhaps a format specific qualifier - in debian's case which file the literal text should go into..

thus, my proposal (and the code i'll write and send you) would have something like (ignore for a moment the pointlessness of specifying the template file like this )

%format rpm %literal %define __perl_provides $prefix/perl.prov %literal %define __perl_requires $prefix/perl.req %format deb %literal(templates) %literal(templates) Template: twiki/wikiwebmaster %literal(templates) Type: string %literal(templates) Default: webmaster@localhost %literal(templates) _Description: Email address of the webmaster for %literal(templates) this TWiki: %literal(templates) This email address gets mail for new user %literal(templates) registration, and is listed on the "oops" page when %literal(templates) things go wrong. %format all

patch for epm and rpm attached :)

Sven

michaelrsweet commented 16 years ago

Original reporter:

I prepared a version of the %literal patch that is implemented as an extension of struct command_t and function add_command(). It allows to specify commands with "%literal(keyword)" similar to "%postinstall" etc. These commands will be stored with type COMMAND_SPECIAL and the specified keyword in the new key field. The package type specific modules (rpm.c, pkg.c etc) can do whatever is needed with these commands. I tried to be compatible to the original patch for RPM's spec file and added "%literal(request)" to specify request scripts for SVR4 (Solaris) pkg format.

Bodo

michaelrsweet commented 16 years ago

Original reporter:

The patch epm-literal2.patch I posted today does not work. I will post a fixed version.

Bodo

michaelrsweet commented 16 years ago

Original reporter: Michael Sweet

Fixed in Subversion repository.

michaelrsweet commented 17 years ago

"epm-literal.patch":

Index: epm.h
===================================================================
--- epm.h       (revision 758)
+++ epm.h       (working copy)
@@ -203,6 +203,12 @@
   const char   *subpackage;            /* Sub-package name */
 } description_t;

+typedef struct                         /**** Literal Structure ****/
+{
+  char         *literal;               /* literal string to be added for a format */
+  const char   *subpackage;            /* Sub-package name (i think this is not needed?) */
+} literal_t;
+
 typedef struct                         /**** Distribution Structure ****/
 {
   char         product[256],           /* Product name */
@@ -217,6 +223,8 @@
   char         **subpackages;          /* Subpackage names */
   int          num_descriptions;       /* Number of description strings */
   description_t        *descriptions;          /* Description strings */
+  int          num_literals;           /* Number of literal strings */
+  literal_t    *literals;              /* Literal strings */
   int          vernumber,              /* Version number */
                epoch;                  /* Epoch number */
   int          num_commands;           /* Number of commands */
@@ -251,6 +259,8 @@
                           const char *subpkg);
 extern void    add_description(dist_t *dist, FILE *fp, const char *description,
                                const char *subpkg);
+extern void    add_literal(dist_t *dist, FILE *fp, const char *literal,
+                               const char *subpkg);
 extern file_t  *add_file(dist_t *dist, const char *subpkg);
 extern char    *add_subpackage(dist_t *dist, const char *subpkg);
 extern int     copy_file(const char *dst, const char *src,
Index: rpm.c
===================================================================
--- rpm.c       (revision 758)
+++ rpm.c       (working copy)
@@ -569,6 +569,7 @@
   int          i;                      /* Looping var */
   char         name[1024];             /* Full product name */
   const char   *product;               /* Product to depend on */
+  literal_t    *literal;               /* Current literal line */
   file_t       *file;                  /* Current distribution file */
   command_t    *c;                     /* Current command */
   depend_t     *d;                     /* Current dependency */
@@ -693,6 +694,9 @@
   else
     have_commands = 0;

+  for (i = dist->num_literals, literal = dist->literals; i > 0; i --, literal ++)
+      fprintf(fp, "%s\n", literal->literal);
+
   for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
     if (tolower(file->type) == 'i' && file->subpackage == subpackage)
       break;
Index: dist.c
===================================================================
--- dist.c      (revision 758)
+++ dist.c      (working copy)
@@ -19,6 +19,7 @@
  *
  *   add_command()      - Add a command to the distribution...
  *   add_depend()       - Add a dependency to the distribution...
+ *   add_literal()      - Add a literal string to the distribution.
  *   add_description()  - Add a description to the distribution.
  *   add_file()         - Add a file to the distribution.
  *   add_subpackage()   - Add a subpackage to the distribution.
@@ -334,7 +335,59 @@
     perror("epm: Out of memory duplicating description");
 }

+/*
+ * 'add_literal()' - Add a literal strings to the distribution.
+ */

+void
+add_literal(dist_t     *dist,  /* I - Distribution */
+                FILE       *fp,                /* I - Source file */
+                const char *literal,/* I - Literal string */
+                const char *subpkg)    /* I - Subpackage name */
+{
+  literal_t    *temp;                  /* Temporary literal array */
+  char         buf[16384];             /* File import buffer */
+
+
+  if (strncmp(literal, "<<", 2) == 0)
+  {
+    for (literal += 2; isspace(*literal & 255); literal ++);
+
+    literal = get_inline(literal, fp, buf, sizeof(buf));
+  }
+  else if (literal[0] == '<' && literal[1])
+  {
+    for (literal ++; isspace(*literal & 255); literal ++);
+
+    literal = get_file(literal, buf, sizeof(buf));
+  }
+
+  if (literal == NULL)
+    return;
+
+  if (dist->num_literals == 0)
+    temp = malloc(sizeof(literal_t));
+  else
+    temp = realloc(dist->literals,
+                   (dist->num_literals + 1) * sizeof(literal_t));
+
+  if (temp == NULL)
+  {
+    perror("epm: Out of memory adding literal");
+    return;
+  }
+
+  dist->literals = temp;
+  temp               += dist->num_literals;
+  dist->num_literals ++;
+
+  temp->subpackage = subpkg;
+
+  if ((temp->literal = strdup(literal)) == NULL)
+    perror("epm: Out of memory duplicating literal");
+}
+
+
 /*
  * 'add_file()' - Add a file to the distribution.
  */
@@ -861,6 +914,8 @@
        }
        else if (strcmp(line, "%description") == 0)
          add_description(dist, listfiles[listlevel], temp, subpkg);
+       else if (strcmp(line, "%literal") == 0)
+         add_literal(dist, listfiles[listlevel], temp, subpkg);
        else if (strcmp(line, "%preinstall") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_PRE_INSTALL, temp,
                      subpkg);
[root@localhost epm-svn]#
michaelrsweet commented 16 years ago

"epm-literal2.patch":

? epm-literal.patch
Index: dist.c
===================================================================
RCS file: /export/cvs/lib/epm/dist.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 dist.c
--- dist.c  3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ dist.c  11 Apr 2008 13:59:13 -0000
@@ -120,7 +120,26 @@
 {
   command_t    *temp;          /* New command */
   char     buf[16384];     /* File import buffer */
+  char     *key = NULL;        /* key string for special command */

+  /* handle key string for special commands */
+  if(type == COMMAND_SPECIAL)
+  {
+    char *ptr;
+    if (command[0] == '(')
+    {
+       command++;
+       ptr = strchr(command, ')');
+       if (ptr != NULL)
+       {
+         *ptr = '\0';
+         key = strdup(command);
+         command = ptr + 1;
+       }
+       /* FIXME: error handling for missing ')' */
+    }
+    if (key == NULL) key = strdup("");
+  }

   if (strncmp(command, "<<", 2) == 0)
   {
@@ -136,7 +155,10 @@
   }

   if (command == NULL)
+  {
+    if(key != NULL) free(key);
     return;
+  }

   if (dist->num_commands == 0)
     temp = malloc(sizeof(command_t));
@@ -146,6 +168,7 @@
   if (temp == NULL)
   {
     perror("epm: Out of memory allocating a command");
+    if(key != NULL) free(key);
     return;
   }

@@ -154,10 +177,12 @@
   temp->type       = type;
   temp->command    = strdup(command);
   temp->subpackage = subpkg;
+  temp->key        = key;

   if (temp->command == NULL)
   {
     perror("epm: Out of memory duplicating a command string");
+    if (key != NULL) free(key);
     return;
   }

@@ -908,6 +933,11 @@
             strcmp(line, "%postpatch") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_POST_PATCH, temp,
                  subpkg);
+   else if (strcmp(line, "%literal") == 0 ||
+                 strncmp(line, "%literal(", 9) == 0)
+          /* we use line+8 instead of temp to allow parsing "(key)" */
+          add_command(dist, listfiles[listlevel], COMMAND_SPECIAL, line+8,
+                 subpkg);
         else if (strcmp(line, "%product") == 0)
    {
           if (!dist->product[0])
Index: epm.h
===================================================================
RCS file: /export/cvs/lib/epm/epm.h,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 epm.h
--- epm.h   3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ epm.h   11 Apr 2008 13:17:54 -0000
@@ -119,7 +119,9 @@
   COMMAND_PRE_PATCH,           /* Command to run before patch */
   COMMAND_POST_PATCH,          /* Command to run after patch */
   COMMAND_PRE_REMOVE,          /* Command to run before remove */
-  COMMAND_POST_REMOVE          /* Command to run after remove */
+  COMMAND_POST_REMOVE,         /* Command to run after remove */
+  COMMAND_SPECIAL          /* special command data (depends
+                      on package format type) */
 };

 /*
@@ -188,6 +190,7 @@
   int      type;           /* Command type */
   char     *command;       /* Command string */
   const char   *subpackage;        /* Sub-package name */
+  const char   *key;           /* key string for special commands */
 } command_t;

 typedef struct             /**** Dependencies ****/
Index: pkg.c
===================================================================
RCS file: /export/cvs/lib/epm/pkg.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 pkg.c
--- pkg.c   3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ pkg.c   11 Apr 2008 13:17:54 -0000
@@ -56,7 +56,8 @@
        preinstall[1024],   /* Pre install script */
        postinstall[1024],  /* Post install script */
        preremove[1024],    /* Pre remove script */
-       postremove[1024];   /* Post remove script */
+       postremove[1024],   /* Post remove script */
+       request[1024];      /* Request script */
   char     current[1024];      /* Current directory */
   file_t   *file;          /* Current distribution file */
   command_t    *c;         /* Current command */
@@ -336,6 +337,47 @@
     postremove[0] = '\0';

  /*
+  * Write the request file for pkgmk...
+  */
+
+  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
+    if ((c->type == COMMAND_SPECIAL) && (strcmp(c->key, "request") == 0))
+      break;
+
+  if (i)
+  {
+   /*
+    * Write the request file for pkgmk...
+    */
+
+    if (Verbosity)
+      puts("Creating request script...");
+
+    snprintf(request, sizeof(request), "%s/%s.request", directory,
+             prodname);
+
+    if ((fp = fopen(request, "w")) == NULL)
+    {
+      fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", request,
+              strerror(errno));
+      return (1);
+    }
+
+    fchmod(fileno(fp), 0755);
+
+    fputs("#!/bin/sh\n", fp);
+    fputs("# " EPM_VERSION "\n", fp);
+
+    for (; i > 0; i --, c ++)
+      if ((c->type == COMMAND_SPECIAL) && (strcmp(c->key, "request") == 0))
+        fprintf(fp, "%s\n", c->command);
+
+    fclose(fp);
+  }
+  else
+    request[0] = '\0';
+
+ /*
   * Add symlinks for init scripts...
   */

@@ -419,6 +461,8 @@
     fprintf(fp, "i preremove=%s\n", pkg_path(preremove, current));
   if (postremove[0])
     fprintf(fp, "i postremove=%s\n", pkg_path(postremove, current));
+  if (request[0])
+    fprintf(fp, "i request=%s\n", pkg_path(request, current));

   for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
     switch (tolower(file->type))
@@ -524,6 +568,8 @@
       unlink(preremove);
     if (postremove[0])
       unlink(postremove);
+    if (request[0])
+      unlink(request);
   }

   /*
Index: rpm.c
===================================================================
RCS file: /export/cvs/lib/epm/rpm.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 rpm.c
--- rpm.c   3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ rpm.c   11 Apr 2008 13:17:54 -0000
@@ -704,6 +704,24 @@
   else
     have_commands = 0;

+  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
+    if (c->type == COMMAND_SPECIAL && c->subpackage == subpackage &&
+        /* allow empty key for compatibility with patch provided
+           by Sven Dowideit or key "spec" */
+        ( c->key[0] == '\0' || strcmp(c->key, "spec") == 0 ) )
+      break;
+
+  if (i > 0)
+  {
+    for (; i > 0; i --, c ++)
+      if (c->type == COMMAND_SPECIAL && c->subpackage == subpackage &&
+          /* allow empty key for compatibility with patch provided
+             by Sven Dowideit or key "spec" */
+          ( c->key[0] == '\0' || strcmp(c->key, "spec") == 0 ) )
+   fprintf(fp, "%s\n", c->command);
+
+  }
+
   for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
     if (tolower(file->type) == 'i' && file->subpackage == subpackage)
       break;
michaelrsweet commented 16 years ago

"epm-literal3.patch":

? epm-literal.patch
Index: pkg.c
===================================================================
RCS file: /export/cvs/lib/epm/pkg.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 pkg.c
--- pkg.c   3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ pkg.c   11 Apr 2008 13:17:54 -0000
@@ -56,7 +56,8 @@
        preinstall[1024],   /* Pre install script */
        postinstall[1024],  /* Post install script */
        preremove[1024],    /* Pre remove script */
-       postremove[1024];   /* Post remove script */
+       postremove[1024],   /* Post remove script */
+       request[1024];      /* Request script */
   char     current[1024];      /* Current directory */
   file_t   *file;          /* Current distribution file */
   command_t    *c;         /* Current command */
@@ -336,6 +337,47 @@
     postremove[0] = '\0';

  /*
+  * Write the request file for pkgmk...
+  */
+
+  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
+    if ((c->type == COMMAND_SPECIAL) && (strcmp(c->key, "request") == 0))
+      break;
+
+  if (i)
+  {
+   /*
+    * Write the request file for pkgmk...
+    */
+
+    if (Verbosity)
+      puts("Creating request script...");
+
+    snprintf(request, sizeof(request), "%s/%s.request", directory,
+             prodname);
+
+    if ((fp = fopen(request, "w")) == NULL)
+    {
+      fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", request,
+              strerror(errno));
+      return (1);
+    }
+
+    fchmod(fileno(fp), 0755);
+
+    fputs("#!/bin/sh\n", fp);
+    fputs("# " EPM_VERSION "\n", fp);
+
+    for (; i > 0; i --, c ++)
+      if ((c->type == COMMAND_SPECIAL) && (strcmp(c->key, "request") == 0))
+        fprintf(fp, "%s\n", c->command);
+
+    fclose(fp);
+  }
+  else
+    request[0] = '\0';
+
+ /*
   * Add symlinks for init scripts...
   */

@@ -419,6 +461,8 @@
     fprintf(fp, "i preremove=%s\n", pkg_path(preremove, current));
   if (postremove[0])
     fprintf(fp, "i postremove=%s\n", pkg_path(postremove, current));
+  if (request[0])
+    fprintf(fp, "i request=%s\n", pkg_path(request, current));

   for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
     switch (tolower(file->type))
@@ -524,6 +568,8 @@
       unlink(preremove);
     if (postremove[0])
       unlink(postremove);
+    if (request[0])
+      unlink(request);
   }

   /*
Index: rpm.c
===================================================================
RCS file: /export/cvs/lib/epm/rpm.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 rpm.c
--- rpm.c   3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ rpm.c   11 Apr 2008 13:17:54 -0000
@@ -704,6 +704,24 @@
   else
     have_commands = 0;

+  for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++)
+    if (c->type == COMMAND_SPECIAL && c->subpackage == subpackage &&
+        /* allow empty key for compatibility with patch provided
+           by Sven Dowideit or key "spec" */
+        ( c->key[0] == '\0' || strcmp(c->key, "spec") == 0 ) )
+      break;
+
+  if (i > 0)
+  {
+    for (; i > 0; i --, c ++)
+      if (c->type == COMMAND_SPECIAL && c->subpackage == subpackage &&
+          /* allow empty key for compatibility with patch provided
+             by Sven Dowideit or key "spec" */
+          ( c->key[0] == '\0' || strcmp(c->key, "spec") == 0 ) )
+   fprintf(fp, "%s\n", c->command);
+
+  }
+
   for (i = dist->num_files, file = dist->files; i > 0; i --, file ++)
     if (tolower(file->type) == 'i' && file->subpackage == subpackage)
       break;
Index: epm.h
===================================================================
RCS file: /export/cvs/lib/epm/epm.h,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.3
diff -u -r1.1.2.1 -r1.1.2.3
--- epm.h   3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ epm.h   11 Apr 2008 15:46:12 -0000  1.1.2.3
@@ -119,7 +119,9 @@
   COMMAND_PRE_PATCH,           /* Command to run before patch */
   COMMAND_POST_PATCH,          /* Command to run after patch */
   COMMAND_PRE_REMOVE,          /* Command to run before remove */
-  COMMAND_POST_REMOVE          /* Command to run after remove */
+  COMMAND_POST_REMOVE,         /* Command to run after remove */
+  COMMAND_SPECIAL          /* special command data (depends
+                      on package format type) */
 };

 /*
@@ -188,6 +190,7 @@
   int      type;           /* Command type */
   char     *command;       /* Command string */
   const char   *subpackage;        /* Sub-package name */
+  const char   *key;           /* key string for special commands */
 } command_t;

 typedef struct             /**** Dependencies ****/
@@ -248,7 +251,8 @@
  */

 extern void    add_command(dist_t *dist, FILE *fp, int type,
-                   const char *command, const char *subpkg);
+                   const char *command, const char *subpkg,
+                            const char *key);
 extern void    add_depend(dist_t *dist, int type, const char *line,
                   const char *subpkg);
 extern void    add_description(dist_t *dist, FILE *fp, const char *description,
Index: dist.c
===================================================================
RCS file: /export/cvs/lib/epm/dist.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.5
diff -u -r1.1.2.1 -r1.1.2.5
--- dist.c  3 Mar 2008 15:52:50 -0000   1.1.2.1
+++ dist.c  11 Apr 2008 15:51:26 -0000  1.1.2.5
@@ -116,12 +116,12 @@
             FILE       *fp,        /* I - Distribution file */
             int        type,       /* I - Command type */
        const char *command,    /* I - Command string */
-       const char *subpkg)     /* I - Subpackage */
+       const char *subpkg,     /* I - Subpackage */
+            const char *key)       /* I - Key for special command */
 {
   command_t    *temp;          /* New command */
   char     buf[16384];     /* File import buffer */

-
   if (strncmp(command, "<<", 2) == 0)
   {
     for (command += 2; isspace(*command & 255); command ++);
@@ -136,7 +136,9 @@
   }

   if (command == NULL)
+  {
     return;
+  }

   if (dist->num_commands == 0)
     temp = malloc(sizeof(command_t));
@@ -153,13 +155,22 @@
   temp             += dist->num_commands;
   temp->type       = type;
   temp->command    = strdup(command);
-  temp->subpackage = subpkg;
-
   if (temp->command == NULL)
   {
     perror("epm: Out of memory duplicating a command string");
     return;
   }
+  temp->subpackage = subpkg;
+  if(key != NULL)
+  {
+    temp->key        = strdup(key);
+    if (temp->key == NULL)
+    {
+      perror("epm: Out of memory duplicating a command string");
+      free(temp->command);
+      return;
+    }
+  }

   dist->num_commands ++;
 }
@@ -889,25 +900,46 @@
      add_description(dist, listfiles[listlevel], temp, subpkg);
    else if (strcmp(line, "%preinstall") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_PRE_INSTALL, temp,
-                 subpkg);
+                 subpkg, NULL);
    else if (strcmp(line, "%install") == 0 ||
             strcmp(line, "%postinstall") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_POST_INSTALL, temp,
-                 subpkg);
+                 subpkg, NULL);
    else if (strcmp(line, "%remove") == 0 ||
             strcmp(line, "%preremove") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_PRE_REMOVE, temp,
-                 subpkg);
+                 subpkg, NULL);
    else if (strcmp(line, "%postremove") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_POST_REMOVE, temp,
-                 subpkg);
+                 subpkg, NULL);
    else if (strcmp(line, "%prepatch") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_PRE_PATCH, temp,
-                 subpkg);
+                 subpkg, NULL);
    else if (strcmp(line, "%patch") == 0 ||
             strcmp(line, "%postpatch") == 0)
           add_command(dist, listfiles[listlevel], COMMAND_POST_PATCH, temp,
-                 subpkg);
+                 subpkg, NULL);
+   else if (strcmp(line, "%literal") == 0 ||
+                 strncmp(line, "%literal(", 9) == 0)
+        {
+          char *ptr;
+          char *key = NULL;
+          ptr = strchr(line, '(');
+          if(ptr != NULL)
+          {
+            key = ptr + 1;
+            ptr = strchr(key, ')');
+            if (ptr != NULL)
+            {
+              *ptr = '\0';
+            }
+            /* FIXME: error handling for missing ')' */
+          }
+          if (key == NULL) key = "";
+
+          add_command(dist, listfiles[listlevel], COMMAND_SPECIAL, temp,
+                 subpkg, key);
+        }
         else if (strcmp(line, "%product") == 0)
    {
           if (!dist->product[0])