/* tla-project-tree.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2003 Tom Lord * Copyright (C) 2005 Canonical Limited * Authors: Robert Collins * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/bugs/exception.h" #include "hackerlab/bugs/panic.h" #include "hackerlab/os/errno.h" #include "hackerlab/vu/safe.h" #include "hackerlab/fs/cwd.h" #include "hackerlab/fs/file-names.h" #include "hackerlab/char/str.h" #include "hackerlab/mem/mem.h" #include "libfsutils/file-contents.h" #include "libawk/trim.h" #include "libarch/ancestry.h" #include "libarch/namespace.h" #include "libarch/patch-id.h" #include "libarch/patch-logs.h" #include "libarch/changelogs.h" #include "libarch/inv-ids.h" #include "libarch/invent.h" #include "libarch/project-tree.h" #include "libarch/tla-project-tree.h" static const char arch_tree_format_str_hackerlab[] = "Hackerlab arch project directory, format version 1."; typedef struct tla_project_tree_ { arch_project_tree_t parent; cached_changeset_inventory_t * inventory_cache; } tla_project_tree_t; /* methods */ static void tla_init (arch_project_tree_t * tree); static enum arch_id_tagging_method tla_id_tagging_method (arch_project_tree_t * tree, enum arch_inventory_category * cat_var, int strict); static void tla_changeset_inventory_traveral (arch_project_tree_t * tree, struct arch_inventory_options * options, inv_callback callback, void * closure); static void tla_project_tree_mutated (arch_project_tree_t * tree); /* will become static eventually */ extern inventory_entry_t * tla_path_id (arch_project_tree_t * tree, int * errn, t_uchar const * const path, struct stat * known_lstat); static int tla_project_tree_destructor(void * data); arch_project_tree_vtable tla_project_tree_vtable = { tla_init, tla_id_tagging_method, tla_path_id, tla_changeset_inventory_traveral, tla_project_tree_mutated, arch_project_tree_vtable_end }; /** * \brief prepare a directory to be a tla tree */ void tla_project_tree_init_directory (t_uchar const * const tree_root) { t_uchar * arch_dir = 0; t_uchar * arch_vsn_file = 0; t_uchar * id_tagging_method_file = 0; t_uchar * id_tagging_method_defaults = 0; int out_fd; arch_dir = file_name_in_vicinity (0, tree_root, "{arch}"); arch_vsn_file = file_name_in_vicinity (0, arch_dir, ".arch-project-tree"); id_tagging_method_file = file_name_in_vicinity (0, arch_dir, "=tagging-method"); safe_mkdir (arch_dir, 0777); out_fd = safe_open (arch_vsn_file, O_WRONLY | O_CREAT | O_EXCL, 0666); safe_printfmt (out_fd, "%s\n", arch_tree_format_str_hackerlab); safe_close (out_fd); id_tagging_method_defaults = arch_default_id_tagging_method_contents (arch_unspecified_id_tagging); out_fd = safe_open (id_tagging_method_file, O_WRONLY | O_CREAT | O_EXCL, 0666); safe_printfmt (out_fd, "%s", id_tagging_method_defaults); safe_close (out_fd); lim_free (0, arch_dir); lim_free (0, arch_vsn_file); lim_free (0, id_tagging_method_defaults); lim_free (0, id_tagging_method_file); } /** * \brief is dir the root of a tla(hackerlab) project tree? * \return non zero on true. */ int tla_project_tree_dir_is_root (void * context, t_uchar const * dir, arch_project_tree_t **out) { int result = 0; t_uchar * arch_dir = file_name_in_vicinity (0, dir, "{arch}"); t_uchar * arch_version_file = file_name_in_vicinity (0, arch_dir, ".arch-project-tree"); if (!safe_access (arch_version_file, F_OK)) { t_uchar * content = trim_surrounding_ws(file_contents (arch_version_file)); if (!str_cmp (content, arch_tree_format_str_hackerlab)) { result = -1; if (out) { *out = (arch_project_tree_t *)talloc (context, tla_project_tree_t); talloc_set_destructor (*out, tla_project_tree_destructor); (*out)->vtable = &tla_project_tree_vtable; } } else /* incompatible tree */ { safe_printfmt (2, "tla_project_tree_dir_is_root: unrecognized project tree format: '%s'\n", content); exit (2); } lim_free (0, content); } lim_free (0, arch_dir); lim_free (0, arch_version_file); return result; } /** * \brief find the id tagging method for a tree */ enum arch_id_tagging_method tla_id_tagging_method (arch_project_tree_t * tree, enum arch_inventory_category * cat_var, int strict) { struct arch_inventory_options options; mem_set0 ((t_uchar *)&options, sizeof (options)); arch_get_inventory_naming_conventions (&options, tree); if (cat_var) { *cat_var = options.untagged_source_category; } tree->untagged_is_source = (options.untagged_source_category == arch_inventory_source); tree->tag_method = options.method; arch_free_inventory_naming_conventions (&options); return tree->tag_method; } /** * \brief see arch_project_tree_init */ void tla_init (arch_project_tree_t * tree) { /* perhaps this should call id_tagging_method ? */ tree->untagged_is_source = 0; tree->tag_method = arch_names_id_tagging; /* ancient default */ tree->id_tagging_shortcut = NULL; tree->explicit_skips = NULL; arch_tree_id_tagging_method (tree, NULL, 0); ((tla_project_tree_t *) tree)->inventory_cache = NULL; } /** * \brief destroy the resources of a tla tree */ int tla_project_tree_destructor (void * data) { tla_project_tree_t * tree = talloc_get_type (data, tla_project_tree_t); arch_project_tree_t * arch_tree = (arch_project_tree_t *) tree; if (!tree) Throw (exception (EINVAL, "invalid tree in tla_project_tree_destructor")); free_assoc_table (arch_tree->id_tagging_shortcut); arch_tree->id_tagging_shortcut = NULL; free_assoc_table (arch_tree->explicit_skips); arch_tree->explicit_skips = NULL; tree->inventory_cache = NULL; arch_project_tree_finalise (arch_tree); return 0; } /** * \brief see arch_project_tree_changeset_inventory_traversal */ void tla_changeset_inventory_traveral (arch_project_tree_t * tree, struct arch_inventory_options * options, inv_callback callback, void * closure) { cached_changeset_inventory_traveral (options, tree, callback, closure, &((tla_project_tree_t *)tree)->inventory_cache); talloc_steal (tree, ((tla_project_tree_t *)tree)->inventory_cache); } /** * \brief see arch_project_tree_mutated */ void tla_project_tree_mutated (arch_project_tree_t * tree) { talloc_free (((tla_project_tree_t *)tree)->inventory_cache); ((tla_project_tree_t *)tree)->inventory_cache = NULL; }