xbps-create: multiple fixes and new additions, 1 item left to finish.

- Added "build-date" object to XBPS_PKGPROPS.
- Added "installed_size" object to XBPS_PKGPROPS.
- Add entries to archive with "./" as prefix to match xbps-src.
- Create binpkg atomically (from caller's perspective) in cwd.
(cherry picked from commit efeae7c346e914bca045ffe44627c18321e45be9)
This commit is contained in:
Juan RP 2012-09-05 09:00:09 +02:00
parent 6d6d31ccc0
commit 215f6d6f31

View File

@ -40,6 +40,9 @@
#include <xbps_api.h>
#include "queue.h"
/*
* XXX: Add a flag to set "packaged-with" object in XBPS_PKGPROPS?
*/
#define _PROGNAME "xbps-create"
struct xentry {
@ -50,6 +53,7 @@ struct xentry {
static TAILQ_HEAD(xentry_head, xentry) xentry_list =
TAILQ_HEAD_INITIALIZER(xentry_list);
static uint64_t instsize;
static prop_dictionary_t pkg_propsd, pkg_filesd;
static const char *destdir;
@ -166,17 +170,18 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
(void)sb;
(void)ftwbuf;
/* Ignore metadata files generated by xbps-src and destdir */
if ((strcmp(fpath, ".") == 0) ||
(strcmp(fpath, "./props.plist") == 0) ||
(strcmp(fpath, "./files.plist") == 0))
(strcmp(fpath, "./files.plist") == 0) ||
(strcmp(fpath, "./flist") == 0))
return 0;
/* sanitized file path */
filep = strchr(fpath, '/') + 1;
filep = strchr(fpath, '.') + 1;
xe = calloc(1, sizeof(*xe));
assert(xe);
xe->file = strdup(filep);
xe->file = strdup(fpath);
assert(xe->file);
if ((strcmp(fpath, "./INSTALL") == 0) ||
@ -188,10 +193,13 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
}
if (type == FTW_SL) {
/* symlink */
/*
* Symlinks.
*
* Find out target file.
*/
xe->type = strdup("links");
assert(xe->type);
/* Find out target file */
memset(&buf, 0, sizeof(buf));
if (realpath(fpath, buf) == NULL)
die("failed to process symlink `%s':", filep);
@ -200,9 +208,10 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
xe->target = strdup(filep);
assert(xe->target);
} else if (type == FTW_F) {
/* file */
/*
* Find out if it's a configuration file or not.
* Regular files.
* Find out if it's a configuration file or not
* and calculate sha256 hash.
*/
if (entry_is_conf_file(filep))
xe->type = strdup("conf_files");
@ -210,9 +219,11 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf)
xe->type = strdup("files");
assert(xe->type);
/* calculate sha256 hash */
if ((xe->hash = xbps_file_hash(fpath)) == NULL)
die("failed to process hash for %s:", fpath);
instsize += sb->st_size;
} else if (type == FTW_D) {
/* directory */
xe->type = strdup("dirs");
@ -230,6 +241,7 @@ process_xentry(const char *key)
prop_array_t a;
prop_dictionary_t d;
struct xentry *xe;
char *p;
bool found = false;
a = prop_array_create();
@ -242,7 +254,9 @@ process_xentry(const char *key)
found = true;
d = prop_dictionary_create();
assert(d);
prop_dictionary_set_cstring(d, "file", xe->file);
/* sanitize file path */
p = strchr(xe->file, '.') + 1;
prop_dictionary_set_cstring(d, "file", p);
if (xe->target)
prop_dictionary_set_cstring(d, "target", xe->target);
else if (xe->hash)
@ -280,7 +294,7 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
{
struct archive *ard;
struct archive_entry *entry;
char buf[BUFSIZ];
char buf[BUFSIZ], *p;
int fd;
size_t len;
@ -299,8 +313,11 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
assert(entry);
archive_entry_set_pathname(entry, xe->file);
if ((fd = open(xe->file, O_RDONLY)) == -1)
die("failed to add entry (open) %s to archive:", xe->file);
p = xbps_xasprintf("%s/%s", destdir, xe->file);
assert(p);
if ((fd = open(p, O_RDONLY)) == -1)
die("failed to add entry (open) %s %s to archive:", xe->file);
if ((archive_read_disk_entry_from_file(ard, entry, fd, NULL)) != 0)
die("failed to add entry %s to archive:", xe->file);
@ -310,6 +327,7 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
while ((len = read(fd, buf, sizeof(buf))) > 0)
archive_write_data(ar, buf, len);
free(p);
close(fd);
archive_entry_free(entry);
archive_read_free(ard);
@ -365,20 +383,24 @@ process_archive(struct archive *ar, const char *pkgver)
/* Add INSTALL/REMOVE metadata scripts first */
TAILQ_FOREACH(xe, &xentry_list, entries) {
process_entry_file(ar, xe, "INSTALL");
process_entry_file(ar, xe, "REMOVE");
process_entry_file(ar, xe, "./INSTALL");
process_entry_file(ar, xe, "./REMOVE");
}
/*
* Add the installed-size object.
*/
prop_dictionary_set_uint64(pkg_propsd, "installed_size", instsize);
/* Add props.plist metadata file */
xml = prop_dictionary_externalize(pkg_propsd);
assert(xml);
process_entry_memory(ar, xml, "props.plist");
process_entry_memory(ar, xml, "./props.plist");
free(xml);
/* Add files.plist metadata file */
xml = prop_dictionary_externalize(pkg_filesd);
assert(xml);
process_entry_memory(ar, xml, "files.plist");
process_entry_memory(ar, xml, "./files.plist");
free(xml);
/* Add all package data files and release resources */
@ -396,6 +418,24 @@ process_archive(struct archive *ar, const char *pkgver)
}
}
static void
set_build_date(void)
{
char outstr[64];
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
assert(tmp);
if (strftime(outstr, sizeof(outstr)-1, "%F %R %Z", tmp) == 0)
die("failed to set build-date object (strftime):");
if (!prop_dictionary_set_cstring(pkg_propsd, "build-date", outstr))
die("failed to add build-date object:");
}
int
main(int argc, char **argv)
{
@ -423,9 +463,10 @@ main(int argc, char **argv)
const char *conflicts, *deps, *homepage, *license, *maint;
const char *provides, *pkgver, *replaces, *desc, *ldesc;
const char *arch, *config_files, *mutable_files, *version;
char *pkgname, *binpkg;
char *pkgname, *binpkg, *tname, *p, cwd[PATH_MAX-1];
bool preserve = false;
int c;
int c, pkg_fd;
mode_t myumask;
arch = conflicts = deps = homepage = license = maint = NULL;
provides = pkgver = replaces = desc = ldesc = NULL;
@ -524,6 +565,7 @@ main(int argc, char **argv)
prop_dictionary_set_cstring_nocopy(pkg_propsd, "version", version);
prop_dictionary_set_cstring_nocopy(pkg_propsd, "pkgver", pkgver);
prop_dictionary_set_cstring_nocopy(pkg_propsd, "short_desc", desc);
set_build_date();
/* Optional properties */
if (homepage)
@ -544,8 +586,13 @@ main(int argc, char **argv)
process_array("provides", provides);
process_array("replaces", replaces);
/* save cwd */
memset(&cwd, 0, sizeof(cwd));
p = getcwd(cwd, sizeof(cwd));
assert(p);
if (chdir(destdir) == -1)
die("cannot chdir() to destdir:");
die("cannot chdir() to destdir %s:", destdir);
/*
* Process XBPS_PKGFILES metadata file.
*/
@ -553,29 +600,56 @@ main(int argc, char **argv)
assert(pkg_filesd);
process_destdir();
/* Back to original cwd after file tree walk processing */
if (chdir(cwd) == -1)
die("cannot chdir() to cwd %s:", cwd);
/*
* Create the real XBPS binary package (ustar compressed with xz).
* Create a temp file to store archive data.
*/
tname = xbps_xasprintf(".xbps-pkg-XXXXXX");
assert(tname);
pkg_fd = mkstemp(tname);
assert(pkg_fd != -1);
/*
* Process the binary package's archive (ustar compressed with xz).
*/
ar = archive_write_new();
assert(ar);
archive_write_add_filter_xz(ar);
archive_write_set_format_ustar(ar);
archive_write_set_options(ar, "compression-level=9");
binpkg = xbps_xasprintf("%s.%s.xbps", pkgver, arch);
assert(binpkg);
if (archive_write_open_filename(ar, binpkg) != 0)
die("failed to create %s:", binpkg);
if (archive_write_open_fd(ar, pkg_fd) != 0)
die("Failed to open %s fd for writing:", tname);
process_archive(ar, pkgver);
archive_write_free(ar);
/*
* Archive was created successfully; flush data to storage,
* set permissions and rename to dest file; from the caller's
* perspective it's atomic.
*/
binpkg = xbps_xasprintf("%s.%s.xbps", pkgver, arch);
assert(binpkg);
printf("%s: binary package created successfully: %s.\n", pkgver, binpkg);
(void)fsync(pkg_fd);
myumask = umask(0);
(void)umask(myumask);
if (fchmod(pkg_fd, 0666 & ~myumask) == -1)
die("cannot fchmod() %s:", tname);
if (rename(tname, binpkg) == -1)
die("cannot rename %s to %s:", tname, binpkg);
/* Success, release resources */
printf("%s: binary package created successfully (%s)\n", pkgver, binpkg);
prop_object_release(pkg_propsd);
prop_object_release(pkg_filesd);
free(binpkg);
free(pkgname);
close(pkg_fd);
prop_object_release(pkg_propsd);
prop_object_release(pkg_filesd);
exit(EXIT_SUCCESS);
}