/* local-cache.c:
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/bugs/panic.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/mem/alloc-limits.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "libfsutils/tmp-files.h"
#include "libfsutils/rmrf.h"
#include "libfsutils/ensure-dir.h"
#include "libarch/ancestry.h"
#include "libarch/build-revision.h"
#include "libarch/pristines.h"
#include "libarch/libraries.h"
#include "libarch/chatter.h"
#include "libarch/my.h"
#include "libarch/namespace.h"
#include "libarch/library-txn.h"
#include "libarch/local-cache.h"




int
arch_greedy_library_wants_revision (arch_patch_id * revision)
{
  int answer = 0;
  rel_table lib_path = 0;

  lib_path = arch_my_library_path (arch_library_path_add_order);

  if (lib_path)
    {
      t_uchar * default_add_lib = 0;
      
      default_add_lib = arch_library_add_choice (revision, 0, 0);
      if (arch_library_is_greedy (default_add_lib))
        {
          answer = 1;
        }

      lim_free (0, default_add_lib);
    }

  rel_free_table (lib_path);

  return answer;
}


t_uchar *
arch_find_local_copy (int chatter_fd,
		      arch_project_tree_t * tree,
		      arch_project_tree_t * cache,
                      t_uchar const * const archive,
                      t_uchar const * const revision,
                      t_uchar const * const hook)
{
   arch_project_tree_t * result_tree = arch_find_local_tree_copy (chatter_fd, tree, cache, archive, revision, hook);
   t_uchar * result = result_tree ? str_save (0, result_tree->root) : NULL;
   arch_project_tree_delete (result_tree);
   return result;
}

arch_project_tree_t *
arch_find_local_tree_copy (int chatter_fd,
			   arch_project_tree_t * tree,
			   arch_project_tree_t * cache,
                      t_uchar const * const archive,
                      t_uchar const * const revision,
                      t_uchar const * const hook)
{
  arch_project_tree_t * result;
  arch_patch_id patch_id;
  arch_patch_id_init_archive (&patch_id, archive, revision);

  if (hook)
    {
      int error;
      
      error = arch_run_hook (hook,
                             "ARCH_ARCHIVE", archive,
                             "ARCH_REVISION", revision,
                             0);
      
      if (error)
        {
          safe_printfmt (2, "baz: error running hook `%s' (%d)\n", hook, error);
          exit (2);
        }
    }

  result = arch_library_find (0, &patch_id, 1);

  if (!result && tree)
    result = arch_find_pristine (tree, &patch_id, arch_tree_pristine_search);

  if (!result && cache)
    result = arch_find_pristine (cache, &patch_id, arch_cache_dir_pristine_search);

  if (!result)
    {
      t_uchar *greedy_choice = 0;
      greedy_choice = arch_library_greedy_add_choice(&patch_id, 0, 1);
      if (greedy_choice)
	{
	  /* something wants a pristine copy that isn't around.
	   *
	   * There is a greedy library in the path, so add the revision to it.
	   */

	  struct arch_archive * arch = 0;

	  arch_chatter (chatter_fd, "* auto-adding %s/%s to greedy revision library %s\n", archive, revision, greedy_choice);
	  arch = arch_archive_connect_readonly (archive);
	  if (!arch)
	    {
	      safe_printfmt (2, "could not connect to %s to add %s/%s\n", archive, archive, revision);
	      exit (2);
	    }
	  arch_library_add (chatter_fd, 1, arch, revision, greedy_choice, 0, -1, 0);
	  result = arch_library_find (0, &patch_id, 1);

	  arch_archive_close (arch);
	}
    }

  if (result)
    {
      if (!arch_project_tree_file_exists(result, ARCH_PROJECT_TREE_ANCESTRY_FILE))
	{
	  struct exception * e;
	  /* FIXME: rather than asking for all we should be more conservative
	   * or allow a user policy
	   */
	  Try
	      patch_ancestry (talloc_context, result, &patch_id, 2);
	  Catch (e)
	    {
	      /* system errors */
	      if (e->code < 0)
		  Throw (e);
	      talloc_free (e);
	    }
	}
      if (!result->fqrevision || str_cmp (archive, result->archive) || str_cmp (revision, result->revision))
        {
          rmrf_file (result->root);
          talloc_free (result);
          return arch_find_local_tree_copy(chatter_fd,
                                           tree,
                                           cache,
                                           archive,
                                           revision,
                                           hook);
        }
    }

  arch_patch_id_finalise (&patch_id);
  return result;
}


/**
  * \brief create a reference tree we can use to get diffs on, reference inventory etc.
  * \param chatter_fd optional output fd (-1 disables)
  * \param tree_root required current tree root
  * \param cache_dir optional directory to build the cache in
  * \param arch optional already connected archive handle
  * \param the name of the archive
  * \param the name of the revision
  * \return the path of the resulting trees root
  */
t_uchar *
arch_find_or_make_local_copy (int chatter_fd,
			      arch_project_tree_t * tree,
			      arch_project_tree_t * cache,
                              struct arch_archive * arch,
                              t_uchar * archive,
                              t_uchar * revision)
{
   arch_project_tree_t * result_tree = arch_find_or_make_local_tree_copy (chatter_fd, tree, cache, arch, archive, revision);
   t_uchar * result = result_tree ? str_save (0, result_tree->root) : NULL;
   arch_project_tree_delete (result_tree);
   return result;
}

/**
  * \brief create a reference tree we can use to get diffs on, reference inventory etc.
  * \param chatter_fd optional output fd (-1 disables)
  * \param tree_root required current tree root
  * \param cache_dir optional directory to build the cache in
  * \param arch optional already connected archive handle
  * \param the name of the archive
  * \param the name of the revision
  * \return the arch project tree
  */
arch_project_tree_t *
arch_find_or_make_local_tree_copy (int chatter_fd,
			      arch_project_tree_t * tree,
			      arch_project_tree_t * cache,
                              struct arch_archive * arch,
                              t_uchar * archive,
                              t_uchar * revision)
{
  arch_project_tree_t * answer = NULL;

  invariant (!!tree);
  invariant (!arch || !str_cmp (archive, arch->official_name));

  answer = arch_find_local_tree_copy (chatter_fd, tree, cache, archive, revision, "make-pristine");

  if (!answer)
    {
      t_uchar * tree_dir = 0;
      t_uchar * tmp_path = 0;

      tree_dir = file_name_directory_file (0, tree->root);
      if (!tree_dir)
        tree_dir = str_save (0, ".");

      tmp_path = talloc_tmp_file_name (talloc_context, tree_dir, ",,new-pristine");

      rmrf_file (tmp_path);
      safe_mkdir (tmp_path, 0777);

      arch_chatter (chatter_fd, "* build pristine tree for %s/%s\n", archive, revision);

      arch_build_revision (tmp_path, arch, archive, revision, cache);

      arch_install_pristine (tree, archive, revision, tmp_path);

      answer = arch_find_local_tree_copy (chatter_fd, tree, cache, archive, revision, 0);

      lim_free (0, tree_dir);
      talloc_free (tmp_path);
    }

  return answer;
}


/**
  * \brief create a temporary reference tree we can use to get diffs on, reference inventory etc.
  * \param chatter_fd optional output fd (-1 disables)
  * \param tmp_dir required dir to place the temp tree in
  * \param tree_root required current tree root
  * \param cache_dir optional directory to build the cache in
  * \param arch optional already connected archive handle
  * \param the name of the archive
  * \param the name of the revision
  * \return the path of the resulting trees root
  */
t_uchar *
arch_find_or_make_tmp_local_copy  (int chatter_fd,
                                   t_uchar const * const tmp_dir,
				   arch_project_tree_t * tree,
				   arch_project_tree_t * cache,
                                   struct arch_archive * arch,
                                   t_uchar const * const archive,
                                   t_uchar const * const revision)
{
  t_uchar * answer = 0;
  invariant (!!tmp_dir);

  answer = arch_find_local_copy (chatter_fd, tree, cache, archive, revision, "make-tmp-pristine");

  if (!answer)
    {
      t_uchar * tmp_stem = 0;
      t_uchar * tmp_path = 0;

      tmp_stem = str_alloc_cat_many (0, ",,", revision, "--", archive, str_end);
      tmp_path = talloc_tmp_file_name (talloc_context, tmp_dir, tmp_stem);

      rmrf_file (tmp_path);
      ensure_directory_exists (tmp_dir);
      safe_mkdir (tmp_path, 0777);

      arch_chatter (chatter_fd, "* build reference tree for %s/%s\n", archive, revision);

      arch_build_revision (tmp_path, arch, archive, revision, cache);

      lim_free (0, tmp_stem);
      answer = str_save (0, tmp_path);
      talloc_free (tmp_path);
    }

  return answer;
}




/* tag: Tom Lord Fri May 23 14:42:03 2003 (local-cache.c)
 */


syntax highlighted by Code2HTML, v. 0.9.1