[devel] changelogs for apt repo

Alexey Tourbin =?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Вс Май 18 06:07:51 MSD 2008


On Sat, May 17, 2008 at 09:34:27AM +0400, Alexey Tourbin wrote:
> Теперь остаётся выяснить, сколько это занимает места.
> 
> Обычная генерация сизифа:
> 
> $ cp -prs /ALT/Sisyphus/x86_64 /ALT/Sisyphus/noarch .
> $ rm -f x86_64/base/* noarch/base/*
> $ PATH=$PWD:$PATH genbasedir --topdir=$PWD x86_64
> $ PATH=$PWD:$PATH genbasedir --topdir=$PWD noarch
> $ du -bk x86_64/base/pkglist.classic.bz2 noarch/base/pkglist.classic.bz2 
> 2421    x86_64/base/pkglist.classic.bz2
> 1049    noarch/base/pkglist.classic.bz2
> $ 
> 
> Генерация с опцией --changelog-since=2007-01-01:
> 
> $ PATH=$PWD:$PATH genbasedir --topdir=$PWD --changelog-since=2007-01-01 x86_64
> $ PATH=$PWD:$PATH genbasedir --topdir=$PWD --changelog-since=2007-01-01 noarch
> $ du -bk x86_64/base/pkglist.classic.bz2 noarch/base/pkglist.classic.bz2
> 3536    x86_64/base/pkglist.classic.bz2
> 1302    noarch/base/pkglist.classic.bz2
> $ 
> 
> Таким образом, размер скачиваемого при 'apt-get update' заметно
> увеличивается (примерно на треть).  Я считаю это приемлемой платой
> за удовольствие просмотреть changelog пакета ДО скачивания и установки.

On Sat, May 17, 2008 at 11:00:34PM +0400, Alexey Tourbin wrote:
> Какая плата тебя бы устроила?  Думаю что плату можно будет немного
> уменьшить, если сначала отсортировать пакеты по %{SOURCERPM}, а уже
> потом выгонять хедеры.  Тогда bzip2 лучше сожмёт одинаковые changelog'и
> подряд идущих подпакетов.

Я сделал предварительную реализацию сортировки по %{SOURCERPM}.
Результаты теперь такие:

$ PATH=$PWD:$PATH genbasedir --topdir=$PWD x86_64
$ PATH=$PWD:$PATH genbasedir --topdir=$PWD noarch
$ du -bk x86_64/base/pkglist.classic.bz2 noarch/base/pkglist.classic.bz2
2384    x86_64/base/pkglist.classic.bz2
1048    noarch/base/pkglist.classic.bz2
$

$ PATH=$PWD:$PATH genbasedir --topdir=$PWD --changelog-since=2007-01-01 x86_64
$ PATH=$PWD:$PATH genbasedir --topdir=$PWD --changelog-since=2007-01-01 noarch
$ du -bk x86_64/base/pkglist.classic.bz2 noarch/base/pkglist.classic.bz2
3306    x86_64/base/pkglist.classic.bz2
1300    noarch/base/pkglist.classic.bz2
$

Из этого видно следующее: для noarch пакетов переупорядочивание
по %{SOURCERPM} почти ничего не дает.  Это связано с тем, что noarch
пакеты реже распиливают, а при распиливании названия подпакетов реже
отличаются по префиксу (то есть глобального переупорядочивания, которое
может повысить степень сжатия, как напр. в случае с lib%name и %name,
не происходит).

Для x86_64 экономия заметна даже без генерации changelog'ов (2421/2384 =
1.6%, за счёт лучшего совпадения других атрибутов подпакетов),
а особенно с changelog'ом (3536/3306 = 7%, за счёт лучшего сжатия
одинаковых changelog'ов подряд идущих подпакетов).

В принципе выгаданные несколько процентов позволяют мне с большей
уверенностью говорить о включении changelog'ов в репозитарий, хотя
общая картина остаётся скорее прежней: если включить changelog'и по
предложенной схеме, то размер скачиваемого при 'apt-get update'
увеличивается примерно на треть.

Вот патч на genpkglist.cc, я его плохо проверил, но вроде работает.
У меня уже патч на патче сидит и я пока не знаю как его лучше приложить
к тому что есть.

--- apt-0.5.15lorg2/tools/genpkglist.cc-	2008-05-18 00:48:01 +0400
+++ apt-0.5.15lorg2/tools/genpkglist.cc	2008-05-18 05:14:06 +0400
@@ -320,7 +320,7 @@ done:
 }
 
 bool copyFields(Header h, Header newHeader,
-		FILE *idxfile, const char *directory, char *filename,
+		FILE *idxfile, const char *directory, const char *filename,
 		unsigned filesize, map<string,UpdateInfo> &updateInfo,
 		bool fullFileList)
 {
@@ -460,99 +460,34 @@ void usage()
    cerr << "                 one preceding entry (if available)" <<endl;
 }
 
-
-
-#ifndef HAVE_SCANDIR
-// from glibc 1.09.1  mod'd by jmik, ins'd by asm, fix'd by sbi
-int alphasort(const void * a, const void * b)
+static void progress(int cur, int total)
 {
-  return strcmp ((*(struct dirent **) a)->d_name,
-                 (*(struct dirent **) b)->d_name);
+   if (cur > 1)
+      printf("\b\b\b\b\b\b\b\b\b\b");
+   printf(" %04i/%04i", cur, total);
+   fflush(stdout);
 }
 
-int scandir(const char * dir, struct dirent *** namelist, 
-        int (* select)(struct dirent *), 
-        int (* cmp)(const void *, const void *))
+struct rpmfile {
+   const char *basename;
+   const char *sourcerpm;
+};
 
+static
+int rpmfilecmp(const void *a, const void *b)
 {
-  DIR *dp = opendir (dir);
-  struct dirent **v = NULL;
-  size_t vsize = 0, i;
-  struct dirent *d;
-  int save;
-
-  if (dp == NULL)
-    return -1;
-
-  save = errno;
-  errno = 0;
-
-  i = 0;
-  while ((d = readdir (dp)) != NULL)
-    {
-    if (select == NULL || (*select) (d))
-      {
-        if (i == vsize)
-          {
-            struct dirent **newv;
-            if (vsize == 0)
-              vsize = 10;
-            else
-              vsize *= 2;
-            newv = (struct dirent **) realloc (v, vsize * sizeof (*v));
-            if (newv == NULL)
-              {
-              lose:
-                errno = ENOMEM;
-                break;
-              }
-            v = newv;
-          }
-
-        v[i] = (struct dirent *) malloc (d->d_reclen);
-        if (v[i] == NULL)
-          goto lose;
-
-        // *v[i++] = *d;
-	memcpy(v[i], d, d->d_reclen);
-	i++;
-      }
-    }
-
-  v[i] = NULL;
-
-  if (errno != 0)
-    {
-      save = errno;
-      (void) closedir (dp);
-      while (i > 0)
-        free (v[--i]);
-      free (v);
-      errno = save;
-      return -1;
-    }
-
-  (void) closedir (dp);
-  errno = save;
-
-  /* Sort the list if we have a comparison function to sort with.  */
-  if (cmp != NULL)
-    qsort (v, i, sizeof (struct dirent *), cmp);
-
-  *namelist = v;
-  return i;
+   const struct rpmfile *A = (struct rpmfile *)a;
+   const struct rpmfile *B = (struct rpmfile *)b;
+   int cmp = strcmp(A->sourcerpm, B->sourcerpm);
+   if (cmp)
+      return cmp;
+   return strcmp(A->basename, B->basename);
 }
-// end of new stuff from glibc
-#endif /* !HAVE_SCANDIR */
-
 
 int main(int argc, char ** argv) 
 {
    string rpmsdir;
    string pkglist_path;
-   FD_t outfd, fd;
-   struct dirent **dirEntries;
-   int entry_no, entry_cur;
    map<string,UpdateInfo> updateInfo;
    CachedMD5 *md5cache;
    char *op_dir;
@@ -561,13 +496,13 @@ int main(int argc, char ** argv) 
    char *op_update = NULL;
    long /* time_t */ changelog_since = 0;
    FILE *idxfile;
-   int i;
    bool fullFileList = false;
    bool progressBar = false;
    const char *pkgListSuffix = NULL;
    bool pkgListAppend = false;
    
    setlocale(LC_ALL, "C");
+   int i;
    for (i = 1; i < argc; i++) {
       if (strcmp(argv[i], "--index") == 0) {
 	 i++;
@@ -674,14 +609,16 @@ int main(int argc, char ** argv) 
 
    string dirtag = "RPMS." + string(op_suf);
 
-   entry_no = scandir(rpmsdir.c_str(), &dirEntries, selectDirent, alphasort);
-   if (entry_no < 0) {
-      cerr << "genpkglist: error opening directory " << rpmsdir << ":"
-	  << strerror(errno);
-      return 1;
+   if (chdir(rpmsdir.c_str())) {
+      perror(rpmsdir.c_str());
+      exit(1);
+   }
+
+   glob_t gl;
+   if (glob("*.rpm", 0, NULL, &gl)) {
+      cerr << rpmsdir << "/" << "*.rpm: glob failed" <<endl;
+      exit(1);
    }
-   
-   chdir(rpmsdir.c_str());
    
    if (pkgListSuffix != NULL)
 	   pkglist_path = pkglist_path + "/base/pkglist." + pkgListSuffix;
@@ -689,6 +626,7 @@ int main(int argc, char ** argv) 
 	   pkglist_path = pkglist_path + "/base/pkglist." + op_suf;
    
    
+   FD_t outfd;
    if (pkgListAppend == true && FileExists(pkglist_path)) {
       outfd = fdOpen(pkglist_path.c_str(), O_WRONLY|O_APPEND, 0644);
    } else {
@@ -711,30 +649,54 @@ int main(int argc, char ** argv) 
    int isSource;
 #endif   
 
-   if (!fullFileList) {
-      // ALT: file list cannot be stripped in a dumb manner -- this is going
-      // to produce unmet dependencies.  First pass is required to initialize
-      // certain data structures.
-      for (entry_cur = 0; entry_cur < entry_no; entry_cur++) {
-         if (progressBar) {
-            if (entry_cur)
-               printf("\b\b\b\b\b\b\b\b\b\b");
-            printf(" %04i/%04i", entry_cur + 1, entry_no);
-            fflush(stdout);
-         }
+   struct rpmfile *rpms = new struct rpmfile[gl.gl_pathc];
+   int ix, n = 0;
+
+   for (ix = 0; ix < gl.gl_pathc; ix++) {
+         if (progressBar)
+	    progress(ix+1, gl.gl_pathc);
+	 
+	 const char *basename = gl.gl_pathv[ix];
+         FD_t fd = Fopen(basename, "r");
+         if (!fd) {
+	    cerr << "Warning: " << basename << ": " << strerror(errno) <<endl;
+	    continue;
+	 }
 
-         fd = fdOpen(dirEntries[entry_cur]->d_name, O_RDONLY, 0666);
-         if (!fd)
-            continue;
          int rc;
          Header h;
 #if RPM_VERSION >= 0x040100
          rc = rpmReadPackageFile(ts, fd, dirEntries[entry_cur]->d_name, &h);
-         if (rc == RPMRC_OK || rc == RPMRC_NOTTRUSTED || rc == RPMRC_NOKEY) {
+         if (rc == RPMRC_OK || rc == RPMRC_NOTTRUSTED || rc == RPMRC_NOKEY)
 #else
          rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
-         if (rc == 0) {
+         if (rc == 0)
 #endif
+	 {
+	    ; // good
+	 }
+	 else {
+	    cerr << "Warning: " << basename << ": cannot read package header" <<endl;
+	    continue;
+	 }
+	 
+	 const char *sourcerpm;
+	 rc = headerGetEntry(h, RPMTAG_SOURCERPM, NULL, (void**)&sourcerpm, NULL);
+	 if (!(rc == 1)) {
+	    cerr << "Warning: " << basename << ": no SOURCERPM tag" <<endl;
+	    continue;
+	 }
+
+	 sourcerpm = strdup(sourcerpm);
+	 assert(sourcerpm);
+	 rpms[n].basename = basename;
+	 rpms[n].sourcerpm = sourcerpm;
+	 n++;
+	 
+      // ALT: file list cannot be stripped in a dumb manner -- this is going
+      // to produce unmet dependencies.  First pass is required to initialize
+      // certain data structures.
+	 if (!fullFileList) {
             // path-like Requires
             int_32 reqtype = 0;
             const char **requires = NULL;
@@ -776,37 +738,35 @@ int main(int argc, char ** argv) 
             headerFreeTag(h, dn, (rpmTagType)dnt);
             headerFreeTag(h, di, (rpmTagType)dit);
             
-            headerFree(h);
          }
+	 headerFree(h);
          Fclose(fd);
-      }
    }
-   for (entry_cur = 0; entry_cur < entry_no; entry_cur++) {
+
+   qsort(rpms, n, sizeof(struct rpmfile), rpmfilecmp);
+
+   for (ix = 0; ix < n; ix++) {
       struct stat sb;
 
-      if (progressBar) {
-         if (entry_cur)
-            printf("\b\b\b\b\b\b\b\b\b\b");
-         printf(" %04i/%04i", entry_cur + 1, entry_no);
-         fflush(stdout);
-      }
+      if (progressBar)
+	 progress(ix+1, n);
 
-      if (stat(dirEntries[entry_cur]->d_name, &sb) < 0) {
-	    cerr << "\nWarning: " << strerror(errno) << ": " << 
-		    dirEntries[entry_cur]->d_name << endl;
-	    continue;
+      const char *basename = rpms[ix].basename;
+
+      if (stat(basename, &sb) < 0) {
+	    cerr << "Fatal: " << basename << ": " << strerror(errno) <<endl;
+	    exit(1);
       }
 
       {
 	 Header h;
 	 int rc;
 	 
-	 fd = fdOpen(dirEntries[entry_cur]->d_name, O_RDONLY, 0666);
+	 FD_t fd = Fopen(basename, "r");
 
 	 if (!fd) {
-	    cerr << "\nWarning: " << strerror(errno) << ": " << 
-		    dirEntries[entry_cur]->d_name << endl;
-	    continue;
+	    cerr << "Fatal: " << basename << ": " << strerror(errno) <<endl;
+	    exit(1);
 	 }
 	 
 #if RPM_VERSION >= 0x040100
@@ -822,14 +782,13 @@ int main(int argc, char ** argv) 
 	    newHeader = headerNew();
 	    
 	    copyFields(h, newHeader, idxfile, dirtag.c_str(),
-		       dirEntries[entry_cur]->d_name,
+		       basename,
 		       sb.st_size, updateInfo, fullFileList);
 
 	    if (changelog_since > 0)
 	       copyChangelog(changelog_since, h, newHeader);
 
-	    md5cache->MD5ForFile(string(dirEntries[entry_cur]->d_name), 
-				 sb.st_mtime, md5);
+	    md5cache->MD5ForFile(string(basename), sb.st_mtime, md5);
 	    headerAddEntry(newHeader, CRPMTAG_MD5, RPM_STRING_TYPE, md5, 1);
 
 	    headerWrite(outfd, newHeader, HEADER_MAGIC_YES);
@@ -837,8 +796,8 @@ int main(int argc, char ** argv) 
 	    headerFree(newHeader);
 	    headerFree(h);
 	 } else {
-	    cerr << "\nWarning: Skipping malformed RPM: " << 
-		    dirEntries[entry_cur]->d_name << endl;
+	    cerr << "Fatal: " << basename << ": cannot read package header" <<endl;
+	    exit(1);
 	 }
 	 Fclose(fd);
       }
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя     : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип     : application/pgp-signature
Размер  : 197 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url     : <http://lists.altlinux.org/pipermail/devel/attachments/20080518/702283be/attachment-0002.bin>


Подробная информация о списке рассылки Devel