/* cacherev.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 "hackerlab/fs/file-names.h"
#include "hackerlab/fs/cwd.h"
#include "tla/libfsutils/tmp-files.h"
#include "tla/libfsutils/rmrf.h"
#include "tla/libarch/namespace.h"
#include "tla/libarch/project-tree.h"
#include "tla/libarch/my.h"
#include "tla/libarch/archive.h"
#include "tla/libarch/patch-logs.h"
#include "tla/libarch/pristines.h"
#include "tla/libarch/build-revision.h"
#include "tla/libarch/cmd.h"
#include "tla/libarch/cmd-cacherev.h"



static t_uchar * usage = "[options] [revision]";
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_cache, 0, "cache DIR", 1, \
      "cache root for trees with pristines")


t_uchar arch_cmd_cacherev_help[] = ("cache a full source tree in an archive\n"
                                    "Cache a full-text copy of the indicated revision\n"
                                    "in the archive.   This can speed up subsequent calls\n"
                                    "to \"tla get\" for that and subsequent revisions.\n\n"
                                    "If no revision is specified, but the command is run\n"
                                    "from within a project tree, cache the latest revision\n"
                                    "in the default version of that tree.\n");


enum options
{
  OPTS (OPT_ENUM)
};

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



int
arch_cmd_cacherev (t_uchar * program_name, int argc, char * argv[])
{
  int o;
  struct opt_parsed * option;
  t_uchar * default_archive = 0;
  t_uchar * cache_dir = 0;
  enum arch_revision_type type;
  int is_cached;

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

        case opt_cache:
          {
            lim_free (0, cache_dir);
            cache_dir = str_save (0, option->arg_string);
            break;
          }
        }
    }

  if (argc > 2)
    goto usage_error;

  default_archive = arch_my_default_archive (default_archive);

  {
    t_uchar * revision_spec;
    t_uchar * archive = 0;
    t_uchar * revision = 0;
    struct arch_archive * arch = 0;
    t_uchar * tmp_dir = 0;
    t_uchar * pristine_dir = 0;

    if (argc == 2)
      {
        revision_spec = str_save(0, argv[1]);

        if (!arch_valid_package_name (revision_spec, arch_maybe_archive, arch_req_patch_level, 1))
          {
            safe_printfmt (2, "%s: invalid revision spec (%s)\n",
                           argv[0], revision_spec);
            exit (2);
          }

        archive = arch_parse_package_name (arch_ret_archive, default_archive, revision_spec);
        revision = arch_parse_package_name (arch_ret_non_archive, 0, revision_spec);
      }
    else
      {
        t_uchar * tree_root = 0;
        t_uchar * version_spec = 0;
        t_uchar * version = 0;
        t_uchar * patch_level = 0;

        tree_root = arch_tree_root (0, ".", 0);

        if (!tree_root)
          {
            safe_printfmt (2, "%s: not in project tree, specify revision to cache\n",
                           argv[0]);
            exit (1);
          }

        version_spec = arch_tree_version (tree_root);

        if (!arch_valid_package_name (version_spec, arch_maybe_archive, arch_req_version, 1))
          {
            safe_printfmt (2, "%s: invalid version spec (%s)\n",
                           argv[0], version_spec);
            exit (2);
          }

        archive = arch_parse_package_name (arch_ret_archive, default_archive, version_spec);
        version = arch_parse_package_name (arch_ret_non_archive, 0, version_spec);
        patch_level = arch_highest_patch_level (tree_root, archive, version);

        revision = str_alloc_cat_many (0, version, "--", patch_level, str_end);

        lim_free (0, tree_root);
        lim_free (0, version_spec);
        lim_free (0, version);
        lim_free (0, patch_level);
      }

    if (!cache_dir)
      cache_dir = str_save (0, ".");

    tmp_dir = tmp_file_name (".", ",,archive-cache-revision");
    pristine_dir = file_name_in_vicinity (0, tmp_dir, revision);

    arch = arch_archive_connect (archive, 0);

    arch_revision_type (&type, &is_cached, arch, revision);
    if (is_cached)
      {
        safe_printfmt (2, "%s: revision already has a cacherev\nrevision: %s\n",
                       argv[0], revision);
        exit (1);
      }

    safe_mkdir (tmp_dir, 0777);
    safe_mkdir (pristine_dir, 0777);

    arch_build_revision (1, pristine_dir, arch, archive, revision, cache_dir);

    {
      t_uchar * errstr;

      if (arch_archive_put_cached (&errstr, arch, revision, pristine_dir))
        {
          safe_printfmt (2, "%s: unable to store cached revision of %s/%s (%s)\n",
                         argv[0], archive, revision, errstr);
          exit (1);
        }
    }

    arch_archive_close (arch);

    rmrf_file (tmp_dir);

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

  lim_free (0, default_archive);
  lim_free (0, cache_dir);

  return 0;
}




/* tag: Tom Lord Thu May 29 22:26:18 2003 (cacherev.c)
q */
