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:
parent
6d6d31ccc0
commit
215f6d6f31
@ -40,6 +40,9 @@
|
|||||||
#include <xbps_api.h>
|
#include <xbps_api.h>
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: Add a flag to set "packaged-with" object in XBPS_PKGPROPS?
|
||||||
|
*/
|
||||||
#define _PROGNAME "xbps-create"
|
#define _PROGNAME "xbps-create"
|
||||||
|
|
||||||
struct xentry {
|
struct xentry {
|
||||||
@ -50,6 +53,7 @@ struct xentry {
|
|||||||
static TAILQ_HEAD(xentry_head, xentry) xentry_list =
|
static TAILQ_HEAD(xentry_head, xentry) xentry_list =
|
||||||
TAILQ_HEAD_INITIALIZER(xentry_list);
|
TAILQ_HEAD_INITIALIZER(xentry_list);
|
||||||
|
|
||||||
|
static uint64_t instsize;
|
||||||
static prop_dictionary_t pkg_propsd, pkg_filesd;
|
static prop_dictionary_t pkg_propsd, pkg_filesd;
|
||||||
static const char *destdir;
|
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)sb;
|
||||||
(void)ftwbuf;
|
(void)ftwbuf;
|
||||||
|
|
||||||
|
/* Ignore metadata files generated by xbps-src and destdir */
|
||||||
if ((strcmp(fpath, ".") == 0) ||
|
if ((strcmp(fpath, ".") == 0) ||
|
||||||
(strcmp(fpath, "./props.plist") == 0) ||
|
(strcmp(fpath, "./props.plist") == 0) ||
|
||||||
(strcmp(fpath, "./files.plist") == 0))
|
(strcmp(fpath, "./files.plist") == 0) ||
|
||||||
|
(strcmp(fpath, "./flist") == 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* sanitized file path */
|
/* sanitized file path */
|
||||||
filep = strchr(fpath, '/') + 1;
|
filep = strchr(fpath, '.') + 1;
|
||||||
|
|
||||||
xe = calloc(1, sizeof(*xe));
|
xe = calloc(1, sizeof(*xe));
|
||||||
assert(xe);
|
assert(xe);
|
||||||
xe->file = strdup(filep);
|
xe->file = strdup(fpath);
|
||||||
assert(xe->file);
|
assert(xe->file);
|
||||||
|
|
||||||
if ((strcmp(fpath, "./INSTALL") == 0) ||
|
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) {
|
if (type == FTW_SL) {
|
||||||
/* symlink */
|
/*
|
||||||
|
* Symlinks.
|
||||||
|
*
|
||||||
|
* Find out target file.
|
||||||
|
*/
|
||||||
xe->type = strdup("links");
|
xe->type = strdup("links");
|
||||||
assert(xe->type);
|
assert(xe->type);
|
||||||
/* Find out target file */
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
memset(&buf, 0, sizeof(buf));
|
||||||
if (realpath(fpath, buf) == NULL)
|
if (realpath(fpath, buf) == NULL)
|
||||||
die("failed to process symlink `%s':", filep);
|
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);
|
xe->target = strdup(filep);
|
||||||
assert(xe->target);
|
assert(xe->target);
|
||||||
} else if (type == FTW_F) {
|
} 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))
|
if (entry_is_conf_file(filep))
|
||||||
xe->type = strdup("conf_files");
|
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");
|
xe->type = strdup("files");
|
||||||
|
|
||||||
assert(xe->type);
|
assert(xe->type);
|
||||||
/* calculate sha256 hash */
|
|
||||||
if ((xe->hash = xbps_file_hash(fpath)) == NULL)
|
if ((xe->hash = xbps_file_hash(fpath)) == NULL)
|
||||||
die("failed to process hash for %s:", fpath);
|
die("failed to process hash for %s:", fpath);
|
||||||
|
|
||||||
|
instsize += sb->st_size;
|
||||||
|
|
||||||
} else if (type == FTW_D) {
|
} else if (type == FTW_D) {
|
||||||
/* directory */
|
/* directory */
|
||||||
xe->type = strdup("dirs");
|
xe->type = strdup("dirs");
|
||||||
@ -230,6 +241,7 @@ process_xentry(const char *key)
|
|||||||
prop_array_t a;
|
prop_array_t a;
|
||||||
prop_dictionary_t d;
|
prop_dictionary_t d;
|
||||||
struct xentry *xe;
|
struct xentry *xe;
|
||||||
|
char *p;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
a = prop_array_create();
|
a = prop_array_create();
|
||||||
@ -242,7 +254,9 @@ process_xentry(const char *key)
|
|||||||
found = true;
|
found = true;
|
||||||
d = prop_dictionary_create();
|
d = prop_dictionary_create();
|
||||||
assert(d);
|
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)
|
if (xe->target)
|
||||||
prop_dictionary_set_cstring(d, "target", xe->target);
|
prop_dictionary_set_cstring(d, "target", xe->target);
|
||||||
else if (xe->hash)
|
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 *ard;
|
||||||
struct archive_entry *entry;
|
struct archive_entry *entry;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ], *p;
|
||||||
int fd;
|
int fd;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@ -299,8 +313,11 @@ process_entry_file(struct archive *ar, struct xentry *xe, const char *filematch)
|
|||||||
assert(entry);
|
assert(entry);
|
||||||
archive_entry_set_pathname(entry, xe->file);
|
archive_entry_set_pathname(entry, xe->file);
|
||||||
|
|
||||||
if ((fd = open(xe->file, O_RDONLY)) == -1)
|
p = xbps_xasprintf("%s/%s", destdir, xe->file);
|
||||||
die("failed to add entry (open) %s to archive:", 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)
|
if ((archive_read_disk_entry_from_file(ard, entry, fd, NULL)) != 0)
|
||||||
die("failed to add entry %s to archive:", xe->file);
|
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)
|
while ((len = read(fd, buf, sizeof(buf))) > 0)
|
||||||
archive_write_data(ar, buf, len);
|
archive_write_data(ar, buf, len);
|
||||||
|
|
||||||
|
free(p);
|
||||||
close(fd);
|
close(fd);
|
||||||
archive_entry_free(entry);
|
archive_entry_free(entry);
|
||||||
archive_read_free(ard);
|
archive_read_free(ard);
|
||||||
@ -365,20 +383,24 @@ process_archive(struct archive *ar, const char *pkgver)
|
|||||||
|
|
||||||
/* Add INSTALL/REMOVE metadata scripts first */
|
/* Add INSTALL/REMOVE metadata scripts first */
|
||||||
TAILQ_FOREACH(xe, &xentry_list, entries) {
|
TAILQ_FOREACH(xe, &xentry_list, entries) {
|
||||||
process_entry_file(ar, xe, "INSTALL");
|
process_entry_file(ar, xe, "./INSTALL");
|
||||||
process_entry_file(ar, xe, "REMOVE");
|
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 */
|
/* Add props.plist metadata file */
|
||||||
xml = prop_dictionary_externalize(pkg_propsd);
|
xml = prop_dictionary_externalize(pkg_propsd);
|
||||||
assert(xml);
|
assert(xml);
|
||||||
process_entry_memory(ar, xml, "props.plist");
|
process_entry_memory(ar, xml, "./props.plist");
|
||||||
free(xml);
|
free(xml);
|
||||||
|
|
||||||
/* Add files.plist metadata file */
|
/* Add files.plist metadata file */
|
||||||
xml = prop_dictionary_externalize(pkg_filesd);
|
xml = prop_dictionary_externalize(pkg_filesd);
|
||||||
assert(xml);
|
assert(xml);
|
||||||
process_entry_memory(ar, xml, "files.plist");
|
process_entry_memory(ar, xml, "./files.plist");
|
||||||
free(xml);
|
free(xml);
|
||||||
|
|
||||||
/* Add all package data files and release resources */
|
/* 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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -423,9 +463,10 @@ main(int argc, char **argv)
|
|||||||
const char *conflicts, *deps, *homepage, *license, *maint;
|
const char *conflicts, *deps, *homepage, *license, *maint;
|
||||||
const char *provides, *pkgver, *replaces, *desc, *ldesc;
|
const char *provides, *pkgver, *replaces, *desc, *ldesc;
|
||||||
const char *arch, *config_files, *mutable_files, *version;
|
const char *arch, *config_files, *mutable_files, *version;
|
||||||
char *pkgname, *binpkg;
|
char *pkgname, *binpkg, *tname, *p, cwd[PATH_MAX-1];
|
||||||
bool preserve = false;
|
bool preserve = false;
|
||||||
int c;
|
int c, pkg_fd;
|
||||||
|
mode_t myumask;
|
||||||
|
|
||||||
arch = conflicts = deps = homepage = license = maint = NULL;
|
arch = conflicts = deps = homepage = license = maint = NULL;
|
||||||
provides = pkgver = replaces = desc = ldesc = 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, "version", version);
|
||||||
prop_dictionary_set_cstring_nocopy(pkg_propsd, "pkgver", pkgver);
|
prop_dictionary_set_cstring_nocopy(pkg_propsd, "pkgver", pkgver);
|
||||||
prop_dictionary_set_cstring_nocopy(pkg_propsd, "short_desc", desc);
|
prop_dictionary_set_cstring_nocopy(pkg_propsd, "short_desc", desc);
|
||||||
|
set_build_date();
|
||||||
|
|
||||||
/* Optional properties */
|
/* Optional properties */
|
||||||
if (homepage)
|
if (homepage)
|
||||||
@ -544,8 +586,13 @@ main(int argc, char **argv)
|
|||||||
process_array("provides", provides);
|
process_array("provides", provides);
|
||||||
process_array("replaces", replaces);
|
process_array("replaces", replaces);
|
||||||
|
|
||||||
|
/* save cwd */
|
||||||
|
memset(&cwd, 0, sizeof(cwd));
|
||||||
|
p = getcwd(cwd, sizeof(cwd));
|
||||||
|
assert(p);
|
||||||
|
|
||||||
if (chdir(destdir) == -1)
|
if (chdir(destdir) == -1)
|
||||||
die("cannot chdir() to destdir:");
|
die("cannot chdir() to destdir %s:", destdir);
|
||||||
/*
|
/*
|
||||||
* Process XBPS_PKGFILES metadata file.
|
* Process XBPS_PKGFILES metadata file.
|
||||||
*/
|
*/
|
||||||
@ -553,29 +600,56 @@ main(int argc, char **argv)
|
|||||||
assert(pkg_filesd);
|
assert(pkg_filesd);
|
||||||
process_destdir();
|
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();
|
ar = archive_write_new();
|
||||||
assert(ar);
|
assert(ar);
|
||||||
archive_write_add_filter_xz(ar);
|
archive_write_add_filter_xz(ar);
|
||||||
archive_write_set_format_ustar(ar);
|
archive_write_set_format_ustar(ar);
|
||||||
archive_write_set_options(ar, "compression-level=9");
|
archive_write_set_options(ar, "compression-level=9");
|
||||||
|
if (archive_write_open_fd(ar, pkg_fd) != 0)
|
||||||
binpkg = xbps_xasprintf("%s.%s.xbps", pkgver, arch);
|
die("Failed to open %s fd for writing:", tname);
|
||||||
assert(binpkg);
|
|
||||||
if (archive_write_open_filename(ar, binpkg) != 0)
|
|
||||||
die("failed to create %s:", binpkg);
|
|
||||||
|
|
||||||
process_archive(ar, pkgver);
|
process_archive(ar, pkgver);
|
||||||
archive_write_free(ar);
|
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(binpkg);
|
||||||
free(pkgname);
|
free(pkgname);
|
||||||
|
close(pkg_fd);
|
||||||
|
prop_object_release(pkg_propsd);
|
||||||
|
prop_object_release(pkg_filesd);
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user