diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 1990c2f5..35907f55 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -26,7 +26,7 @@ jobs: libseccomp-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \ libgirepository1.0-dev libappstream-dev libdconf-dev clang socat flatpak \ libcurl4-gnutls-dev libflatpak-dev libyaml-dev elfutils git patch libarchive-tools \ - docbook-xsl xmlto xsltproc + docbook-xsl xmlto xsltproc git-lfs - name: Check out flatpak uses: actions/checkout@v4 with: @@ -59,7 +59,7 @@ jobs: libseccomp-dev libsystemd-dev libxml2-utils libgpgme11-dev gobject-introspection \ libgirepository1.0-dev libappstream-dev libdconf-dev clang flatpak \ libcurl4-gnutls-dev libflatpak-dev libyaml-dev elfutils git patch libarchive-tools \ - docbook-xsl xmlto xsltproc + docbook-xsl xmlto xsltproc git-lfs - name: Check out flatpak uses: actions/checkout@v4 with: @@ -135,7 +135,8 @@ jobs: libarchive-tools \ docbook-xsl \ xmlto \ - xsltproc + xsltproc \ + git-lfs - name: Check out flatpak-builder uses: actions/checkout@v4 diff --git a/README.md b/README.md index 852cfc7c..10f3ec1d 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Very commonly used: * git * 7z * bsdunzip (libarchive) + * git-lfs Rarely used: diff --git a/data/flatpak-manifest.schema.json b/data/flatpak-manifest.schema.json index 6172c1fd..b9bb8be4 100644 --- a/data/flatpak-manifest.schema.json +++ b/data/flatpak-manifest.schema.json @@ -840,6 +840,10 @@ "disable-submodules": { "description": "Don't checkout the git submodules when cloning the repository.", "type": "boolean" + }, + "disable-lfs": { + "description": "Don't explicitly fetch or checkout LFS git objects.", + "type": "boolean" } }, "patternProperties": { diff --git a/doc/flatpak-manifest.xml b/doc/flatpak-manifest.xml index f0536636..1bd03591 100644 --- a/doc/flatpak-manifest.xml +++ b/doc/flatpak-manifest.xml @@ -772,6 +772,10 @@ (boolean) Don't checkout the git submodules when cloning the repository. + + (boolean) + Don't explicitly fetch or checkout LFS git objects. This will be ignored by Git if LFS filters are active in system or global gitconfig. + diff --git a/src/builder-git.c b/src/builder-git.c index 64b48eb8..b1f14063 100644 --- a/src/builder-git.c +++ b/src/builder-git.c @@ -148,6 +148,89 @@ git_has_version (int major, return TRUE; } +static gboolean +git_lfs (GFile *dir, + char **output, + GSubprocessFlags flags, + GError **error, + const char **args) +{ + g_autoptr(GPtrArray) full_args = g_ptr_array_new (); + gboolean res; + + g_ptr_array_add (full_args, "git"); + g_ptr_array_add (full_args, "lfs"); + + for (const char **arg = args; *arg; arg++) + g_ptr_array_add (full_args, (char *) *arg); + + g_ptr_array_add (full_args, NULL); + + res = flatpak_spawnv (dir, output, flags, error, (const char **) full_args->pdata, NULL); + + return res; +} + +static gboolean +git_lfs_is_available (void) +{ + static gsize lfs_available = 0; + + if (g_once_init_enter (&lfs_available)) + { + g_autoptr(GError) my_error = NULL; + gsize new_lfs_available = 2; + + if (git_lfs (NULL, NULL, 0, &my_error, (const char *[]){"version", NULL})) + new_lfs_available = 1; + else + g_debug ("git-lfs is not available: %s", my_error->message); + + g_once_init_leave (&lfs_available, new_lfs_available); + } + + return lfs_available == 1; +} + +static gboolean +builder_git_run_lfs (GFile *dir, + FlatpakGitMirrorFlags flags, + GError **error, + const char *subcommand, + ...) +{ + va_list ap; + g_autoptr(GPtrArray) args = g_ptr_array_new (); + const char *arg; + gboolean ok; + + if (flags & FLATPAK_GIT_MIRROR_FLAGS_DISABLE_LFS) + return TRUE; + + if (!git_lfs_is_available ()) + return TRUE; + + g_ptr_array_add (args, (char *) subcommand); + + va_start (ap, subcommand); + while ((arg = va_arg (ap, const char *))) + g_ptr_array_add (args, (char *) arg); + va_end (ap); + + g_ptr_array_add (args, NULL); + + g_print ("Running git lfs %s\n", subcommand); + ok = git_lfs (dir, NULL, 0, error, (const char **) args->pdata); + + if (!ok) + { + git_lfs (dir, NULL, 0, NULL, (const char *[]){"logs", "last", NULL}); + return FALSE; + } + + return TRUE; +} + static gboolean git_version_supports_fsck_and_shallow (void) { @@ -578,6 +661,10 @@ builder_git_mirror_repo (const char *repo_location, origin, full_ref_mapping, NULL)) return FALSE; + if (!builder_git_run_lfs (mirror_dir, flags, error, + "fetch", "--all", NULL)) + return FALSE; + /* It turns out that older versions of git (at least 2.7.4) * cannot check out a commit unless a real tag/branch points * to it, which is not the case for e.g. gitbug pull requests. @@ -606,6 +693,10 @@ builder_git_mirror_repo (const char *repo_location, was_shallow ? "--unshallow" : NULL, NULL)) return FALSE; + + if (!builder_git_run_lfs (mirror_dir, flags, error, + "fetch", "--all", NULL)) + return FALSE; } if (alternates) @@ -708,6 +799,10 @@ builder_git_shallow_mirror_ref (const char *repo_location, "fetch", "--depth", "1", "origin", full_ref_colon_full_ref, NULL)) return FALSE; + if (!builder_git_run_lfs (mirror_dir, flags, error, + "fetch", "origin", full_ref, NULL)) + return FALSE; + /* Always mirror submodules */ current_commit = git_get_current_commit (mirror_dir, ref, FALSE, context, error); if (current_commit == NULL) @@ -858,10 +953,18 @@ builder_git_checkout (const char *repo_location, "config", "--bool", "core.bare", "false", NULL)) return FALSE; + if (!builder_git_run_lfs (dest, mirror_flags, error, + "install", "--local", NULL)) + return FALSE; + if (!git (dest, NULL, 0, error, "checkout", branch, NULL)) return FALSE; + if (!builder_git_run_lfs (dest, mirror_flags, error, + "checkout", NULL)) + return FALSE; + if (mirror_flags & FLATPAK_GIT_MIRROR_FLAGS_MIRROR_SUBMODULES) if (!git_extract_submodule (repo_location, dest, branch, context, error)) return FALSE; @@ -897,4 +1000,4 @@ builder_git_get_default_branch (const char *repo_location) g_debug ("Failed to auto-detect default branch from git output"); return g_strdup ("master"); -} \ No newline at end of file +} diff --git a/src/builder-git.h b/src/builder-git.h index d27fe5e4..db297795 100644 --- a/src/builder-git.h +++ b/src/builder-git.h @@ -31,6 +31,7 @@ typedef enum { FLATPAK_GIT_MIRROR_FLAGS_DISABLE_FSCK = 1 << 2, FLATPAK_GIT_MIRROR_FLAGS_DISABLE_SHALLOW = 1 << 3, FLATPAK_GIT_MIRROR_FLAGS_WILL_FETCH_FROM = 1 << 4, + FLATPAK_GIT_MIRROR_FLAGS_DISABLE_LFS = 1 << 5, } FlatpakGitMirrorFlags; gboolean builder_git_mirror_repo (const char *repo_location, diff --git a/src/builder-source-git.c b/src/builder-source-git.c index e6b9ad9f..cf26ff9b 100644 --- a/src/builder-source-git.c +++ b/src/builder-source-git.c @@ -48,6 +48,7 @@ struct BuilderSourceGit gboolean disable_fsckobjects; gboolean disable_shallow_clone; gboolean disable_submodules; + gboolean disable_lfs; }; typedef struct @@ -67,6 +68,7 @@ enum { PROP_DISABLE_FSCKOBJECTS, PROP_DISABLE_SHALLOW_CLONE, PROP_DISABLE_SUBMODULES, + PROP_DISABLE_LFS, LAST_PROP }; @@ -128,6 +130,10 @@ builder_source_git_get_property (GObject *object, g_value_set_boolean (value, self->disable_submodules); break; + case PROP_DISABLE_LFS: + g_value_set_boolean (value, self->disable_lfs); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -180,6 +186,10 @@ builder_source_git_set_property (GObject *object, self->disable_submodules = g_value_get_boolean (value); break; + case PROP_DISABLE_LFS: + self->disable_lfs = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -255,6 +265,8 @@ builder_source_git_download (BuilderSource *source, if (!self->disable_submodules) flags |= FLATPAK_GIT_MIRROR_FLAGS_MIRROR_SUBMODULES; + if (self->disable_lfs) + flags |= FLATPAK_GIT_MIRROR_FLAGS_DISABLE_LFS; if (update_vcs) flags |= FLATPAK_GIT_MIRROR_FLAGS_UPDATE; if (self->disable_fsckobjects) @@ -303,6 +315,9 @@ builder_source_git_extract (BuilderSource *source, if (!self->disable_submodules) mirror_flags |= FLATPAK_GIT_MIRROR_FLAGS_MIRROR_SUBMODULES; + if (self->disable_lfs) + mirror_flags |= FLATPAK_GIT_MIRROR_FLAGS_DISABLE_LFS; + if (!builder_git_checkout (location, get_branch (self, location), dest, context, mirror_flags, error)) return FALSE; @@ -336,6 +351,9 @@ builder_source_git_bundle (BuilderSource *source, if (!self->disable_submodules) flags |= FLATPAK_GIT_MIRROR_FLAGS_MIRROR_SUBMODULES; + if (self->disable_lfs) + flags |= FLATPAK_GIT_MIRROR_FLAGS_DISABLE_LFS; + if (!builder_git_shallow_mirror_ref (location, flatpak_file_get_path_cached (mirror_dir), flags, @@ -481,6 +499,14 @@ builder_source_git_class_init (BuilderSourceGitClass *klass) "", FALSE, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_DISABLE_LFS, + g_param_spec_boolean ("disable-lfs", + "", + "", + FALSE, + G_PARAM_READWRITE)); } static void