From: Michael Tremer Date: Thu, 19 Aug 2021 19:05:58 +0000 (+0000) Subject: repo: Add scaffolding/experimental code to compose repositories X-Git-Tag: 0.9.28~989 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c54d9960a5d7a6c2c1ccf00c6ed8993de0b61cce;p=pakfire.git repo: Add scaffolding/experimental code to compose repositories Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 46814ec0b..f3675e44a 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -1051,6 +1051,24 @@ static PyObject* Pakfire_open(PakfireObject* self, PyObject* args) { return object; } +static PyObject* Pakfire_repo_compose(PakfireObject* self, PyObject* args, PyObject* kwargs) { + char* kwlist[] = { "path", NULL }; + const char* path = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &path)) + return NULL; + + const int flags = 0; + + int r = pakfire_repo_compose(self->pakfire, path, flags); + if (r) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + static struct PyMethodDef Pakfire_methods[] = { { "bind", @@ -1154,6 +1172,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS, NULL, }, + { + "repo_compose", + (PyCFunction)Pakfire_repo_compose, + METH_VARARGS|METH_KEYWORDS, + NULL + }, { "search", (PyCFunction)Pakfire_search, diff --git a/src/libpakfire/include/pakfire/repo.h b/src/libpakfire/include/pakfire/repo.h index c9edbe6fe..40ccb8e27 100644 --- a/src/libpakfire/include/pakfire/repo.h +++ b/src/libpakfire/include/pakfire/repo.h @@ -88,6 +88,10 @@ int pakfire_repo_scan(struct pakfire_repo* repo, int flags); int pakfire_repo_refresh(struct pakfire_repo* repo, int force); +// Compose + +int pakfire_repo_compose(struct pakfire* pakfire, const char* path, int flags); + #ifdef PAKFIRE_PRIVATE #include diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 21fe73fe7..bea7c2bd2 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -234,6 +234,7 @@ global: # repo pakfire_repo_add_archive; pakfire_repo_cmp; + pakfire_repo_compose; pakfire_repo_count; pakfire_repo_clean; pakfire_repo_create; diff --git a/src/libpakfire/repo.c b/src/libpakfire/repo.c index 586cdfe8d..96d67344d 100644 --- a/src/libpakfire/repo.c +++ b/src/libpakfire/repo.c @@ -1020,3 +1020,140 @@ PAKFIRE_EXPORT int pakfire_repo_refresh(struct pakfire_repo* repo, int force) { // Refresh metadata return pakfire_repo_refresh_metadata(repo, force); } + +static int pakfire_repo_write_database(struct pakfire_repo* repo, const char* path) { + char database[PATH_MAX]; + char filename[NAME_MAX]; + char tmp[PATH_MAX]; + int r; + + // Create path for a temporary database export file + r = pakfire_string_format(tmp, "%s/repodata/.pakfire-solv.XXXXXX", path); + if (r < 0) + return r; + + // Create a temporary file to write to + FILE* f = pakfire_mktemp(tmp); + if (!f) { + ERROR(repo->pakfire, "Could not open temporary file for writing: %m\n"); + return 1; + } + + // Write the SOLV database to the temporary file + r = pakfire_repo_write_solv_fp(repo, f, 0); + if (r) { + ERROR(repo->pakfire, "Could not write SOLV data: %m\n"); + goto ERROR; + } + + // Close file + fclose(f); + f = NULL; + + // Create a filename for the database file + r = pakfire_strftime_now(filename, "repodata/%Y-%m-%d-%H%M.%s.db"); + if (r) { + ERROR(repo->pakfire, "Could not format database filename: %m\n"); + goto ERROR; + } + + // Make final database path + r = pakfire_path_join(database, path, filename); + if (r < 0) { + ERROR(repo->pakfire, "Could not join database path: %m\n"); + goto ERROR; + } + + // Link database to its destination + r = link(tmp, database); + if (r) { + ERROR(repo->pakfire, "Could not link database %s: %m\n", database); + goto ERROR; + } + +ERROR: + if (f) + fclose(f); + + // Remove temporary file + unlink(tmp); + + return r; +} + +static int pakfire_repo_write_metadata(struct pakfire_repo* repo) { + int r = 1; + + // This can only be called for local repositories + if (!pakfire_repo_is_local(repo)) { + errno = ENOTSUP; + return 1; + } + + // Fetch the base path + const char* path = pakfire_repo_get_path(repo); + if (!path) + return 1; + + // Write the database + r = pakfire_repo_write_database(repo, path); + if (r) + return r; + + return 0; +} + +PAKFIRE_EXPORT int pakfire_repo_compose(struct pakfire* pakfire, const char* path, int flags) { + struct pakfire_repo* repo = NULL; + int r; + + // path cannot be NULL + if (!path) { + errno = EINVAL; + return 1; + } + + char baseurl[PATH_MAX]; + + // Prefix path with file:// to form baseurl + r = pakfire_string_format(baseurl, "file://%s", path); + if (r < 0) + return 1; + + // Create a new temporary repository at path + r = pakfire_repo_create(&repo, pakfire, "@tmp"); + if (r) { + ERROR(pakfire, "Could not create a temporary repository: %m\n"); + return r; + } + + // Set baseurl to path + r = pakfire_repo_set_baseurl(repo, baseurl); + if (r) { + ERROR(pakfire, "Could not set baseurl %s: %m\n", baseurl); + goto ERROR; + } + + // Find everything that is already part of the repository + r = pakfire_repo_scan(repo, 0); + if (r) { + ERROR(pakfire, "Could not refresh repository: %m\n"); + goto ERROR; + } + + // XXX Add more files + + // Write metadata to disk + r = pakfire_repo_write_metadata(repo); + if (r) + goto ERROR; + + // Success + r = 0; + +ERROR: + pakfire_repo_clear(repo); + pakfire_repo_unref(repo); + + return r; +} diff --git a/src/scripts/pakfire-builder.in b/src/scripts/pakfire-builder.in index 28fb374e6..c5419e349 100644 --- a/src/scripts/pakfire-builder.in +++ b/src/scripts/pakfire-builder.in @@ -125,6 +125,26 @@ class Cli(object): help=_("List all currently enabled repositories")) repolist.set_defaults(func=self._repolist) + # Repo + repo = subparsers.add_parser("repo", + help=_("Deal with repositories")) + + repo_subparsers = repo.add_subparsers() + + # repo compose + repo_compose = repo_subparsers.add_parser("compose", + help=_("Create a new repository")) + repo_compose.add_argument("path", + help=_("The path to the repository"), + ) + repo_compose.add_argument("archive", nargs="+", + help=_("Archives to be added to this repository") + ) + repo_compose.add_argument("--key", + help=_("Key used to sign archives"), + ) + repo_compose.set_defaults(func=self._repo_compose) + # search search = subparsers.add_parser("search", help=_("Search for a given pattern")) search.add_argument("pattern", help=_("A pattern to search for")) @@ -269,6 +289,13 @@ class Cli(object): for repo in p.repos: print(FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))) + def _repo_compose(self, ns): + """ + Composes a repository + """ + p = self.pakfire(ns) + p.repo_compose(ns.path) + def _shell(self, ns): """ Open a shell in a build environment