Logo Search packages:      
Sourcecode: bazaar version File versions

archive-mirror.c

/* archive-mirror.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 "libfsutils/ensure-dir.h"
#include "libfsutils/tmp-files.h"
#include "libawk/relational.h"
#include "libawk/associative.h"
#include "libarch/my.h"
#include "libarch/chatter.h"
#include "libarch/archive.h"
#include "libarch/namespace.h"
#include "libarch/archive-mirror.h"
#include "libarch/archive-setup.h"
#include "libarch/patch-logs.h"


/* __STDC__ prototypes for static functions */
static void mirror_revision (struct arch_archive * arch,
                             struct arch_archive * to_arch,
                             t_uchar * revision,
                             t_uchar * prev_level,
                       struct arch_archive_mirror_options * archive_mirror_opts);
static int list_contains (rel_table list, t_uchar * elt);
static void mirror_cached_revision(int is_cached,
                           struct arch_archive_mirror_options * archive_mirror_opts,
                           enum arch_revision_type type,
                           struct arch_archive * arch,
                           struct arch_archive * to_arch, 
                           t_uchar * revision, 
                           t_uchar * continuation_archive);
static void mirror_revision_ancestry (int has_ancestry, struct arch_archive_mirror_options * archive_mirror_opts,
                           enum arch_revision_type type,
                           struct arch_archive * arch,
                           struct arch_archive * to_arch, 
                           t_uchar * revision, 
                           t_uchar * continuation_archive);



void
arch_archive_mirror (int chatter_fd,
                     struct arch_archive * arch,
                     struct arch_archive * to_arch,
                     t_uchar * limit,
                 struct arch_archive_mirror_options * archive_mirror_opts)
{
  t_uchar * only_category = 0;
  t_uchar * only_branch = 0;
  t_uchar * only_version = 0;
  t_uchar * only_revision = 0;
  rel_table categories = 0;
  rel_table to_categories = 0;
  rel_table missing_categories = 0;
  int branchless_version = 0;
  int c;

  if (!limit)
    arch_chatter (chatter_fd, "* mirroring %s to %s\n", arch->name, to_arch->name);
  else
    arch_chatter (chatter_fd, "* mirroring %s to %s with limit %s\n", arch->name, to_arch->name, limit);

  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);
                }
            }
        }
    }


  if (only_version && ! only_branch)
    branchless_version = 1;

  categories = arch_archive_categories (arch);
  to_categories = arch_archive_categories (to_arch);
  missing_categories = rel_join (1, rel_join_output (1,0, -1), 0, 0, categories, to_categories);

  for (c = 0; c < rel_n_records (categories); ++c)
    {
      rel_table branches = 0;
      rel_table to_branches = 0;
      rel_table missing_branches = 0;
      int b;

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

      branches = arch_archive_branches (arch, categories[c][0]);
      to_branches = arch_archive_branches (to_arch, categories[c][0]);
      missing_branches = rel_join (1, rel_join_output (1,0, -1), 0, 0, branches, to_branches);

      for (b = 0; b < rel_n_records (branches); ++b)
        {
          rel_table versions = 0;
          rel_table to_versions = 0;
          rel_table missing_versions = 0;
          int v;
          
          if (only_branch && str_cmp (only_branch, branches[b][0]))
            continue;

          if ( branchless_version && str_length(branches[b][0]) > 0)
            continue;


          versions = arch_archive_versions (arch, branches[b][0]);
          to_versions = arch_archive_versions (to_arch, branches[b][0]);
          missing_versions = rel_join (1, rel_join_output (1,0, -1), 0, 0, versions, to_versions);

          for (v = 0; v < rel_n_records (versions); ++v)
            {
              rel_table revisions = 0;
              rel_table to_revisions = 0;
              rel_table missing_revisions = 0;
              int r;

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

              if (list_contains (missing_versions, versions[v][0]))
                {
                    arch_setup_archive_simple_ext (chatter_fd, to_arch, versions[v][0]);
                }

              revisions = arch_archive_revisions (arch, versions[v][0], 2);
              to_revisions = arch_archive_revisions (to_arch, versions[v][0], 2);
              missing_revisions = rel_join (1, rel_join_output (1,0, -1), 0, 0, revisions, to_revisions);

              for (r = 0; r < rel_n_records (revisions); ++r)
                {
                  if (only_revision && str_cmp (only_revision, revisions[r][0]))
                    continue;

                  if (list_contains (missing_revisions, revisions[r][0]))
                    {
                      t_uchar * prev_level = 0;

                      if (r)
                        {
                          prev_level = arch_parse_package_name (arch_ret_patch_level, 0, revisions[r - 1][0]);
                        }

                      arch_chatter (chatter_fd, "** adding revision %s\n", revisions[r][0]);
                      mirror_revision (arch, to_arch, revisions[r][0], prev_level, archive_mirror_opts);

                      lim_free (0, prev_level);
                    }
              else if (only_revision && 0 == str_cmp (only_revision, revisions[r][0]))
                {
                      t_uchar * prev_level = 0;
                  enum arch_revision_type type; 
                  int is_cached;
                      int has_ancestry;
                        t_uchar * continuation = 0;
                  t_uchar * continuation_archive = 0;

                      if (r)
                        {
                          prev_level = arch_parse_package_name (arch_ret_patch_level, 0, revisions[r - 1][0]);
                        }

                      arch_chatter (chatter_fd, "** adding revision %s\n", revisions[r][0]); 
                  arch_revision_type (&type, &is_cached, &has_ancestry, arch, revisions[r][0]); 
                  if (type == arch_continuation_revision)
                  {
                    continuation = arch_get_continuation (arch, revisions[r][0]);
                    continuation_archive = arch_parse_package_name (arch_ret_archive, 0, continuation);
                  }
                  mirror_cached_revision (is_cached, archive_mirror_opts, type, arch, to_arch, revisions[r][0], continuation_archive);
                  mirror_revision_ancestry (has_ancestry, archive_mirror_opts, type, arch, to_arch, revisions[r][0], continuation_archive);
                        lim_free (0, continuation);
                  lim_free (0, continuation_archive);
                      lim_free (0, prev_level);
                }
                }


              rel_free_table (revisions);
              rel_free_table (to_revisions);
              rel_free_table (missing_revisions);
            }

          rel_free_table (versions);
          rel_free_table (to_versions);
          rel_free_table (missing_versions);
        }

      rel_free_table (branches);
      rel_free_table (to_branches);
      rel_free_table (missing_branches);
    }



  lim_free (0, only_category);
  lim_free (0, only_branch);
  lim_free (0, only_version);
  lim_free (0, only_revision);
  rel_free_table (categories);
  rel_free_table (to_categories);
  rel_free_table (missing_categories);
}


static void
mirror_revision (struct arch_archive * arch,
                 struct arch_archive * to_arch,
                 t_uchar * revision,
                 t_uchar * prev_level,
                 struct arch_archive_mirror_options * archive_mirror_opts)
{
  t_uchar * version = 0;
  t_uchar * this_level = 0;
  t_uchar * errstr = 0;
  enum arch_revision_type type;
  int is_cached;
  int has_ancestry;
  t_uchar * my_uid = 0;
  t_uchar * txn_id = 0;
  t_uchar * log = 0;
  t_uchar * continuation_archive = 0;

  version = arch_parse_package_name (arch_ret_package_version, 0, revision);
  this_level = arch_parse_package_name (arch_ret_patch_level, 0, revision);

  arch_revision_type (&type, &is_cached, &has_ancestry, arch, revision);

  my_uid = arch_my_id_uid_default ("Unknown User <example@example.com>");
  txn_id = arch_generate_txn_id ();

  if (arch_archive_lock_revision (&errstr, to_arch, version, prev_level, my_uid, txn_id, this_level))
    {
      safe_printfmt (2, "arch-mirror: unable to acquire revision lock (%s)\n    revision: %s/%s\n",
                     errstr, to_arch->name, revision);
      exit (2);
    }

  log = arch_archive_log (arch, revision);
  if (arch_archive_put_log (&errstr, to_arch, version, prev_level, my_uid, txn_id, log))
    {
      safe_printfmt (2, "arch-mirror: unable to send log message to archive (%s)\n    revision: %s/%s\n",
                     errstr, to_arch->name, version);
      exit (2);
    }

  if (type == arch_import_revision)
    {
      t_uchar * tmp_path = 0;
      int fd;

      tmp_path = tmp_file_name ("/tmp", ",,arch-mirror-changeset");
      fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
      safe_unlink (tmp_path);

      arch_get_import_targz (fd, arch, revision);

      safe_lseek (fd, (off_t)0, SEEK_SET);

      if (arch_archive_put_import_targz (&errstr, to_arch, version, prev_level, my_uid, txn_id, this_level, fd))
        {
          safe_printfmt (2, "arch-mirror: unable to send import tree to archive (%s)\n    revision: %s/%s\n",
                         errstr, arch->name, version);
          exit (2);
        }

      safe_close (fd);

      lim_free (0, tmp_path);
    }
  else
    {
      t_uchar * tmp_path = 0;
      int fd;

      tmp_path = tmp_file_name ("/tmp", ",,arch-mirror-full-text");
      fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
      safe_unlink (tmp_path);

      arch_get_patch_targz (fd, arch, revision);

      safe_lseek (fd, (off_t)0, SEEK_SET);

      if (arch_archive_put_changeset_targz (&errstr, to_arch, version, prev_level, my_uid, txn_id, this_level, fd))
        {
          safe_printfmt (2, "arch-mirror: unable to send changeset to archive (%s)\n    revision: %s/%s\n",
                         errstr, arch->name, version);
          exit (2);
        }

      safe_close (fd);

      lim_free (0, tmp_path);
    }

  if (type == arch_continuation_revision)
    {
      t_uchar * continuation = 0;

      continuation = arch_get_continuation (arch, revision);

      continuation_archive = arch_parse_package_name (arch_ret_archive, 0, continuation);

      if (arch_archive_put_continuation (&errstr, to_arch, version, prev_level, my_uid, txn_id, continuation))
        {
          safe_printfmt (2, "arch-mirror: unable to send tagged revision id to archive (%s)\n    revision: %s/%s\n",
                         errstr, to_arch->name, revision);
          exit (2);
        }

      lim_free (0, continuation);
    }

  if (arch_revision_ready (&errstr, to_arch, version, prev_level, my_uid, txn_id, this_level))
    {
      safe_printfmt (2, "arch-mirror: unable to complete phase-1 commit transaction (%s)\n    revision: %s/%s\n",
                     errstr, to_arch->name, version);
      exit (2);
    }

  if (arch_archive_finish_revision (&errstr, to_arch, version, prev_level, my_uid, txn_id, this_level))
    {
      safe_printfmt (2, "arch-mirror: unable to complete commit transaction (%s)\n    revision: %s/%s\n",
                     errstr, to_arch->name, version);
      exit (2);
    }

  if (archive_mirror_opts->print_summary)
    {
      t_uchar * log = arch_archive_log (to_arch, revision);
      assoc_table headers = 0;
      t_uchar * body = 0;
      
      arch_parse_log (0, &headers, &body, log);
      arch_print_headers_summary (1, 4, headers, arch_include_summary);
      lim_free (0, log);
      free_assoc_table (headers);
      lim_free (0, body);
    }
  
  mirror_cached_revision(is_cached, archive_mirror_opts, type, arch, to_arch, revision, continuation_archive);
  mirror_revision_ancestry(has_ancestry, archive_mirror_opts, type, arch, to_arch, revision, continuation_archive);

  lim_free (0, version);
  lim_free (0, my_uid);
  lim_free (0, txn_id);
  lim_free (0, log);
  lim_free (0, continuation_archive);
}

void
mirror_cached_revision(int is_cached,
                   struct arch_archive_mirror_options * archive_mirror_opts,
                   enum arch_revision_type type,
                   struct arch_archive * arch,
                   struct arch_archive * to_arch, 
                   t_uchar * revision, 
                   t_uchar * continuation_archive)
{
  t_uchar * version = 0;
  version = arch_parse_package_name (arch_ret_package_version, 0, revision);
  if (is_cached
      && ((archive_mirror_opts->cachedrevs == arch_mirror_all_cachedrevs)
          || ((archive_mirror_opts->cachedrevs == arch_mirror_foreign_continuation_cachedrevs)
              && (type == arch_continuation_revision)
              && (str_cmp (arch->official_name, continuation_archive)))))
    {
      t_uchar * errstr = 0;
      t_uchar * tmp_path = 0;
      int fd;

      tmp_path = tmp_file_name ("/tmp", ",,arch-mirror-archive-cached");
      fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
      safe_unlink (tmp_path);

      arch_get_cached_revision_targz (fd, arch, revision);

      safe_lseek (fd, (off_t)0, SEEK_SET);

      if (arch_archive_put_cached_targz (&errstr, to_arch, revision, fd))
        {
          safe_printfmt (2, "arch-mirror: unable to send cached revision to archive (%s)\n    revision: %s/%s\n",
                         errstr, arch->name, version);
          exit (2);
        }

      safe_close (fd);

      lim_free (0, tmp_path);
    }
  else 
    {
      t_uchar * errstr = 0;

      if (arch_archive_delete_cached (&errstr, to_arch, revision))
        {
          safe_printfmt (2, "%s: unable to delete cached revision of %s (%s)\n",
                         to_arch->name, revision, errstr);
          exit (1);
        }
    }
  lim_free (0, version);
}

void
mirror_revision_ancestry(int has_ancestry,
                         struct arch_archive_mirror_options * archive_mirror_opts,
                   enum arch_revision_type type,
                   struct arch_archive * arch,
                   struct arch_archive * to_arch, 
                   t_uchar * revision, 
                   t_uchar * continuation_archive)
{
    t_uchar * errstr = 0;
    t_uchar * tmp_path = 0;
    int fd;

    /* remove the target ancestry if present */
    arch_archive_delete_ancestry (NULL, to_arch, revision);

    /* if there is no ancestry, do nothing */
    if (!has_ancestry)
        return;
    
    tmp_path = tmp_file_name ("/tmp", ",,arch-mirror-archive-ancestry");
    fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
    /* FIXME: this isn't portable - windows cannot unlink in use files */
    safe_unlink (tmp_path);
    
    arch_archive_get_ancestry (fd, arch, revision);
    
    safe_lseek (fd, (off_t)0, SEEK_SET);
    
    if (arch_archive_put_ancestry (&errstr, to_arch, revision, fd))
      {
        safe_printfmt (2, "arch-mirror: unable to send cached revision to archive (%s)\n    revision: %s/%s\n",
                       errstr, arch->name, revision);
        exit (2);
      }
    
    safe_close (fd);
    
    lim_free (0, tmp_path);
}




static int
list_contains (rel_table list, t_uchar * elt)
{
  int x;

  for (x = 0; x < rel_n_records (list); ++x)
    {
      if (!str_cmp (elt, list[x][0]))
        return 1;
    }
  return 0;
}





/* tag: Tom Lord Mon Jun  9 23:29:24 2003 (archive-mirror.c)
 */

Generated by  Doxygen 1.6.0   Back to index