]> git.ipfire.org Git - pakfire.git/commitdiff
repo: Add scaffolding/experimental code to compose repositories
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Aug 2021 19:05:58 +0000 (19:05 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Aug 2021 19:05:58 +0000 (19:05 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/pakfire.c
src/libpakfire/include/pakfire/repo.h
src/libpakfire/libpakfire.sym
src/libpakfire/repo.c
src/scripts/pakfire-builder.in

index 46814ec0b31cbb608596b20ac0cd868bcce98546..f3675e44a6b87cc19b94f1e96280d2dd3179cb5a 100644 (file)
@@ -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,
index c9edbe6fe3be36b03159cfb9bda25dbce52a3da3..40ccb8e27cf32d9a79563b371a82a429e3448b36 100644 (file)
@@ -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 <solv/repo.h>
index 21fe73fe746075eb2c2f85093f2c6cd553ba5a47..bea7c2bd21e7afb54ef29b98e35569d90fa9c07f 100644 (file)
@@ -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;
index 586cdfe8d383101b1fc21d33de86ef82d44fd670..96d67344d30bab713a08b8cb90bab4eb0d916214 100644 (file)
@@ -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;
+}
index 28fb374e61dd3501954b61f3e97a1505ac4fb2ce..c5419e34934dc5466044464ecc34ede343cdf97e 100644 (file)
@@ -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