xbps-fbulk: misc changes (v3).
- Re-add original behaviour now I fixed the real issue for missing logs. Keep the build/run pipeline full as soon as possible. - Added -s, --system. System build mode. To only build pkgs that are installed manually in your system. - Added long options; sync usage. - Restrict max jobs to ncores; there are issues with shared data, and until they are resolved this is the only way to make it work reliably.
This commit is contained in:
parent
a1d66032bd
commit
1f4cfc377b
@ -38,7 +38,7 @@
|
|||||||
* This program iterates all srcpkgs directories, runs './xbps-src show-build-deps',
|
* This program iterates all srcpkgs directories, runs './xbps-src show-build-deps',
|
||||||
* and builds a dependency tree on the fly.
|
* and builds a dependency tree on the fly.
|
||||||
*
|
*
|
||||||
* When the dependency tree is built, terminal dependencies are built
|
* As the dependency tree is being built, terminal dependencies are built
|
||||||
* and packaged on the fly.
|
* and packaged on the fly.
|
||||||
*
|
*
|
||||||
* As these builds complete additional dependencies may be satisfied and be
|
* As these builds complete additional dependencies may be satisfied and be
|
||||||
@ -100,7 +100,6 @@ int NRunning;
|
|||||||
unsigned int NBuilt = 0;
|
unsigned int NBuilt = 0;
|
||||||
unsigned int NFinished = 0;
|
unsigned int NFinished = 0;
|
||||||
unsigned int NChecked = 0;
|
unsigned int NChecked = 0;
|
||||||
unsigned int NSkipped = 0;
|
|
||||||
unsigned int NTotal = 0;
|
unsigned int NTotal = 0;
|
||||||
char *LogDir;
|
char *LogDir;
|
||||||
|
|
||||||
@ -135,8 +134,14 @@ addItem(const char *pkgn)
|
|||||||
static void __attribute__((noreturn))
|
static void __attribute__((noreturn))
|
||||||
usage(const char *progname)
|
usage(const char *progname)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s [-h] [-j procs] [-l logdir] [-V]"
|
fprintf(stderr, "%s [OPTIONS] /path/to/void-packages [pkg pkg+N]\n"
|
||||||
" /path/to/void-packages [pkg pkgN]\n", progname);
|
"OPTIONS\n"
|
||||||
|
" -j, --jobs <N> Number of parallel builds\n"
|
||||||
|
" -l, --logdir <path> Path to store logs\n"
|
||||||
|
" -s, --system System rebuild mode\n"
|
||||||
|
" -V, --verbose Enable verbose mode\n"
|
||||||
|
" -v, --version Show XBPS version\n"
|
||||||
|
" -h, --help Show usage\n\n", progname);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +176,7 @@ processCompletion(struct item *item)
|
|||||||
assert(item);
|
assert(item);
|
||||||
/*
|
/*
|
||||||
* If XRUN we have to move the logfile to the correct directory.
|
* If XRUN we have to move the logfile to the correct directory.
|
||||||
* (If XDEPFAIL the log is at correct location).
|
* (If XDEPFAIL the logfile is already in the correct directory).
|
||||||
*/
|
*/
|
||||||
if (item->status == XRUN) {
|
if (item->status == XRUN) {
|
||||||
logpath = xbps_xasprintf("%s/run/%s.txt", LogDir, item->pkgn);
|
logpath = xbps_xasprintf("%s/run/%s.txt", LogDir, item->pkgn);
|
||||||
@ -192,9 +197,18 @@ processCompletion(struct item *item)
|
|||||||
free(logpath2);
|
free(logpath2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure that item has already run (XRUN) or
|
||||||
|
* failed due to dependencies (XDEPFAIL).
|
||||||
|
*
|
||||||
|
* When XWAITING the item is waiting for its dependencies.
|
||||||
|
* When XBUILD the item is in the build list.
|
||||||
|
*/
|
||||||
assert(item->status == XRUN || item->status == XDEPFAIL);
|
assert(item->status == XRUN || item->status == XDEPFAIL);
|
||||||
item->status = XDONE;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process reverse dependencies for the item.
|
||||||
|
*/
|
||||||
for (depn = item->dbase; depn; depn = depn->dnext) {
|
for (depn = item->dbase; depn; depn = depn->dnext) {
|
||||||
xitem = depn->item;
|
xitem = depn->item;
|
||||||
assert(xitem->dcount > 0);
|
assert(xitem->dcount > 0);
|
||||||
@ -224,10 +238,13 @@ processCompletion(struct item *item)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(logpath);
|
free(logpath);
|
||||||
processCompletion(xitem);
|
processCompletion(xitem);
|
||||||
++NSkipped;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Item has been processed successfully.
|
||||||
|
*/
|
||||||
|
item->status = XDONE;
|
||||||
++NFinished;
|
++NFinished;
|
||||||
|
|
||||||
printf("[%u/%u] Finished %s (PID: %u RET: %d)\n",
|
printf("[%u/%u] Finished %s (PID: %u RET: %d)\n",
|
||||||
@ -255,6 +272,10 @@ waitRunning(int flags)
|
|||||||
while (((pid = waitpid(0, &status, flags)) < 0) && !flags)
|
while (((pid = waitpid(0, &status, flags)) < 0) && !flags)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE! The pid may be associated with one of our popen()'s
|
||||||
|
* so just ignore it if we cannot find it.
|
||||||
|
*/
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
status = WEXITSTATUS(status);
|
status = WEXITSTATUS(status);
|
||||||
itemp = &RunList;
|
itemp = &RunList;
|
||||||
@ -270,6 +291,8 @@ waitRunning(int flags)
|
|||||||
--NRunning;
|
--NRunning;
|
||||||
processCompletion(item);
|
processCompletion(item);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
item = NULL;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@ -279,7 +302,9 @@ waitRunning(int flags)
|
|||||||
* which can potentialy add new items to the build list.
|
* which can potentialy add new items to the build list.
|
||||||
*
|
*
|
||||||
* This routine will maintain up to NParallel builds. A new build is
|
* This routine will maintain up to NParallel builds. A new build is
|
||||||
* only started once its dependencies have been completed successfully.
|
* only started once its dependencies have completed successfully so
|
||||||
|
* when the bulk build starts it typically takes a little while before
|
||||||
|
* xbps-fbulk can keep the parallel pipeline full.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
runBuilds(const char *bpath)
|
runBuilds(const char *bpath)
|
||||||
@ -322,7 +347,6 @@ runBuilds(const char *bpath)
|
|||||||
if (chdir(bpath) < 0)
|
if (chdir(bpath) < 0)
|
||||||
_exit(99);
|
_exit(99);
|
||||||
|
|
||||||
|
|
||||||
fd = open(logpath, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
fd = open(logpath, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||||
if (fd != 1)
|
if (fd != 1)
|
||||||
dup2(fd, 1);
|
dup2(fd, 1);
|
||||||
@ -360,7 +384,7 @@ runBuilds(const char *bpath)
|
|||||||
++NRunning;
|
++NRunning;
|
||||||
++NBuilt;
|
++NBuilt;
|
||||||
printf("[%u/%u] Building %s (PID: %u)\n",
|
printf("[%u/%u] Building %s (PID: %u)\n",
|
||||||
NBuilt+NSkipped, NTotal, item->pkgn, item->pid);
|
NBuilt, NTotal, item->pkgn, item->pid);
|
||||||
}
|
}
|
||||||
free(logpath);
|
free(logpath);
|
||||||
}
|
}
|
||||||
@ -381,6 +405,8 @@ static void
|
|||||||
addDepn(struct item *item, struct item *xitem)
|
addDepn(struct item *item, struct item *xitem)
|
||||||
{
|
{
|
||||||
struct depn *depn = malloc(sizeof(struct depn));
|
struct depn *depn = malloc(sizeof(struct depn));
|
||||||
|
FILE *fp;
|
||||||
|
char *logpath;
|
||||||
|
|
||||||
assert(item);
|
assert(item);
|
||||||
assert(xitem);
|
assert(xitem);
|
||||||
@ -389,8 +415,28 @@ addDepn(struct item *item, struct item *xitem)
|
|||||||
depn->item = item;
|
depn->item = item;
|
||||||
depn->dnext = xitem->dbase;
|
depn->dnext = xitem->dbase;
|
||||||
xitem->dbase = depn;
|
xitem->dbase = depn;
|
||||||
|
if (xitem->status == XDONE) {
|
||||||
|
if (xitem->xcode) {
|
||||||
|
/*
|
||||||
|
* If reverse dependency has failed,
|
||||||
|
* current item also failed!
|
||||||
|
*/
|
||||||
|
assert(item->status == XWAITING ||
|
||||||
|
item->status == XDEPFAIL);
|
||||||
|
item->xcode = xitem->xcode;
|
||||||
|
item->status = XDEPFAIL;
|
||||||
|
logpath = xbps_xasprintf("%s/deps/%s.txt",
|
||||||
|
LogDir, item->pkgn);
|
||||||
|
fp = fopen(logpath, "a");
|
||||||
|
fprintf(fp, "%s\n", xitem->pkgn);
|
||||||
|
fclose(fp);
|
||||||
|
free(logpath);
|
||||||
|
++NBuilt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
++item->dcount;
|
++item->dcount;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recursively execute 'xbps-src show-build-deps' to calculate all required
|
* Recursively execute 'xbps-src show-build-deps' to calculate all required
|
||||||
@ -408,7 +454,8 @@ ordered_depends(const char *bpath, const char *pkgn)
|
|||||||
|
|
||||||
item = addItem(pkgn);
|
item = addItem(pkgn);
|
||||||
/*
|
/*
|
||||||
* Retrieve and process dependencies recursively.
|
* Retrieve and process dependencies recursively. Note that
|
||||||
|
* addDepn() can modify item's status.
|
||||||
*/
|
*/
|
||||||
++NChecked;
|
++NChecked;
|
||||||
printf("[%u] Checking %s\n", NChecked, item->pkgn);
|
printf("[%u] Checking %s\n", NChecked, item->pkgn);
|
||||||
@ -456,20 +503,59 @@ ordered_depends(const char *bpath, const char *pkgn)
|
|||||||
pclose(fp);
|
pclose(fp);
|
||||||
++NTotal;
|
++NTotal;
|
||||||
/*
|
/*
|
||||||
* If the item has no dependencies left add it to the build list.
|
* If the item has no dependencies left either add it to the
|
||||||
|
* build list or do completion processing (i.e. if some of the
|
||||||
|
* dependencies failed).
|
||||||
*/
|
*/
|
||||||
if (item->dcount == 0) {
|
if (item->dcount == 0) {
|
||||||
|
switch (item->status) {
|
||||||
|
case XWAITING:
|
||||||
addBuild(item);
|
addBuild(item);
|
||||||
|
break;
|
||||||
|
case XDEPFAIL:
|
||||||
|
processCompletion(item);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* Might happen due to excessive NParallel jobs!
|
||||||
|
* Error out because this is critical.
|
||||||
|
*/
|
||||||
|
printf("%s: item->xcode %d item->status %d\n",
|
||||||
|
item->pkgn, item->xcode, item->status);
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (VerboseOpt)
|
if (VerboseOpt)
|
||||||
printf("Deferred package: %s\n", item->pkgn);
|
printf("Deferred package: %s\n", item->pkgn);
|
||||||
}
|
}
|
||||||
|
runBuilds(bpath);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pkgdb_get_pkgs_cb(struct xbps_handle *xhp UNUSED,
|
||||||
|
xbps_object_t obj, const char *key UNUSED,
|
||||||
|
void *arg, bool *done UNUSED)
|
||||||
|
{
|
||||||
|
xbps_array_t *array = arg;
|
||||||
|
const char *pkgname;
|
||||||
|
bool automatic = false;
|
||||||
|
|
||||||
|
xbps_dictionary_get_bool(obj, "automatic-install", &automatic);
|
||||||
|
if (automatic)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
|
||||||
|
xbps_array_add_cstring_nocopy(*array, pkgname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
struct xbps_handle xh = {0};
|
||||||
|
xbps_array_t array;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *den;
|
struct dirent *den;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -477,13 +563,23 @@ main(int argc, char **argv)
|
|||||||
const char *logdirs[] = { "good", "bad", "run", "deps", "skipped" };
|
const char *logdirs[] = { "good", "bad", "run", "deps", "skipped" };
|
||||||
char *bpath, *rpath, *tmp, cwd[PATH_MAX];
|
char *bpath, *rpath, *tmp, cwd[PATH_MAX];
|
||||||
size_t blen;
|
size_t blen;
|
||||||
int ch;
|
int ch, NCores, rv;
|
||||||
|
bool RebuildSystem = false;
|
||||||
const struct option longopts[] = {
|
const struct option longopts[] = {
|
||||||
|
{ "system", no_argument, NULL, 's' },
|
||||||
|
{ "jobs", required_argument, NULL, 'j' },
|
||||||
|
{ "logdir", required_argument, NULL, 'l' },
|
||||||
|
{ "verbose", no_argument, NULL, 'v' },
|
||||||
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv, "hj:l:vV", longopts, NULL)) != -1) {
|
while ((ch = getopt_long(argc, argv, "hj:l:svV", longopts, NULL)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case 's':
|
||||||
|
RebuildSystem = true;
|
||||||
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
NParallel = strtol(optarg, NULL, 0);
|
NParallel = strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
@ -510,6 +606,16 @@ main(int argc, char **argv)
|
|||||||
/* NOT REACHED */
|
/* NOT REACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME
|
||||||
|
* Limit NParallel to max cores, due to program design
|
||||||
|
* this won't work when it's higher, and we'd need to
|
||||||
|
* synchronize shared data!
|
||||||
|
*/
|
||||||
|
NCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (NParallel > NCores)
|
||||||
|
NParallel = NCores;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check masterdir is properly initialized.
|
* Check masterdir is properly initialized.
|
||||||
*/
|
*/
|
||||||
@ -560,6 +666,34 @@ main(int argc, char **argv)
|
|||||||
free(tmp);
|
free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RebuildSystem: only rebuild packages that were installed
|
||||||
|
* manually.
|
||||||
|
*/
|
||||||
|
if (RebuildSystem) {
|
||||||
|
rv = xbps_init(&xh);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "ERROR: failed to initialize libxbps: %s", strerror(rv));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
array = xbps_array_create();
|
||||||
|
rv = xbps_pkgdb_foreach_cb_multi(&xh, pkgdb_get_pkgs_cb, &array);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "ERROR: xbps_pkgdb_foreach_cb_multi: %s", strerror(rv));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < xbps_array_count(array); i++) {
|
||||||
|
const char *pkgname = NULL;
|
||||||
|
|
||||||
|
xbps_array_get_cstring_nocopy(array, i, &pkgname);
|
||||||
|
if (pkgname && !lookupItem(pkgname)) {
|
||||||
|
ordered_depends(bpath, pkgname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xbps_end(&xh);
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate dependency tree. This is done in two steps to know how
|
* Generate dependency tree. This is done in two steps to know how
|
||||||
* many packages will be built.
|
* many packages will be built.
|
||||||
@ -606,9 +740,10 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
(void)closedir(dir);
|
(void)closedir(dir);
|
||||||
}
|
}
|
||||||
|
start:
|
||||||
/*
|
/*
|
||||||
* Start building collected packages, keep the pipeline full
|
* Wait for all current builds to finish running, keep the pipeline
|
||||||
* until both the BuildList and RunList have been exhausted.
|
* full until both the BuildList and RunList have been exhausted.
|
||||||
*/
|
*/
|
||||||
free(rpath);
|
free(rpath);
|
||||||
runBuilds(bpath);
|
runBuilds(bpath);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.Dd April 14, 2020
|
.Dd April 20, 2020
|
||||||
.Dt XBPS-FBULK 1
|
.Dt XBPS-FBULK 1
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm xbps-fbulk
|
.Nm xbps-fbulk
|
||||||
@ -7,7 +7,7 @@
|
|||||||
.Nm xbps-fbulk
|
.Nm xbps-fbulk
|
||||||
.Op OPTIONS
|
.Op OPTIONS
|
||||||
.Ar /path/to/void-packages
|
.Ar /path/to/void-packages
|
||||||
.Op pkgN pkgN+1 ...
|
.Op pkgN pkg+N ...
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
@ -19,22 +19,32 @@ arguments, and then runs
|
|||||||
.Ar 'xbps-src show-build-deps'
|
.Ar 'xbps-src show-build-deps'
|
||||||
to build a dependency tree on the fly.
|
to build a dependency tree on the fly.
|
||||||
.Pp
|
.Pp
|
||||||
When the dependency tree is built, terminal dependencies are built
|
As the dependency tree is built, terminal dependencies are built
|
||||||
and packaged on the fly.
|
and packaged on the fly.
|
||||||
.Pp
|
.Pp
|
||||||
As these builds complete additional dependencies may be satisfied and be
|
As these builds complete, additional dependencies may be satisfied and be
|
||||||
added to the build order. Ultimately the entire tree is built.
|
added to the build order. Ultimately the entire tree is built.
|
||||||
.Pp
|
.Pp
|
||||||
Only one attempt is made to build any given package, no matter how many
|
Only one attempt is made to build any given package, no matter how many
|
||||||
other packages depend on it.
|
other packages depend on it.
|
||||||
|
.Pp
|
||||||
|
When using
|
||||||
|
.Ar system mode
|
||||||
|
only installed packages that are in manual mode (see
|
||||||
|
.Xr xbps-pkgdb 1)
|
||||||
|
will be processed.
|
||||||
|
This is useful to keep up a running system up-to-date.
|
||||||
.Sh OPTIONS
|
.Sh OPTIONS
|
||||||
.Bl -tag -width -x
|
.Bl -tag -width -x
|
||||||
.It Fl j Ar X
|
.It Fl j, Fl -jobs Ar X
|
||||||
Set number of parallel builds running at the same time. By default set to 1.
|
Set number of parallel builds running at the same time. By default set to 1.
|
||||||
.It Fl l Ar logdir
|
.It Fl l, Fl -logdir Ar logdir
|
||||||
Set the log directory. By default set to `fbulk-log.<pid>`.
|
Set the log directory. By default set to `fbulk-log.<pid>`.
|
||||||
.It Fl d, Fl -debug
|
.It Fl d, Fl -debug
|
||||||
Enables extra debugging shown to stderr.
|
Enables extra debugging shown to stderr.
|
||||||
|
.It Fl s, Fl -system
|
||||||
|
System build mode. If set, only packages that were installed manually
|
||||||
|
in your system will be processed.
|
||||||
.It Fl h, Fl -help
|
.It Fl h, Fl -help
|
||||||
Show the help message.
|
Show the help message.
|
||||||
.It Fl v, Fl -verbose
|
.It Fl v, Fl -verbose
|
||||||
@ -53,7 +63,7 @@ Packages that failed to build.
|
|||||||
.It Ar logdir/skipped
|
.It Ar logdir/skipped
|
||||||
Packages that were not built because they had to be skipped (unsupported architecture, broken or restricted).
|
Packages that were not built because they had to be skipped (unsupported architecture, broken or restricted).
|
||||||
.It Ar logdir/deps
|
.It Ar logdir/deps
|
||||||
Packages that were not built due to missing dependencies.
|
Packages that were not built due to failed or missing dependencies.
|
||||||
.El
|
.El
|
||||||
.Sh NOTES
|
.Sh NOTES
|
||||||
The
|
The
|
||||||
|
Loading…
Reference in New Issue
Block a user