Hello community,

here is the log from the commit of package ostree for openSUSE:Factory checked 
in at 2016-10-28 10:44:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ostree (Old)
 and      /work/SRC/openSUSE:Factory/.ostree.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ostree"

Changes:
--------
--- /work/SRC/openSUSE:Factory/ostree/ostree.changes    2016-10-18 
10:29:35.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.ostree.new/ostree.changes       2016-10-28 
10:44:04.000000000 +0200
@@ -1,0 +2,17 @@
+Wed Oct 26 10:15:24 UTC 2016 - [email protected]
+
+- Update to version 2016.12:
+  + pull: Support inherit-transaction.
+  + pull: Support multiple specifications of --subpath.
+  + docs: amend vmlinuz & initramfs naming convention.
+  + ostree-sysroot-deploy.c: delete redundant check.
+  + OstreeFetcher: provide proxy credentials if needed.
+  + core: Do create hardlinks to symlinks for checkouts.
+  + add .redhat-ci.yml and .redhat-ci.Dockerfile.
+  + .redhat-ci.yml: use projectatomic/ostree-tester.
+  + Fix regression for symlinks in bare-user repos.
+  + ostree_repo_read_commit_detached_metadata: Handle parent repo.
+  + detached metadata: Put these in transaction.
+  + Release 2016.12.
+
+-------------------------------------------------------------------

Old:
----
  ostree-2016.11.tar.xz

New:
----
  ostree-2016.12.tar.xz

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

Other differences:
------------------
++++++ ostree.spec ++++++
--- /var/tmp/diff_new_pack.dQslmI/_old  2016-10-28 10:44:05.000000000 +0200
+++ /var/tmp/diff_new_pack.dQslmI/_new  2016-10-28 10:44:05.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           ostree
-Version:        2016.11
+Version:        2016.12
 Release:        0
 Summary:        Git for operating system binaries
 License:        GPL-2.0+

++++++ _service ++++++
--- /var/tmp/diff_new_pack.dQslmI/_old  2016-10-28 10:44:05.000000000 +0200
+++ /var/tmp/diff_new_pack.dQslmI/_new  2016-10-28 10:44:05.000000000 +0200
@@ -2,9 +2,9 @@
   <service name="tar_scm" mode="disabled">
     <param name="url">https://github.com/ostreedev/ostree.git</param>
     <param name="scm">git</param>
-    <param name="versionformat">2016.11</param>
+    <param name="versionformat">2016.12</param>
     <param name="changesgenerate">enable</param>
-    <param name="revision">refs/tags/v2016.11</param>
+    <param name="revision">refs/tags/v2016.12</param>
   </service>
   <service name="recompress" mode="disabled">
     <param name="file">*.tar</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.dQslmI/_old  2016-10-28 10:44:05.000000000 +0200
+++ /var/tmp/diff_new_pack.dQslmI/_new  2016-10-28 10:44:05.000000000 +0200
@@ -3,4 +3,4 @@
             <param name="url">git://git.gnome.org/ostree</param>
           <param 
name="changesrevision">bfa23bdc1f13a646f1c91f8a2724022eef2d5656</param></service><service
 name="tar_scm">
             <param name="url">https://github.com/ostreedev/ostree.git</param>
-          <param 
name="changesrevision">a0e1344cf80f2b3f3d0501d7f3559ad67c32dac4</param></service></servicedata>
\ No newline at end of file
+          <param 
name="changesrevision">d3f14f02e3d9f7259c7ec6b25980ae43f03c4906</param></service></servicedata>
\ No newline at end of file

++++++ ostree-2016.11.tar.xz -> ostree-2016.12.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/.redhat-ci.Dockerfile 
new/ostree-2016.12/.redhat-ci.Dockerfile
--- old/ostree-2016.11/.redhat-ci.Dockerfile    1970-01-01 01:00:00.000000000 
+0100
+++ new/ostree-2016.12/.redhat-ci.Dockerfile    2016-10-21 21:24:31.000000000 
+0200
@@ -0,0 +1,21 @@
+FROM fedora:24
+MAINTAINER Jonathan Lebon <[email protected]>
+
+RUN dnf install -y \
+        gcc \
+        sudo \
+        which \
+        attr \
+        fuse \
+        gjs \
+        parallel \
+        gnome-desktop-testing \
+        redhat-rpm-config \
+        elfutils \
+        'dnf-command(builddep)' \
+ && dnf builddep -y \
+        ostree \
+ && dnf clean all
+
+# create an unprivileged user for testing
+RUN adduser testuser
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/.redhat-ci.yml 
new/ostree-2016.12/.redhat-ci.yml
--- old/ostree-2016.11/.redhat-ci.yml   1970-01-01 01:00:00.000000000 +0100
+++ new/ostree-2016.12/.redhat-ci.yml   2016-10-21 21:24:31.000000000 +0200
@@ -0,0 +1,25 @@
+branches:
+    - master
+    - auto
+    - try
+
+container:
+    image: projectatomic/ostree-tester
+
+tests:
+    - sh autogen.sh
+        --prefix=/usr
+        --libdir=/usr/lib64
+        --enable-installed-tests
+        --enable-gtk-doc
+    - make -j2
+    - make syntax-check
+    - make check
+    - make install
+    - gnome-desktop-testing-runner ostree
+    - sudo --user=testuser gnome-desktop-testing-runner ostree
+
+timeout: 30m
+
+artifacts:
+    - test-suite.log
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/configure.ac 
new/ostree-2016.12/configure.ac
--- old/ostree-2016.11/configure.ac     2016-10-07 21:21:41.000000000 +0200
+++ new/ostree-2016.12/configure.ac     2016-10-21 21:24:31.000000000 +0200
@@ -1,6 +1,6 @@
 AC_PREREQ([2.63])
 dnl If incrementing the version here, remember to update libostree.sym too
-AC_INIT([ostree], [2016.11], [[email protected]])
+AC_INIT([ostree], [2016.12], [[email protected]])
 AC_CONFIG_HEADER([config.h])
 AC_CONFIG_MACRO_DIR([buildutil])
 AC_CONFIG_AUX_DIR([build-aux])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/docs/manual/deployment.md 
new/ostree-2016.12/docs/manual/deployment.md
--- old/ostree-2016.11/docs/manual/deployment.md        2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/docs/manual/deployment.md        2016-10-21 
21:24:31.000000000 +0200
@@ -43,13 +43,14 @@
 distinguish it from the concept of a deployment.
 
 First, the tree must include a kernel stored as
-`/boot/vmlinuz-$checksum`.  The checksum should be a SHA256 hash of
-the kernel contents; it must be pre-computed before storing the kernel
-in the repository.  Optionally, the tree can contain an initramfs,
-stored as `/boot/initramfs-$checksum`.  If this exists, the checksum
-must include both the kernel and initramfs contents.  OSTree will use
-this to determine which kernels are shared.  The rationale for this is
-to avoid computing checksums on the client by default.
+`vmlinuz(-.*)?-$checksum` in either `/boot` or `/usr/lib/ostree-boot`.
+The checksum should be a SHA256 hash of the kernel contents; it must be
+pre-computed before storing the kernel in the repository.  Optionally,
+the directory can also contain an initramfs, stored as
+`initramfs(-.*)?-$checksum`.  If this exists, the checksum must include
+both the kernel and initramfs contents.  OSTree will use this to
+determine which kernels are shared.  The rationale for this is to avoid
+computing checksums on the client by default.
 
 The deployment should not have a traditional UNIX `/etc`; instead, it
 should include `/usr/etc`.  This is the "default configuration".  When
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/libostree/libostree.sym 
new/ostree-2016.12/src/libostree/libostree.sym
--- old/ostree-2016.11/src/libostree/libostree.sym      2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/libostree/libostree.sym      2016-10-21 
21:24:31.000000000 +0200
@@ -356,6 +356,7 @@
 /* No new symbols in 2016.9 */
 /* No new symbols in 2016.10 */
 /* No new symbols in 2016.11 */
+/* No new symbols in 2016.12 */
 
 /*                         NOTE NOTE NOTE
  * Versions above here are released.  Only add symbols below this line.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/libostree/ostree-fetcher.c 
new/ostree-2016.12/src/libostree/ostree-fetcher.c
--- old/ostree-2016.11/src/libostree/ostree-fetcher.c   2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/libostree/ostree-fetcher.c   2016-10-21 
21:24:31.000000000 +0200
@@ -65,6 +65,9 @@
 
   /* Also protected by output_stream_set_lock. */
   guint64 total_downloaded;
+
+  GError *oob_error;
+
 } ThreadClosure;
 
 static void
@@ -159,6 +162,8 @@
       g_clear_pointer (&thread_closure->output_stream_set, g_hash_table_unref);
       g_mutex_clear (&thread_closure->output_stream_set_lock);
 
+      g_clear_pointer (&thread_closure->oob_error, g_error_free);
+
       g_slice_free (ThreadClosure, thread_closure);
     }
 }
@@ -277,6 +282,29 @@
 }
 
 static void
+on_authenticate (SoupSession *session, SoupMessage *msg, SoupAuth *auth,
+                 gboolean retrying, gpointer user_data)
+{
+  ThreadClosure *thread_closure = user_data;
+
+  if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED)
+    {
+      SoupURI *uri = NULL;
+      g_object_get (session, SOUP_SESSION_PROXY_URI, &uri, NULL);
+      if (retrying)
+        {
+          g_autofree char *s = soup_uri_to_string (uri, FALSE);
+          g_set_error (&thread_closure->oob_error,
+                       G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED,
+                       "Invalid username or password for proxy '%s'", s);
+        }
+      else
+        soup_auth_authenticate (auth, soup_uri_get_user (uri),
+                                      soup_uri_get_password (uri));
+    }
+}
+
+static void
 session_thread_set_proxy_cb (ThreadClosure *thread_closure,
                              gpointer data)
 {
@@ -285,6 +313,17 @@
   g_object_set (thread_closure->session,
                 SOUP_SESSION_PROXY_URI,
                 proxy_uri, NULL);
+
+  /* libsoup won't necessarily pass any embedded username and password to proxy
+   * requests, so we have to be ready to handle 407 and handle them ourselves.
+   * See also: https://bugzilla.gnome.org/show_bug.cgi?id=772932
+   * */
+  if (soup_uri_get_user (proxy_uri) &&
+      soup_uri_get_password (proxy_uri))
+    {
+      g_signal_connect (thread_closure->session, "authenticate",
+                        G_CALLBACK (on_authenticate), thread_closure);
+    }
 }
 
 #ifdef HAVE_LIBSOUP_CLIENT_CERTS
@@ -998,10 +1037,23 @@
                   code = G_IO_ERROR_FAILED;
                 }
 
-              local_error = g_error_new (G_IO_ERROR, code,
-                                         "Server returned status %u: %s",
-                                         msg->status_code,
-                                         soup_status_get_phrase 
(msg->status_code));
+              {
+                g_autofree char *errmsg =
+                  g_strdup_printf ("Server returned status %u: %s",
+                                   msg->status_code,
+                                   soup_status_get_phrase (msg->status_code));
+
+                /* Let's make OOB errors be the final one since they're 
probably
+                 * the cause for the error here. */
+                if (pending->thread_closure->oob_error)
+                  {
+                    local_error =
+                      g_error_copy (pending->thread_closure->oob_error);
+                    g_prefix_error (&local_error, "%s: ", errmsg);
+                  }
+                else
+                  local_error = g_error_new_literal (G_IO_ERROR, code, errmsg);
+              }
 
               if (pending->mirrorlist->len > 1)
                 g_prefix_error (&local_error,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/libostree/ostree-repo-checkout.c 
new/ostree-2016.12/src/libostree/ostree-repo-checkout.c
--- old/ostree-2016.11/src/libostree/ostree-repo-checkout.c     2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/libostree/ostree-repo-checkout.c     2016-10-21 
21:24:31.000000000 +0200
@@ -437,7 +437,7 @@
 
       need_copy = FALSE;
     }
-  else if (!is_symlink)
+  else
     {
       gboolean did_hardlink = FALSE;
       /* Try to do a hardlink first, if it's a regular file.  This also
@@ -450,7 +450,9 @@
           gboolean is_bare = ((current_repo->mode == OSTREE_REPO_MODE_BARE
                                && options->mode == 
OSTREE_REPO_CHECKOUT_MODE_NONE) ||
                               (current_repo->mode == OSTREE_REPO_MODE_BARE_USER
-                               && options->mode == 
OSTREE_REPO_CHECKOUT_MODE_USER));
+                               && options->mode == 
OSTREE_REPO_CHECKOUT_MODE_USER
+                               /* NOTE: bare-user symlinks are not stored as 
symlinks */
+                               && !is_symlink));
           gboolean current_can_cache = (options->enable_uncompressed_cache
                                         && 
current_repo->enable_uncompressed_cache);
           gboolean is_archive_z2_with_cache = (current_repo->mode == 
OSTREE_REPO_MODE_ARCHIVE_Z2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/libostree/ostree-repo-commit.c 
new/ostree-2016.12/src/libostree/ostree-repo-commit.c
--- old/ostree-2016.11/src/libostree/ostree-repo-commit.c       2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/libostree/ostree-repo-commit.c       2016-10-21 
21:24:31.000000000 +0200
@@ -2035,8 +2035,9 @@
   g_autoptr(GVariant) ret_metadata = NULL;
 
   _ostree_loose_path (buf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, 
self->mode);
-  
-  if (!ot_util_variant_map_at (self->objects_dir_fd, buf,
+
+  if (self->commit_stagedir_fd != -1 &&
+      !ot_util_variant_map_at (self->commit_stagedir_fd, buf,
                                G_VARIANT_TYPE ("a{sv}"),
                                OT_VARIANT_MAP_ALLOW_NOENT | 
OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
     {
@@ -2044,6 +2045,21 @@
       goto out;
     }
 
+  if (ret_metadata == NULL &&
+      !ot_util_variant_map_at (self->objects_dir_fd, buf,
+                               G_VARIANT_TYPE ("a{sv}"),
+                               OT_VARIANT_MAP_ALLOW_NOENT | 
OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
+    {
+      g_prefix_error (error, "Unable to read existing detached metadata: ");
+      goto out;
+    }
+
+  if (ret_metadata == NULL && self->parent_repo)
+    return ostree_repo_read_commit_detached_metadata (self->parent_repo,
+                                                      checksum,
+                                                      out_metadata,
+                                                      cancellable,
+                                                      error);
   ret = TRUE;
   ot_transfer_out_value (out_metadata, &ret_metadata);
  out:
@@ -2073,10 +2089,16 @@
   g_autoptr(GVariant) normalized = NULL;
   gsize normalized_size = 0;
   const guint8 *data = NULL;
+  int dest_dfd;
+
+  if (self->in_transaction)
+    dest_dfd = self->commit_stagedir_fd;
+  else
+    dest_dfd = self->objects_dir_fd;
 
   _ostree_loose_path (pathbuf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, 
self->mode);
 
-  if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, checksum,
+  if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, checksum,
                                             cancellable, error))
     return FALSE;
 
@@ -2090,7 +2112,7 @@
   if (data == NULL)
     data = (guint8*)"";
 
-  if (!glnx_file_replace_contents_at (self->objects_dir_fd, pathbuf,
+  if (!glnx_file_replace_contents_at (dest_dfd, pathbuf,
                                       data, normalized_size,
                                       0, cancellable, error))
     {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/libostree/ostree-repo-pull.c 
new/ostree-2016.12/src/libostree/ostree-repo-pull.c
--- old/ostree-2016.11/src/libostree/ostree-repo-pull.c 2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/libostree/ostree-repo-pull.c 2016-10-21 
21:24:31.000000000 +0200
@@ -99,7 +99,7 @@
   gboolean          is_commit_only;
   gboolean          is_untrusted;
 
-  char         *dir;
+  GPtrArray        *dirs;
   gboolean      commitpartial_exists;
 
   gboolean      have_previous_bytes;
@@ -117,6 +117,7 @@
 typedef struct {
   OtPullData  *pull_data;
   GVariant    *object;
+  char        *path;
   gboolean     is_detached_meta;
 
   /* Only relevant when is_detached_meta is TRUE.  Controls
@@ -133,6 +134,7 @@
 
 typedef struct {
   guchar csum[OSTREE_SHA256_DIGEST_LEN];
+  char *path;
   OstreeObjectType objtype;
   guint recursion_depth;
 } ScanObjectQueueData;
@@ -140,16 +142,19 @@
 static void queue_scan_one_metadata_object (OtPullData         *pull_data,
                                             const char         *csum,
                                             OstreeObjectType    objtype,
+                                            const char         *path,
                                             guint               
recursion_depth);
 
 static void queue_scan_one_metadata_object_c (OtPullData         *pull_data,
                                               const guchar       *csum,
                                               OstreeObjectType    objtype,
+                                              const char         *path,
                                               guint               
recursion_depth);
 
 static gboolean scan_one_metadata_object_c (OtPullData         *pull_data,
                                             const guchar       *csum,
                                             OstreeObjectType    objtype,
+                                            const char         *path,
                                             guint               
recursion_depth,
                                             GCancellable       *cancellable,
                                             GError            **error);
@@ -278,11 +283,13 @@
   scan_one_metadata_object_c (pull_data,
                               scan_data->csum,
                               scan_data->objtype,
+                              scan_data->path,
                               scan_data->recursion_depth,
                               pull_data->cancellable,
                               &error);
   check_outstanding_requests_handle_error (pull_data, error);
 
+  g_free (scan_data->path);
   g_free (scan_data);
   return G_SOURCE_CONTINUE;
 }
@@ -381,12 +388,80 @@
 enqueue_one_object_request (OtPullData        *pull_data,
                             const char        *checksum,
                             OstreeObjectType   objtype,
+                            const char        *path,
                             gboolean           is_detached_meta,
                             gboolean           object_is_stored);
 
 static gboolean
+matches_pull_dir (const char *current_file,
+                  const char *pull_dir,
+                  gboolean current_file_is_dir)
+{
+  const char *rest;
+
+  if (g_str_has_prefix (pull_dir, current_file))
+    {
+      rest = pull_dir + strlen (current_file);
+      if (*rest == 0)
+        {
+          /* The current file is exactly the same as the specified
+             pull dir. This matches always, even if the file is not a
+             directory. */
+          return TRUE;
+        }
+
+      if (*rest == '/')
+        {
+          /* The current file is a directory-prefix of the pull_dir.
+             Match only if this is supposed to be a directory */
+          return current_file_is_dir;
+        }
+
+      /* Matched a non-directory prefix such as /foo being a prefix of /fooo,
+         no match */
+      return FALSE;
+    }
+
+  if (g_str_has_prefix (current_file, pull_dir))
+    {
+      rest = current_file + strlen (pull_dir);
+      /* Only match if the prefix match matched the entire directory
+         component */
+      return *rest == '/';
+    }
+
+  return FALSE;
+}
+
+
+static gboolean
+pull_matches_subdir (OtPullData *pull_data,
+                     const char *path,
+                     const char *basename,
+                     gboolean basename_is_dir)
+{
+  int i;
+  g_autofree char *file = NULL;
+
+  if (pull_data->dirs == NULL)
+    return TRUE;
+
+  file = g_strconcat (path, basename, NULL);
+
+  for (i = 0; i < pull_data->dirs->len; i++)
+    {
+      const char *pull_dir = g_ptr_array_index (pull_data->dirs, i);
+      if (matches_pull_dir (file, pull_dir, basename_is_dir))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
 scan_dirtree_object (OtPullData   *pull_data,
                      const char   *checksum,
+                     const char   *path,
                      int           recursion_depth,
                      GCancellable *cancellable,
                      GError      **error)
@@ -396,7 +471,6 @@
   g_autoptr(GVariant) tree = NULL;
   g_autoptr(GVariant) files_variant = NULL;
   g_autoptr(GVariant) dirs_variant = NULL;
-  char *subdir_target = NULL;
   const char *dirname = NULL;
 
   if (recursion_depth > OSTREE_MAX_RECURSION)
@@ -429,10 +503,7 @@
 
       /* Skip files if we're traversing a request only directory, unless it 
exactly
        * matches the path */
-      if (pull_data->dir &&
-          /* Should always an initial slash, we assert it in 
scan_dirtree_object */
-          pull_data->dir[0] == '/' &&
-          strcmp (pull_data->dir+1, filename) != 0)
+      if (!pull_matches_subdir (pull_data, path, filename, FALSE))
         continue;
 
       file_checksum = ostree_checksum_from_bytes_v (csum);
@@ -451,32 +522,11 @@
       else if (!file_is_stored && !g_hash_table_lookup 
(pull_data->requested_content, file_checksum))
         {
           g_hash_table_insert (pull_data->requested_content, file_checksum, 
file_checksum);
-          enqueue_one_object_request (pull_data, file_checksum, 
OSTREE_OBJECT_TYPE_FILE, FALSE, FALSE);
+          enqueue_one_object_request (pull_data, file_checksum, 
OSTREE_OBJECT_TYPE_FILE, path, FALSE, FALSE);
           file_checksum = NULL;  /* Transfer ownership */
         }
     }
 
-    if (pull_data->dir)
-      {
-        const char *subpath = NULL;  
-        const char *nextslash = NULL;
-        g_autofree char *dir_data = NULL;
-
-        g_assert (pull_data->dir[0] == '/'); // assert it starts with / like 
"/usr/share/rpm"
-        subpath = pull_data->dir + 1;  // refers to name minus / like 
"usr/share/rpm"
-        nextslash = strchr (subpath, '/'); //refers to start of next slash 
like "/share/rpm"
-        dir_data = pull_data->dir; // keep the original pointer around since 
strchr() points into it
-        pull_data->dir = NULL;
-
-        if (nextslash)
-          {
-            subdir_target = g_strndup (subpath, nextslash - subpath); // 
refers to first dir, like "usr"
-            pull_data->dir = g_strdup (nextslash); // sets dir to new deeper 
level like "/share/rpm"
-          }
-        else // we're as deep as it goes, i.e. subpath = "rpm"
-          subdir_target = g_strdup (subpath); 
-      }
-
   n = g_variant_n_children (dirs_variant);
 
   for (i = 0; i < n; i++)
@@ -485,6 +535,7 @@
       g_autoptr(GVariant) meta_csum = NULL;
       const guchar *tree_csum_bytes;
       const guchar *meta_csum_bytes;
+      g_autofree char *subpath = NULL;
 
       g_variant_get_child (dirs_variant, i, "(&s@ay@ay)",
                            &dirname, &tree_csum, &meta_csum);
@@ -492,7 +543,7 @@
       if (!ot_util_filename_validate (dirname, error))
         goto out;
 
-      if (subdir_target && strcmp (subdir_target, dirname) != 0)
+      if (!pull_matches_subdir (pull_data, path, dirname, TRUE))
         continue;
 
       tree_csum_bytes = ostree_checksum_bytes_peek_validate (tree_csum, error);
@@ -503,10 +554,12 @@
       if (meta_csum_bytes == NULL)
         goto out;
 
+      subpath = g_strconcat (path, dirname, "/", NULL);
+
       queue_scan_one_metadata_object_c (pull_data, tree_csum_bytes,
-                                        OSTREE_OBJECT_TYPE_DIR_TREE, 
recursion_depth + 1);
+                                        OSTREE_OBJECT_TYPE_DIR_TREE, subpath, 
recursion_depth + 1);
       queue_scan_one_metadata_object_c (pull_data, meta_csum_bytes,
-                                        OSTREE_OBJECT_TYPE_DIR_META, 
recursion_depth + 1);
+                                        OSTREE_OBJECT_TYPE_DIR_META, subpath, 
recursion_depth + 1);
     }
 
   ret = TRUE;
@@ -584,6 +637,14 @@
 }
 
 static void
+fetch_object_data_free (FetchObjectData *fetch_data)
+{
+  g_variant_unref (fetch_data->object);
+  g_free (fetch_data->path);
+  g_free (fetch_data);
+}
+
+static void
 content_fetch_on_write_complete (GObject        *object,
                                  GAsyncResult   *result,
                                  gpointer        user_data)
@@ -622,8 +683,7 @@
  out:
   pull_data->n_outstanding_content_write_requests--;
   check_outstanding_requests_handle_error (pull_data, local_error);
-  g_variant_unref (fetch_data->object);
-  g_free (fetch_data);
+  fetch_object_data_free (fetch_data);
 }
 
 static void
@@ -712,10 +772,7 @@
   pull_data->n_outstanding_content_fetches--;
   check_outstanding_requests_handle_error (pull_data, local_error);
   if (free_fetch_data)
-    {
-      g_variant_unref (fetch_data->object);
-      g_free (fetch_data);
-    }
+    fetch_object_data_free (fetch_data);
 }
 
 static void
@@ -753,12 +810,11 @@
       goto out;
     }
 
-  queue_scan_one_metadata_object_c (pull_data, csum, objtype, 0);
+  queue_scan_one_metadata_object_c (pull_data, csum, objtype, 
fetch_data->path, 0);
 
  out:
   pull_data->n_outstanding_metadata_write_requests--;
-  g_variant_unref (fetch_data->object);
-  g_free (fetch_data);
+  fetch_object_data_free (fetch_data);
 
   check_outstanding_requests_handle_error (pull_data, local_error);
 }
@@ -796,7 +852,7 @@
               /* There isn't any detached metadata, just fetch the commit */
               g_clear_error (&local_error);
               if (!fetch_data->object_is_stored)
-                enqueue_one_object_request (pull_data, checksum, objtype, 
FALSE, FALSE);
+                enqueue_one_object_request (pull_data, checksum, objtype, 
fetch_data->path, FALSE, FALSE);
             }
 
           /* When traversing parents, do not fail on a missing commit.
@@ -811,7 +867,7 @@
               if (pull_data->has_tombstone_commits)
                 {
                   enqueue_one_object_request (pull_data, checksum, 
OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT,
-                                              FALSE, FALSE);
+                                              fetch_data->path, FALSE, FALSE);
                 }
             }
         }
@@ -844,7 +900,7 @@
         goto out;
 
       if (!fetch_data->object_is_stored)
-        enqueue_one_object_request (pull_data, checksum, objtype, FALSE, 
FALSE);
+        enqueue_one_object_request (pull_data, checksum, objtype, 
fetch_data->path, FALSE, FALSE);
     }
   else
     {
@@ -874,10 +930,7 @@
   pull_data->n_fetched_metadata++;
   check_outstanding_requests_handle_error (pull_data, local_error);
   if (free_fetch_data)
-    {
-      g_variant_unref (fetch_data->object);
-      g_free (fetch_data);
-    }
+    fetch_object_data_free (fetch_data);
 }
 
 static void
@@ -1053,7 +1106,8 @@
   if (parent_csum_bytes != NULL && pull_data->maxdepth == -1)
     {
       queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
-                                        OSTREE_OBJECT_TYPE_COMMIT, 
recursion_depth + 1);
+                                        OSTREE_OBJECT_TYPE_COMMIT, NULL,
+                                        recursion_depth + 1);
     }
   else if (parent_csum_bytes != NULL && depth > 0)
     {
@@ -1078,7 +1132,9 @@
           g_hash_table_insert (pull_data->commit_to_depth, g_strdup 
(parent_checksum),
                                GINT_TO_POINTER (parent_depth));
           queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
-                                            OSTREE_OBJECT_TYPE_COMMIT, 
recursion_depth + 1);
+                                            OSTREE_OBJECT_TYPE_COMMIT,
+                                            NULL,
+                                            recursion_depth + 1);
         }
     }
 
@@ -1101,10 +1157,10 @@
         goto out;
 
       queue_scan_one_metadata_object_c (pull_data, tree_contents_csum_bytes,
-                                        OSTREE_OBJECT_TYPE_DIR_TREE, 
recursion_depth + 1);
+                                        OSTREE_OBJECT_TYPE_DIR_TREE, "/", 
recursion_depth + 1);
 
       queue_scan_one_metadata_object_c (pull_data, tree_meta_csum_bytes,
-                                        OSTREE_OBJECT_TYPE_DIR_META, 
recursion_depth + 1);
+                                        OSTREE_OBJECT_TYPE_DIR_META, NULL, 
recursion_depth + 1);
     }
 
   ret = TRUE;
@@ -1116,23 +1172,26 @@
 queue_scan_one_metadata_object (OtPullData         *pull_data,
                                 const char         *csum,
                                 OstreeObjectType    objtype,
+                                const char         *path,
                                 guint               recursion_depth)
 {
   guchar buf[OSTREE_SHA256_DIGEST_LEN];
   ostree_checksum_inplace_to_bytes (csum, buf);
-  queue_scan_one_metadata_object_c (pull_data, buf, objtype, recursion_depth);
+  queue_scan_one_metadata_object_c (pull_data, buf, objtype, path, 
recursion_depth);
 }
 
 static void
 queue_scan_one_metadata_object_c (OtPullData         *pull_data,
                                   const guchar         *csum,
                                   OstreeObjectType    objtype,
+                                  const char         *path,
                                   guint               recursion_depth)
 {
   ScanObjectQueueData *scan_data = g_new0 (ScanObjectQueueData, 1);
 
   memcpy (scan_data->csum, csum, sizeof (scan_data->csum));
   scan_data->objtype = objtype;
+  scan_data->path = g_strdup (path);
   scan_data->recursion_depth = recursion_depth;
 
   g_queue_push_tail (&pull_data->scan_object_queue, scan_data);
@@ -1143,6 +1202,7 @@
 scan_one_metadata_object_c (OtPullData         *pull_data,
                             const guchar         *csum,
                             OstreeObjectType    objtype,
+                            const char         *path,
                             guint               recursion_depth,
                             GCancellable       *cancellable,
                             GError            **error)
@@ -1190,7 +1250,7 @@
       g_hash_table_insert (pull_data->requested_metadata, duped_checksum, 
duped_checksum);
 
       do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT);
-      enqueue_one_object_request (pull_data, tmp_checksum, objtype, 
do_fetch_detached, FALSE);
+      enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, 
do_fetch_detached, FALSE);
     }
   else if (objtype == OSTREE_OBJECT_TYPE_COMMIT && pull_data->is_commit_only)
     {
@@ -1207,7 +1267,7 @@
 
       /* For commits, always refetch detached metadata. */
       if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
-        enqueue_one_object_request (pull_data, tmp_checksum, objtype, TRUE, 
TRUE);
+        enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, 
TRUE, TRUE);
 
       /* For commits, check whether we only had a partial fetch */
       if (!do_scan && objtype == OSTREE_OBJECT_TYPE_COMMIT)
@@ -1245,7 +1305,7 @@
             case OSTREE_OBJECT_TYPE_DIR_META:
               break;
             case OSTREE_OBJECT_TYPE_DIR_TREE:
-              if (!scan_dirtree_object (pull_data, tmp_checksum, 
recursion_depth,
+              if (!scan_dirtree_object (pull_data, tmp_checksum, path, 
recursion_depth,
                                         pull_data->cancellable, error))
                 goto out;
               break;
@@ -1267,6 +1327,7 @@
 enqueue_one_object_request (OtPullData        *pull_data,
                             const char        *checksum,
                             OstreeObjectType   objtype,
+                            const char        *path,
                             gboolean           is_detached_meta,
                             gboolean           object_is_stored)
 {
@@ -1308,6 +1369,7 @@
   fetch_data = g_new0 (FetchObjectData, 1);
   fetch_data->pull_data = pull_data;
   fetch_data->object = ostree_object_name_serialize (checksum, objtype);
+  fetch_data->path = g_strdup (path);
   fetch_data->is_detached_meta = is_detached_meta;
   fetch_data->object_is_stored = object_is_stored;
 
@@ -1478,7 +1540,7 @@
               g_hash_table_insert (pull_data->requested_metadata, checksum, 
checksum);
               
               do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT);
-              enqueue_one_object_request (pull_data, checksum, objtype, 
do_fetch_detached, FALSE);
+              enqueue_one_object_request (pull_data, checksum, objtype, NULL, 
do_fetch_detached, FALSE);
               checksum = NULL;  /* Transfer ownership */
             }
         }
@@ -1487,7 +1549,7 @@
           if (!g_hash_table_lookup (pull_data->requested_content, checksum))
             {
               g_hash_table_insert (pull_data->requested_content, checksum, 
checksum);
-              enqueue_one_object_request (pull_data, checksum, 
OSTREE_OBJECT_TYPE_FILE, FALSE, FALSE);
+              enqueue_one_object_request (pull_data, checksum, 
OSTREE_OBJECT_TYPE_FILE, NULL, FALSE, FALSE);
               checksum = NULL;  /* Transfer ownership */
             }
         }
@@ -2227,6 +2289,7 @@
  *   * refs (as): Array of string refs
  *   * flags (i): An instance of #OstreeRepoPullFlags
  *   * subdir (s): Pull just this subdirectory
+ *   * subdirs (as): Pull just these subdirectories
  *   * override-remote-name (s): If local, add this remote to refspec
  *   * gpg-verify (b): GPG verify commits
  *   * gpg-verify-summary (b): GPG verify summary
@@ -2236,6 +2299,7 @@
  *   * override-commit-ids (as): Array of specific commit IDs to fetch for refs
  *   * dry-run (b): Only print information on what will be downloaded 
(requires static deltas)
  *   * override-url (s): Fetch objects from this URL if remote specifies no 
metalink in options
+ *   * inherit-transaction (b): Don't initiate, finish or abort a transaction, 
usefult to do mutliple pulls in one transaction.
  */
 gboolean
 ostree_repo_pull_with_options (OstreeRepo             *self,
@@ -2262,6 +2326,7 @@
   guint64 end_time;
   OstreeRepoPullFlags flags = 0;
   const char *dir_to_pull = NULL;
+  g_autofree char **dirs_to_pull = NULL;
   g_autofree char **refs_to_fetch = NULL;
   char **override_commit_ids = NULL;
   GSource *update_timeout = NULL;
@@ -2273,6 +2338,8 @@
   g_autofree char *base_meta_url = NULL;
   g_autofree char *base_content_url = NULL;
   gboolean mirroring_into_archive;
+  gboolean inherit_transaction = FALSE;
+  int i;
 
   if (options)
     {
@@ -2282,6 +2349,7 @@
       /* Reduce risk of issues if enum happens to be 64 bit for some reason */
       flags = flags_i;
       (void) g_variant_lookup (options, "subdir", "&s", &dir_to_pull);
+      (void) g_variant_lookup (options, "subdirs", "^a&s", &dirs_to_pull);
       (void) g_variant_lookup (options, "override-remote-name", "s", 
&pull_data->remote_name);
       opt_gpg_verify_set =
         g_variant_lookup (options, "gpg-verify", "b", &pull_data->gpg_verify);
@@ -2293,6 +2361,7 @@
       (void) g_variant_lookup (options, "override-commit-ids", "^a&s", 
&override_commit_ids);
       (void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run);
       (void) g_variant_lookup (options, "override-url", "&s", &url_override);
+      (void) g_variant_lookup (options, "inherit-transaction", "b", 
&inherit_transaction);
     }
 
   g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE);
@@ -2302,6 +2371,9 @@
   if (dir_to_pull)
     g_return_val_if_fail (dir_to_pull[0] == '/', FALSE);
 
+  for (i = 0; dirs_to_pull != NULL && dirs_to_pull[i] != NULL; i++)
+    g_return_val_if_fail (dirs_to_pull[i][0] == '/', FALSE);
+
   g_return_val_if_fail (!(disable_static_deltas && require_static_deltas), 
FALSE);
   /* We only do dry runs with static deltas, because we don't really have any
    * in-advance information for bare fetches.
@@ -2340,7 +2412,19 @@
                                                         
(GDestroyNotify)g_free, NULL);
   pull_data->requested_metadata = g_hash_table_new_full (g_str_hash, 
g_str_equal,
                                                          
(GDestroyNotify)g_free, NULL);
-  pull_data->dir = g_strdup (dir_to_pull);
+  if (dir_to_pull != NULL || dirs_to_pull != NULL)
+    {
+      pull_data->dirs = g_ptr_array_new_with_free_func (g_free);
+      if (dir_to_pull != NULL)
+        g_ptr_array_add (pull_data->dirs, g_strdup (dir_to_pull));
+
+      if (dirs_to_pull != NULL)
+        {
+          for (i = 0; dirs_to_pull[i] != NULL; i++)
+            g_ptr_array_add (pull_data->dirs, g_strdup (dirs_to_pull[i]));
+        }
+    }
+
   g_queue_init (&pull_data->scan_object_queue);
 
   pull_data->start_time = g_get_monotonic_time ();
@@ -2822,7 +2906,9 @@
   if (pull_data->fetcher == NULL)
     goto out;
 
-  if (!ostree_repo_prepare_transaction (pull_data->repo, 
&pull_data->legacy_transaction_resuming,
+  pull_data->legacy_transaction_resuming = FALSE;
+  if (!inherit_transaction &&
+      !ostree_repo_prepare_transaction (pull_data->repo, 
&pull_data->legacy_transaction_resuming,
                                         cancellable, error))
     goto out;
 
@@ -2833,7 +2919,7 @@
   while (g_hash_table_iter_next (&hash_iter, &key, &value))
     {
       const char *commit = value;
-      queue_scan_one_metadata_object (pull_data, commit, 
OSTREE_OBJECT_TYPE_COMMIT, 0);
+      queue_scan_one_metadata_object (pull_data, commit, 
OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
     }
 
   g_hash_table_iter_init (&hash_iter, requested_refs_to_fetch);
@@ -2866,7 +2952,7 @@
               goto out;
             }
           g_debug ("no delta superblock for %s-%s", from_revision ? 
from_revision : "empty", to_revision);
-          queue_scan_one_metadata_object (pull_data, to_revision, 
OSTREE_OBJECT_TYPE_COMMIT, 0);
+          queue_scan_one_metadata_object (pull_data, to_revision, 
OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
         }
       else
         {
@@ -2954,7 +3040,8 @@
         }
     }
 
-  if (!ostree_repo_commit_transaction (pull_data->repo, NULL, cancellable, 
error))
+  if (!inherit_transaction &&
+      !ostree_repo_commit_transaction (pull_data->repo, NULL, cancellable, 
error))
     goto out;
 
   end_time = g_get_monotonic_time ();
@@ -2988,7 +3075,7 @@
     }
 
   /* iterate over commits fetched and delete any commitpartial files */
-  if (!dir_to_pull && !pull_data->is_commit_only)
+  if (pull_data->dirs == NULL && !pull_data->is_commit_only)
     {
       g_hash_table_iter_init (&hash_iter, requested_refs_to_fetch);
       while (g_hash_table_iter_next (&hash_iter, &key, &value))
@@ -3020,8 +3107,9 @@
     g_propagate_error (error, pull_data->cached_async_error);
   else
     g_clear_error (&pull_data->cached_async_error);
-    
-  ostree_repo_abort_transaction (pull_data->repo, cancellable, NULL);
+
+  if (!inherit_transaction)
+    ostree_repo_abort_transaction (pull_data->repo, cancellable, NULL);
   g_main_context_unref (pull_data->main_context);
   if (update_timeout)
     g_source_destroy (update_timeout);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/libostree/ostree-sysroot-deploy.c 
new/ostree-2016.12/src/libostree/ostree-sysroot-deploy.c
--- old/ostree-2016.11/src/libostree/ostree-sysroot-deploy.c    2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/libostree/ostree-sysroot-deploy.c    2016-10-21 
21:24:31.000000000 +0200
@@ -2002,7 +2002,7 @@
     g_ptr_array_new_with_free_func (g_object_unref);
 
   osdir = ot_gfile_get_child_build_path (self->path, "ostree/deploy", osname, 
NULL);
-  
+
   if (!_ostree_sysroot_list_deployment_dirs_for_os (osdir, 
tmp_current_deployments,
                                                     cancellable, error))
     goto out;
@@ -2010,9 +2010,7 @@
   for (i = 0; i < tmp_current_deployments->len; i++)
     {
       OstreeDeployment *deployment = tmp_current_deployments->pdata[i];
-      
-      if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
-        continue;
+
       if (strcmp (ostree_deployment_get_csum (deployment), revision) != 0)
         continue;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/src/ostree/ot-builtin-pull.c 
new/ostree-2016.12/src/ostree/ot-builtin-pull.c
--- old/ostree-2016.11/src/ostree/ot-builtin-pull.c     2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/src/ostree/ot-builtin-pull.c     2016-10-21 
21:24:31.000000000 +0200
@@ -34,7 +34,7 @@
 static gboolean opt_disable_static_deltas;
 static gboolean opt_require_static_deltas;
 static gboolean opt_untrusted;
-static char* opt_subpath;
+static char** opt_subpaths;
 static char* opt_cache_dir;
 static int opt_depth = 0;
 static char* opt_url;
@@ -46,7 +46,7 @@
    { "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, 
&opt_disable_static_deltas, "Do not use static deltas", NULL },
    { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, 
&opt_require_static_deltas, "Require static deltas", NULL },
    { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for 
a mirror", NULL },
-   { "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Only pull the 
provided subpath", NULL },
+   { "subpath", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_subpaths, "Only pull the 
provided subpath(s)", NULL },
    { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust 
(local) sources", NULL },
    { "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information 
on what will be downloaded (requires static deltas)", NULL },
    { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents 
(-1=infinite) (default: 0)", "DEPTH" },
@@ -216,9 +216,17 @@
     if (opt_url)
       g_variant_builder_add (&builder, "{s@v}", "override-url",
                              g_variant_new_variant (g_variant_new_string 
(opt_url)));
-    if (opt_subpath)
-      g_variant_builder_add (&builder, "{s@v}", "subdir",
-                             g_variant_new_variant (g_variant_new_string 
(opt_subpath)));
+    if (opt_subpaths && opt_subpaths[0] != NULL)
+      {
+        /* Special case the one-element case so that we excercise this
+           old single-argument version in the tests */
+        if (opt_subpaths[1] == NULL)
+          g_variant_builder_add (&builder, "{s@v}", "subdir",
+                                 g_variant_new_variant (g_variant_new_string 
(opt_subpaths[0])));
+        else
+          g_variant_builder_add (&builder, "{s@v}", "subdirs",
+                                 g_variant_new_variant (g_variant_new_strv 
((const char *const*) opt_subpaths, -1)));
+      }
     g_variant_builder_add (&builder, "{s@v}", "flags",
                            g_variant_new_variant (g_variant_new_int32 
(pullflags)));
     if (refs_to_fetch)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ostree-2016.11/tests/test-pull-subpath.sh 
new/ostree-2016.12/tests/test-pull-subpath.sh
--- old/ostree-2016.11/tests/test-pull-subpath.sh       2016-10-07 
21:21:41.000000000 +0200
+++ new/ostree-2016.12/tests/test-pull-subpath.sh       2016-10-21 
21:24:31.000000000 +0200
@@ -36,9 +36,10 @@
 ${CMD_PREFIX} ostree --repo=repo init
 ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin 
${remoteurl}
 
-${CMD_PREFIX} ostree --repo=repo pull --subpath=/baz origin main
+${CMD_PREFIX} ostree --repo=repo pull --subpath=/baz/deeper 
--subpath=/baz/another origin main
 
-${CMD_PREFIX} ostree --repo=repo ls origin:main /baz
+${CMD_PREFIX} ostree --repo=repo ls origin:main /baz/deeper
+${CMD_PREFIX} ostree --repo=repo ls origin:main /baz/another
 if ${CMD_PREFIX} ostree --repo=repo ls origin:main /firstfile 2>err.txt; then
     assert_not_reached
 fi


Reply via email to