/* archives.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/bugs/panic.h"
#include "hackerlab/char/char-class.h"
#include "hackerlab/char/str.h"
#include "hackerlab/mem/mem.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/fs/cwd.h"
#include "hackerlab/vu/safe.h"
#include "tla/libfsutils/tmp-files.h"
#include "tla/libfsutils/read-line.h"
#include "tla/libfsutils/dir-listing.h"
#include "tla/libawk/relational.h"
#include "tla/libarch/my.h"
#include "tla/libarch/namespace.h"
#include "tla/libarch/archive-version.h"
#include "tla/libarch/archives.h"



t_uchar *
arch_archive_location_file (t_uchar * archive_name)
{
  t_uchar * location_dir = 0;
  t_uchar * answer = 0;

  if (! arch_valid_archive_name(archive_name)) 
    {
      int ign;

      printfmt (&ign, 2, "Invalid archive name `%s'.", archive_name);
      exit (2);
    }

  location_dir = arch_my_archive_locations_dir ();
  answer = file_name_in_vicinity (0, location_dir, archive_name);

  lim_free (0, location_dir);

  return answer;
}


void
arch_set_archive_location (t_uchar * archive_name, t_uchar * location, int force_p, int quietly_fail)
{
  t_uchar * file = 0;
  t_uchar * dir = 0;
  t_uchar * tmp_name = 0;

  file = arch_archive_location_file (archive_name);
  dir = file_name_directory_file (0, file);
  tmp_name = tmp_file_name (dir, ",,new-location");

  if (!force_p && !safe_access (file, F_OK))
    {
      if (! quietly_fail)
        {
          safe_printfmt (2, "archive already registered: %s\n", archive_name);
          if (quietly_fail == ARCH_REG_FAIL_NOFAIL)
            {
              return;
            }
          else
            {
              exit (2);
            }
        }
    }
  else
    {
      int ign;
      int out_fd;

      arch_ensure_my_arch_params ();
      vu_mkdir (&ign, dir, 0700);

      out_fd = safe_open (tmp_name, O_WRONLY | O_CREAT | O_EXCL, 0666);
      safe_printfmt (out_fd, "%s\n", location);
      safe_close (out_fd);

      safe_rename (tmp_name, file);
    }

  lim_free (0, file);
  lim_free (0, dir);
  lim_free (0, tmp_name);
}


t_uchar *
arch_archive_location (t_uchar * archive_name, int soft)
{
  t_uchar * file = 0;
  t_uchar * first_line = 0;
  t_uchar * start;
  t_uchar * end;
  t_uchar * answer = 0;

  file = arch_archive_location_file (archive_name);

  if (safe_access (file, F_OK))
    {
      if (soft)
        return 0;

      safe_printfmt (2, "archive not registered: %s\n", archive_name);
      safe_printfmt (2, "  (see register-archive)\n");
      exit (2);
    }

  first_line = read_line_from_file (file);

  for (start = first_line; char_is_blank (*start); ++start)
    ;
  for (end = start; *end && !char_is_space (*start); ++end)
    ;

  answer = str_save_n (0, start, end - start);

  lim_free (0, file);
  lim_free (0, first_line);

  return answer;
}


void
arch_delete_archive_location (t_uchar * archive_name, int force_p)
{
  t_uchar * file = 0;
  int errn;

  file = arch_archive_location_file (archive_name);

  if (vu_unlink (&errn, file))
    {
      if (!(force_p && (errn == ENOENT)))
        {
          safe_printfmt (2, "archive not registered: %s\n", archive_name);
          safe_printfmt (2, "  (see register-archive)\n");
          exit (2);
        }
    }

  lim_free (0, file);
}


rel_table
arch_registered_archives (void)
{
  t_uchar * dir = 0;
  rel_table files = 0;
  rel_table answer = 0;
  int x;

  dir = arch_my_archive_locations_dir ();
  files = maybe_directory_files (dir);

  for (x = 0; x < rel_n_records (files); ++x)
    {
      t_uchar * f;

      f = files[x][0];
      if (str_cmp (".", f) && str_cmp ("..", f) && arch_valid_archive_name (f))
        {
          t_uchar * location = 0;

          location = arch_archive_location (f, 0);
          rel_add_records (&answer, rel_make_record (f, location, 0), 0);

          lim_free (0, location);
        }
    }


  lim_free (0, dir);
  rel_free_table (files);

  return answer;
}

t_uchar *
arch_mirrored_at_name (t_uchar * archive)
{
  t_uchar * mirror_name = 0;

  mirror_name = str_alloc_cat (0, archive, "-MIRROR");

  return mirror_name;
}

t_uchar *
arch_mirrored_from_name (t_uchar * archive)
{
  t_uchar * source_name = 0;

  source_name = str_alloc_cat (0, archive, "-SOURCE");

  return source_name;
}

t_uchar *
arch_mirrored_at (t_uchar * archive)
{
  t_uchar * mirror_name = 0;
  t_uchar * mirror_loc = 0;

  mirror_name = arch_mirrored_at_name (archive);
  mirror_loc = arch_archive_location (mirror_name, 1);

  if (!mirror_loc)
    {
      lim_free (0, mirror_name);
      mirror_name = 0;
    }

  lim_free (0, mirror_loc);
  return mirror_name;
}


t_uchar *
arch_mirrored_from (t_uchar * archive)
{
  t_uchar * source_name = 0;
  t_uchar * source_loc = 0;

  source_name = arch_mirrored_from_name (archive);
  source_loc = arch_archive_location (source_name, 1);

  if (!source_loc)
    {
      lim_free (0, source_name);
      source_name = 0;
    }

  lim_free (0, source_loc);
  return source_name;
}



t_uchar *
arch_fs_archive_archive_version_path (t_uchar * archive_path)
{
  return file_name_in_vicinity (0, archive_path, ".archive-version");
}

t_uchar *
arch_fs_archive_meta_info_path (t_uchar * archive_path)
{
  return file_name_in_vicinity (0, archive_path, "=meta-info");
}

t_uchar *
arch_fs_archive_meta_info_item_path (t_uchar * archive_path, t_uchar * meta_info_name)
{
  t_uchar * meta_info_dir = 0;
  t_uchar * meta_info_path;

  meta_info_dir = arch_fs_archive_meta_info_path (archive_path);
  meta_info_path = file_name_in_vicinity (0, meta_info_dir, meta_info_name);

  lim_free (0, meta_info_dir);

  return meta_info_path;
}


t_uchar *
arch_fs_archive_category_path (t_uchar * archive_path, t_uchar * category)
{
  return file_name_in_vicinity (0, archive_path, category);
}

t_uchar *
arch_fs_archive_branch_path (t_uchar * archive_path, t_uchar * package)
{
  t_uchar * category = 0;
  t_uchar * category_path = 0;
  t_uchar * branch_path = 0;

  invariant (arch_valid_package_name (package, arch_no_archive, arch_req_package, 0));

  category = arch_parse_package_name (arch_ret_category, 0, package);
  category_path = arch_fs_archive_category_path (archive_path, category);
  branch_path = file_name_in_vicinity (0, category_path, package);

  lim_free (0, category);
  lim_free (0, category_path);
  return branch_path;
}

t_uchar *
arch_fs_archive_version_path (t_uchar * archive_path, t_uchar * version)
{
  t_uchar * package = 0;
  t_uchar * package_path = 0;
  t_uchar * version_path = 0;

  invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0));

  package = arch_parse_package_name (arch_ret_package, 0, version);
  package_path = arch_fs_archive_branch_path (archive_path, package);
  version_path = file_name_in_vicinity (0, package_path, version);

  lim_free (0, package);
  lim_free (0, package_path);

  return version_path;
}


t_uchar *
arch_fs_archive_revision_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * version = 0;
  t_uchar * version_path = 0;
  t_uchar * level = 0;
  t_uchar * revision_path = 0;

  invariant (arch_valid_package_name (revision, arch_no_archive, arch_req_patch_level, 0));

  version = arch_parse_package_name (arch_ret_package_version, 0, revision);
  version_path = arch_fs_archive_version_path (archive_path, version);
  level = arch_parse_package_name (arch_ret_patch_level, 0, revision);
  revision_path = file_name_in_vicinity (0, version_path, level);

  lim_free (0, version);
  lim_free (0, version_path);
  lim_free (0, level);

  return revision_path;
}

t_uchar *
arch_fs_archive_revision_log_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * revision_path = 0;
  t_uchar * log_path = 0;

  revision_path = arch_fs_archive_revision_path (archive_path, revision);
  log_path = file_name_in_vicinity (0, revision_path, "log");

  lim_free (0, revision_path);

  return log_path;
}

t_uchar *
arch_fs_archive_changeset_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * revision_path = 0;
  t_uchar * changeset_path;

  revision_path = arch_fs_archive_revision_path (archive_path, revision);
  changeset_path = file_name_in_vicinity (0, revision_path, revision);
  changeset_path = str_realloc_cat (0, changeset_path, ".patches.tar.gz");

  lim_free (0, revision_path);

  return changeset_path;
}

t_uchar *
arch_fs_archive_import_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * revision_path = 0;
  t_uchar * changeset_path;

  revision_path = arch_fs_archive_revision_path (archive_path, revision);
  changeset_path = file_name_in_vicinity (0, revision_path, revision);
  changeset_path = str_realloc_cat (0, changeset_path, ".src.tar.gz");

  lim_free (0, revision_path);

  return changeset_path;
}


t_uchar *
arch_fs_archive_cached_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * revision_path = 0;
  t_uchar * changeset_path;

  revision_path = arch_fs_archive_revision_path (archive_path, revision);
  changeset_path = file_name_in_vicinity (0, revision_path, revision);
  changeset_path = str_realloc_cat (0, changeset_path, ".tar.gz");

  lim_free (0, revision_path);

  return changeset_path;
}

t_uchar *
arch_fs_archive_cached_checksum_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * revision_path = 0;
  t_uchar * checksum_path = 0;

  revision_path = arch_fs_archive_revision_path (archive_path, revision);
  checksum_path = file_name_in_vicinity (0, revision_path, "checksum.cacherev");

  lim_free (0, revision_path);

  return checksum_path;
}


t_uchar *
arch_fs_archive_continuation_path (t_uchar * archive_path, t_uchar * revision)
{
  t_uchar * revision_path = 0;
  t_uchar * continuation_path;

  revision_path = arch_fs_archive_revision_path (archive_path, revision);
  continuation_path = file_name_in_vicinity (0, revision_path, "CONTINUATION");

  lim_free (0, revision_path);

  return continuation_path;
}



t_uchar *
arch_fs_archive_revision_lock_unlocked_path (t_uchar * archive_path,
                                             t_uchar * version,
                                             t_uchar * prev_level)
{
  t_uchar * answer = 0;

  invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0));

  if (!prev_level)
    {
      t_uchar * version_path = 0;

      version_path = arch_fs_archive_version_path (archive_path, version);
      answer = file_name_in_vicinity (0, version_path, "++revision-lock");

      lim_free (0, version_path);
    }
  else
    {
      t_uchar * revision = 0;
      t_uchar * revision_path = 0;

      revision = str_alloc_cat_many (0, version, "--", prev_level, str_end);
      revision_path = arch_fs_archive_revision_path (archive_path, revision);

      answer = file_name_in_vicinity (0, revision_path, "++revision-lock");

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

  return answer;
}


t_uchar *
arch_fs_archive_revision_lock_locked_path (t_uchar * archive_path,
                                           t_uchar * version,
                                           t_uchar * prev_level,
                                           t_uchar * arch_user_id,
                                           t_uchar * txn_id)
{
  t_uchar * version_path = 0;
  t_uchar * lock_basename = 0;
  t_uchar * answer = 0;

  invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0));

  version_path = arch_fs_archive_version_path (archive_path, version);

  lock_basename = str_alloc_cat_many (0,
                                      "++revision-lock-held--",
                                      (prev_level ? prev_level : (t_uchar *)"absolute-0"),
                                      "--",
                                      arch_user_id,
                                      (txn_id ? "--" : 0),
                                      txn_id,
                                      str_end);

  answer = file_name_in_vicinity (0, version_path, lock_basename);

  lim_free (0, version_path);
  lim_free (0, lock_basename);
  return answer;
}


t_uchar *
arch_fs_archive_revision_lock_locked_contents_path (t_uchar * archive_path,
                                                    t_uchar * version,
                                                    t_uchar * prev_level,
                                                    t_uchar * arch_user_id,
                                                    t_uchar * txn_id)
{
  t_uchar * locked_path = 0;
  t_uchar * answer = 0;

  locked_path = arch_fs_archive_revision_lock_locked_path (archive_path, version, prev_level, arch_user_id, txn_id);
  answer = file_name_in_vicinity (0, locked_path, "+contents");

  lim_free (0, locked_path);
  return answer;
}


t_uchar *
arch_fs_archive_revision_lock_broken_path (t_uchar * archive_path,
                                           t_uchar * version,
                                           t_uchar * prev_level)
{
  t_uchar * version_path = 0;
  t_uchar * lock_dir_basename = 0;
  t_uchar * lock_basename = 0;
  t_uchar * broken_dir = 0;
  t_uchar * answer = 0;

  version_path = arch_fs_archive_version_path (archive_path, version);

  lock_dir_basename = str_alloc_cat (0, "++revision-lock-broken--", (prev_level ? prev_level : (t_uchar *)"absolute-0"));
  lock_basename = str_alloc_cat (0, ",,remade-lock--", (prev_level ? prev_level : (t_uchar *)"absolute-0"));

  broken_dir = file_name_in_vicinity (0, version_path, lock_dir_basename);
  answer = file_name_in_vicinity (0, broken_dir, lock_basename);

  lim_free (0, version_path);
  lim_free (0, lock_dir_basename);
  lim_free (0, lock_basename);
  lim_free (0, broken_dir);
  return answer;
}






/* tag: Tom Lord Sun May 18 19:17:40 2003 (archives.c)
 */
