Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package flatpak-builder for openSUSE:Factory 
checked in at 2026-08-21 22:17:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/flatpak-builder (Old)
 and      /work/SRC/openSUSE:Factory/.flatpak-builder.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "flatpak-builder"

Fri Aug 21 22:17:20 2026 rev:33 rq:1372896 version:1.4.10

Changes:
--------
--- /work/SRC/openSUSE:Factory/flatpak-builder/flatpak-builder.changes  
2026-04-21 12:48:10.934790655 +0200
+++ 
/work/SRC/openSUSE:Factory/.flatpak-builder.new.1258/flatpak-builder.changes    
    2026-08-21 22:17:22.825067144 +0200
@@ -1,0 +2,11 @@
+Thu Aug 20 11:47:54 UTC 2026 - Dominique Leuenberger <[email protected]>
+
+- Update to version 1.4.10:
+  + Rewrite locale migration to use fd-based traversal
+  + Various improvements to tests
+- Changes from version 1.4.9:
+  + Fix various leaks found by ASAN
+  + Fix various build warnings and fix the build with GCC 15 and
+    GLIBC 2.43
+
+-------------------------------------------------------------------

Old:
----
  flatpak-builder-1.4.8.tar.xz

New:
----
  flatpak-builder-1.4.10.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ flatpak-builder.spec ++++++
--- /var/tmp/diff_new_pack.v7yJRv/_old  2026-08-21 22:17:23.489090859 +0200
+++ /var/tmp/diff_new_pack.v7yJRv/_new  2026-08-21 22:17:23.491090931 +0200
@@ -22,7 +22,7 @@
 %bcond_without system_debugedit
 %endif
 Name:           flatpak-builder
-Version:        1.4.8
+Version:        1.4.10
 Release:        0
 Summary:        Tool to build flatpaks from source
 License:        LGPL-2.1-or-later

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.v7yJRv/_old  2026-08-21 22:17:23.529092288 +0200
+++ /var/tmp/diff_new_pack.v7yJRv/_new  2026-08-21 22:17:23.532092395 +0200
@@ -1,6 +1,6 @@
-mtime: 1776647994
-commit: d18852ec71cbebc4d88d5818f74f61159c877a1df780ccc12456d8240795a2a1
+mtime: 1787226539
+commit: 93838cc2b09c9dd2e22409c769ca185431e4f62d209a64567b3601ac1bd039aa
 url: https://src.opensuse.org/GNOME/flatpak-builder
-revision: d18852ec71cbebc4d88d5818f74f61159c877a1df780ccc12456d8240795a2a1
+revision: 93838cc2b09c9dd2e22409c769ca185431e4f62d209a64567b3601ac1bd039aa
 projectscmsync: https://src.opensuse.org/GNOME/_ObsPrj
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-08-20 13:48:59.000000000 +0200
@@ -0,0 +1,4 @@
+*.obscpio
+*.osc
+_build.*
+.pbuild

++++++ flatpak-builder-1.4.8.tar.xz -> flatpak-builder-1.4.10.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/Makefile.in 
new/flatpak-builder-1.4.10/Makefile.in
--- old/flatpak-builder-1.4.8/Makefile.in       2026-04-09 20:49:54.000000000 
+0200
+++ new/flatpak-builder-1.4.10/Makefile.in      2026-06-18 03:03:50.000000000 
+0200
@@ -650,7 +650,8 @@
 RECHECK_LOGS = $(TEST_LOGS)
 am__EXEEXT_6 = tests/test-builder.sh tests/test-builder-deprecated.sh \
        tests/test-builder-python.sh tests/test-builder-cleanup.sh \
-       tests/test-builder-licence-paths.sh $(am__EXEEXT_1)
+       tests/test-builder-licence-paths.sh \
+       tests/test-builder-locale-migration.sh $(am__EXEEXT_1)
 TEST_SUITE_LOG = test-suite.log
 TEST_EXTENSIONS = @EXEEXT@ .test
 LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
@@ -1155,6 +1156,7 @@
        tests/test-builder-python.sh \
        tests/test-builder-cleanup.sh \
        tests/test-builder-licence-paths.sh \
+       tests/test-builder-locale-migration.sh \
        $(NULL)
 
 VALGRIND_SUPPRESSIONS_FILES = tests/flatpak.supp tests/glib.supp
@@ -2810,6 +2812,13 @@
        $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
        --log-file $$b.log --trs-file $$b.trs \
        $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) 
-- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
+tests/test-builder-locale-migration.sh.log: 
tests/test-builder-locale-migration.sh
+       @p='tests/test-builder-locale-migration.sh'; \
+       b='tests/test-builder-locale-migration.sh'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) 
-- $(LOG_COMPILE) \
        "$$tst" $(AM_TESTS_FD_REDIRECT)
 test-libglnx-xattrs.log: test-libglnx-xattrs$(EXEEXT)
        @p='test-libglnx-xattrs$(EXEEXT)'; \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/NEWS 
new/flatpak-builder-1.4.10/NEWS
--- old/flatpak-builder-1.4.8/NEWS      2026-04-09 20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/NEWS     2026-06-18 03:01:50.000000000 +0200
@@ -1,3 +1,15 @@
+Changes in 1.4.10
+=================
+
+* Rewrite locale migration to use fd-based traversal
+* Various improvements to tests
+
+Changes in 1.4.9
+================
+
+* Fix various leaks found by ASAN
+* Fix various build warnings and fix the build with GCC 15 and GLIBC 2.43
+
 Changes in 1.4.8
 ================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/configure 
new/flatpak-builder-1.4.10/configure
--- old/flatpak-builder-1.4.8/configure 2026-04-09 20:49:53.000000000 +0200
+++ new/flatpak-builder-1.4.10/configure        2026-06-18 03:03:49.000000000 
+0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for flatpak-builder 1.4.8.
+# Generated by GNU Autoconf 2.71 for flatpak-builder 1.4.10.
 #
 # Report bugs to <https://github.com/flatpak/flatpak-builder/issues>.
 #
@@ -621,8 +621,8 @@
 # Identity of this package.
 PACKAGE_NAME='flatpak-builder'
 PACKAGE_TARNAME='flatpak-builder'
-PACKAGE_VERSION='1.4.8'
-PACKAGE_STRING='flatpak-builder 1.4.8'
+PACKAGE_VERSION='1.4.10'
+PACKAGE_STRING='flatpak-builder 1.4.10'
 PACKAGE_BUGREPORT='https://github.com/flatpak/flatpak-builder/issues'
 PACKAGE_URL='http://flatpak.org/'
 
@@ -1444,7 +1444,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures flatpak-builder 1.4.8 to adapt to many kinds of 
systems.
+\`configure' configures flatpak-builder 1.4.10 to adapt to many kinds of 
systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1515,7 +1515,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of flatpak-builder 1.4.8:";;
+     short | recursive ) echo "Configuration of flatpak-builder 1.4.10:";;
    esac
   cat <<\_ACEOF
 
@@ -1672,7 +1672,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-flatpak-builder configure 1.4.8
+flatpak-builder configure 1.4.10
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2023,7 +2023,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by flatpak-builder $as_me 1.4.8, which was
+It was created by flatpak-builder $as_me 1.4.10, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -14150,7 +14150,7 @@
 
 # Define the identity of the package.
  PACKAGE='flatpak-builder'
- VERSION='1.4.8'
+ VERSION='1.4.10'
 
 
 # Some tools Automake needs.
@@ -18218,7 +18218,7 @@
   fi
 
 
-FLATPAK_BUILDER_VERSION=1.4.8
+FLATPAK_BUILDER_VERSION=1.4.10
 
 
 ac_config_files="$ac_config_files Makefile data/Makefile doc/Makefile 
doc/flatpak-builder-docs.xml"
@@ -18778,7 +18778,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by flatpak-builder $as_me 1.4.8, which was
+This file was extended by flatpak-builder $as_me 1.4.10, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -18847,7 +18847,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-flatpak-builder config.status 1.4.8
+flatpak-builder config.status 1.4.10
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/configure.ac 
new/flatpak-builder-1.4.10/configure.ac
--- old/flatpak-builder-1.4.8/configure.ac      2026-04-09 20:47:23.000000000 
+0200
+++ new/flatpak-builder-1.4.10/configure.ac     2026-06-18 03:01:50.000000000 
+0200
@@ -2,7 +2,7 @@
 
 m4_define([flatpak_builder_major_version], [1])
 m4_define([flatpak_builder_minor_version], [4])
-m4_define([flatpak_builder_micro_version], [8])
+m4_define([flatpak_builder_micro_version], [10])
 m4_define([flatpak_builder_version],
           
[flatpak_builder_major_version.flatpak_builder_minor_version.flatpak_builder_micro_version])
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/meson.build 
new/flatpak-builder-1.4.10/meson.build
--- old/flatpak-builder-1.4.8/meson.build       2026-04-09 20:47:23.000000000 
+0200
+++ new/flatpak-builder-1.4.10/meson.build      2026-06-18 03:01:50.000000000 
+0200
@@ -3,7 +3,7 @@
   'c',
   license: 'LGPL-2.1-or-later',
   meson_version: '>= 0.56.2',
-  version: '1.4.8',
+  version: '1.4.10',
   default_options: 'c_std=gnu99',
 )
 
@@ -37,6 +37,17 @@
   endif
 endforeach
 
+if cc.get_id() == 'clang'
+  clang_args = [
+    '-Wno-typedef-redefinition',
+  ]
+  foreach arg : clang_args
+    if cc.has_argument(arg)
+      add_project_arguments(arg, language: 'c')
+    endif
+  endforeach
+endif
+
 # The debugedit program is a hard dependency
 debugedit = find_program('debugedit', version: '>= 5.0')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/src/builder-context.c 
new/flatpak-builder-1.4.10/src/builder-context.c
--- old/flatpak-builder-1.4.8/src/builder-context.c     2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/src/builder-context.c    2026-06-18 
03:01:50.000000000 +0200
@@ -130,6 +130,7 @@
   g_free (self->default_branch);
   g_free (self->state_subdir);
   g_free (self->stop_at);
+  g_free (self->opt_mirror_screenshots_url);
   g_strfreev (self->cleanup);
   g_strfreev (self->cleanup_platform);
   glnx_release_lock_file(&self->rofiles_file_lock);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/src/builder-flatpak-utils.c 
new/flatpak-builder-1.4.10/src/builder-flatpak-utils.c
--- old/flatpak-builder-1.4.8/src/builder-flatpak-utils.c       2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/src/builder-flatpak-utils.c      2026-06-18 
03:01:50.000000000 +0200
@@ -185,7 +185,7 @@
           /* special case * at end */
           if (c == 0)
             {
-              char *tmp = strchr (string, '/');
+              const char *tmp = strchr (string, '/');
               if (tmp != NULL)
                 return tmp;
               return string + strlen (string);
@@ -1163,11 +1163,11 @@
   if (curl_session == NULL)
     return NULL;
 
-  curl_easy_setopt (curl_session, CURLOPT_CONNECTTIMEOUT, 60);
-  curl_easy_setopt (curl_session, CURLOPT_FAILONERROR, 1);
-  curl_easy_setopt (curl_session, CURLOPT_FOLLOWLOCATION, 1);
-  curl_easy_setopt (curl_session, CURLOPT_MAXREDIRS, 50);
-  curl_easy_setopt (curl_session, CURLOPT_NOPROGRESS, 0);
+  curl_easy_setopt (curl_session, CURLOPT_CONNECTTIMEOUT, 60L);
+  curl_easy_setopt (curl_session, CURLOPT_FAILONERROR, 1L);
+  curl_easy_setopt (curl_session, CURLOPT_FOLLOWLOCATION, 1L);
+  curl_easy_setopt (curl_session, CURLOPT_MAXREDIRS, 50L);
+  curl_easy_setopt (curl_session, CURLOPT_NOPROGRESS, 0L);
   curl_easy_setopt (curl_session, CURLOPT_LOW_SPEED_TIME, 60L);
   curl_easy_setopt (curl_session, CURLOPT_LOW_SPEED_LIMIT, 10000L);
   curl_easy_setopt (curl_session, CURLOPT_USERAGENT, user_agent);
@@ -1633,7 +1633,7 @@
                               const char **suffix,
                               const char **dir)
 {
-  char *slash;
+  const char *slash;
   const char *rest;
   g_autofree char *prefix = NULL;
   gsize len;
@@ -2087,7 +2087,7 @@
                               GError     **error)
 {
   FlatpakContext *context = data;
-  char *t;
+  const char *t;
   g_autofree char *key = NULL;
   const char *policy_value;
 
@@ -2114,7 +2114,7 @@
                                  GError     **error)
 {
   FlatpakContext *context = data;
-  char *t;
+  const char *t;
   g_autofree char *key = NULL;
   const char *policy_value;
   g_autofree char *extended_value = NULL;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/src/builder-main.c 
new/flatpak-builder-1.4.10/src/builder-main.c
--- old/flatpak-builder-1.4.8/src/builder-main.c        2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/src/builder-main.c       2026-06-18 
03:01:50.000000000 +0200
@@ -350,8 +350,6 @@
             const gchar    *branch,
             GError        **error)
 {
-  g_autofree char *ref = NULL;
-
   g_autoptr(GPtrArray) args = NULL;
 
   args = g_ptr_array_new_with_free_func (g_free);
@@ -375,9 +373,8 @@
   for (size_t i = 0; i < manifest_ids->len; i++)
     {
       const gchar *id = g_ptr_array_index (manifest_ids, i);
-      ref = flatpak_build_untyped_ref (id, branch,
-                                       builder_context_get_arch 
(build_context));
-      g_ptr_array_add (args, g_strdup (ref));
+      g_ptr_array_add (args, flatpak_build_untyped_ref (id, branch,
+                                                        
builder_context_get_arch (build_context)));
     }
 
   g_ptr_array_add (args, NULL);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/src/builder-manifest.c 
new/flatpak-builder-1.4.10/src/builder-manifest.c
--- old/flatpak-builder-1.4.8/src/builder-manifest.c    2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/src/builder-manifest.c   2026-06-18 
03:01:50.000000000 +0200
@@ -186,6 +186,7 @@
   BuilderManifest *self = (BuilderManifest *) object;
 
   g_free (self->id);
+  g_free (self->id_platform);
   g_free (self->branch);
   g_free (self->default_branch);
   g_free (self->collection_id);
@@ -216,12 +217,15 @@
   g_strfreev (self->inherit_extensions);
   g_strfreev (self->inherit_sdk_extensions);
   g_strfreev (self->tags);
+  g_strfreev (self->rename_mime_icons);
+  g_strfreev (self->base_extensions);
+  g_strfreev (self->sdk_extensions);
+  g_strfreev (self->platform_extensions);
   g_free (self->rename_desktop_file);
   g_free (self->rename_appdata_file);
   g_free (self->rename_mime_file);
   g_free (self->appdata_license);
   g_free (self->rename_icon);
-  g_free (self->rename_mime_icons);
   g_free (self->desktop_file_name_prefix);
   g_free (self->desktop_file_name_suffix);
 
@@ -2891,7 +2895,8 @@
                       flatpak_xml_add (n_root, n_provides);
                     }
                   n_provides_id = flatpak_xml_new ("id");
-                  id_text = flatpak_xml_new_text (g_steal_pointer (&old_id));
+                  id_text = flatpak_xml_new_text (old_id);
+                  g_clear_pointer (&old_id, g_free);
                   flatpak_xml_add (n_provides_id, id_text);
                   flatpak_xml_add (n_provides, n_provides_id);
                 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/src/builder-utils.c 
new/flatpak-builder-1.4.10/src/builder-utils.c
--- old/flatpak-builder-1.4.8/src/builder-utils.c       2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/src/builder-utils.c      2026-06-18 
03:01:50.000000000 +0200
@@ -283,78 +283,228 @@
   return empty;
 }
 
+static char *
+locale_name_to_language (const char *name)
+{
+  char *language = g_strdup (name);
+  char *c;
+
+  if ((c = strchr (language, '@'))) *c = '\0';
+  if ((c = strchr (language, '_'))) *c = '\0';
+  if ((c = strchr (language, '.'))) *c = '\0';
+
+  return language;
+}
+
 static gboolean
-migrate_locale_dir (GFile      *source_dir,
-                    GFile      *separate_dir,
-                    const char *subdir,
-                    GError    **error)
+migrate_locale_dir_contents (int      src_dfd,
+                             int      dst_dfd,
+                             GError **error)
 {
-  g_autoptr(GFileEnumerator) dir_enum = NULL;
-  GFileInfo *next;
-  GError *temp_error = NULL;
-
-  dir_enum = g_file_enumerate_children (source_dir, 
"standard::name,standard::type",
-                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                        NULL, NULL);
-  if (!dir_enum)
-    return TRUE;
+  g_auto(GLnxDirFdIterator) iter = { 0, };
+  struct dirent *dent;
+
+  if (!glnx_dirfd_iterator_init_at (src_dfd, ".", FALSE, &iter, error))
+    return FALSE;
 
-  while ((next = g_file_enumerator_next_file (dir_enum, NULL, &temp_error)))
+  while (TRUE)
     {
-      g_autoptr(GFileInfo) child_info = next;
-      g_autoptr(GFile) locale_subdir = NULL;
+      glnx_autofd int chase_fd = -1;
+      struct glnx_statx stx;
+      char tmp_name[] = ".locale-XXXXXX";
+
+      if (!glnx_dirfd_iterator_next_dent (&iter, &dent, NULL, error))
+        return FALSE;
+
+      if (dent == NULL)
+        break;
+
+      chase_fd = glnx_chase_and_statxat (src_dfd, dent->d_name,
+                                         GLNX_CHASE_NOFOLLOW |
+                                         GLNX_CHASE_RESOLVE_BENEATH,
+                                         GLNX_STATX_TYPE,
+                                         &stx,
+                                         error);
+      if (chase_fd < 0)
+        return FALSE;
+
+      glnx_gen_temp_name (tmp_name);
+
+      if (!glnx_renameat (src_dfd, dent->d_name, src_dfd, tmp_name, error))
+        return FALSE;
 
-      if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
+      if (S_ISREG (stx.stx_mode) || S_ISLNK (stx.stx_mode))
         {
-          g_autoptr(GFile) child = NULL;
-          const char *name = g_file_info_get_name (child_info);
-          g_autofree char *language = g_strdup (name);
-          g_autofree char *relative = NULL;
-          g_autofree char *target = NULL;
-          char *c;
-
-          c = strchr (language, '@');
-          if (c != NULL)
-            *c = 0;
-          c = strchr (language, '_');
-          if (c != NULL)
-            *c = 0;
-          c = strchr (language, '.');
-          if (c != NULL)
-            *c = 0;
-
-          /* We ship english and C locales always */
-          if (strcmp (language, "C") == 0 ||
-              strcmp (language, "en") == 0)
-            continue;
-
-          child = g_file_get_child (source_dir, g_file_info_get_name 
(child_info));
-
-          relative = g_build_filename (language, subdir, name, NULL);
-          locale_subdir = g_file_resolve_relative_path (separate_dir, 
relative);
-          if (!flatpak_mkdir_p (locale_subdir, NULL, error))
+          if (!glnx_file_copy_at (src_dfd, tmp_name, NULL,
+                                  dst_dfd, dent->d_name,
+                                  GLNX_FILE_COPY_OVERWRITE |
+                                  GLNX_FILE_COPY_NOCHOWN |
+                                  GLNX_FILE_COPY_NOXATTRS,
+                                  NULL, error))
             return FALSE;
 
-          if (!flatpak_cp_a (child, locale_subdir, NULL,
-                             FLATPAK_CP_FLAGS_MERGE | FLATPAK_CP_FLAGS_MOVE,
-                             NULL, NULL, error))
+          if (unlinkat (src_dfd, tmp_name, 0) < 0)
+            return glnx_throw_errno_prefix (error, "unlinkat %s", tmp_name);
+        }
+      else if (S_ISDIR (stx.stx_mode))
+        {
+          glnx_autofd int src_child_dfd = -1;
+          glnx_autofd int child_dst_dfd = -1;
+
+          src_child_dfd = glnx_fd_reopen (chase_fd, O_RDONLY | O_DIRECTORY, 
error);
+          if (src_child_dfd < 0)
+            return FALSE;
+
+          if (!glnx_ensure_dir (dst_dfd, dent->d_name, 0755, error))
             return FALSE;
 
-          target = g_build_filename ("../../share/runtime/locale", relative, 
NULL);
+          if (!glnx_opendirat (dst_dfd, dent->d_name, FALSE,
+                               &child_dst_dfd, error))
+            return FALSE;
 
-          if (!g_file_make_symbolic_link (child, target,
-                                          NULL, error))
+          if (!migrate_locale_dir_contents (src_child_dfd, child_dst_dfd, 
error))
             return FALSE;
 
+          if (unlinkat (src_dfd, tmp_name, AT_REMOVEDIR) < 0)
+            return glnx_throw_errno_prefix (error, "unlinkat %s", tmp_name);
         }
+      else
+        return glnx_throw (error, "unexpected entry type %s", dent->d_name);
     }
+  return TRUE;
+}
+
+static gboolean
+migrate_lang_dir (int         source_dfd,
+                  const char *lang_name,
+                  const char *src_tmp_name,
+                  int         lang_dfd,
+                  int         separate_dfd,
+                  const char *subdir,
+                  GError    **error)
+{
+  glnx_autofd int locale_subdir_dfd = -1;
+  g_autofree char *language = locale_name_to_language (lang_name);
+  g_autofree char *target = NULL;
+
+  const char *components[] = { language, subdir, lang_name, NULL };
+
+  if (!builder_ensure_dirs_at (separate_dfd, components, &locale_subdir_dfd, 
error))
+    return FALSE;
+
+  if (!migrate_locale_dir_contents (lang_dfd, locale_subdir_dfd, error))
+    return FALSE;
+
+  target = g_build_filename ("../../share/runtime/locale",
+                             language, subdir, lang_name, NULL);
+
+  if (unlinkat (source_dfd, src_tmp_name, AT_REMOVEDIR) < 0)
+    return glnx_throw_errno_prefix (error, "unlinkat %s", src_tmp_name);
+
+  if (symlinkat (target, source_dfd, lang_name) < 0)
+    return glnx_throw_errno_prefix (error, "symlinkat %s", lang_name);
+
+  return TRUE;
+}
 
-  if (temp_error != NULL)
+static gboolean
+migrate_locale_dir (int         root_dfd,
+                    const char *source_rel,
+                    int         root_dfd_separate,
+                    const char *subdir,
+                    GError    **error)
+{
+  glnx_autofd int chase_fd = -1;
+  glnx_autofd int source_dfd = -1;
+  glnx_autofd int separate_dfd = -1;
+  g_auto(GLnxDirFdIterator) iter = { 0, };
+  struct dirent *dent;
+  const char *separate_components[] = { "share", "runtime", "locale", NULL };
+  g_autoptr(GPtrArray) names = g_ptr_array_new_with_free_func (g_free);
+
+  chase_fd = glnx_chaseat (root_dfd, source_rel,
+                           GLNX_CHASE_RESOLVE_BENEATH |
+                           GLNX_CHASE_MUST_BE_DIRECTORY,
+                           error);
+  if (chase_fd < 0)
     {
-      g_propagate_error (error, temp_error);
+      if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+        {
+          g_clear_error (error);
+          return TRUE;
+        }
       return FALSE;
     }
 
+  source_dfd = glnx_fd_reopen (chase_fd, O_RDONLY | O_DIRECTORY, error);
+  if (source_dfd < 0)
+    return glnx_prefix_error (error, "failed to reopen %s", source_rel);
+
+  if (!glnx_dirfd_iterator_init_at (source_dfd, ".", FALSE, &iter, error))
+    return FALSE;
+
+  while (TRUE)
+    {
+      if (!glnx_dirfd_iterator_next_dent (&iter, &dent, NULL, error))
+        return FALSE;
+
+      if (dent == NULL)
+        break;
+
+      {
+        g_autofree char *language = locale_name_to_language (dent->d_name);
+
+        /* We ship english and C locales always */
+        if (strcmp (language, "C") == 0 ||
+            strcmp (language, "en") == 0)
+          continue;
+      }
+
+      g_ptr_array_add (names, g_strdup (dent->d_name));
+    }
+
+  if (names->len == 0)
+    return TRUE;
+
+  if (!builder_ensure_dirs_at (root_dfd_separate, separate_components,
+                               &separate_dfd, error))
+    return FALSE;
+
+  for (size_t i = 0; i < names->len; i++)
+    {
+      const char *name = names->pdata[i];
+      glnx_autofd int lang_dfd = -1;
+      glnx_autofd int reopened_lang_dfd = -1;
+      char tmp_name[] = ".locale-XXXXXX";
+
+      lang_dfd = glnx_chaseat (source_dfd, name,
+                               GLNX_CHASE_RESOLVE_BENEATH |
+                               GLNX_CHASE_MUST_BE_DIRECTORY,
+                               error);
+      if (lang_dfd < 0)
+        {
+          if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY))
+            {
+              g_clear_error (error);
+              continue;
+            }
+          return FALSE;
+        }
+
+      reopened_lang_dfd = glnx_fd_reopen (lang_dfd, O_RDONLY | O_DIRECTORY, 
error);
+      if (reopened_lang_dfd < 0)
+        return glnx_prefix_error (error, "failed to reopen %s", name);
+
+      glnx_gen_temp_name (tmp_name);
+
+      if (!glnx_renameat (source_dfd, name, source_dfd, tmp_name, error))
+        return FALSE;
+
+      if (!migrate_lang_dir (source_dfd, name, tmp_name, reopened_lang_dfd,
+                             separate_dfd, subdir, error))
+        return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -395,18 +545,17 @@
 builder_migrate_locale_dirs (GFile   *root_dir,
                              GError **error)
 {
-  g_autoptr(GFile) separate_dir = NULL;
-  g_autoptr(GFile) lib_locale_dir = NULL;
-  g_autoptr(GFile) share_locale_dir = NULL;
+  glnx_autofd int root_dfd = -1;
 
-  lib_locale_dir = g_file_resolve_relative_path (root_dir, "lib/locale");
-  share_locale_dir = g_file_resolve_relative_path (root_dir, "share/locale");
-  separate_dir = g_file_resolve_relative_path (root_dir, 
"share/runtime/locale");
+  if (!glnx_opendirat (AT_FDCWD,
+                       flatpak_file_get_path_cached (root_dir),
+                       FALSE, &root_dfd, error))
+    return FALSE;
 
-  if (!migrate_locale_dir (lib_locale_dir, separate_dir, "lib", error))
+  if (!migrate_locale_dir (root_dfd, "lib/locale", root_dfd, "lib", error))
     return FALSE;
 
-  if (!migrate_locale_dir (share_locale_dir, separate_dir, "share", error))
+  if (!migrate_locale_dir (root_dfd, "share/locale", root_dfd, "share", error))
     return FALSE;
 
   return TRUE;
@@ -1117,10 +1266,10 @@
 } CURLWriteData;
 
 static gsize
-builder_curl_write_cb (gpointer *buffer,
+builder_curl_write_cb (char     *buffer,
                        gsize     size,
                        gsize     nmemb,
-                       gpointer *userdata)
+                       void     *userdata)
 {
   gsize bytes_written;
   CURLWriteData *write_data = (CURLWriteData *) userdata;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/tests/Makefile.am.inc 
new/flatpak-builder-1.4.10/tests/Makefile.am.inc
--- old/flatpak-builder-1.4.8/tests/Makefile.am.inc     2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/tests/Makefile.am.inc    2026-06-18 
03:01:50.000000000 +0200
@@ -89,6 +89,7 @@
        tests/test-builder-python.sh \
        tests/test-builder-cleanup.sh \
        tests/test-builder-licence-paths.sh \
+       tests/test-builder-locale-migration.sh \
        $(NULL)
 
 @VALGRIND_CHECK_RULES@
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/tests/libtest.sh 
new/flatpak-builder-1.4.10/tests/libtest.sh
--- old/flatpak-builder-1.4.8/tests/libtest.sh  2026-04-09 20:47:23.000000000 
+0200
+++ new/flatpak-builder-1.4.10/tests/libtest.sh 2026-06-18 03:01:50.000000000 
+0200
@@ -115,6 +115,12 @@
     test -d "$1" || (echo 1>&2 "Couldn't find '$1'"; exit 1)
 }
 
+assert_not_has_symlink () {
+    if test -L "$1"; then
+        echo 1>&2 "Symlink '$1' exists"; exit 1
+    fi
+}
+
 assert_not_has_file () {
     if test -f "$1"; then
         sed -e 's/^/# /' < "$1" >&2
@@ -293,6 +299,37 @@
     ${CMD_PREFIX} flatpak run --command=bash ${ARGS-} org.test.Hello -c "$*"
 }
 
+: "${FORCE_CLEAN:=1}"
+
+builder_run_app () {
+    local appdir="${APPDIR:-appdir}"
+
+    ${FLATPAK_BUILDER} --run "$appdir" "$@"
+}
+
+_run_build () {
+    local appdir="${APPDIR:-appdir}"
+
+    if [ -n "${BUILD_LOG:-}" ]; then
+        ${FLATPAK_BUILDER} ${FORCE_CLEAN:+--force-clean} \
+            "$appdir" "$@" >&2 2>"$BUILD_LOG"
+    else
+        ${FLATPAK_BUILDER} ${FORCE_CLEAN:+--force-clean} \
+            "$appdir" "$@" >&2
+    fi
+}
+
+run_build () {
+    _run_build "$@"
+}
+
+run_build_fail () {
+    if _run_build "$@"; then
+        echo "build of ${!#} unexpectedly succeeded" >&2
+        exit 1
+    fi
+}
+
 # fuse support is needed (and the kernel module needs to be loaded) for several
 # flatpak-builder tests
 skip_without_fuse () {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/tests/meson.build 
new/flatpak-builder-1.4.10/tests/meson.build
--- old/flatpak-builder-1.4.8/tests/meson.build 2026-04-09 20:47:23.000000000 
+0200
+++ new/flatpak-builder-1.4.10/tests/meson.build        2026-06-18 
03:01:50.000000000 +0200
@@ -13,6 +13,7 @@
   'test-builder-python',
   'test-builder-cleanup',
   'test-builder-licence-paths',
+  'test-builder-locale-migration',
 ]
 
 tap_test = find_program(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/tests/test-builder-cleanup.sh 
new/flatpak-builder-1.4.10/tests/test-builder-cleanup.sh
--- old/flatpak-builder-1.4.8/tests/test-builder-cleanup.sh     2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/tests/test-builder-cleanup.sh    2026-06-18 
03:01:50.000000000 +0200
@@ -32,11 +32,6 @@
 
 cd "$TEST_DATA_DIR"
 
-run_build () {
-    local manifest=$1
-    ${FLATPAK_BUILDER} --force-clean appdir "$manifest" >&2
-}
-
 cat > test-cleanup-toplevel.json <<'EOF'
 {
   "app-id": "org.test.CleanupToplevel",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flatpak-builder-1.4.8/tests/test-builder-deprecated.sh 
new/flatpak-builder-1.4.10/tests/test-builder-deprecated.sh
--- old/flatpak-builder-1.4.8/tests/test-builder-deprecated.sh  2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/tests/test-builder-deprecated.sh 2026-06-18 
03:01:50.000000000 +0200
@@ -42,49 +42,49 @@
 cp "$srcdir"/hello.sh .
 cp "$srcdir"/hello.tar.xz .
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.MD5.archive.json 
>&2 2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.MD5.archive.json
 assert_file_has_content build-error-log 'The "md5" source property is 
deprecated due to the weakness of MD5 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated MD5 hash for archive in JSON"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.MD5.archive.yaml 
>&2 2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.MD5.archive.yaml
 assert_file_has_content build-error-log 'The "md5" source property is 
deprecated due to the weakness of MD5 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated MD5 hash for archive in YAML"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.MD5.file.json >&2 
2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.MD5.file.json
 assert_file_has_content build-error-log 'The "md5" source property is 
deprecated due to the weakness of MD5 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated MD5 hash for file in JSON"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.MD5.file.yaml >&2 
2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.MD5.file.yaml
 assert_file_has_content build-error-log 'The "md5" source property is 
deprecated due to the weakness of MD5 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated MD5 hash for file in YAML"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.SHA1.archive.json 
>&2 2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.SHA1.archive.json
 assert_file_has_content build-error-log 'The "sha1" source property is 
deprecated due to the weakness of SHA1 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated SHA1 hash for archive in JSON"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.SHA1.archive.yaml 
>&2 2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.SHA1.archive.yaml
 assert_file_has_content build-error-log 'The "sha1" source property is 
deprecated due to the weakness of SHA1 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated SHA1 hash for archive in YAML"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.SHA1.file.json >&2 
2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.SHA1.file.json
 assert_file_has_content build-error-log 'The "sha1" source property is 
deprecated due to the weakness of SHA1 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
 echo "ok deprecated SHA1 hash for file in JSON"
 
-${FLATPAK_BUILDER} --force-clean appdir org.test.Deprecated.SHA1.file.yaml >&2 
2> build-error-log
+BUILD_LOG=build-error-log run_build org.test.Deprecated.SHA1.file.yaml
 assert_file_has_content build-error-log 'The "sha1" source property is 
deprecated due to the weakness of SHA1 hashes.'
 assert_file_has_content build-error-log 'Use the "sha256" property for the 
more secure SHA256 hash.'
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flatpak-builder-1.4.8/tests/test-builder-licence-paths.sh 
new/flatpak-builder-1.4.10/tests/test-builder-licence-paths.sh
--- old/flatpak-builder-1.4.8/tests/test-builder-licence-paths.sh       
2026-04-09 20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/tests/test-builder-licence-paths.sh      
2026-06-18 03:01:50.000000000 +0200
@@ -34,19 +34,6 @@
 
 REPO="$(pwd)/repos/test"
 
-run_build () {
-    local manifest=$1
-    ${FLATPAK_BUILDER} --force-clean appdir "$manifest" >&2
-}
-
-run_build_fail () {
-    local manifest=$1
-    if ${FLATPAK_BUILDER} --force-clean appdir "$manifest" >&2; then
-        echo "build of $manifest unexpectedly succeeded" >&2
-        exit 1
-    fi
-}
-
 mkdir -p source_licence_1
 ln -s /proc/self source_licence_1/licenses
 tar czf source_licence_1.tar.gz source_licence_1/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flatpak-builder-1.4.8/tests/test-builder-locale-migration.sh 
new/flatpak-builder-1.4.10/tests/test-builder-locale-migration.sh
--- old/flatpak-builder-1.4.8/tests/test-builder-locale-migration.sh    
1970-01-01 01:00:00.000000000 +0100
+++ new/flatpak-builder-1.4.10/tests/test-builder-locale-migration.sh   
2026-06-18 03:01:50.000000000 +0200
@@ -0,0 +1,220 @@
+#!/bin/bash
+#
+# Copyright (C) 2026 Boudhayan Bhattacharya <[email protected]>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+skip_without_fuse
+
+echo "1..4"
+
+setup_repo
+install_repo
+setup_sdk_repo
+install_sdk_repo
+
+cd "$TEST_DATA_DIR"
+
+cat > test-locale-migration.json <<'EOF'
+{
+    "app-id": "org.test.locale_migration",
+    "runtime": "org.test.Platform",
+    "sdk": "org.test.Sdk",
+    "modules": [{
+        "name": "test",
+        "buildsystem": "simple",
+        "build-commands": [
+            "mkdir -p /app/share/locale/de/LC_MESSAGES",
+            "echo 'de translation' > /app/share/locale/de/LC_MESSAGES/test.mo",
+
+            "mkdir -p /app/share/locale/C/LC_MESSAGES",
+            "echo 'C locale' > /app/share/locale/C/LC_MESSAGES/test.mo",
+            "mkdir -p /app/share/locale/en/LC_MESSAGES",
+            "echo 'en locale' > /app/share/locale/en/LC_MESSAGES/test.mo",
+
+            "mkdir -p /app/lib/locale/ru/LC_MESSAGES",
+            "echo 'ru translation' > /app/lib/locale/ru/LC_MESSAGES/test.mo",
+
+            "mkdir -p /app/share/locale/[email protected]/LC_MESSAGES",
+            "echo 'sr combined' > 
/app/share/locale/[email protected]/LC_MESSAGES/test.mo",
+
+            "mkdir -p /app/share/locale/ko/LC_MESSAGES",
+            "echo 'app1' > /app/share/locale/ko/LC_MESSAGES/app1.mo",
+            "echo 'app2' > /app/share/locale/ko/LC_MESSAGES/app2.mo",
+
+            "mkdir -p /app/share/locale/es/LC_MESSAGES",
+            "echo 'es share' > /app/share/locale/es/LC_MESSAGES/test.mo",
+            "mkdir -p /app/lib/locale/es/LC_CTYPE",
+            "echo 'es lib' > /app/lib/locale/es/LC_CTYPE/test.mo",
+
+            "mkdir -p /app/share/locale/de_DE/LC_MESSAGES",
+            "echo 'de_DE translation' > 
/app/share/locale/de_DE/LC_MESSAGES/test.mo",
+            "mkdir -p /app/share/locale/de_AT/LC_MESSAGES",
+            "echo 'de_AT translation' > 
/app/share/locale/de_AT/LC_MESSAGES/test.mo",
+
+            "touch /app/share/locale/plain-file",
+
+            "mkdir -p /app/share/locale/sv"
+        ]
+    }]
+}
+EOF
+
+run_build test-locale-migration.json
+
+# share/locale is migrated to share/runtime/locale/$lang
+assert_has_symlink appdir/files/share/locale/de
+assert_symlink_has_content appdir/files/share/locale/de 
'share/runtime/locale/de'
+assert_has_file 
appdir/files/share/runtime/locale/de/share/de/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/de/share/de/LC_MESSAGES/test.mo 'de 
translation'
+
+# lib/locale is migrated to share/runtime/locale/$lang
+assert_has_symlink appdir/files/lib/locale/ru
+assert_symlink_has_content appdir/files/lib/locale/ru 'share/runtime/locale/ru'
+assert_has_file appdir/files/share/runtime/locale/ru/lib/ru/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/ru/lib/ru/LC_MESSAGES/test.mo 'ru translation'
+
+# C and en locales are not migrated
+assert_has_dir appdir/files/share/locale/C
+assert_has_file appdir/files/share/locale/C/LC_MESSAGES/test.mo
+assert_file_has_content appdir/files/share/locale/C/LC_MESSAGES/test.mo 'C 
locale'
+
+assert_has_dir appdir/files/share/locale/en
+assert_has_file appdir/files/share/locale/en/LC_MESSAGES/test.mo
+assert_file_has_content appdir/files/share/locale/en/LC_MESSAGES/test.mo 'en 
locale'
+
+# [email protected] -> sr
+assert_has_symlink appdir/files/share/locale/[email protected]
+assert_has_file 
appdir/files/share/runtime/locale/sr/share/[email protected]/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/sr/share/[email protected]/LC_MESSAGES/test.mo
 'sr combined'
+
+# multiple files in a single locale dir are migrated
+assert_has_symlink appdir/files/share/locale/ko
+assert_has_file 
appdir/files/share/runtime/locale/ko/share/ko/LC_MESSAGES/app1.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/ko/share/ko/LC_MESSAGES/app1.mo 'app1'
+assert_has_file 
appdir/files/share/runtime/locale/ko/share/ko/LC_MESSAGES/app2.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/ko/share/ko/LC_MESSAGES/app2.mo 'app2'
+
+# same language in share/locale and lib/locale is merged to same target
+assert_has_symlink appdir/files/share/locale/es
+assert_has_file 
appdir/files/share/runtime/locale/es/share/es/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/es/share/es/LC_MESSAGES/test.mo 'es share'
+assert_has_symlink appdir/files/lib/locale/es
+assert_has_file appdir/files/share/runtime/locale/es/lib/es/LC_CTYPE/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/es/lib/es/LC_CTYPE/test.mo 'es lib'
+
+# language variants are merged
+assert_has_symlink appdir/files/share/locale/de_DE
+assert_has_symlink appdir/files/share/locale/de_AT
+assert_has_file 
appdir/files/share/runtime/locale/de/share/de_DE/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/de/share/de_DE/LC_MESSAGES/test.mo 'de_DE 
translation'
+assert_has_file 
appdir/files/share/runtime/locale/de/share/de_AT/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/files/share/runtime/locale/de/share/de_AT/LC_MESSAGES/test.mo 'de_AT 
translation'
+
+# empty locale dir creates empty migration dir
+assert_has_dir appdir/files/share/locale/sv
+assert_has_dir appdir/files/share/runtime/locale/sv
+
+# non-directory entries are ignored
+assert_has_file appdir/files/share/locale/plain-file
+assert_not_has_symlink appdir/files/share/locale/plain-file
+
+echo "ok locale dirs migrated"
+
+cat > test-locale-disabled.json <<'EOF'
+{
+    "app-id": "org.test.locale_migration_disabled",
+    "runtime": "org.test.Platform",
+    "sdk": "org.test.Sdk",
+    "separate-locales": false,
+    "modules": [{
+        "name": "test",
+        "buildsystem": "simple",
+        "build-commands": [
+            "mkdir -p /app/share/locale/de/LC_MESSAGES",
+            "echo 'de translation' > /app/share/locale/de/LC_MESSAGES/test.mo"
+        ]
+    }]
+}
+EOF
+
+run_build test-locale-disabled.json
+
+assert_has_dir appdir/files/share/locale/de
+assert_has_file appdir/files/share/locale/de/LC_MESSAGES/test.mo
+assert_file_has_content appdir/files/share/locale/de/LC_MESSAGES/test.mo 'de 
translation'
+assert_not_has_dir appdir/files/share/runtime/locale
+
+echo "ok locale dirs migration is disabled on separate-locales false"
+
+cat > test-locale-migration-runtime.json <<'EOF'
+{
+    "app-id": "org.test.locale_migration_runtime",
+    "runtime": "org.test.Platform",
+    "sdk": "org.test.Sdk",
+    "build-runtime": true,
+    "modules": [{
+        "name": "test",
+        "buildsystem": "simple",
+        "build-commands": [
+            "mkdir -p /usr/share/locale/pl/LC_MESSAGES",
+            "echo 'pl translation' > /usr/share/locale/pl/LC_MESSAGES/test.mo",
+
+            "mkdir -p /usr/lib/locale/cs/LC_MESSAGES",
+            "echo 'cs translation' > /usr/lib/locale/cs/LC_MESSAGES/test.mo"
+        ]
+    }]
+}
+EOF
+
+run_build test-locale-migration-runtime.json
+
+assert_has_symlink appdir/usr/share/locale/pl
+assert_has_file appdir/usr/share/runtime/locale/pl/share/pl/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/usr/share/runtime/locale/pl/share/pl/LC_MESSAGES/test.mo 'pl translation'
+
+assert_has_symlink appdir/usr/lib/locale/cs
+assert_has_file appdir/usr/share/runtime/locale/cs/lib/cs/LC_MESSAGES/test.mo
+assert_file_has_content 
appdir/usr/share/runtime/locale/cs/lib/cs/LC_MESSAGES/test.mo 'cs translation'
+
+echo "ok locale dirs migration works with runtime"
+
+cat > test-locale-no-dirs.json <<'EOF'
+{
+    "app-id": "org.test.locale_no_dirs",
+    "runtime": "org.test.Platform",
+    "sdk": "org.test.Sdk",
+    "modules": [{
+        "name": "test",
+        "buildsystem": "simple",
+        "build-commands": [
+            "mkdir -p /app/bin",
+            "echo test > /app/bin/test"
+        ]
+    }]
+}
+EOF
+
+run_build test-locale-no-dirs.json
+
+assert_has_file appdir/files/bin/test
+assert_not_has_dir appdir/files/share/runtime/locale
+
+echo "ok locale migration handles missing locale dirs"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/tests/test-builder-python.sh 
new/flatpak-builder-1.4.10/tests/test-builder-python.sh
--- old/flatpak-builder-1.4.8/tests/test-builder-python.sh      2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/tests/test-builder-python.sh     2026-06-18 
03:01:50.000000000 +0200
@@ -42,22 +42,23 @@
 cp $(dirname $0)/importme.py .
 cp $(dirname $0)/importme2.py .
 chmod u+w *.py
-flatpak-builder --force-clean appdir org.test.Python.json >&2
+
+run_build org.test.Python.json
 
 assert_has_file appdir/files/bin/importme.pyc
 
-flatpak-builder --run appdir org.test.Python.json testpython.py > 
testpython.out
+builder_run_app org.test.Python.json testpython.py > testpython.out
 
 assert_file_has_content testpython.out ^modified$
 
 echo "ok handled pyc rewriting multiple times"
 
-flatpak-builder --force-clean appdir org.test.Python2.json >&2
+run_build org.test.Python2.json
 
 assert_not_has_file appdir/files/bin/importme.py
 assert_has_file appdir/files/bin/importme.pyc
 
-flatpak-builder --run appdir org.test.Python2.json testpython.py > 
testpython.out
+builder_run_app org.test.Python2.json testpython.py > testpython.out
 
 assert_file_has_content testpython.out "^first   $"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flatpak-builder-1.4.8/tests/test-builder.sh 
new/flatpak-builder-1.4.10/tests/test-builder.sh
--- old/flatpak-builder-1.4.8/tests/test-builder.sh     2026-04-09 
20:47:23.000000000 +0200
+++ new/flatpak-builder-1.4.10/tests/test-builder.sh    2026-06-18 
03:01:50.000000000 +0200
@@ -73,7 +73,7 @@
 
 for MANIFEST in test.json test.yaml test-rename.json test-rename-appdata.json 
; do
     echo "building manifest $MANIFEST" >&2
-    ${FLATPAK_BUILDER} --repo=$REPO $FL_GPGARGS --force-clean appdir $MANIFEST 
>&2
+    run_build --repo="$REPO" $FL_GPGARGS "$MANIFEST"
 
     assert_file_has_content appdir/files/share/app-data version1
     assert_file_has_content appdir/metadata shared=network;
@@ -120,9 +120,9 @@
 echo "ok install+run"
 
 echo "version2" > app-data
-${FLATPAK_BUILDER} $FL_GPGARGS --repo=$REPO --force-clean appdir test.json >&2
+run_build $FL_GPGARGS --repo="$REPO" test.json
 assert_file_has_content appdir/files/share/app-data version2
-${FLATPAK_BUILDER} $FL_GPGARGS --repo=$REPO --force-clean appdir test.yaml >&2
+run_build $FL_GPGARGS --repo="$REPO" test.yaml
 assert_file_has_content appdir/files/share/app-data version2
 
 ${FLATPAK} ${U} update -y org.test.Hello2 master >&2
@@ -134,15 +134,16 @@
 
 # The build-args of --help should prevent the faulty cleanup and
 # platform-cleanup commands from executing
-${FLATPAK_BUILDER} $FL_GPGARGS --repo=$REPO --force-clean runtimedir \
-    test-runtime.json >&2
+APPDIR=runtimedir run_build $FL_GPGARGS --repo="$REPO" test-runtime.json
 
 echo "ok runtime build cleanup with build-args"
 
 # test screenshot ref commit
-${FLATPAK_BUILDER} --repo=$REPO/repo_sc --force-clean builddir_sc \
+APPDIR=builddir_sc \
+run_build \
+    --repo="$REPO/repo_sc" \
     --mirror-screenshots-url=https://example.org/media \
-    org.flatpak_builder.gui.json >&2
+    org.flatpak_builder.gui.json
 ostree --repo=$REPO/repo_sc refs|grep -Eq "^screenshots/$(flatpak 
--default-arch)$"
 ostree checkout --repo=$REPO/repo_sc -U screenshots/$(flatpak --default-arch) 
outdir_sc
 find outdir_sc -path "*/icons/64x64/org.test.Hello.png" -type f | grep -q .
@@ -150,11 +151,12 @@
 echo "ok screenshot ref commit"
 
 # test compose partial url policy
-${FLATPAK_BUILDER} --force-clean builddir_sc \
+APPDIR=builddir_sc \
+run_build \
     --mirror-screenshots-url=https://example.org/media \
     --state-dir .fp-compose-url-policy-partial \
     --compose-url-policy=partial \
-    org.flatpak.appstream_media.json >&2
+    org.flatpak.appstream_media.json
 # we test for the icon tag instead of screenshot
 # the former works offline the latter does not
 gzip -cdq 
builddir_sc/files/share/app-info/xmls/org.flatpak.appstream_media.xml.gz|grep 
-Eq 
'>org/flatpak/appstream_media/[^/]+/icons/128x128/org.flatpak.appstream_media.png</icon>'
@@ -163,11 +165,12 @@
 
 # test compose full url policy
 if appstream_has_version 0 16 3; then
-    ${FLATPAK_BUILDER} --force-clean builddir_sc \
+    APPDIR=builddir_sc \
+    run_build \
         --mirror-screenshots-url=https://example.org/media \
         --state-dir .fp-compose-url-policy-full \
         --compose-url-policy=full \
-        org.flatpak.appstream_media.json >&2
+        org.flatpak.appstream_media.json
 
     gzip -cdq 
builddir_sc/files/share/app-info/xmls/org.flatpak.appstream_media.xml.gz|grep 
-Eq 
'>https://example.org/media/org/flatpak/appstream_media/[^/]+/icons/128x128/org.flatpak.appstream_media.png</icon>'
 
@@ -177,8 +180,8 @@
 fi
 
 # test install
-${FLATPAK_BUILDER} --user --install \
-    --force-clean builddir org.flatpak.install_test.json >&2
+APPDIR=builddir run_build --user --install org.flatpak.install_test.json
+
 REFS=$(flatpak list --all --columns=ref 2>/dev/null)
 echo "$REFS" | grep -q "org\.flatpak\.install_test"
 echo "$REFS" | grep -q "org\.flatpak\.install_test\.Debug"
@@ -186,7 +189,7 @@
 
 echo "ok install"
 
-${FLATPAK_BUILDER} --repo=$REPO --force-clean appdir test-locale-cleanup.json 
>&2
+run_build --repo="$REPO" test-locale-cleanup.json
 
 assert_not_has_file appdir/files/share/runtime/locale/es/share/es/testA.mo
 assert_has_file appdir/files/share/runtime/locale/es/share/es/testB.mo

Reply via email to