diff --git a/Makefile-libostree.am b/Makefile-libostree.am index 99e85c29..e2443932 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -33,6 +33,8 @@ libostree_la_SOURCES = src/libostree/ostree.h \ src/libostree/ostree-types.h \ src/libostree/ostree-traverse.c \ src/libostree/ostree-traverse.h \ + src/libostree/ostree-sysroot.c \ + src/libostree/ostree-sysroot.h \ $(NULL) if USE_LIBARCHIVE libostree_la_SOURCES += src/libostree/ostree-libarchive-input-stream.h \ diff --git a/gnomeos/gnomeos-clone-qemu.sh b/gnomeos/gnomeos-clone-qemu.sh index e87332e4..be1bb713 100755 --- a/gnomeos/gnomeos-clone-qemu.sh +++ b/gnomeos/gnomeos-clone-qemu.sh @@ -76,10 +76,10 @@ chmod a=rwxt tmp if ! test -d ostree; then mkdir -p ostree - $SRCDIR/ostree-setup.sh $(pwd)/ostree + $SRCDIR/gnomeos-setup.sh $(pwd)/ostree fi -rsync -a -H -v ${WORKDIR}/repo ${WORKDIR}/current ${WORKDIR}/modules ${WORKDIR}/gnomeos-3.4-* ./ostree +rsync -a -H -v ${WORKDIR}/repo ${WORKDIR}/current ${WORKDIR}/modules ${WORKDIR}/var ${WORKDIR}/gnomeos-3.4-* ./ostree current_uname=$(uname -r) diff --git a/gnomeos/gnomeos-install.sh b/gnomeos/gnomeos-install.sh index d66c16f4..f99c13f5 100755 --- a/gnomeos/gnomeos-install.sh +++ b/gnomeos/gnomeos-install.sh @@ -48,16 +48,15 @@ if ! test -d /ostree/repo/objects; then $SRCDIR/gnomeos-setup.sh /ostree fi -ostree --repo=repo remote add origin http://ostree.gnome.org/repo -ostree-pull --repo=repo origin gnomeos-3.4-i686-runtime -ostree-pull --repo=repo origin gnomeos-3.4-i686-devel +ostree --repo=repo remote add origin http://ostree.gnome.org/repo ${BRANCH_PREFIX}{runtime,devel} +ostree-pull --repo=repo origin +for branch in runtime devel; do + ostree --repo=repo checkout --atomic-retarget ${BRANCH_PREFIX}${branch} +done +ln -sf ${BRANCH_PREFIX}runtime current uname=$(uname -r) -$SRCDIR/gnomeos-update-branches.sh - -cd - - if test -d /etc/grub.d; then cp $SRCDIR/15_ostree /etc/grub.d/ else @@ -74,7 +73,9 @@ EOF exit 1 fi -cp -ar /lib/modules/${uname} /ostree/modules/${uname} +if ! test -d /ostree/modules/${uname}; then + cp -ar /lib/modules/${uname} /ostree/modules/${uname} +fi initrd_name=initramfs-ostree-${uname}.img if ! test -f "/boot/${initrd_name}"; then diff --git a/gnomeos/gnomeos-update-branches.sh b/gnomeos/gnomeos-update-branches.sh index f00e0c36..4913a993 100755 --- a/gnomeos/gnomeos-update-branches.sh +++ b/gnomeos/gnomeos-update-branches.sh @@ -26,13 +26,7 @@ BRANCH_PREFIX="gnomeos-3.4-${ARCH}-" test -d repo || exit 1 for branch in runtime devel; do - rev=$(ostree --repo=$(pwd)/repo rev-parse ${BRANCH_PREFIX}${branch}); - if ! test -d ${BRANCH_PREFIX}${branch}-${rev}; then - ostree --repo=repo checkout ${rev} ${BRANCH_PREFIX}${branch}-${rev} - ostbuild chroot-run-triggers ${BRANCH_PREFIX}${branch}-${rev} - fi - ln -sf ${BRANCH_PREFIX}${branch}-${rev} ${BRANCH_PREFIX}${branch}-current.new - mv ${BRANCH_PREFIX}${branch}-current{.new,} + ostree --repo=repo checkout --atomic-retarget ${BRANCH_PREFIX}${branch} done ln -sf ${BRANCH_PREFIX}runtime-current current.new mv current.new current diff --git a/src/libostree/README.md b/src/libostree/README.md index 9a769279..35fe48d8 100644 --- a/src/libostree/README.md +++ b/src/libostree/README.md @@ -47,6 +47,7 @@ MILESTONE 2 * Add index size to superindex, pack size to index - So pull can calculate how much we need to download * Split pack files into metadata/data +* pull: Extract all we can from each packfile one at a time, then delete it * Restructure repository so that links can be generated as a cache; i.e. objects/raw, pack files are now the canonical * For files, checksum combination of metadata variant + raw data diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c new file mode 100644 index 00000000..cb0ede42 --- /dev/null +++ b/src/libostree/ostree-sysroot.c @@ -0,0 +1,121 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012 Colin Walters + * + * 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. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include + +#include "ostree.h" +#include "otutil.h" + +static const char * const sysroot_environ[] = { + "HOME=/", + "PWD=/", + "HOSTNAME=ostreesysroot", + "LANG=C", + "PATH=/usr/bin:/bin:/usr/sbin:/sbin", + "SHELL=/bin/bash", + "TERM=vt100", + "TMPDIR=/tmp", + "TZ=EST5EDT", + NULL +}; + +const char *const* +ostree_get_sysroot_environ (void) +{ + return (const char *const*)sysroot_environ; +} + +/** + * @root: (allow-none): Change to this root; if %NULL, don't chroot + * + * Triggers are a set of programs to run on a root to regenerate cache + * files. This API call will simply run them against the given root. + */ +gboolean +ostree_run_triggers_in_root (GFile *root, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + int estatus; + char *rel_triggerdir = NULL; + GFile *triggerdir = NULL; + GPtrArray *argv = NULL; + + rel_triggerdir = g_build_filename ("usr", "libexec", "ostree", "triggers.d", NULL); + + if (root) + triggerdir = g_file_resolve_relative_path (root, rel_triggerdir); + else + triggerdir = ot_gfile_new_for_path (rel_triggerdir); + + if (g_file_query_exists (triggerdir, cancellable)) + { + argv = g_ptr_array_new (); + if (root) + { + g_ptr_array_add (argv, "linux-user-chroot"); + g_ptr_array_add (argv, "--unshare-pid"); + g_ptr_array_add (argv, "--unshare-ipc"); + /* FIXME - unshare net too */ + g_ptr_array_add (argv, "--mount-proc"); + g_ptr_array_add (argv, "/proc"); + g_ptr_array_add (argv, "--mount-bind"); + g_ptr_array_add (argv, "/dev"); + g_ptr_array_add (argv, "/dev"); + g_ptr_array_add (argv, (char*)ot_gfile_get_path_cached (root)); + } + g_ptr_array_add (argv, "ostree-run-triggers"); + g_ptr_array_add (argv, NULL); + + if (!g_spawn_sync (NULL, (char**)argv->pdata, + (char**) ostree_get_sysroot_environ (), + G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL, + NULL, NULL, NULL, NULL, &estatus, error)) + goto out; + + if (WIFEXITED (estatus)) + { + if (WEXITSTATUS (estatus) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Trigger process exited with code %d", (int)WEXITSTATUS (estatus)); + goto out; + } + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Trigger process failed due to signal"); + goto out; + } + } + + ret = TRUE; + out: + g_free (rel_triggerdir); + g_clear_object (&triggerdir); + ot_clear_ptrarray (&argv); + return ret; +} diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h new file mode 100644 index 00000000..b10246df --- /dev/null +++ b/src/libostree/ostree-sysroot.h @@ -0,0 +1,39 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2011 Colin Walters + * + * 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. + * + * Author: Colin Walters + */ + +#ifndef _OSTREE_SYSROOT +#define _OSTREE_SYSROOT + +#include "ostree-core.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +const char *const* ostree_get_sysroot_environ (void); + +gboolean ostree_run_triggers_in_root (GFile *root, + GCancellable *cancellable, + GError **error); + +G_END_DECLS + +#endif diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h index ecd84779..571aea96 100644 --- a/src/libostree/ostree.h +++ b/src/libostree/ostree.h @@ -27,5 +27,6 @@ #include #include #include +#include #endif diff --git a/src/ostree/ostree-pull.c b/src/ostree/ostree-pull.c index b3c1f5a2..695251fd 100644 --- a/src/ostree/ostree-pull.c +++ b/src/ostree/ostree-pull.c @@ -977,6 +977,7 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error) GHashTableIter hash_iter; gpointer key, value; char *branch_rev = NULL; + char **configured_branches = NULL; int i; context = g_option_context_new ("REMOTE [BRANCH...] - Download data from remote repository"); @@ -1036,15 +1037,58 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error) } else { - summary_uri = soup_uri_copy (pull_data->base_uri); - path = g_build_filename (soup_uri_get_path (summary_uri), "refs", "summary", NULL); - soup_uri_set_path (summary_uri, path); + GError *temp_error = NULL; + gboolean fetch_all_refs; - if (!fetch_uri_contents_utf8 (pull_data, summary_uri, &summary_data, cancellable, error)) - goto out; + refs_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + configured_branches = g_key_file_get_string_list (config, key, "branches", NULL, &temp_error); + if (configured_branches == NULL && temp_error != NULL) + { + if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) + { + g_clear_error (&temp_error); + fetch_all_refs = TRUE; + } + else + { + g_propagate_error (error, temp_error); + goto out; + } + } + else + fetch_all_refs = FALSE; - if (!parse_ref_summary (summary_data, &refs_to_fetch, error)) - goto out; + if (fetch_all_refs) + { + summary_uri = soup_uri_copy (pull_data->base_uri); + path = g_build_filename (soup_uri_get_path (summary_uri), "refs", "summary", NULL); + soup_uri_set_path (summary_uri, path); + + if (!fetch_uri_contents_utf8 (pull_data, summary_uri, &summary_data, cancellable, error)) + goto out; + + if (!parse_ref_summary (summary_data, &refs_to_fetch, error)) + goto out; + } + else + { + char **branches_iter = configured_branches; + + if (!*branches_iter) + g_print ("No configured branches for remote %s\n", pull_data->remote_name); + for (;*branches_iter; branches_iter++) + { + const char *branch = *branches_iter; + char *contents; + + if (!fetch_ref_contents (pull_data, branch, &contents, cancellable, error)) + goto out; + + /* Transfer ownership of contents */ + g_hash_table_insert (refs_to_fetch, g_strdup (branch), contents); + } + } } g_hash_table_iter_init (&hash_iter, refs_to_fetch); @@ -1058,10 +1102,19 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error) goto out; } + g_print ("Cleaning cached pack files...\n"); + + if (!ostree_repo_clean_cached_remote_pack_data (pull_data->repo, pull_data->remote_name, + cancellable, error)) + goto out; + + g_print ("Done\n"); + ret = TRUE; out: if (refs_to_fetch) g_hash_table_unref (refs_to_fetch); + g_strfreev (configured_branches); g_free (path); g_free (baseurl); g_free (summary_data); diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index fbdac135..a2a56b05 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -28,6 +28,8 @@ #include static gboolean user_mode; +static gboolean opt_atomic_retarget; +static gboolean opt_no_triggers; static char *subpath; static gboolean opt_union; @@ -35,9 +37,85 @@ static GOptionEntry options[] = { { "user-mode", 'U', 0, G_OPTION_ARG_NONE, &user_mode, "Do not change file ownership or initialze extended attributes", NULL }, { "subpath", 0, 0, G_OPTION_ARG_STRING, &subpath, "Checkout sub-directory PATH", "PATH" }, { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, + { "atomic-retarget", 0, 0, G_OPTION_ARG_NONE, &opt_atomic_retarget, "Make a symbolic link for destination, suffix with checksum", NULL }, + { "no-triggers", 0, 0, G_OPTION_ARG_NONE, &opt_no_triggers, "Don't run triggers", NULL }, { NULL } }; +static gboolean +atomic_symlink_swap (GFile *dest, + const char *target, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GFile *parent = NULL; + char *tmp_name = NULL; + GFile *tmp_link = NULL; + + parent = g_file_get_parent (dest); + /* HACK - should use randomly generated temporary target name */ + tmp_name = g_strconcat (ot_gfile_get_basename_cached (dest), + "-tmplink", NULL); + tmp_link = g_file_get_child (parent, tmp_name); + if (symlink (target, ot_gfile_get_path_cached (tmp_link)) < 0) + { + ot_util_set_error_from_errno (error, errno); + goto out; + } + if (!ot_gfile_rename (tmp_link, dest, cancellable, error)) + goto out; + + ret = TRUE; + out: + g_free (tmp_name); + g_clear_object (&parent); + g_clear_object (&tmp_link); + return ret; +} + +static gboolean +parse_commit_from_symlink (GFile *symlink, + char **out_commit, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GFileInfo *file_info = NULL; + const char *target; + const char *last_dash; + const char *checksum; + char *ret_commit = NULL; + + file_info = g_file_query_info (symlink, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!file_info) + goto out; + + target = g_file_info_get_symlink_target (file_info); + last_dash = strrchr (target, '-'); + if (last_dash == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid existing symlink target; no trailing dash"); + goto out; + } + checksum = last_dash + 1; + + if (!ostree_validate_structureof_checksum_string (checksum, error)) + goto out; + + ret_commit = g_strdup (checksum); + + ret = TRUE; + ot_transfer_out_value (out_commit, &ret_commit); + out: + g_free (ret_commit); + g_clear_object (&file_info); + return ret; +} + gboolean ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error) { @@ -46,12 +124,19 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error gboolean ret = FALSE; OstreeRepo *repo = NULL; const char *commit; + char *existing_commit = NULL; char *resolved_commit = NULL; const char *destination; + char *suffixed_destination = NULL; + char *tmp_destination = NULL; OstreeRepoFile *root = NULL; OstreeRepoFile *subtree = NULL; GFileInfo *file_info = NULL; - GFile *destf = NULL; + GFileInfo *symlink_file_info = NULL; + GFile *checkout_target = NULL; + GFile *checkout_target_tmp = NULL; + GFile *symlink_target = NULL; + gboolean skip_checkout; context = g_option_context_new ("COMMIT DESTINATION - Check out a commit into a filesystem tree"); g_option_context_add_main_entries (context, options, NULL); @@ -63,57 +148,120 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error if (!ostree_repo_check (repo, error)) goto out; - if (argc < 3) + if (argc < 2) { gchar *help = g_option_context_get_help (context, TRUE, NULL); g_printerr ("%s\n", help); g_free (help); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "COMMIT and DESTINATION must be specified"); + "COMMIT must be specified"); goto out; } commit = argv[1]; - destination = argv[2]; - - destf = ot_gfile_new_for_path (destination); + if (argc < 3) + destination = commit; + else + destination = argv[2]; if (!ostree_repo_resolve_rev (repo, commit, FALSE, &resolved_commit, error)) goto out; - root = (OstreeRepoFile*)ostree_repo_file_new_root (repo, resolved_commit); - if (!ostree_repo_file_ensure_resolved (root, error)) - goto out; - - if (subpath) + if (opt_atomic_retarget) { - subtree = (OstreeRepoFile*)g_file_resolve_relative_path ((GFile*)root, subpath); + GError *temp_error = NULL; + + suffixed_destination = g_strconcat (destination, "-", resolved_commit, NULL); + checkout_target = ot_gfile_new_for_path (suffixed_destination); + tmp_destination = g_strconcat (suffixed_destination, ".tmp", NULL); + checkout_target_tmp = ot_gfile_new_for_path (tmp_destination); + symlink_target = ot_gfile_new_for_path (destination); + + if (!parse_commit_from_symlink (symlink_target, &existing_commit, + cancellable, &temp_error)) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + skip_checkout = FALSE; + g_clear_error (&temp_error); + } + else + { + g_propagate_error (error, temp_error); + goto out; + } + } + else + { + skip_checkout = strcmp (existing_commit, resolved_commit) == 0; + } } else { - subtree = g_object_ref (root); + checkout_target = ot_gfile_new_for_path (destination); + skip_checkout = FALSE; } - file_info = g_file_query_info ((GFile*)subtree, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, error); - if (!file_info) - goto out; + if (!skip_checkout) + { + root = (OstreeRepoFile*)ostree_repo_file_new_root (repo, resolved_commit); + if (!ostree_repo_file_ensure_resolved (root, error)) + goto out; - if (!ostree_repo_checkout_tree (repo, user_mode ? OSTREE_REPO_CHECKOUT_MODE_USER : 0, - opt_union ? OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES : 0, - destf, subtree, file_info, cancellable, error)) - goto out; + if (subpath) + { + subtree = (OstreeRepoFile*)g_file_resolve_relative_path ((GFile*)root, subpath); + } + else + { + subtree = g_object_ref (root); + } + + file_info = g_file_query_info ((GFile*)subtree, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!file_info) + goto out; + + if (!ostree_repo_checkout_tree (repo, user_mode ? OSTREE_REPO_CHECKOUT_MODE_USER : 0, + opt_union ? OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES : 0, + checkout_target_tmp ? checkout_target_tmp : checkout_target, + subtree, file_info, cancellable, error)) + goto out; + + if (!opt_no_triggers) + { + if (!ostree_run_triggers_in_root (checkout_target_tmp ? checkout_target_tmp : checkout_target, + cancellable, error)) + goto out; + } + + if (opt_atomic_retarget) + { + if (!ot_gfile_rename (checkout_target_tmp, checkout_target, cancellable, error)) + goto out; + if (!atomic_symlink_swap (symlink_target, + ot_gfile_get_basename_cached (checkout_target), + cancellable, error)) + goto out; + } + } ret = TRUE; out: + g_free (suffixed_destination); + g_free (tmp_destination); g_free (resolved_commit); + g_free (existing_commit); + g_clear_object (&symlink_target); + g_clear_object (&checkout_target_tmp); + g_clear_object (&checkout_target); if (context) g_option_context_free (context); g_clear_object (&repo); - g_clear_object (&destf); g_clear_object (&root); g_clear_object (&subtree); g_clear_object (&file_info); + g_clear_object (&symlink_file_info); return ret; } diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c index 6ec33460..8cb47e25 100644 --- a/src/ostree/ot-builtin-remote.c +++ b/src/ostree/ot-builtin-remote.c @@ -49,6 +49,8 @@ ostree_builtin_remote (int argc, char **argv, GFile *repo_path, GError **error) OstreeRepo *repo = NULL; const char *op; GKeyFile *config = NULL; + GPtrArray *branches = NULL; + guint i; context = g_option_context_new ("OPERATION [args] - Control remote repository configuration"); g_option_context_add_main_entries (context, options, NULL); @@ -78,8 +80,17 @@ ostree_builtin_remote (int argc, char **argv, GFile *repo_path, GError **error) usage_error (context, "NAME and URL must be specified", error); goto out; } + + branches = g_ptr_array_new (); + for (i = 4; i < argc; i++) + g_ptr_array_add (branches, argv[i]); + key = g_strdup_printf ("remote \"%s\"", argv[2]); g_key_file_set_string (config, key, "url", argv[3]); + if (branches->len > 0) + g_key_file_set_string_list (config, key, "branches", + (const char *const *)branches->pdata, + branches->len); g_free (key); } else @@ -93,6 +104,7 @@ ostree_builtin_remote (int argc, char **argv, GFile *repo_path, GError **error) ret = TRUE; out: + ot_clear_ptrarray (&branches); if (context) g_option_context_free (context); if (config) diff --git a/src/triggers/ostree-run-triggers.c b/src/triggers/ostree-run-triggers.c index e533915f..6662c2e4 100644 --- a/src/triggers/ostree-run-triggers.c +++ b/src/triggers/ostree-run-triggers.c @@ -25,15 +25,16 @@ #include #include -static gboolean quiet; +static gboolean verbose; static GOptionEntry options[] = { - { "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't display informational messages", NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Display informational messages", NULL }, { NULL } }; static gboolean run_trigger (const char *path, + GCancellable *cancellable, GError **error) { gboolean ret = FALSE; @@ -47,8 +48,9 @@ run_trigger (const char *path, g_ptr_array_add (args, (char*)path); g_ptr_array_add (args, NULL); - - g_print ("Running trigger: %s\n", path); + + if (verbose) + g_print ("Running trigger: %s\n", path); if (!g_spawn_sync (NULL, (char**)args->pdata, NULL, @@ -69,65 +71,6 @@ run_trigger (const char *path, return ret; } -static gboolean -check_trigger (GFile *trigger, - GError **error) -{ - gboolean ret = FALSE; - GInputStream *instream = NULL; - GDataInputStream *datain = NULL; - GError *temp_error = NULL; - char *line; - gsize len; - char *ifexecutable_path = NULL; - char *trigger_path = NULL; - gboolean matched = TRUE; - - trigger_path = g_file_get_path (trigger); - - instream = (GInputStream*)g_file_read (trigger, NULL, error); - if (!instream) - goto out; - datain = g_data_input_stream_new (instream); - - while ((line = g_data_input_stream_read_line (datain, &len, NULL, &temp_error)) != NULL) - { - if (g_str_has_prefix (line, "# IfExecutable: ")) - { - char *executable = g_strdup (line + strlen ("# IfExecutable: ")); - g_strchomp (executable); - g_free (ifexecutable_path); - ifexecutable_path = g_find_program_in_path (executable); - g_free (executable); - if (!ifexecutable_path) - { - matched = FALSE; - break; - } - break; - } - g_free (line); - } - if (line == NULL && temp_error != NULL) - { - g_propagate_error (error, temp_error); - goto out; - } - if (matched) - { - if (!run_trigger (trigger_path, error)) - goto out; - } - - ret = TRUE; - out: - g_free (trigger_path); - g_free (ifexecutable_path); - g_clear_object (&instream); - g_clear_object (&datain); - return ret; -} - static int compare_files_by_basename (gconstpointer ap, gconstpointer bp) @@ -147,6 +90,7 @@ compare_files_by_basename (gconstpointer ap, static gboolean get_sorted_triggers (GPtrArray **out_triggers, + GCancellable *cancellable, GError **error) { gboolean ret = FALSE; @@ -164,12 +108,12 @@ get_sorted_triggers (GPtrArray **out_triggers, enumerator = g_file_enumerate_children (triggerdir, "standard::name,standard::type", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, + cancellable, error); if (!enumerator) goto out; - while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL) + while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, &temp_error)) != NULL) { const char *name; guint32 type; @@ -214,25 +158,31 @@ get_sorted_triggers (GPtrArray **out_triggers, } gboolean -run_triggers (GError **error) +run_triggers (GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; int i; GPtrArray *triggers = NULL; + char *path = NULL; - if (!get_sorted_triggers (&triggers, error)) + if (!get_sorted_triggers (&triggers, cancellable, error)) goto out; for (i = 0; i < triggers->len; i++) { - GFile *trigger = triggers->pdata[i]; + GFile *trigger_path = triggers->pdata[i]; - if (!check_trigger (trigger, error)) + g_free (path); + path = g_file_get_path (trigger_path); + + if (!run_trigger (path, cancellable, error)) goto out; } ret = TRUE; out: + g_free (path); if (triggers) g_ptr_array_unref (triggers); return ret; @@ -245,6 +195,7 @@ main (int argc, GOptionContext *context; GError *real_error = NULL; GError **error = &real_error; + GCancellable *cancellable = NULL; gboolean ret = FALSE; g_type_init (); @@ -255,7 +206,7 @@ main (int argc, if (!g_option_context_parse (context, &argc, &argv, error)) goto out; - if (!run_triggers (error)) + if (!run_triggers (cancellable, error)) goto out; ret = TRUE; diff --git a/src/triggers/triggers.d/0001ldconfig.trigger b/src/triggers/triggers.d/0001ldconfig.trigger index b4126039..daed471a 100755 --- a/src/triggers/triggers.d/0001ldconfig.trigger +++ b/src/triggers/triggers.d/0001ldconfig.trigger @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Post-installation hook for shared libraries. -*- mode: sh -*- # # Written by Colin Walters @@ -18,7 +18,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: ldconfig -# REMatch: /lib.*/\.so.* - -ldconfig -r . +if test -x "$(which ldconfig 2>/dev/null)"; then + exec ldconfig +fi diff --git a/src/triggers/triggers.d/0010mime-database.trigger b/src/triggers/triggers.d/0010mime-database.trigger index bfe301ff..e99cf2ec 100755 --- a/src/triggers/triggers.d/0010mime-database.trigger +++ b/src/triggers/triggers.d/0010mime-database.trigger @@ -18,7 +18,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: update-mime-database -# REMatch: /mime/packages/.*\.xml - -exec update-mime-database ./usr/share/mime +if test -x "$(which update-mime-database 2>/dev/null)"; then + exec update-mime-database /usr/share/mime +fi diff --git a/src/triggers/triggers.d/0020dconf.trigger b/src/triggers/triggers.d/0020dconf.trigger index 335364c8..620d4e0e 100755 --- a/src/triggers/triggers.d/0020dconf.trigger +++ b/src/triggers/triggers.d/0020dconf.trigger @@ -18,7 +18,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: dconf -# LiteralMatch: /etc/dconf/* - -exec dconf update +if test -x "$(which dconf 2>/dev/null)"; then + exec dconf update +fi diff --git a/src/triggers/triggers.d/0030glib.trigger b/src/triggers/triggers.d/0030glib.trigger index 734b6721..8c8bf506 100755 --- a/src/triggers/triggers.d/0030glib.trigger +++ b/src/triggers/triggers.d/0030glib.trigger @@ -18,7 +18,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: glib-compile-schemas -# LiteralMatch: /share/glib-2.0/schemas/ - -exec glib-compile-schemas ./usr/share/glib-2.0/schemas +if test -x "$(which glib-compile-schemas 2>/dev/null)"; then + exec glib-compile-schemas /usr/share/glib-2.0/schemas +fi diff --git a/src/triggers/triggers.d/0040gdk-pixbuf.trigger b/src/triggers/triggers.d/0040gdk-pixbuf.trigger index 07c84b0f..989d08b2 100755 --- a/src/triggers/triggers.d/0040gdk-pixbuf.trigger +++ b/src/triggers/triggers.d/0040gdk-pixbuf.trigger @@ -19,8 +19,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: gdk-pixbuf-query-loaders -# RequiresChroot: true -# LiteralMatch: /gdk-pixbuf-2.0/2.10.0/loaders/ - -exec gdk-pixbuf-query-loaders --update-cache +if test -x "$(which gdk-pixbuf-query-loaders 2>/dev/null)"; then + exec gdk-pixbuf-query-loaders --update-cache +fi diff --git a/src/triggers/triggers.d/0060immodules.trigger b/src/triggers/triggers.d/0060immodules.trigger index daad42a0..b9738eec 100755 --- a/src/triggers/triggers.d/0060immodules.trigger +++ b/src/triggers/triggers.d/0060immodules.trigger @@ -18,7 +18,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: gtk-query-immodules-3.0 -# REMatch: /lib.*/gtk-3\.0/3\.0\.0/immodules/.*\.so - -gtk-query-immodules-3.0 --update-cache +if test -x "$(which gtk-query-immodules-3.0 2>/dev/null)"; then + exec gtk-query-immodules-3.0 --update-cache +fi diff --git a/src/triggers/triggers.d/0070pango.trigger b/src/triggers/triggers.d/0070pango.trigger index 69935464..ad41e750 100755 --- a/src/triggers/triggers.d/0070pango.trigger +++ b/src/triggers/triggers.d/0070pango.trigger @@ -19,8 +19,7 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: pango-querymodules -# REMatch: /lib.*/pango/.*/modules/.*\.so - -DEST=/etc/pango/pango.modules -pango-querymodules --system > ${DEST}.tmp && mv ${DEST}.tmp ${DEST} +if test -x "$(which pango-querymodules 2>/dev/null)"; then + DEST=/etc/pango/pango.modules + pango-querymodules --system > ${DEST}.tmp && mv ${DEST}.tmp ${DEST} +fi diff --git a/src/triggers/triggers.d/0080gtk+.trigger b/src/triggers/triggers.d/0080gtk+.trigger index 26b313f4..85b9e799 100755 --- a/src/triggers/triggers.d/0080gtk+.trigger +++ b/src/triggers/triggers.d/0080gtk+.trigger @@ -18,14 +18,13 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: gtk-update-icon-cache -# LiteralMatch: /share/icons/ - -for dir in ./usr/share/icons/*; do - if test -f $dir/index.theme; then - if ! gtk-update-icon-cache --quiet $dir; then - echo "Failed to run gtk-update-icon-cache for $dir" - exit 1 - fi - fi -done +if test -x "$(which gtk-update-icon-cache 2>/dev/null)"; then + for dir in /usr/share/icons/*; do + if test -f $dir/index.theme; then + if ! gtk-update-icon-cache --quiet $dir; then + echo "Failed to run gtk-update-icon-cache for $dir" + exit 1 + fi + fi + done +fi diff --git a/src/triggers/triggers.d/0090desktop-database.trigger b/src/triggers/triggers.d/0090desktop-database.trigger index 017d27cf..25da1e9b 100755 --- a/src/triggers/triggers.d/0090desktop-database.trigger +++ b/src/triggers/triggers.d/0090desktop-database.trigger @@ -18,7 +18,6 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -# IfExecutable: update-desktop-database -# REMatch: /share/applications/.*/.*\.desktop - -exec update-desktop-database -q ./usr/share/applications +if test -x "$(which update-desktop-database 2>/dev/null)"; then + exec update-desktop-database -q /usr/share/applications +fi diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh index 2d55e201..6cb79ab2 100755 --- a/tests/t0000-basic.sh +++ b/tests/t0000-basic.sh @@ -19,7 +19,7 @@ set -e -echo "1..28" +echo "1..30" . libtest.sh @@ -206,3 +206,16 @@ cmp union-files-count{,.new} cd checkout-test2-union assert_file_has_content ./yet/another/tree/green "leaf" echo "ok checkout union 1" + +cd ${test_tmpdir} +$OSTREE checkout --atomic-retarget test2 checkout-atomic-test2 +cd checkout-atomic-test2 +assert_file_has_content ./yet/another/tree/green "leaf" +echo "ok checkout atomic" + +cd ${test_tmpdir} +rm -rf test2 +$OSTREE checkout --atomic-retarget test2 +cd test2 +assert_file_has_content ./yet/another/tree/green "leaf" +echo "ok checkout short form"