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

#include "hackerlab/os/errno.h"
#include "hackerlab/os/errno-to-string.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "tla/libfsutils/ensure-dir.h"
#include "tla/libfsutils/tmp-files.h"
#include "tla/libawk/relational.h"
#include "tla/libarch/archive.h"
#include "tla/libarch/namespace.h"
#include "tla/libarch/archive-snapshot.h"


/* __STDC__ prototypes for static functions */
static void put_file_contents (t_uchar * path, t_uchar * contents);
static void ensure_basename (t_uchar * dir, t_uchar * basename);



void
archive_snapshot (struct arch_archive * arch, t_uchar * limit, t_uchar * dir)
{
  t_uchar * only_category = 0;
  t_uchar * only_branch = 0;
  t_uchar * only_version = 0;
  t_uchar * only_revision = 0;
  t_uchar * archive_basename = 0;
  t_uchar * archive_subdir = 0;
  rel_table categories = 0;
  int c;

  if (limit)
    {
      only_category = arch_parse_package_name (arch_ret_category, 0, limit);

      if (arch_valid_package_name (limit, arch_no_archive, arch_req_package, 1))
        {
          only_branch = arch_parse_package_name (arch_ret_package, 0, limit);

          if (!str_cmp (only_branch, only_category))
            {
              lim_free (0, only_branch);
              only_branch = 0;
            }
          else if (arch_valid_package_name (limit, arch_no_archive, arch_req_version, 1))
            {
              only_version = arch_parse_package_name (arch_ret_package_version, 0, limit);

              if (arch_valid_package_name (limit, arch_no_archive, arch_req_patch_level, 1))
                {
                  only_revision = arch_parse_package_name (arch_ret_non_archive, 0, limit);
                }
            }
        }
    }


  archive_basename = str_alloc_cat (0, arch->name, ".added");
  ensure_basename (dir, archive_basename);

  archive_subdir = file_name_in_vicinity (0, dir, arch->name);
  ensure_directory_exists (archive_subdir);

  categories = arch_archive_categories (arch);

  for (c = 0; c < rel_n_records (categories); ++c)
    {
      t_uchar * category_basename = 0;
      t_uchar * category_subdir = 0;
      rel_table branches = 0;
      int b;

      if (only_category && str_cmp (only_category, categories[c][0]))
        continue;

      category_basename = str_alloc_cat (0, categories[c][0], ".added");
      category_subdir = file_name_in_vicinity (0, archive_subdir, categories[c][0]);
      branches = arch_archive_branches (arch, categories[c][0]);

      ensure_basename (archive_subdir, category_basename);
      ensure_directory_exists (category_subdir);

      for (b = 0; b < rel_n_records (branches); ++b)
        {
          t_uchar * branch_basename = 0;
          t_uchar * branch_subdir = 0;
          rel_table versions = 0;
          int v;

          if (only_branch && str_cmp (only_branch, branches[b][0]))
            continue;

          branch_basename = str_alloc_cat (0, branches[b][0], ".added");
          branch_subdir = file_name_in_vicinity (0, category_subdir, branches[b][0]);
          versions = arch_archive_versions (arch, branches[b][0]);

          ensure_basename (category_subdir, branch_basename);
          ensure_directory_exists (branch_subdir);

          for (v = 0; v < rel_n_records (versions); ++v)
            {
              t_uchar * version_basename = 0;
              t_uchar * version_subdir = 0;
              rel_table revisions = 0;
              int r;

              if (only_version && str_cmp (only_version, versions[v][0]))
                continue;

              version_basename = str_alloc_cat (0, versions[v][0], ".added");
              version_subdir = file_name_in_vicinity (0, branch_subdir, versions[v][0]);
              revisions = arch_archive_revisions (arch, versions[v][0], 2);

              ensure_basename (branch_subdir, version_basename);
              ensure_directory_exists (version_subdir);

              for (r = 0; r < rel_n_records (revisions); ++r)
                {
                  t_uchar * revision_basename = 0;
                  t_uchar * revision_file = 0;
                  t_uchar * log = 0;

                  if (only_revision && str_cmp (only_revision, revisions[r][0]))
                    continue;

                  revision_basename = str_alloc_cat (0, revisions[r][0], ".added");
                  revision_file = file_name_in_vicinity (0, version_subdir, revision_basename);
                  if (safe_access (revision_file, F_OK))
                    {
                      t_uchar * tmp_file = 0;

                      tmp_file = tmp_file_name (version_subdir, ",,new-log");
                      log = arch_archive_log (arch, revisions[r][0]);
                      put_file_contents (tmp_file, log);
                      safe_rename (tmp_file, revision_file);

                      lim_free (0, tmp_file);
                    }


                  lim_free (0, revision_basename);
                  lim_free (0, revision_file);
                  lim_free (0, log);
                }


              lim_free (0, version_basename);
              lim_free (0, version_subdir);
              rel_free_table (revisions);
            }


          lim_free (0, branch_basename);
          lim_free (0, branch_subdir);
          rel_free_table (versions);
        }


      lim_free (0, category_basename);
      lim_free (0, category_subdir);
      rel_free_table (branches);
    }



  lim_free (0, only_category);
  lim_free (0, only_branch);
  lim_free (0, only_version);
  lim_free (0, only_revision);
  lim_free (0, archive_basename);
  lim_free (0, archive_subdir);
  rel_free_table (categories);
}



static void
put_file_contents (t_uchar * path, t_uchar * contents)
{
  int out_fd;

  out_fd = safe_open (path, O_WRONLY | O_CREAT | O_EXCL, 0444);
  safe_printfmt (out_fd, "%s\n", contents);
  safe_close (out_fd);
}

static void
ensure_basename (t_uchar * dir, t_uchar * basename)
{
  int errn;
  t_uchar * path = 0;
  int in_fd;

  path = file_name_in_vicinity (0, dir, basename);
  in_fd = vu_open (&errn, path, O_WRONLY | O_CREAT | O_EXCL, 0444);
  if (in_fd >= 0)
    safe_close (in_fd);
  else if (errn != EEXIST)
    {
      safe_printfmt (2, "archive-snapshot: error creating file %s/%s (%s)\n", dir, basename, errno_to_string (errn));
      exit (2);
    }

  lim_free (0, path);
}




/* tag: Tom Lord Mon Jun  9 01:03:59 2003 (archive-snapshot.c)
 */
