[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