Imported Upstream version 0.6.27
[platform/upstream/libsolv.git] / tools / common_write.c
index 7862338..e20f64f 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "repo.h"
 #include "repo_write.h"
 #include "common_write.h"
+#include "solvversion.h"
 
-static char *verticals[] = {
-  "authors",
-  "description",
-  "messagedel",
-  "messageins",
-  "eula",
-  "diskusage",
+/* toolversion history
+ * 1.0: initial tool version
+ * 1.1: changed PRODUCT_ENDOFLIFE parsing
+*/
+
+static Id verticals[] = {
+  SOLVABLE_AUTHORS,
+  SOLVABLE_DESCRIPTION,
+  SOLVABLE_MESSAGEDEL,
+  SOLVABLE_MESSAGEINS,
+  SOLVABLE_EULA,
+  SOLVABLE_DISKUSAGE,
+  SOLVABLE_FILELIST,
+  SOLVABLE_CHANGELOG_AUTHOR,
+  SOLVABLE_CHANGELOG_TEXT,
   0
 };
 
-static unsigned char *filter;
-static int nfilter;
-
-static void
-create_filter(Pool *pool)
-{
-  char **s;
-  Id id;
-  for (s = verticals; *s; s++)
-    {
-      id = str2id(pool, *s, 1);
-      if (id >= nfilter)
-       {
-         filter = sat_realloc(filter, id + 16);
-         memset(filter + nfilter, 0, id + 16 - nfilter);
-         nfilter = id + 16;
-       }
-      filter[id] = 1;
-    }
-}
+static char *languagetags[] = {
+  "solvable:summary:",
+  "solvable:description:",
+  "solvable:messageins:",
+  "solvable:messagedel:",
+  "solvable:eula:",
+  0
+};
 
 static int test_separate = 0;
 
+struct keyfilter_data {
+  char **languages;
+  int nlanguages;
+  int haveaddedfileprovides;
+  int haveexternal;
+};
+
 static int
 keyfilter_solv(Repo *data, Repokey *key, void *kfdata)
 {
+  struct keyfilter_data *kd = kfdata;
+  int i;
+  const char *keyname;
+
   if (test_separate && key->storage != KEY_STORAGE_SOLVABLE)
     return KEY_STORAGE_DROPPED;
-  if (key->name < nfilter && filter[key->name])
-    return KEY_STORAGE_VERTICAL_OFFSET;
+  if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
+    return KEY_STORAGE_DROPPED;
+  if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
+    return KEY_STORAGE_DROPPED;
+  for (i = 0; verticals[i]; i++)
+    if (key->name == verticals[i])
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  keyname = pool_id2str(data->pool, key->name);
+  for (i = 0; languagetags[i] != 0; i++)
+    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
+      return KEY_STORAGE_VERTICAL_OFFSET;
   return KEY_STORAGE_INCORE;
 }
 
 static int
 keyfilter_attr(Repo *data, Repokey *key, void *kfdata)
 {
+  int i;
+  const char *keyname;
   if (key->storage == KEY_STORAGE_SOLVABLE)
     return KEY_STORAGE_DROPPED;
-  if (key->name < nfilter && filter[key->name])
-    return KEY_STORAGE_VERTICAL_OFFSET;
+  /* those must only be in the main solv file */
+  if (key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_TOOLVERSION)
+    return KEY_STORAGE_DROPPED;
+  for (i = 0; verticals[i]; i++)
+    if (key->name == verticals[i])
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  keyname = pool_id2str(data->pool, key->name);
+  for (i = 0; languagetags[i] != 0; i++)
+    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
+      return KEY_STORAGE_VERTICAL_OFFSET;
   return KEY_STORAGE_INCORE;
 }
 
-int
-tool_write(Repo *repo, const char *basename, int separate)
+static int
+keyfilter_language(Repo *repo, Repokey *key, void *kfdata)
 {
   Pool *pool = repo->pool;
-  Repodatafile fileinfoa[1];
-  Repodatafile *fileinfo = 0;
-  int nsubfiles = 0;
+  const char *name, *p;
+  char *lang = kfdata;
+  int i;
 
-  create_filter(pool);
-  memset (fileinfoa, 0, sizeof fileinfoa);
-  if (separate)
+  name = pool_id2str(repo->pool, key->name);
+  p = strrchr(name, ':');
+  if (!p || strcmp(p + 1, lang) != 0)
+    return KEY_STORAGE_DROPPED;
+  for (i = 0; verticals[i]; i++)
     {
+      const char *vname = pool_id2str(pool, verticals[i]);
+      if (!strncmp(name, vname, p - name) && vname[p - name] == 0)
+       return KEY_STORAGE_VERTICAL_OFFSET;
+    }
+  return KEY_STORAGE_INCORE;
+}
+
+static int
+keyfilter_DU(Repo *repo, Repokey *key, void *kfdata)
+{
+  int i;
+  if (key->name != SOLVABLE_DISKUSAGE)
+    return KEY_STORAGE_DROPPED;
+  for (i = 0; verticals[i]; i++)
+    if (key->name == verticals[i])
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  return KEY_STORAGE_INCORE;
+}
+
+static int
+keyfilter_FL(Repo *repo, Repokey *key, void *kfdata)
+{
+  int i;
+  if (key->name != SOLVABLE_FILELIST)
+    return KEY_STORAGE_DROPPED;
+  for (i = 0; verticals[i]; i++)
+    if (key->name == verticals[i])
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  return KEY_STORAGE_INCORE;
+}
+
+static int
+keyfilter_other(Repo *repo, Repokey *key, void *kfdata)
+{
+  const char *name, *p;
+  struct keyfilter_data *kd = kfdata;
+  int i;
+
+  if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
+    return KEY_STORAGE_DROPPED;
+  if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
+    return KEY_STORAGE_DROPPED;
+
+  if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE)
+    return KEY_STORAGE_DROPPED;
+
+  name = pool_id2str(repo->pool, key->name);
+  p = strrchr(name, ':');
+  if (p)
+    {
+      for (i = 0; i < kd->nlanguages; i++)
+       if (!strcmp(p + 1, kd->languages[i]))
+         return KEY_STORAGE_DROPPED;
+    }
+  for (i = 0; verticals[i]; i++)
+    if (key->name == verticals[i])
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  return KEY_STORAGE_INCORE;
+}
+
+/*
+ * Write <repo> to stdout
+ * If <attrname> is given, write attributes to <attrname>
+ * If <basename> is given, split attributes
+ */
+
+#define REPODATAFILE_BLOCK 15
+
+static void
+write_info(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Repodata *info, const char *location)
+{
+  Id h;
+  Queue keyq;
+
+  queue_init(&keyq);
+  if (repo_write_filtered(repo, fp, keyfilter, kfdata, &keyq) != 0)
+    {
+      fprintf(stderr, "repo_write failed\n");
+      exit(1);
+    }
+  h = repodata_new_handle(info);
+  if (keyq.count)
+    repodata_set_idarray(info, h, REPOSITORY_KEYS, &keyq);
+  queue_free(&keyq);
+  repodata_set_str(info, h, REPOSITORY_LOCATION, location);
+  repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h);
+}
+
+void
+tool_write(Repo *repo, const char *basename, const char *attrname)
+{
+  Repodata *data;
+  Repodata *info = 0;
+  Repokey *key;
+  char **languages = 0;
+  int nlanguages = 0;
+  int i, j, k, l;
+  struct keyfilter_data kd;
+  Queue addedfileprovides;
+
+  memset(&kd, 0, sizeof(kd));
+  info = repo_add_repodata(repo, 0);
+  repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
+  queue_init(&addedfileprovides);
+  pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0);
+  if (addedfileprovides.count)
+    {
+      kd.haveaddedfileprovides = 1;
+      repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides);
+    }
+  queue_free(&addedfileprovides);
+
+  pool_freeidhashes(repo->pool);       /* free some mem */
+
+  if (basename)
+    {
+      char fn[4096];
+      FILE *fp;
+      int has_DU = 0;
+      int has_FL = 0;
+
+      /* find languages and other info */
+      FOR_REPODATAS(repo, i, data)
+       {
+         for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
+           {
+             const char *keyname = pool_id2str(repo->pool, key->name);
+             if (key->name == SOLVABLE_DISKUSAGE)
+               has_DU = 1;
+             if (key->name == SOLVABLE_FILELIST)
+               has_FL = 1;
+             for (k = 0; languagetags[k] != 0; k++)
+               if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
+                 break;
+             if (!languagetags[k])
+               continue;
+             l = strlen(languagetags[k]);
+             if (strlen(keyname + l) > 5)
+               continue;
+             for (k = 0; k < nlanguages; k++)
+               if (!strcmp(languages[k], keyname + l))
+                 break;
+             if (k < nlanguages)
+               continue;
+             languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *));
+             languages[nlanguages++] = strdup(keyname + l);
+           }
+       }
+      /* write language subfiles */
+      for (i = 0; i < nlanguages; i++)
+        {
+         sprintf(fn, "%s.%s.solv", basename, languages[i]);
+         if (!(fp = fopen(fn, "w")))
+           {
+             perror(fn);
+             exit(1);
+           }
+         write_info(repo, fp, keyfilter_language, languages[i], info, fn);
+         fclose(fp);
+         kd.haveexternal = 1;
+        }
+      /* write DU subfile */
+      if (has_DU)
+       {
+         sprintf(fn, "%s.DU.solv", basename);
+         if (!(fp = fopen(fn, "w")))
+           {
+             perror(fn);
+             exit(1);
+           }
+         write_info(repo, fp, keyfilter_DU, 0, info, fn);
+         fclose(fp);
+         kd.haveexternal = 1;
+       }
+      /* write filelist */
+      if (has_FL)
+       {
+         sprintf(fn, "%s.FL.solv", basename);
+         if (!(fp = fopen(fn, "w")))
+           {
+             perror(fn);
+             exit(1);
+           }
+         write_info(repo, fp, keyfilter_FL, 0, info, fn);
+         fclose(fp);
+         kd.haveexternal = 1;
+       }
+      /* write everything else */
+      sprintf(fn, "%s.solv", basename);
+      if (!(fp = fopen(fn, "w")))
+       {
+         perror(fn);
+         exit(1);
+       }
+      kd.languages = languages;
+      kd.nlanguages = nlanguages;
+      repodata_internalize(info);
+      if (repo_write_filtered(repo, fp, keyfilter_other, &kd, 0) != 0)
+       {
+         fprintf(stderr, "repo_write failed\n");
+         exit(1);
+       }
+      if (fclose(fp) != 0)
+       {
+         perror("fclose");
+         exit(1);
+       }
+      for (i = 0; i < nlanguages; i++)
+       free(languages[i]);
+      solv_free(languages);
+      repodata_free(info);
+    }
+  if (attrname)
+    {
+      FILE *fp;
       test_separate = 1;
-      fileinfo = fileinfoa;
-      FILE *fp = fopen ("test.attr", "w");
-      repo_write(repo, fp, keyfilter_attr, 0, fileinfo, 0);
-      fclose (fp);
-      fileinfo->location = strdup ("test.attr");
-      fileinfo++;
-
-      nsubfiles = fileinfo - fileinfoa;
-      fileinfo = fileinfoa;
+      fp = fopen(attrname, "w");
+      write_info(repo, fp, keyfilter_attr, 0, info, attrname);
+      fclose(fp);
+      kd.haveexternal = 1;
+    }
+  repodata_internalize(info);
+  if (repo_write_filtered(repo, stdout, keyfilter_solv, &kd, 0) != 0)
+    {
+      fprintf(stderr, "repo_write failed\n");
+      exit(1);
     }
-  repo_write(repo, stdout, keyfilter_solv, 0, fileinfo, nsubfiles);
-  return 0;
+  repodata_free(info);
 }