/* cmd-archive-setup.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/namespace.h"
#include "tla/libarch/archive-setup.h"
#include "tla/libarch/my.h"
#include "tla/libarch/cmd-archive-setup.h"



static t_uchar * usage = "[options] [version ...]";
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_archive, "A", "archive", 1, \
      "Override `my-default-archive'") \
  OP (opt_list_file, "f", "file FILE", 1, \
      "read the list of desired versions from FILE") \
  OP (opt_base0_tag, "b", "branches", 0, \
      "make base-0 tags") \
  OP (opt_cache, "c", "cache", 0, \
      "archive cache when creating base-0 tags")


t_uchar arch_cmd_archive_setup_help[] = ("create new categories, branches and versions\n"
                                         "Given a list of categories, branches, and versions,\n"
                                         "ensure that these exist in the appropriate archive.\n"
                                         "\n"
                                         "For example, starting with an empty archive,:\n"
                                         "\n"
                                         "    % tla archive-setup  proja--devo--1.0 projb\n"
                                         "\n"
                                         "creates a category, branch, and version for project A,\n"
                                         "and a category for project B\n"
                                         "\n"
                                         "When the --file option is used, the list of items to\n"
                                         "create is read from a file (use \"-\" to indicate\n"
                                         "standard input).\n"
                                         "\n"
                                         "With the --file option, the option --branches may\n"
                                         "be provided.  In this case, the input should have\n"
                                         "two items per line:  a target version (to create), and\n"
                                         "a source version to build a tag from.   For example,\n"
                                         "given an input file containg:\n"
                                         "\n"
                                         "    proja--devo--1.0  his@foo.com/proja--devo--1.0\n"
                                         "\n"
                                         "with --branches, archive-setup creates a proja version\n"
                                         "in your default archive, and adds a base-0 revision\n"
                                         "to that project which is a tag of the latest revision\n"
                                         "in his@foo.com's archive.  (This can make it quite easy\n"
                                         "to set-up a new archive which contains branches from\n"
                                         "existing archives, for example.)\n"
                                         "\n"
                                         "If --branches is used, the --cache option may also be\n"
                                         "used.   It causes each new base-0 revision to be\n"
                                         "archive-cached (see \"tla cacherev -H\")\n");


enum options
{
  OPTS (OPT_ENUM)
};

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



int
arch_cmd_archive_setup (t_uchar * program_name, int argc, char * argv[])
{
  int o;
  struct opt_parsed * option;
  t_uchar * default_archive = 0;
  t_uchar * list_file = 0;
  enum arch_archive_setup_tag_op tag_op = arch_archive_setup_no_tags;
  int do_cache = 0;

  vu_push_dash_handler (0);

  default_archive = 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_archive_setup_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_archive:
          {
            default_archive = str_save (0, option->arg_string);
            break;
          }

        case opt_list_file:
          {
            list_file = str_save (0, option->arg_string);
            break;
          }

        case opt_base0_tag:
          {
            tag_op = arch_archive_setup_make_base0_tag;
            break;
          }

        case opt_cache:
          {
            do_cache = 1;
            break;
          }
        }
    }

  if (!list_file && (argc < 2))
    goto usage_error;

  if (default_archive && !arch_valid_archive_name (default_archive))
    {
      safe_printfmt (2, "%s: invalid archive name %s\n",
                     argv[0], default_archive);
      exit (1);
    }
  default_archive = arch_my_default_archive (default_archive);

  {
    int x;
    rel_table wants = rel_table_nil;
    rel_table wants_decomposed = rel_table_nil;

    if (list_file)
      {
        int in_fd;

        in_fd = safe_open (list_file, O_RDONLY, 0);

        if (tag_op == arch_archive_setup_no_tags)
          wants = rel_read_table (in_fd, 1, argv[0], list_file);
        else
          wants = rel_read_table (in_fd, 2, argv[0], list_file);
        safe_close (in_fd);
      }
    else
      {
        if (arch_archive_setup_no_tags)
          {
            safe_printfmt (2, "%s: use -f input when creating tags\n", argv[0]);
            exit (1);
          }
        for (x = 1; x < argc; ++x)
          rel_add_records (&wants, rel_singleton_record_taking (rel_make_field_str (argv[x])), rel_record_null);
      }

    for (x = 0; x < rel_n_records (wants); ++x)
      {
        t_uchar * archive = 0;
        t_uchar * non_archive = 0;

        if (!arch_valid_package_name (rel_peek_str (wants, x, 0), arch_maybe_archive, arch_req_category, 1))
          {
            safe_printfmt (2, "%s: invalid package name %s\n",
                           argv[0], rel_peek_str (wants, x, 0));
            exit (1);
          }

        archive = arch_parse_package_name (arch_ret_archive, default_archive, rel_peek_str (wants, x, 0));
        non_archive = arch_parse_package_name (arch_ret_non_archive, 0, rel_peek_str (wants, x, 0));

        if (arch_is_system_package_name (non_archive))
          {
            safe_printfmt (2, "%s: user's can not create system categories, branches or versions\n  illegal spec: %s\n", argv[0], non_archive);
            exit (2);
          }

        if (tag_op == arch_archive_setup_no_tags)
          rel_add_records (&wants_decomposed, rel_make_record_2_taking (rel_make_field_str (archive), rel_make_field_str (non_archive)), rel_record_null);
        else
          {
            t_uchar * from_archive = 0;
            t_uchar * from_rev_spec = 0;

            if (!arch_valid_package_name (rel_peek_str (wants, x, 1), arch_maybe_archive, arch_req_version, 1))
              {
                safe_printfmt (2, "%s: invalid tag-revision specification %s\n",
                               argv[0], rel_peek_str (wants, x, 1));
                exit (1);
              }

            from_archive = arch_parse_package_name (arch_ret_archive, default_archive, rel_peek_str (wants, x, 1));
            from_rev_spec = arch_parse_package_name (arch_ret_non_archive, default_archive, rel_peek_str (wants, x, 1));

            rel_add_records (&wants_decomposed,
                             rel_make_record_4_taking (rel_make_field_str (archive),
                                                       rel_make_field_str (non_archive),
                                                       rel_make_field_str (from_archive),
                                                       rel_make_field_str (from_rev_spec)),
                             rel_record_null);

            lim_free (0, from_archive);
            lim_free (0, from_rev_spec);
          }

        lim_free (0, archive);
        lim_free (0, non_archive);
      }

    arch_setup_archive (1, wants_decomposed, tag_op, do_cache);

    rel_free_table (wants);
    rel_free_table (wants_decomposed);
  }

  lim_free (0, default_archive);
  lim_free (0, list_file);
  return 0;
}



/* tag: Tom Lord Wed Jun 11 11:47:44 2003 (cmd-archive-setup.c)
 */
