/* 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 "file-utils/libfsutils/tmp-files.h"
#include "file-utils/libfsutils/read-line.h"
#include "file-utils/libfsutils/dir-listing.h"
#include "file-utils/libawk/relational.h"
#include "file-utils/libarch/my.h"
#include "file-utils/libarch/namespace.h"
#include "file-utils/libarch/archive-version.h"
#include "file-utils/libarch/archives.h"



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

  invariant (arch_valid_archive_name (archive_name));

  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)
{
  t_uchar * file = 0;
  t_uchar * dir = 0;
  t_uchar * tmp_name = 0;

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


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

      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)
{
  t_uchar * file = 0;
  int errn;

  file = arch_archive_location_file (archive_name);

  if (vu_unlink (&errn, file) && (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 = 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;
}



void
arch_make_archive (t_uchar * name, t_uchar * target_path)
{
  t_uchar * current_loc = 0;
  int here_fd;
  t_uchar * full_path = 0;
  t_uchar * meta_info_path = 0;
  t_uchar * name_file_path = 0;
  t_uchar * archive_version_path = 0;
  int name_fd;
  int version_fd;

  invariant (arch_valid_archive_name (name));

  current_loc = arch_archive_location (name, 1);

  if (current_loc)
    {
      safe_printfmt (2, "arch_make_archive: archive already registered\n  name: %s\n", name);
      exit (2);
    }

  here_fd = safe_open (".", O_RDONLY, 0);
  safe_mkdir (target_path, 0777);
  safe_chdir (target_path);
  full_path = safe_current_working_directory ();
  safe_fchdir (here_fd);
  safe_close (here_fd);

  meta_info_path = file_name_in_vicinity (0, full_path, "=meta-info");
  archive_version_path = file_name_in_vicinity (0, full_path, ".archive-version");
  name_file_path = file_name_in_vicinity (0, meta_info_path, "name");

  safe_mkdir (meta_info_path, 0777);

  name_fd = safe_open (name_file_path, O_WRONLY | O_EXCL | O_CREAT, 0666);
  safe_printfmt (name_fd, "%s\n", name);
  safe_close (name_fd);

  version_fd = safe_open (archive_version_path, O_WRONLY | O_EXCL | O_CREAT, 0666);
  safe_printfmt (version_fd, "%s\n", arch_archive_version_for_new_archive ());
  safe_close (version_fd);
  
  arch_set_archive_location (name, full_path, 0);

  lim_free (0, full_path);
  lim_free (0, meta_info_path);
  lim_free (0, name_file_path);
  lim_free (0, archive_version_path);
}



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_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_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)
 */
