/* cacherev.c
*
****************************************************************
* Copyright (C) 2003 Tom Lord
* Copyright (C) 2004 Canonical, Ltd.
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "config-options.h"
#include "po/gettext.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/cmd/main.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/fs/cwd.h"
#include "libfsutils/tmp-files.h"
#include "libfsutils/rmrf.h"
#include "libarch/namespace.h"
#include "libarch/project-tree.h"
#include "libarch/my.h"
#include "libarch/archive.h"
#include "libarch/patch-logs.h"
#include "libarch/pristines.h"
#include "libarch/build-revision.h"
#include "commands/cmd.h"
#include "commands/cmdutils.h"
#include "commands/cacherev.h"
#include "commands/version.h"
static t_uchar * usage = N_("[options] [ARCHIVE/[PACKAGE[--VERSION[--PATCHLEVEL]]]] or [PATCHLEVEL]");
#define OPTS(OP) \
OP (opt_help_msg, "h", "help", 0, \
N_("Display a help message and exit.")) \
OP (opt_long_help, "H", 0, 0, \
N_("Display a verbose help message and exit.")) \
OP (opt_version, "V", "version", 0, \
N_("Display a release identifier string\n" \
"and exit."))
t_uchar arch_cmd_cacherev_help[] = N_("cache a full source tree in an archive\n"
"Cache a full-text copy of the indicated revision\n"
"in the archive. This can speed up subsequent calls\n"
"to \"baz get\" for that and subsequent revisions.\n\n"
"If no nothing is specified, but the command is run\n"
"from within a project tree, cache the latest revision\n"
"in the default version of that tree.\n");
enum options
{
OPTS (OPT_ENUM)
};
static struct opt_desc opts[] =
{
OPTS (OPT_DESC)
{-1, 0, 0, 0, 0}
};
int
arch_cmd_cacherev (t_uchar * program_name, int argc, char * argv[])
{
int o;
struct opt_parsed * option;
struct arch_archive * arch = 0;
t_uchar * default_archive = 0;
t_uchar * archive = 0;
t_uchar * revision = 0;
t_uchar * package = NULL;
safe_buffer_fd (1, 0, O_WRONLY, 0);
option = 0;
while (1)
{
o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, libarch_version_string, arch_cmd_cacherev_help, opt_help_msg, opt_long_help, opt_version);
if (o == opt_none)
break;
switch (o)
{
default:
safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
panic ("internal error parsing arguments");
usage_error:
opt_usage (2, argv[0], program_name, usage, 1);
exit (1);
/* bogus_arg: */
safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
goto usage_error;
}
}
if (argc > 2)
goto usage_error;
{
/* First, we need to know which archive we're going to be working
* against. Once we have that, then we can figure out what the
* latest revision is, according to what the user gave us */
t_uchar * target;
t_uchar * maybe_revision;
default_archive = arch_my_default_archive (default_archive);
if ( argc == 2)
{
/* At this point, we should have been handed either a patchlevel
* or a (un)?qualified (package|version|revision). So lets act
* accordingly
*/
if (!arch_valid_patch_level_name (argv[1]))
{
/* Not a patch, so lets treat it like a package/version etc. */
target = str_save(0, argv[1]);
}
else
{
/* WHoohoo! We have a patch. Grab the tree version and use it */
t_uchar * tree_version = 0;
tree_version = arch_tree_version (".");
safe_printfmt(2, "tree version is %s\n", tree_version);
target = str_alloc_cat_many (0,
tree_version,
"--",
argv[1],
str_end);
safe_printfmt(2, "Target is %s\n", target);
}
}
else
{
t_uchar * tree_root = 0;
target = arch_project_tree_revision (argv[0], tree_root);
}
arch = arch_archive_connect_writeable_branch (target, &package);
if(!arch)
{
safe_printfmt (2, "%s is not a valid archive name/version or url.\n", target);
exit (2);
}
archive = arch_parse_package_name (arch_ret_archive,
default_archive,
package);
/* Now we need to parse the unknown component. It could be anything
* from a package to a revision. We need to figure out which
*/
maybe_revision = arch_parse_package_name (arch_ret_non_archive,
default_archive,
package);
/* First, we need to know if its a full revision or not */
if ( arch_valid_package_name (maybe_revision, arch_no_archive, arch_req_patch_level, 0))
{
/* Yup. Given a full revision. Lets use that */
revision = str_save(0, maybe_revision);
}
else
{
/* Nope. Its either a package or a version. Hand that to latest_revision.
* It'll know what to do with it. The only catch is that we have to
* strip the archive name back off.
*/
t_uchar * fqrn = 0;
fqrn = arch_archive_latest_revision(arch, maybe_revision, 1);
revision = arch_parse_package_name (arch_ret_non_archive,
default_archive,
fqrn);
lim_free(0, fqrn);
}
lim_free (0, target);
lim_free (0, package);
lim_free (0, maybe_revision);
}
{
/* Here, we check to see if we've already cachereved. We the only
* variable we need is is_cached, but we get type for "free" */
enum arch_revision_type type;
int is_cached;
int has_ancestry;
arch_patch_id * revision_patch = arch_patch_id_new_archive (arch->official_name, revision);
arch_revision_type (&type, &is_cached, &has_ancestry, arch, revision_patch);
if (is_cached)
{
safe_printfmt (2, "%s: revision already has a cacherev\nrevision: %s\n",
argv[0], revision);
exit (1);
}
/* Finished checking for double cacherev */
talloc_free (revision_patch);
}
{
/* Now, we can finally build our cached revision. Lets give it
* a shot */
t_uchar * errstr;
t_uchar * pristine_dir;
t_uchar * tmp_dir;
tmp_dir = talloc_tmp_file_name (talloc_context, ".", ",,archive-cache-revision");
pristine_dir = file_name_in_vicinity (0, tmp_dir, revision);
safe_mkdir (tmp_dir, 0777);
safe_mkdir (pristine_dir, 0777);
/* FIXME: surely this should use arch_archive_cache ?? */
arch_build_revision (pristine_dir, arch, archive, revision, NULL);
if (arch_archive_put_cached (&errstr, arch, revision, pristine_dir))
{
safe_printfmt (2, "%s: unable to store cached revision of %s/%s (%s)\n",
argv[0], archive, revision, errstr);
exit (1);
}
rmrf_file (tmp_dir);
talloc_free (tmp_dir);
/* Done creating and moving up cached revision */
}
arch_archive_close (arch);
lim_free(0, revision);
lim_free(0, archive);
return 0;
}
/* tag: Tom Lord Thu May 29 22:26:18 2003 (cacherev.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1