/* cmd-tree-root.c
 *
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "config-options.h"
#include "hackerlab/cmd/main.h"
#include "tla/libarch/project-tree.h"
#include "tla/libarch/cmd-tree-root.h"



static t_uchar * usage = "[options] [dir]";
static t_uchar * version_string = (cfg__std__package " from regexps.com\n"
                                   "\n"
                                   "Copyright 2003 Tom Lord\n"
                                   "\n"
                                   "This is free software; see the source for copying conditions.\n"
                                   "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
                                   "PARTICULAR PURPOSE.\n"
                                   "\n"
                                   "Report bugs to " cfg__tla_bug_mail ".\n"
                                   "\n"
                                   cfg__std__release_id_string
                                   "\n");

#define OPTS(OP) \
  OP (opt_help_msg, "h", "help", 0, \
      "Display a help message and exit.") \
  OP (opt_long_help, "H", 0, 0, \
      "Display a verbose help message and exit.") \
  OP (opt_version, "V", "version", 0, \
      "Display a release identifier string\n" \
      "and exit.") \
  OP (opt_accurate, 0, "accurate", 0, \
      "error for mid-txn trees") \
  OP (opt_silent, "s", "silent", 0, \
      "exit status only")

t_uchar arch_cmd_tree_root_help[] = ("find and print the root of a project tree\n"
                                     "Find and print the root of the project tree that contains\n"
                                     "DIR (or the current directory).\n"
                                     "The option --accurate checks for three possibilities:\n"
                                     "\n"
                                     "    1) The project tree was the subject of a commit that\n"
                                     "       was killed before the log entry was added to the\n"
                                     "       tree's patch log.  It is unknown whether or not\n"
                                     "       the commit took place in the archive.  The {arch}\n"
                                     "       directory contains the log file as \"++mid-commit\".\n"
                                     "\n"
                                     "    2) The project tree was the subject of a killed commit, but\n"
                                     "       it is certain the commit took place.  The log file\n"
                                     "       is stored as \"++commit-definite\".\n"
                                     "\n"
                                     "    3) The project tree patch log is fully up-to-date (as far as\n"
                                     "       arch knows).\n"
                                     "\n"
                                     "In case 1, exit with an error and error message.\n"
                                     "\n"
                                     "In case 2, install the log file before printing the tree root and\n"
                                     "exiting normally.\n"
                                     "\n"
                                     "In case 3, print the tree root and exit normally.\n");

enum options
{
  OPTS (OPT_ENUM)
};

static struct opt_desc opts[] =
{
  OPTS (OPT_DESC)
    {-1, 0, 0, 0, 0}
};



int
arch_cmd_tree_root (t_uchar * program_name, int argc, char * argv[])
{
  int o;
  struct opt_parsed * option;
  int silent;
  int accurate;
  char * dir;
  t_uchar * result;
  enum arch_tree_state tree_state;
  int status;

  silent = 0;
  accurate = 0;

  safe_buffer_fd (1, 0, O_WRONLY, 0);

  option = 0;

  while (1)
    {
      o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, version_string, arch_cmd_tree_root_help, opt_help_msg, opt_long_help, opt_version);
      if (o == opt_none)
        break;
      switch (o)
        {
        default:
          safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
          panic ("internal error parsing arguments");

        usage_error:
          opt_usage (2, argv[0], program_name, usage, 1);
          exit (1);

          /* bogus_arg: */
          safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
          goto usage_error;


        case opt_silent:
          {
            silent = 1;
            break;
          }

        case opt_accurate:
          {
            accurate = 1;
            break;
          }
        }
    }

  if (argc > 2)
    goto usage_error;

  if (argc == 1)
    dir = 0;
  else
    dir = argv[1];

  result = arch_tree_root (&tree_state, (t_uchar *)dir, accurate);

  if (!result)
    {
      status = 1;
      if (!silent)
        safe_printfmt (2, "%s: not in a project tree\n  dir: %s\n",
                       argv[0], (dir ? dir : "."));
    }
  else if (!accurate || (tree_state == arch_tree_in_ok_state))
    {
      status = 0;
      if (!silent)
        safe_printfmt (1, "%s\n", result);
    }
  else
    {
      /* in a project tree, but not in an ok state, --accurate specified
       *
       * --silent doesn't supress these error messages.
       */

      status = 1;
      switch (tree_state)
        {
        default:
          panic ("unknown project tree state");
          break;

        case arch_tree_in_resolve_conflicts:
          {
            safe_printfmt (2, "%s: project tree in mid-merge\n  dir: %s\n  project tree %s\n",
                           argv[0],
                           (dir ? dir : "."),
                           result);
            break;
          }

        case arch_tree_in_commit_definite:
        case arch_tree_in_mid_commit:
          {
            safe_printfmt (2, "%s: project tree in mid-commit\n  dir: %s\n  project tree %s\n",
                           argv[0],
                           (dir ? dir : "."),
                           result);

            /* The larch version just implicitly repairs the tree for
             * arch_tree_in_commit_definite.   This vesion should too,
             * eventually.
             */
            break;
          }
        }
    }


  exit (status);
  return 0;
}




/* tag: Tom Lord Mon May 12 12:25:44 2003 (tree-root.c)
 */
