[ostree] Refactor command-line parsing



commit 97558276e4f855442337be01abc8f90cf0dd1810
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Nov 14 14:00:13 2014 -0500

    Refactor command-line parsing
    
    Refactor command-line parsing to better utilize GOptionContext.  This
    eliminates most of the manual parsing and global options are now shown
    in the help output.
    
    Here's a sample:
    
        $ ostree admin --help
        Usage:
          ostree admin [OPTION...] --print-current-dir|COMMAND
    
        Builtin "admin" Commands:
          cleanup
          config-diff
          deploy
          init-fs
          instutil
          os-init
          status
          switch
          undeploy
          upgrade
    
        Help Options:
          -h, --help         Show help options
    
        Application Options:
          --sysroot=PATH     Create a new OSTree sysroot at PATH
          -v, --verbose      Print debug information during command processing
          --version          Print version information and exit
    
    https://bugzilla.gnome.org/show_bug.cgi?id=740295

 src/ostree/main.c                                  |   48 ++--
 src/ostree/ot-admin-builtin-cleanup.c              |    8 +-
 src/ostree/ot-admin-builtin-deploy.c               |    8 +-
 src/ostree/ot-admin-builtin-diff.c                 |    6 +-
 src/ostree/ot-admin-builtin-init-fs.c              |    7 +-
 src/ostree/ot-admin-builtin-instutil.c             |  139 ++++----
 src/ostree/ot-admin-builtin-os-init.c              |    7 +-
 src/ostree/ot-admin-builtin-status.c               |    8 +-
 src/ostree/ot-admin-builtin-switch.c               |    7 +-
 src/ostree/ot-admin-builtin-undeploy.c             |    8 +-
 src/ostree/ot-admin-builtin-upgrade.c              |    7 +-
 src/ostree/ot-admin-builtins.h                     |   24 +-
 .../ot-admin-instutil-builtin-grub2-generate.c     |    8 +-
 ...admin-instutil-builtin-selinux-ensure-labeled.c |    8 +-
 src/ostree/ot-admin-instutil-builtin-set-kargs.c   |    8 +-
 src/ostree/ot-admin-instutil-builtins.h            |    6 +-
 src/ostree/ot-builtin-admin.c                      |  185 ++++-------
 src/ostree/ot-builtin-cat.c                        |    7 +-
 src/ostree/ot-builtin-checkout.c                   |    7 +-
 src/ostree/ot-builtin-checksum.c                   |    6 +-
 src/ostree/ot-builtin-commit.c                     |   10 +-
 src/ostree/ot-builtin-config.c                     |    7 +-
 src/ostree/ot-builtin-diff.c                       |    6 +-
 src/ostree/ot-builtin-fsck.c                       |    7 +-
 src/ostree/ot-builtin-init.c                       |    7 +-
 src/ostree/ot-builtin-log.c                        |    6 +-
 src/ostree/ot-builtin-ls.c                         |    7 +-
 src/ostree/ot-builtin-prune.c                      |    7 +-
 src/ostree/ot-builtin-pull-local.c                 |   10 +-
 src/ostree/ot-builtin-pull.c                       |    7 +-
 src/ostree/ot-builtin-refs.c                       |   10 +-
 src/ostree/ot-builtin-remote.c                     |    7 +-
 src/ostree/ot-builtin-reset.c                      |    9 +-
 src/ostree/ot-builtin-rev-parse.c                  |    7 +-
 src/ostree/ot-builtin-show.c                       |    7 +-
 src/ostree/ot-builtin-static-delta.c               |    7 +-
 src/ostree/ot-builtin-summary.c                    |    7 +-
 src/ostree/ot-builtin-trivial-httpd.c              |    7 +-
 src/ostree/ot-builtins-common.c                    |    1 +
 src/ostree/ot-builtins.h                           |    2 +-
 src/ostree/ot-main.c                               |  367 ++++++++++++--------
 src/ostree/ot-main.h                               |   18 +-
 42 files changed, 545 insertions(+), 490 deletions(-)
---
diff --git a/src/ostree/main.c b/src/ostree/main.c
index e114690..b8dccd6 100644
--- a/src/ostree/main.c
+++ b/src/ostree/main.c
@@ -33,31 +33,31 @@
 #include "ot-builtins.h"
 
 static OstreeCommand commands[] = {
-  { "admin", ostree_builtin_admin, OSTREE_BUILTIN_FLAG_NO_REPO },
-  { "cat", ostree_builtin_cat, 0 },
-  { "checkout", ostree_builtin_checkout, 0 },
-  { "checksum", ostree_builtin_checksum, OSTREE_BUILTIN_FLAG_NO_REPO },
-  { "commit", ostree_builtin_commit, 0 },
-  { "config", ostree_builtin_config, 0 },
-  { "diff", ostree_builtin_diff, 0 },
-  { "fsck", ostree_builtin_fsck, 0 },
-  { "init", ostree_builtin_init, OSTREE_BUILTIN_FLAG_NO_CHECK },
-  { "log", ostree_builtin_log, 0 },
-  { "ls", ostree_builtin_ls, 0 },
-  { "prune", ostree_builtin_prune, 0 },
-  { "pull-local", ostree_builtin_pull_local, 0 },
+  { "admin", ostree_builtin_admin },
+  { "cat", ostree_builtin_cat },
+  { "checkout", ostree_builtin_checkout },
+  { "checksum", ostree_builtin_checksum },
+  { "commit", ostree_builtin_commit },
+  { "config", ostree_builtin_config },
+  { "diff", ostree_builtin_diff },
+  { "fsck", ostree_builtin_fsck },
+  { "init", ostree_builtin_init },
+  { "log", ostree_builtin_log },
+  { "ls", ostree_builtin_ls },
+  { "prune", ostree_builtin_prune },
+  { "pull-local", ostree_builtin_pull_local },
 #ifdef HAVE_LIBSOUP 
-  { "pull", ostree_builtin_pull, 0 },
+  { "pull", ostree_builtin_pull },
 #endif
-  { "refs", ostree_builtin_refs, 0 },
-  { "remote", ostree_builtin_remote, 0 },
-  { "reset", ostree_builtin_reset, 0 },
-  { "rev-parse", ostree_builtin_rev_parse, 0 },
-  { "show", ostree_builtin_show, 0 },
-  { "static-delta", ostree_builtin_static_delta, 0 },
-  { "summary", ostree_builtin_summary, 0 },
+  { "refs", ostree_builtin_refs },
+  { "remote", ostree_builtin_remote },
+  { "reset", ostree_builtin_reset },
+  { "rev-parse", ostree_builtin_rev_parse },
+  { "show", ostree_builtin_show },
+  { "static-delta", ostree_builtin_static_delta },
+  { "summary", ostree_builtin_summary },
 #ifdef HAVE_LIBSOUP 
-  { "trivial-httpd", ostree_builtin_trivial_httpd, OSTREE_BUILTIN_FLAG_NO_REPO },
+  { "trivial-httpd", ostree_builtin_trivial_httpd },
 #endif
   { NULL }
 };
@@ -71,9 +71,11 @@ main (int    argc,
 
   setlocale (LC_ALL, "");
 
+  g_set_prgname (argv[0]);
+
   ret = ostree_run (argc, argv, commands, &error);
   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
-    ostree_usage (argv, commands, TRUE);
+    ostree_usage (commands, TRUE);
 
   if (error != NULL)
     {
diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c
index 015dfe7..be9aaf3 100644
--- a/src/ostree/ot-admin-builtin-cleanup.c
+++ b/src/ostree/ot-admin-builtin-cleanup.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ostree.h"
@@ -34,16 +35,15 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_cleanup (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gboolean ret = FALSE;
 
   context = g_option_context_new ("Delete untagged deployments and repository objects");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index 3584dee..6c4327b 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ostree.h"
@@ -49,11 +50,12 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   const char *refspec;
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   GKeyFile *origin = NULL;
   gs_unref_object OstreeRepo *repo = NULL;
   gs_unref_ptrarray GPtrArray *new_deployments = NULL;
@@ -64,9 +66,7 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
 
   context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c
index 2e9abc0..55a8911 100644
--- a/src/ostree/ot-admin-builtin-diff.c
+++ b/src/ostree/ot-admin-builtin-diff.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ostree.h"
@@ -37,9 +38,10 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gboolean ret = FALSE;
   gs_unref_object OstreeDeployment *deployment = NULL;
   gs_unref_object GFile *deployment_dir = NULL;
@@ -53,7 +55,7 @@ ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellab
 
   g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
   
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-builtin-init-fs.c b/src/ostree/ot-admin-builtin-init-fs.c
index 01114c5..9fe46f4 100644
--- a/src/ostree/ot-admin-builtin-init-fs.c
+++ b/src/ostree/ot-admin-builtin-init-fs.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "otutil.h"
@@ -34,9 +35,10 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_init_fs (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gboolean ret = FALSE;
   gs_unref_object GFile *dir = NULL;
   gs_unref_object GFile *child = NULL;
@@ -45,9 +47,8 @@ ot_admin_builtin_init_fs (int argc, char **argv, OstreeSysroot *sysroot, GCancel
   const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"};
 
   context = g_option_context_new ("PATH - Initialize a root filesystem");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c
index 7a17dd3..ba4d9b4 100644
--- a/src/ostree/ot-admin-builtin-instutil.c
+++ b/src/ostree/ot-admin-builtin-instutil.c
@@ -32,7 +32,7 @@
 
 typedef struct {
   const char *name;
-  gboolean (*fn) (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
+  gboolean (*fn) (int argc, char **argv, GCancellable *cancellable, GError **error);
 } OstreeAdminInstUtilCommand;
 
 static OstreeAdminInstUtilCommand admin_instutil_subcommands[] = {
@@ -44,101 +44,62 @@ static OstreeAdminInstUtilCommand admin_instutil_subcommands[] = {
   { NULL, NULL }
 };
 
+static GOptionContext *
+ostree_admin_instutil_option_context_new_with_commands (void)
+{
+  OstreeAdminInstUtilCommand *command = admin_instutil_subcommands;
+  GOptionContext *context;
+  GString *summary;
+
+  context = g_option_context_new ("COMMAND");
+
+  summary = g_string_new ("Builtin \"admin instutil\" Commands:");
+
+  while (command->name != NULL)
+    {
+      g_string_append_printf (summary, "\n  %s", command->name);
+      command++;
+    }
+
+  g_option_context_set_summary (context, summary->str);
+
+  g_string_free (summary, TRUE);
+
+  return context;
+}
+
 gboolean
-ot_admin_builtin_instutil (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   OstreeAdminInstUtilCommand *subcommand;
   const char *subcommand_name = NULL;
-  gboolean want_help = FALSE;
-  int in, out, i;
-  gboolean skip;
+  gs_free char *prgname = NULL;
+  int in, out;
 
   for (in = 1, out = 1; in < argc; in++, out++)
     {
       /* The non-option is the command, take it out of the arguments */
       if (argv[in][0] != '-')
         {
-          skip = (subcommand_name == NULL);
           if (subcommand_name == NULL)
-            subcommand_name = argv[in];
-        }
-
-      /* The global long options */
-      else if (argv[in][1] == '-')
-        {
-          skip = FALSE;
-
-          if (g_str_equal (argv[in], "--"))
-            {
-              break;
-            }
-          else if (g_str_equal (argv[in], "--help"))
-            {
-              want_help = TRUE;
-            }
-          else if (subcommand_name == NULL)
             {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Unknown or invalid admin instutil option: %s", argv[in]);
-              goto out;
+              subcommand_name = argv[in];
+              out--;
+              continue;
             }
         }
 
-      /* The global short options */
-      else
+      else if (g_str_equal (argv[in], "--"))
         {
-          skip = FALSE;
-          for (i = 1; argv[in][i] != '\0'; i++)
-            {
-              switch (argv[in][i])
-              {
-                case 'h':
-                  want_help = TRUE;
-                  break;
-
-                default:
-                  if (subcommand_name == NULL)
-                    {
-                      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                                   "Unknown or invalid admin instutil option: %s", argv[in]);
-                      goto out;
-                    }
-                  break;
-              }
-            }
+          break;
         }
 
-      /* Skipping this argument? */
-      if (skip)
-        out--;
-      else
-        argv[out] = argv[in];
+      argv[out] = argv[in];
     }
 
   argc = out;
 
-  if (subcommand_name == NULL)
-    {
-      void (*print_func) (const gchar *format, ...) = want_help ? g_print : g_printerr;
-
-      subcommand = admin_instutil_subcommands;
-      print_func ("usage: ostree admin instutil COMMAND [options]\n");
-      print_func ("Builtin commands:\n");
-      while (subcommand->name)
-        {
-          print_func ("  %s\n", subcommand->name);
-          subcommand++;
-        }
-
-      if (want_help)
-        ret = TRUE;
-      else
-        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                             "No command specified");
-      goto out;
-    }
-
   subcommand = admin_instutil_subcommands;
   while (subcommand->name)
     {
@@ -149,14 +110,38 @@ ot_admin_builtin_instutil (int argc, char **argv, OstreeSysroot *sysroot, GCance
 
   if (!subcommand->name)
     {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-                   "Unknown admin instutil command '%s'", subcommand_name);
+      GOptionContext *context;
+      gs_free char *help;
+
+      context = ostree_admin_instutil_option_context_new_with_commands ();
+
+      /* This will not return for some options (e.g. --version). */
+      if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, NULL, cancellable, error))
+        {
+          if (subcommand_name == NULL)
+            {
+              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                   "No \"admin instutil\" subcommand specified");
+            }
+          else
+            {
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                           "Unknown \"admin instutil\" subcommand '%s'", subcommand_name);
+            }
+        }
+
+      help = g_option_context_get_help (context, FALSE, NULL);
+      g_printerr ("%s", help);
+
+      g_option_context_free (context);
+
       goto out;
     }
 
-  g_set_prgname (g_strdup_printf ("ostree admin instutil %s", subcommand_name));
+  prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name);
+  g_set_prgname (prgname);
 
-  if (!subcommand->fn (argc, argv, sysroot, cancellable, error))
+  if (!subcommand->fn (argc, argv, cancellable, error))
     goto out;
  
   ret = TRUE;
diff --git a/src/ostree/ot-admin-builtin-os-init.c b/src/ostree/ot-admin-builtin-os-init.c
index 19ed4a1..a94837e 100644
--- a/src/ostree/ot-admin-builtin-os-init.c
+++ b/src/ostree/ot-admin-builtin-os-init.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "otutil.h"
@@ -34,18 +35,18 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_os_init (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_os_init (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gboolean ret = FALSE;
   const char *osname = NULL;
   gs_unref_object GFile *deploy_dir = NULL;
   gs_unref_object GFile *dir = NULL;
 
   context = g_option_context_new ("OSNAME - Initialize empty state for given operating system");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (!ostree_sysroot_ensure_initialized (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c
index 9ce2f43..382c5e6 100644
--- a/src/ostree/ot-admin-builtin-status.c
+++ b/src/ostree/ot-admin-builtin-status.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ostree.h"
@@ -49,9 +50,10 @@ version_of_commit (OstreeRepo *repo, const char *checksum)
 }
 
 gboolean
-ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gboolean ret = FALSE;
   gs_unref_object OstreeRepo *repo = NULL;
   OstreeDeployment *booted_deployment = NULL;
@@ -60,9 +62,7 @@ ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancell
 
   context = g_option_context_new ("List deployments");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c
index 3900b81..2f6c334 100644
--- a/src/ostree/ot-admin-builtin-switch.c
+++ b/src/ostree/ot-admin-builtin-switch.c
@@ -20,6 +20,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ot-builtins-common.h"
@@ -40,10 +41,11 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   const char *new_provided_refspec = NULL;
   gs_unref_object OstreeRepo *repo = NULL;
   gs_free char *origin_refspec = NULL;
@@ -66,9 +68,8 @@ ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   GKeyFile *new_origin = NULL;
 
   context = g_option_context_new ("REF - Construct new tree from current origin and deploy it, if it 
changed");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c
index 055209d..edf89bf 100644
--- a/src/ostree/ot-admin-builtin-undeploy.c
+++ b/src/ostree/ot-admin-builtin-undeploy.c
@@ -22,6 +22,7 @@
 
 #include <stdlib.h>
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ostree.h"
@@ -32,10 +33,11 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   const char *deploy_index_str;
   int deploy_index;
   gs_unref_ptrarray GPtrArray *current_deployments = NULL;
@@ -44,9 +46,7 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance
 
   context = g_option_context_new ("INDEX - Delete deployment INDEX");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index ffb93d4..1dff0a5 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
 #include "ot-builtins-common.h"
@@ -45,10 +46,11 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError 
**error)
+ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
   gs_free char *origin_remote = NULL;
   gs_free char *origin_ref = NULL;
@@ -65,9 +67,8 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
   OstreeSysrootUpgraderPullFlags upgraderpullflags = 0;
 
   context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-builtins.h b/src/ostree/ot-admin-builtins.h
index a4e5754..9858f5b 100644
--- a/src/ostree/ot-admin-builtins.h
+++ b/src/ostree/ot-admin-builtins.h
@@ -26,18 +26,18 @@
 
 G_BEGIN_DECLS
 
-gboolean ot_admin_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeSysroot *sysroot, 
GCancellable *cancellable, GError **error);
-gboolean ot_admin_builtin_os_init (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_install (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_instutil (int argc, char **argv, OstreeSysroot *sysroot, GCancellable 
*cancellable, GError **error);
-gboolean ot_admin_builtin_init_fs (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCancellable 
*cancellable, GError **error);
-gboolean ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_cleanup (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
-gboolean ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, 
GError **error);
+gboolean ot_admin_builtin_selinux_ensure_labeled (int argc, char **argv, GCancellable *cancellable, GError 
**error);
+gboolean ot_admin_builtin_os_init (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_install (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GError **error);
+gboolean ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GError **error);
 
 G_END_DECLS
 
diff --git a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c 
b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c
index 4aa58d0..617b160 100644
--- a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c
+++ b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <glib-unix.h>
 
+#include "ot-main.h"
 #include "ot-admin-instutil-builtins.h"
 #include "ostree-cmdprivate.h"
 
@@ -33,7 +34,7 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeSysroot *sysroot, GCancellable 
*cancellable, GError **error)
+ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   guint bootversion;
@@ -41,13 +42,12 @@ ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeSysroot *
   gs_unref_object OstreeSePolicy *sepolicy = NULL;
   gs_unref_ptrarray GPtrArray *deployments = NULL;
   GOptionContext *context = NULL;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gs_unref_object GFile *deployment_path = NULL;
 
   context = g_option_context_new ("[BOOTVERSION] - generate GRUB2 configuration from given BLS entries");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (argc >= 2)
diff --git a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c 
b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c
index 8bd0c8a..7e9ca06 100644
--- a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c
+++ b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <glib-unix.h>
 
+#include "ot-main.h"
 #include "ot-admin-instutil-builtins.h"
 
 #include "otutil.h"
@@ -178,7 +179,7 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeSysroot *sysroot, 
GCancellable *cancellable, GError **error)
+ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, GCancellable *cancellable, GError 
**error)
 {
   gboolean ret = FALSE;
   const char *policy_name;
@@ -188,13 +189,12 @@ ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeS
   gs_unref_ptrarray GPtrArray *deployments = NULL;
   OstreeDeployment *first_deployment;
   GOptionContext *context = NULL;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   gs_unref_object GFile *deployment_path = NULL;
 
   context = g_option_context_new ("[SUBPATH PREFIX] - relabel all or part of a deployment");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-instutil-builtin-set-kargs.c 
b/src/ostree/ot-admin-instutil-builtin-set-kargs.c
index b683f19..cef5242 100644
--- a/src/ostree/ot-admin-instutil-builtin-set-kargs.c
+++ b/src/ostree/ot-admin-instutil-builtin-set-kargs.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <glib-unix.h>
 
+#include "ot-main.h"
 #include "ot-admin-instutil-builtins.h"
 
 #include "otutil.h"
@@ -43,20 +44,19 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ot_admin_instutil_builtin_set_kargs (int argc, char **argv, OstreeSysroot *sysroot, GCancellable 
*cancellable, GError **error)
+ot_admin_instutil_builtin_set_kargs (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   guint i;
   gs_unref_ptrarray GPtrArray *deployments = NULL;
   OstreeDeployment *first_deployment = NULL;
   GOptionContext *context = NULL;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
   __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
 
   context = g_option_context_new ("ARGS - set new kernel command line arguments");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv, &sysroot, cancellable, error))
     goto out;
 
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-instutil-builtins.h b/src/ostree/ot-admin-instutil-builtins.h
index 5442eb5..16abe42 100644
--- a/src/ostree/ot-admin-instutil-builtins.h
+++ b/src/ostree/ot-admin-instutil-builtins.h
@@ -24,9 +24,9 @@
 
 G_BEGIN_DECLS
 
-gboolean ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeSysroot *sysroot, 
GCancellable *cancellable, GError **error);
-gboolean ot_admin_instutil_builtin_set_kargs (int argc, char **argv, OstreeSysroot *sysroot, GCancellable 
*cancellable, GError **error);
-gboolean ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeSysroot *sysroot, 
GCancellable *cancellable, GError **error);
+gboolean ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, GCancellable *cancellable, 
GError **error);
+gboolean ot_admin_instutil_builtin_set_kargs (int argc, char **argv, GCancellable *cancellable, GError 
**error);
+gboolean ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, GCancellable *cancellable, GError 
**error);
 
 G_END_DECLS
 
diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c
index 2165656..47cf1b7 100644
--- a/src/ostree/ot-builtin-admin.c
+++ b/src/ostree/ot-builtin-admin.c
@@ -34,7 +34,7 @@
 
 typedef struct {
   const char *name;
-  gboolean (*fn) (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
+  gboolean (*fn) (int argc, char **argv, GCancellable *cancellable, GError **error);
 } OstreeAdminCommand;
 
 static OstreeAdminCommand admin_subcommands[] = {
@@ -51,19 +51,38 @@ static OstreeAdminCommand admin_subcommands[] = {
   { NULL, NULL }
 };
 
+static GOptionContext *
+ostree_admin_option_context_new_with_commands (void)
+{
+  OstreeAdminCommand *command = admin_subcommands;
+  GOptionContext *context;
+  GString *summary;
+
+  context = g_option_context_new ("--print-current-dir|COMMAND");
+
+  summary = g_string_new ("Builtin \"admin\" Commands:");
+
+  while (command->name != NULL)
+    {
+      g_string_append_printf (summary, "\n  %s", command->name);
+      command++;
+    }
+
+  g_option_context_set_summary (context, summary->str);
+
+  g_string_free (summary, TRUE);
+
+  return context;
+}
+
 gboolean
-ostree_builtin_admin (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_admin (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
-  const char *opt_sysroot = "/";
   const char *subcommand_name = NULL;
   OstreeAdminCommand *subcommand;
-  gs_unref_object GFile *sysroot_path = NULL;
-  gs_unref_object OstreeSysroot *sysroot = NULL;
-  gboolean want_help = FALSE;
-  gboolean want_current_dir = FALSE;
-  int in, out, i;
-  gboolean skip;
+  gs_free char *prgname = NULL;
+  int in, out;
 
   /*
    * Parse the global options. We rearrange the options as
@@ -76,148 +95,66 @@ ostree_builtin_admin (int argc, char **argv, OstreeRepo *repo, GCancellable *can
       /* The non-option is the command, take it out of the arguments */
       if (argv[in][0] != '-')
         {
-          skip = (subcommand_name == NULL);
           if (subcommand_name == NULL)
-            subcommand_name = argv[in];
-        }
-
-      /* The global long options */
-      else if (argv[in][1] == '-')
-        {
-          skip = FALSE;
-
-          if (g_str_equal (argv[in], "--"))
-            {
-              break;
-            }
-          else if (g_str_equal (argv[in], "--help"))
-            {
-              want_help = TRUE;
-            }
-          else if (g_str_equal (argv[in], "--print-current-dir"))
-            {
-              want_current_dir = TRUE;
-            }
-          else if (g_str_equal (argv[in], "--sysroot") && in + 1 < argc)
             {
-              opt_sysroot = argv[in + 1];
-              skip = TRUE;
-              in++;
-            }
-          else if (g_str_has_prefix (argv[in], "--sysroot="))
-            {
-              opt_sysroot = argv[in] + 10;
-              skip = TRUE;
-            }
-          else if (subcommand_name == NULL)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Unknown or invalid admin option: %s", argv[in]);
-              goto out;
+              subcommand_name = argv[in];
+              out--;
+              continue;
             }
         }
 
-      /* The global short options */
-      else
+      else if (g_str_equal (argv[in], "--"))
         {
-          skip = FALSE;
-          for (i = 1; argv[in][i] != '\0'; i++)
-            {
-              switch (argv[in][i])
-              {
-                case 'h':
-                  want_help = TRUE;
-                  break;
-
-                default:
-                  if (subcommand_name == NULL)
-                    {
-                      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                                   "Unknown or invalid admin option: %s", argv[in]);
-                      goto out;
-                    }
-                  break;
-              }
-            }
+          break;
         }
 
-      /* Skipping this argument? */
-      if (skip)
-        out--;
-      else
-        argv[out] = argv[in];
+      argv[out] = argv[in];
     }
 
   argc = out;
 
-  if (subcommand_name == NULL && (want_help || !want_current_dir))
+  subcommand = admin_subcommands;
+  while (subcommand->name)
     {
-      void (*print_func) (const gchar *format, ...) = want_help ? g_print : g_printerr;
-
-      subcommand = admin_subcommands;
-      print_func ("usage: ostree admin [--sysroot=PATH] [--print-current-dir|COMMAND] [options]\n");
-      print_func ("Builtin commands:\n");
-      while (subcommand->name)
-        {
-          print_func ("  %s\n", subcommand->name);
-          subcommand++;
-        }
-
-      if (want_help)
-        ret = TRUE;
-      else
-        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                             "No command specified");
-      goto out;
+      if (g_strcmp0 (subcommand_name, subcommand->name) == 0)
+        break;
+      subcommand++;
     }
 
-  sysroot_path = g_file_new_for_path (opt_sysroot);
-  sysroot = ostree_sysroot_new (sysroot_path);
-
-  if (want_current_dir)
+  if (!subcommand->name)
     {
-      gs_unref_ptrarray GPtrArray *deployments = NULL;
-      OstreeDeployment *first_deployment;
-      gs_unref_object GFile *deployment_file = NULL;
-      gs_free char *deployment_path = NULL;
+      GOptionContext *context;
+      gs_free char *help;
 
-      if (!ostree_sysroot_load (sysroot, cancellable, error))
-        goto out;
+      context = ostree_admin_option_context_new_with_commands ();
 
-      deployments = ostree_sysroot_get_deployments (sysroot);
-      if (deployments->len == 0)
+      /* This will not return for some options (e.g. --version). */
+      if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, NULL, cancellable, error))
         {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "Unable to find a deployment in sysroot");
-          goto out;
+          if (subcommand_name == NULL)
+            {
+              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                   "No \"admin\" subcommand specified");
+            }
+          else
+            {
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                           "Unknown \"admin\" subcommand '%s'", subcommand_name);
+            }
         }
-      first_deployment = deployments->pdata[0];
-      deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment);
-      deployment_path = g_file_get_path (deployment_file);
 
-      g_print ("%s\n", deployment_path);
-      ret = TRUE;
-      goto out;
-    }
+      help = g_option_context_get_help (context, FALSE, NULL);
+      g_printerr ("%s", help);
 
-  subcommand = admin_subcommands;
-  while (subcommand->name)
-    {
-      if (g_strcmp0 (subcommand_name, subcommand->name) == 0)
-        break;
-      subcommand++;
-    }
+      g_option_context_free (context);
 
-  if (!subcommand->name)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-                   "Unknown admin command '%s'", subcommand_name);
       goto out;
     }
 
-  g_set_prgname (g_strdup_printf ("ostree admin %s", subcommand_name));
+  prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name);
+  g_set_prgname (prgname);
 
-  if (!subcommand->fn (argc, argv, sysroot, cancellable, error))
+  if (!subcommand->fn (argc, argv, cancellable, error))
     goto out;
  
   ret = TRUE;
diff --git a/src/ostree/ot-builtin-cat.c b/src/ostree/ot-builtin-cat.c
index 92d4c84..721f992 100644
--- a/src/ostree/ot-builtin-cat.c
+++ b/src/ostree/ot-builtin-cat.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -55,9 +56,10 @@ cat_one_file (GFile         *f,
 }
 
 gboolean
-ostree_builtin_cat (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_cat (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   int i;
   const char *rev;
@@ -66,9 +68,8 @@ ostree_builtin_cat (int argc, char **argv, OstreeRepo *repo, GCancellable *cance
   gs_unref_object GFile *f = NULL;
 
   context = g_option_context_new ("COMMIT PATH... - Concatenate contents of files");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc <= 2)
diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c
index 3f77619..b3284ef 100644
--- a/src/ostree/ot-builtin-checkout.c
+++ b/src/ostree/ot-builtin-checkout.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <gio/gunixinputstream.h>
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -170,9 +171,10 @@ process_many_checkouts (OstreeRepo         *repo,
 }
 
 gboolean
-ostree_builtin_checkout (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_checkout (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *commit;
   const char *destination;
@@ -180,9 +182,8 @@ ostree_builtin_checkout (int argc, char **argv, OstreeRepo *repo, GCancellable *
   gs_unref_object GFile *checkout_target = NULL;
 
   context = g_option_context_new ("COMMIT [DESTINATION] - Check out a commit into a filesystem tree");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-builtin-checksum.c b/src/ostree/ot-builtin-checksum.c
index e7d5dd8..5c534f8 100644
--- a/src/ostree/ot-builtin-checksum.c
+++ b/src/ostree/ot-builtin-checksum.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "libgsystem.h"
@@ -56,7 +57,7 @@ on_checksum_received (GObject    *obj,
 }
 
 gboolean
-ostree_builtin_checksum (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_checksum (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
   gboolean ret = FALSE;
@@ -64,9 +65,8 @@ ostree_builtin_checksum (int argc, char **argv, OstreeRepo *repo, GCancellable *
   AsyncChecksumData data = { 0, };
 
   context = g_option_context_new ("PATH - Checksum a file or directory");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, 
cancellable, error))
     goto out;
 
   if (argc > 1)
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index eda556e..47c9b7c 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ot-editor.h"
 #include "ostree.h"
@@ -309,9 +310,10 @@ parse_keyvalue_strings (char             **strings,
 }
 
 gboolean
-ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   gboolean skip_commit = FALSE;
   gs_unref_object GFile *arg = NULL;
@@ -328,9 +330,8 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
   OstreeRepoTransactionStats stats;
 
   context = g_option_context_new ("[PATH] - Commit a new revision");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (opt_statoverride_file)
@@ -563,7 +564,8 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
 
   ret = TRUE;
  out:
-  ostree_repo_abort_transaction (repo, cancellable, NULL);
+  if (repo)
+    ostree_repo_abort_transaction (repo, cancellable, NULL);
   if (context)
     g_option_context_free (context);
   if (modifier)
diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c
index 56ddf86..235e498 100644
--- a/src/ostree/ot-builtin-config.c
+++ b/src/ostree/ot-builtin-config.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -52,9 +53,10 @@ split_key_string (const char   *k,
 }
 
 gboolean
-ostree_builtin_config (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_config (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context = NULL;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *op;
   const char *section_key;
@@ -64,9 +66,8 @@ ostree_builtin_config (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
   GKeyFile *config = NULL;
 
   context = g_option_context_new ("- Change configuration settings");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-builtin-diff.c b/src/ostree/ot-builtin-diff.c
index 65d55be..7948c5d 100644
--- a/src/ostree/ot-builtin-diff.c
+++ b/src/ostree/ot-builtin-diff.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -115,10 +116,11 @@ object_set_total_size (OstreeRepo    *repo,
 }
 
 gboolean
-ostree_builtin_diff (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   const char *src;
   const char *target;
   gs_free char *src_prev = NULL;
@@ -131,7 +133,7 @@ ostree_builtin_diff (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
   context = g_option_context_new ("REV TARGETDIR - Compare directory TARGETDIR against revision REV");
   g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c
index 79bb5f2..333614c 100644
--- a/src/ostree/ot-builtin-fsck.c
+++ b/src/ostree/ot-builtin-fsck.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -233,10 +234,11 @@ fsck_reachable_objects_from_commits (OstreeRepo            *repo,
 }
 
 gboolean
-ostree_builtin_fsck (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   GHashTableIter hash_iter;
   gpointer key, value;
   gboolean found_corruption = FALSE;
@@ -244,9 +246,8 @@ ostree_builtin_fsck (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
   gs_unref_hashtable GHashTable *commits = NULL;
 
   context = g_option_context_new ("- Check the repository for consistency");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (!opt_quiet)
diff --git a/src/ostree/ot-builtin-init.c b/src/ostree/ot-builtin-init.c
index d57ed5c..9aceda5 100644
--- a/src/ostree/ot-builtin-init.c
+++ b/src/ostree/ot-builtin-init.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "libgsystem.h"
@@ -34,16 +35,16 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ostree_builtin_init (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_init (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context = NULL;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   OstreeRepoMode mode;
 
   context = g_option_context_new ("- Initialize a new empty repository");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NO_CHECK, &repo, 
cancellable, error))
     goto out;
 
   if (!ostree_repo_mode_from_string (opt_mode, &mode, error))
diff --git a/src/ostree/ot-builtin-log.c b/src/ostree/ot-builtin-log.c
index 89445cd..5147adb 100644
--- a/src/ostree/ot-builtin-log.c
+++ b/src/ostree/ot-builtin-log.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ot-dump.h"
 #include "ostree.h"
@@ -77,20 +78,19 @@ out:
 gboolean
 ostree_builtin_log (int           argc,
                     char        **argv,
-                    OstreeRepo   *repo,
                     GCancellable *cancellable,
                     GError      **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *rev;
   gs_free char *checksum = NULL;
   OstreeDumpFlags flags = OSTREE_DUMP_NONE;
 
   context = g_option_context_new ("REF - Show log starting at commit or ref");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (opt_raw)
diff --git a/src/ostree/ot-builtin-ls.c b/src/ostree/ot-builtin-ls.c
index f0a85be..1fce500 100644
--- a/src/ostree/ot-builtin-ls.c
+++ b/src/ostree/ot-builtin-ls.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "ostree-repo-file.h"
@@ -239,18 +240,18 @@ print_one_argument (OstreeRepo   *repo,
 }
 
 gboolean
-ostree_builtin_ls (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_ls (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *rev;
   int i;
   gs_unref_object GFile *root = NULL;
 
   context = g_option_context_new ("COMMIT [PATH...] - List file paths");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc <= 1)
diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c
index e483bf5..cd05b2f 100644
--- a/src/ostree/ot-builtin-prune.c
+++ b/src/ostree/ot-builtin-prune.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "libgsystem.h"
@@ -38,10 +39,11 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ostree_builtin_prune (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gs_free char *formatted_freed_size = NULL;
   OstreeRepoPruneFlags pruneflags = 0;
   gint n_objects_total;
@@ -49,9 +51,8 @@ ostree_builtin_prune (int argc, char **argv, OstreeRepo *repo, GCancellable *can
   guint64 objsize_total;
 
   context = g_option_context_new ("- Search for unreachable objects");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (opt_refs_only)
diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c
index bd9773b..808773d 100644
--- a/src/ostree/ot-builtin-pull-local.c
+++ b/src/ostree/ot-builtin-pull-local.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -105,10 +106,11 @@ idle_print_status (gpointer user_data)
 }
 
 gboolean
-ostree_builtin_pull_local (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError 
**error)
+ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   const char *src_repo_path;
   int i;
   GHashTableIter hash_iter;
@@ -124,9 +126,8 @@ ostree_builtin_pull_local (int argc, char **argv, OstreeRepo *repo, GCancellable
   OtLocalCloneData *data = &datav;
 
   context = g_option_context_new ("SRC_REPO [REFS...] -  Copy data from SRC_REPO");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   data->dest_repo = g_object_ref (repo);
@@ -270,6 +271,7 @@ ostree_builtin_pull_local (int argc, char **argv, OstreeRepo *repo, GCancellable
     g_object_unref (data->dest_repo);
   if (context)
     g_option_context_free (context);
-  ostree_repo_abort_transaction (repo, cancellable, NULL);
+  if (repo)
+    ostree_repo_abort_transaction (repo, cancellable, NULL);
   return ret;
 }
diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c
index 46bf5c7..ed013ca 100644
--- a/src/ostree/ot-builtin-pull.c
+++ b/src/ostree/ot-builtin-pull.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ot-builtins-common.h"
 #include "ostree.h"
@@ -41,9 +42,10 @@ static int opt_depth = 0;
  };
 
 gboolean
-ostree_builtin_pull (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   gs_free char *remote = NULL;
   OstreeRepoPullFlags pullflags = 0;
@@ -52,9 +54,8 @@ ostree_builtin_pull (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
   gs_unref_object OstreeAsyncProgress *progress = NULL;
 
   context = g_option_context_new ("REMOTE [BRANCH...] - Download data from remote repository");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c
index 9c291fb..10dcc72 100644
--- a/src/ostree/ot-builtin-refs.c
+++ b/src/ostree/ot-builtin-refs.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "libgsystem.h"
@@ -34,19 +35,19 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ostree_builtin_refs (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   const char *refspec_prefix = NULL;
   gs_unref_hashtable GHashTable *refs = NULL;
   GHashTableIter hashiter;
   gpointer hashkey, hashvalue;
 
   context = g_option_context_new ("[PREFIX] - List refs");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc >= 2)
@@ -87,6 +88,7 @@ ostree_builtin_refs (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
  out:
   if (context)
     g_option_context_free (context);
-  ostree_repo_abort_transaction (repo, cancellable, NULL);
+  if (repo)
+    ostree_repo_abort_transaction (repo, cancellable, NULL);
   return ret;
 }
diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c
index 6e63a48..541cf76 100644
--- a/src/ostree/ot-builtin-remote.c
+++ b/src/ostree/ot-builtin-remote.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -64,9 +65,10 @@ parse_keyvalue (const char  *keyvalue,
 }
 
 gboolean
-ostree_builtin_remote (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_remote (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *op;
   gs_free char *key = NULL;
@@ -75,9 +77,8 @@ ostree_builtin_remote (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
   const char *remote_name;
 
   context = g_option_context_new ("OPERATION NAME [args] - Control remote repository configuration");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc < 3)
diff --git a/src/ostree/ot-builtin-reset.c b/src/ostree/ot-builtin-reset.c
index a2ab429..0a72846 100644
--- a/src/ostree/ot-builtin-reset.c
+++ b/src/ostree/ot-builtin-reset.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -83,11 +84,11 @@ out:
 gboolean
 ostree_builtin_reset (int           argc,
                       char        **argv,
-                      OstreeRepo   *repo,
                       GCancellable *cancellable,
                       GError      **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *ref;
   const char *target = NULL;
@@ -95,9 +96,8 @@ ostree_builtin_reset (int           argc,
   gs_free gchar *checksum = NULL;
 
   context = g_option_context_new ("[ARG] - Reset a ref to a previous commit");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc <= 2)
@@ -130,6 +130,7 @@ ostree_builtin_reset (int           argc,
  out:
   if (context)
     g_option_context_free (context);
-  ostree_repo_abort_transaction (repo, cancellable, NULL);
+  if (repo)
+    ostree_repo_abort_transaction (repo, cancellable, NULL);
   return ret;
 }
diff --git a/src/ostree/ot-builtin-rev-parse.c b/src/ostree/ot-builtin-rev-parse.c
index 6c60b6f..f0835ca 100644
--- a/src/ostree/ot-builtin-rev-parse.c
+++ b/src/ostree/ot-builtin-rev-parse.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -31,18 +32,18 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ostree_builtin_rev_parse (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_rev_parse (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *rev = "master";
   int i;
   gs_free char *resolved_rev = NULL;
 
   context = g_option_context_new ("REV - Output the target of a rev");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc < 2)
diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c
index 4b87782..d094974 100644
--- a/src/ostree/ot-builtin-show.c
+++ b/src/ostree/ot-builtin-show.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ot-dump.h"
 #include "ostree.h"
@@ -199,17 +200,17 @@ print_if_found (OstreeRepo        *repo,
 }
 
 gboolean
-ostree_builtin_show (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_show (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gboolean ret = FALSE;
   const char *rev;
   gs_free char *resolved_rev = NULL;
 
   context = g_option_context_new ("OBJECT - Output a metadata object");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (argc <= 1)
diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c
index be535a6..6fa01a1 100644
--- a/src/ostree/ot-builtin-static-delta.c
+++ b/src/ostree/ot-builtin-static-delta.c
@@ -20,6 +20,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -36,16 +37,16 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ostree_builtin_static_delta (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError 
**error)
+ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
   gs_unref_ptrarray GPtrArray *delta_names = NULL;
 
   context = g_option_context_new ("Manage static delta files");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (opt_apply)
diff --git a/src/ostree/ot-builtin-summary.c b/src/ostree/ot-builtin-summary.c
index 2f9cae5..d7bed44 100644
--- a/src/ostree/ot-builtin-summary.c
+++ b/src/ostree/ot-builtin-summary.c
@@ -20,6 +20,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -32,15 +33,15 @@ static GOptionEntry options[] = {
 };
 
 gboolean
-ostree_builtin_summary (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
+ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
+  gs_unref_object OstreeRepo *repo = NULL;
 
   context = g_option_context_new ("Manage summary metadata");
-  g_option_context_add_main_entries (context, options, NULL);
 
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, 
cancellable, error))
     goto out;
 
   if (opt_update)
diff --git a/src/ostree/ot-builtin-trivial-httpd.c b/src/ostree/ot-builtin-trivial-httpd.c
index 5ca1e4b..31c541a 100644
--- a/src/ostree/ot-builtin-trivial-httpd.c
+++ b/src/ostree/ot-builtin-trivial-httpd.c
@@ -22,6 +22,7 @@
 
 #include <libsoup/soup.h>
 
+#include "ot-main.h"
 #include "ot-builtins.h"
 #include "ostree.h"
 #include "otutil.h"
@@ -322,7 +323,7 @@ on_dir_changed (GFileMonitor  *mon,
 }
 
 gboolean
-ostree_builtin_trivial_httpd (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError 
**error)
+ostree_builtin_trivial_httpd (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
   gboolean ret = FALSE;
   GOptionContext *context;
@@ -334,9 +335,7 @@ ostree_builtin_trivial_httpd (int argc, char **argv, OstreeRepo *repo, GCancella
 
   context = g_option_context_new ("[DIR] - Simple webserver");
 
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
+  if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, 
cancellable, error))
     goto out;
 
   if (argc > 1)
diff --git a/src/ostree/ot-builtins-common.c b/src/ostree/ot-builtins-common.c
index 5e3e4e6..9595ab4 100644
--- a/src/ostree/ot-builtins-common.c
+++ b/src/ostree/ot-builtins-common.c
@@ -20,6 +20,7 @@
 
 #include "config.h"
 
+#include "ot-main.h"
 #include "ot-builtins-common.h"
 #include "otutil.h"
 
diff --git a/src/ostree/ot-builtins.h b/src/ostree/ot-builtins.h
index b8b6507..d423a3a 100644
--- a/src/ostree/ot-builtins.h
+++ b/src/ostree/ot-builtins.h
@@ -26,7 +26,7 @@
 
 G_BEGIN_DECLS
 
-#define BUILTINPROTO(name) gboolean ostree_builtin_ ## name (int argc, char **argv, OstreeRepo *repo, 
GCancellable *cancellable, GError **error)
+#define BUILTINPROTO(name) gboolean ostree_builtin_ ## name (int argc, char **argv, GCancellable 
*cancellable, GError **error)
 
 BUILTINPROTO(admin);
 BUILTINPROTO(cat);
diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c
index 585e44f..43e09a3 100644
--- a/src/ostree/ot-main.c
+++ b/src/ostree/ot-main.c
@@ -24,6 +24,7 @@
 
 #include <gio/gio.h>
 
+#include <stdlib.h>
 #include <string.h>
 
 #include "ostree.h"
@@ -31,28 +32,73 @@
 #include "otutil.h"
 #include "libgsystem.h"
 
+static char *opt_repo;
+static char *opt_sysroot = "/";
+static gboolean opt_verbose;
+static gboolean opt_version;
+static gboolean opt_print_current_dir;
+
+static GOptionEntry global_entries[] = {
+  { "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", 
NULL },
+  { "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, "Print version information and exit", NULL },
+  { NULL }
+};
+
+static GOptionEntry repo_entry[] = {
+  { "repo", 0, 0, G_OPTION_ARG_STRING, &opt_repo, "Path to OSTree repository (defaults to 
/sysroot/ostree/repo)", "PATH" },
+  { NULL }
+};
+
+static GOptionEntry global_admin_entries[] = {
+  /* No description since it's hidden from --help output. */
+  { "print-current-dir", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_print_current_dir, NULL, NULL },
+  { "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" },
+  { NULL }
+};
+
+static GOptionContext *
+ostree_option_context_new_with_commands (OstreeCommand *commands)
+{
+  GOptionContext *context;
+  GString *summary;
+
+  context = g_option_context_new ("COMMAND");
+
+  summary = g_string_new ("Builtin Commands:");
+
+  while (commands->name != NULL)
+    {
+      g_string_append_printf (summary, "\n  %s", commands->name);
+      commands++;
+    }
+
+  g_option_context_set_summary (context, summary->str);
+
+  g_string_free (summary, TRUE);
+
+  return context;
+}
+
 int
-ostree_usage (char **argv,
-              OstreeCommand *commands,
+ostree_usage (OstreeCommand *commands,
               gboolean is_error)
 {
-  OstreeCommand *command = commands;
-  void (*print_func) (const gchar *format, ...);
+  GOptionContext *context;
+  gs_free char *help;
+
+  context = ostree_option_context_new_with_commands (commands);
+
+  g_option_context_add_main_entries (context, global_entries, NULL);
+
+  help = g_option_context_get_help (context, FALSE, NULL);
 
   if (is_error)
-    print_func = g_printerr;
+    g_printerr ("%s", help);
   else
-    print_func = g_print;
+    g_print ("%s", help);
 
-  print_func ("usage: %s --repo=PATH COMMAND [options]\n",
-              argv[0]);
-  print_func ("Builtin commands:\n");
+  g_option_context_free (context);
 
-  while (command->name)
-    {
-      print_func ("  %s\n", command->name);
-      command++;
-    }
   return (is_error ? 1 : 0);
 }
 
@@ -78,24 +124,16 @@ ostree_run (int    argc,
   OstreeCommand *command;
   GError *error = NULL;
   GCancellable *cancellable = NULL;
-  gs_unref_object OstreeRepo *repo = NULL;
-  const char *cmd = NULL;
-  const char *repo_arg = NULL;
-  gboolean want_help = FALSE;
-  gboolean skip;
+  const char *command_name = NULL;
+  gs_free char *prgname = NULL;
   gboolean success = FALSE;
-  int in, out, i;
+  int in, out;
 
   /* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
   g_setenv ("GIO_USE_VFS", "local", TRUE);
 
-  g_set_prgname (argv[0]);
-
   g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE, message_handler, NULL);
 
-  if (argc < 2)
-    return ostree_usage (argv, commands, TRUE);
-
   /*
    * Parse the global options. We rearrange the options as
    * necessary, in order to pass relevant options through
@@ -107,164 +145,217 @@ ostree_run (int    argc,
       /* The non-option is the command, take it out of the arguments */
       if (argv[in][0] != '-')
         {
-          skip = (cmd == NULL);
-          if (cmd == NULL)
-              cmd = argv[in];
-        }
-
-      /* The global long options */
-      else if (argv[in][1] == '-')
-        {
-          skip = FALSE;
-
-          if (g_str_equal (argv[in], "--"))
-            {
-              break;
-            }
-          else if (g_str_equal (argv[in], "--help"))
-            {
-              want_help = TRUE;
-            }
-          else if (g_str_equal (argv[in], "--repo") && in + 1 < argc)
+          if (command_name == NULL)
             {
-              repo_arg = argv[in + 1];
-              skip = TRUE;
-              in++;
-            }
-          else if (g_str_has_prefix (argv[in], "--repo="))
-            {
-              repo_arg = argv[in] + 7;
-              skip = TRUE;
-            }
-          else if (g_str_equal (argv[in], "--verbose"))
-            {
-              g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, message_handler, NULL);
-              skip = TRUE;
-            }
-          else if (cmd == NULL && g_str_equal (argv[in], "--version"))
-            {
-              g_print ("%s\n  %s\n", PACKAGE_STRING, OSTREE_FEATURES);
-              return 0;
-            }
-          else if (cmd == NULL)
-            {
-              g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Unknown or invalid global option: %s", argv[in]);
-              goto out;
+              command_name = argv[in];
+              out--;
+              continue;
             }
         }
 
-      /* The global short options */
-      else
+      else if (g_str_equal (argv[in], "--"))
         {
-          skip = FALSE;
-          for (i = 1; argv[in][i] != '\0'; i++)
-            {
-              switch (argv[in][i])
-              {
-                case 'h':
-                  want_help = TRUE;
-                  break;
-                case 'v':
-                  g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, message_handler, NULL);
-                  skip = TRUE;
-                  break;
-                default:
-                  if (cmd == NULL)
-                    {
-                      g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                                   "Unknown or invalid global option: %s", argv[in]);
-                      goto out;
-                    }
-                  break;
-              }
-            }
+          break;
         }
 
-      /* Skipping this argument? */
-      if (skip)
-        out--;
-      else
-        argv[out] = argv[in];
+      argv[out] = argv[in];
     }
 
   argc = out;
 
-  if (cmd == NULL)
-    {
-      if (want_help)
-        {
-          success = TRUE;
-        }
-      else
-        {
-          g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                               "No command specified");
-        }
-      ostree_usage (argv, commands, !want_help);
-      goto out;
-    }
-
   command = commands;
   while (command->name)
     {
-      if (g_strcmp0 (cmd, command->name) == 0)
+      if (g_strcmp0 (command_name, command->name) == 0)
         break;
       command++;
     }
 
   if (!command->fn)
     {
-      gs_free char *msg = g_strdup_printf ("Unknown command '%s'", cmd);
-      g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, msg);
+      GOptionContext *context;
+      gs_free char *help;
+
+      context = ostree_option_context_new_with_commands (commands);
+
+      /* This will not return for some options (e.g. --version). */
+      if (ostree_option_context_parse (context, NULL, &argc, &argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, 
cancellable, &error))
+        {
+          if (command_name == NULL)
+            {
+              g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                   "No command specified");
+            }
+          else
+            {
+              g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                           "Unknown command '%s'", command_name);
+            }
+        }
+
+      help = g_option_context_get_help (context, FALSE, NULL);
+      g_printerr ("%s", help);
+
+      g_option_context_free (context);
+
       goto out;
     }
 
-  g_set_prgname (g_strdup_printf ("ostree %s", cmd));
+  prgname = g_strdup_printf ("%s %s", g_get_prgname (), command_name);
+  g_set_prgname (prgname);
 
-  if (repo_arg == NULL && !want_help &&
-      !(command->flags & OSTREE_BUILTIN_FLAG_NO_REPO))
+  
+  if (!command->fn (argc, argv, cancellable, &error))
+    goto out;
+
+  success = TRUE;
+ out:
+  g_assert (success || error);
+
+  if (error)
     {
-      GError *temp_error = NULL;
+      g_propagate_error (res_error, error);
+      return 1;
+    }
+  return 0;
+}
+
+gboolean
+ostree_option_context_parse (GOptionContext *context,
+                             const GOptionEntry *main_entries,
+                             int *argc,
+                             char ***argv,
+                             OstreeBuiltinFlags flags,
+                             OstreeRepo **out_repo,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+  gs_unref_object OstreeRepo *repo = NULL;
+  gboolean success = FALSE;
+
+  /* Entries are listed in --help output in the order added.  We add the
+   * main entries ourselves so that we can add the --repo entry first. */
+
+  if (!(flags & OSTREE_BUILTIN_FLAG_NO_REPO))
+    g_option_context_add_main_entries (context, repo_entry, NULL);
+
+  if (main_entries != NULL)
+    g_option_context_add_main_entries (context, main_entries, NULL);
+
+  g_option_context_add_main_entries (context, global_entries, NULL);
+
+  if (!g_option_context_parse (context, argc, argv, error))
+    return FALSE;
+
+  if (opt_version)
+    {
+      g_print ("%s\n  %s\n", PACKAGE_STRING, OSTREE_FEATURES);
+      exit (EXIT_SUCCESS);
+    }
+
+  if (opt_verbose)
+    g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, message_handler, NULL);
+
+  if (opt_repo == NULL && !(flags & OSTREE_BUILTIN_FLAG_NO_REPO))
+    {
+      GError *local_error = NULL;
+
       repo = ostree_repo_new_default ();
-      if (!ostree_repo_open (repo, cancellable, &temp_error))
+      if (!ostree_repo_open (repo, cancellable, &local_error))
         {
-          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+          if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
             {
-              g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
+              gs_free char *help = NULL;
+
+              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                    "Command requires a --repo argument");
-              g_error_free (temp_error);
-              ostree_usage (argv, commands, TRUE);
+              g_error_free (local_error);
+
+              help = g_option_context_get_help (context, FALSE, NULL);
+              g_printerr ("%s", help);
             }
           else
             {
-              g_propagate_error (&error, temp_error);
+              g_propagate_error (error, local_error);
             }
           goto out;
         }
     }
-  else if (repo_arg)
+  else if (opt_repo != NULL)
     {
-      gs_unref_object GFile *repo_file = g_file_new_for_path (repo_arg);
+      gs_unref_object GFile *repo_file = g_file_new_for_path (opt_repo);
+
       repo = ostree_repo_new (repo_file);
-      if (!(command->flags & OSTREE_BUILTIN_FLAG_NO_CHECK))
+      if (!(flags & OSTREE_BUILTIN_FLAG_NO_CHECK))
         {
-          if (!ostree_repo_open (repo, cancellable, &error))
+          if (!ostree_repo_open (repo, cancellable, error))
             goto out;
         }
     }
-  
-  if (!command->fn (argc, argv, repo, cancellable, &error))
-    goto out;
+
+  gs_transfer_out_value (out_repo, &repo);
 
   success = TRUE;
- out:
-  g_assert (success || error);
 
-  if (error)
+out:
+  return success;
+}
+
+gboolean
+ostree_admin_option_context_parse (GOptionContext *context,
+                                   const GOptionEntry *main_entries,
+                                   int *argc,
+                                   char ***argv,
+                                   OstreeSysroot **out_sysroot,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+  gs_unref_object GFile *sysroot_path = NULL;
+  gs_unref_object OstreeSysroot *sysroot = NULL;
+  gboolean success = FALSE;
+
+  /* Entries are listed in --help output in the order added.  We add the
+   * main entries ourselves so that we can add the --sysroot entry first. */
+
+  g_option_context_add_main_entries (context, global_admin_entries, NULL);
+
+  if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, 
cancellable, error))
+    goto out;
+
+  sysroot_path = g_file_new_for_path (opt_sysroot);
+  sysroot = ostree_sysroot_new (sysroot_path);
+
+  if (opt_print_current_dir)
     {
-      g_propagate_error (res_error, error);
-      return 1;
+      gs_unref_ptrarray GPtrArray *deployments = NULL;
+      OstreeDeployment *first_deployment;
+      gs_unref_object GFile *deployment_file = NULL;
+      gs_free char *deployment_path = NULL;
+
+      if (!ostree_sysroot_load (sysroot, cancellable, error))
+        goto out;
+
+      deployments = ostree_sysroot_get_deployments (sysroot);
+      if (deployments->len == 0)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Unable to find a deployment in sysroot");
+          goto out;
+        }
+      first_deployment = deployments->pdata[0];
+      deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment);
+      deployment_path = g_file_get_path (deployment_file);
+
+      g_print ("%s\n", deployment_path);
+
+      exit (EXIT_SUCCESS);
     }
-  return 0;
+
+  gs_transfer_out_value (out_sysroot, &sysroot);
+
+  success = TRUE;
+
+out:
+  return success;
 }
+
diff --git a/src/ostree/ot-main.h b/src/ostree/ot-main.h
index 49e310e..5f31b24 100644
--- a/src/ostree/ot-main.h
+++ b/src/ostree/ot-main.h
@@ -32,10 +32,22 @@ typedef enum {
 
 typedef struct {
   const char *name;
-  gboolean (*fn) (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error);
-  int flags; /* OstreeBuiltinFlags */
+  gboolean (*fn) (int argc, char **argv, GCancellable *cancellable, GError **error);
 } OstreeCommand;
 
 int ostree_run (int argc, char **argv, OstreeCommand *commands, GError **error);
 
-int ostree_usage (char **argv, OstreeCommand *commands, gboolean is_error);
+int ostree_usage (OstreeCommand *commands, gboolean is_error);
+
+gboolean ostree_option_context_parse (GOptionContext *context,
+                                      const GOptionEntry *main_entries,
+                                      int *argc, char ***argv,
+                                      OstreeBuiltinFlags flags,
+                                      OstreeRepo **out_repo,
+                                      GCancellable *cancellable, GError **error);
+
+gboolean ostree_admin_option_context_parse (GOptionContext *context,
+                                            const GOptionEntry *main_entries,
+                                            int *argc, char ***argv,
+                                            OstreeSysroot **out_sysroot,
+                                            GCancellable *cancellable, GError **error);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]