/* cmdutils.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2004 Tom Lord, Canonical Ltd. * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ /** * @file cmdutils.c * @brief Utility functions for sub-commands */ /** * \defgroup cmdutils Utility functions for sub-commands * @{ */ #include "hackerlab/bugs/panic.h" #include "hackerlab/bugs/exception.h" #include "hackerlab/vu/safe.h" #include "hackerlab/vu/vu.h" #include "hackerlab/os/errno.h" #include "hackerlab/os/errno-to-string.h" #include "hackerlab/char/str.h" #include "po/gettext.h" #include "commands/cmdutils.h" #include "commands/diff.h" #include "libarch/libraries.h" #include "libarch/project-tree.h" #include "libarch/patch-logs.h" #include "libarch/pfs.h" #include "libarch/local-cache.h" #include "libfsutils/dir-as-cwd.h" #include "libfsutils/rmrf.h" #include "libarch/local-cache.h" #include "libarch/changeset-report.h" #include "libarch/make-changeset.h" #include "libarch/inode-sig.h" #include "libarch/arch.h" /* __STDC__ prototypes for static functions */ static t_uchar * missing_string (enum arch_valid_package_name_types type); static t_uchar * name_string (enum arch_valid_package_name_types type); static enum arch_parse_package_name_type valid_to_parse (enum arch_valid_package_name_types type); /* Gather a fully-qualified revision name from the current tree * and input (e.g. patch-10) */ t_uchar * arch_fqrvsn_from_tree_and_input (void * context, t_uchar *cmd, t_uchar * string, t_uchar * dir) { t_uchar * ret = 0; arch_project_tree_t * tree; if (arch_valid_package_name (string, arch_req_archive, arch_req_patch_level, 0)) return talloc_strdup (context, string); tree = arch_project_tree_new (talloc_context, dir); if (!tree->root) { safe_printfmt (2, "%s: not in a project tree\n dir: %s\n", cmd, directory_as_cwd (dir)); exit (2); } if (!tree->fqversion) { safe_printfmt (2, "%s: no tree-version set\n tree: %s\n", cmd, tree->root); exit (2); } if (arch_valid_package_name (string, arch_maybe_archive, arch_req_patch_level, 0)) { ret = arch_fully_qualify (tree->archive, string); ret = str_replace (ret, talloc_strdup (context, ret)); } else if (arch_valid_package_name (string, arch_maybe_archive, arch_req_version, 0)) { t_uchar * archive = arch_parse_package_name (arch_ret_archive, tree->archive, string); t_uchar * version = arch_parse_package_name (arch_ret_package_version, 0, string); t_uchar * patch_level = arch_highest_patch_level (tree->root, archive, version); t_uchar * revision = str_alloc_cat_many (0, version, "--", patch_level, str_end); ret = arch_fully_qualify (archive, revision); ret = str_replace (ret, talloc_strdup (talloc_context, ret)); lim_free (0, archive); lim_free (0, version); lim_free (0, patch_level); lim_free (0, revision); } else { ret = str_alloc_cat_many (0, tree->fqversion, "--", string, str_end); if (!arch_valid_package_name (ret, arch_req_archive, arch_req_patch_level, 0)) { /* TODO let this archive connection be cached open - propogate it back up */ struct arch_archive *temp_arch = NULL; lim_free (0, ret); ret = NULL; arch_project_tree_check_name (tree, &temp_arch, &ret, string); if (!temp_arch) { safe_printfmt (2, "%s: invalid revision or patch name (%s)\n", cmd, string); exit (2); } arch_archive_close (temp_arch); /* FUGLY. FIXME - overhaul the entire api in the style of arch_project_tree_check_name .. * perhaps arch_project_tree_validate_input which /may/ connect if needed */ ret = str_replace (ret, arch_fqrvsn_from_tree_and_input (talloc_context, cmd, ret, dir)); } else ret = str_replace (ret, talloc_strdup (talloc_context, ret)); } talloc_free (tree); return talloc_steal (context, ret); } int arch_category_exists (struct arch_archive *arch, t_uchar * package) { t_uchar * category = 0; rel_table categories = 0; int x; category = arch_parse_package_name (arch_ret_category, 0, package); categories = arch_archive_categories (arch); for (x = 0; x < rel_n_records (categories); ++x) { if (!str_cmp (category, categories[x][0])) { lim_free (0, category); rel_free_table (categories); return 1; } } return 0; } int arch_package_exists (struct arch_archive * arch, t_uchar * package) { t_uchar * category = 0; t_uchar * branch = 0; rel_table categories = 0; rel_table branches = 0; int x; int found_it = 0; category = arch_parse_package_name (arch_ret_category, 0, package); branch = arch_parse_package_name (arch_ret_package, 0, package); categories = arch_archive_categories (arch); for (x = 0; x < rel_n_records (categories); ++x) { if (!str_cmp (category, categories[x][0])) break; } if (x < rel_n_records (categories)) { branches = arch_archive_branches (arch, category); for (x = 0; x < rel_n_records (branches); ++x) { if (!str_cmp (branch, branches[x][0])) { found_it = 1; break; } } } lim_free (0, category); lim_free (0, branch); rel_free_table (categories); rel_free_table (branches); return found_it; } int arch_version_exists (struct arch_archive * arch, t_uchar * version_spec) { t_uchar * branch = 0; t_uchar * version = 0; rel_table versions = 0; int x; int found_it = 0; branch = arch_parse_package_name (arch_ret_package, 0, version_spec); version = arch_parse_package_name (arch_ret_package_version, 0, version_spec); versions = arch_archive_versions (arch, branch); for (x = 0; x < rel_n_records (versions); ++x) { if (!str_cmp (version, versions[x][0])) { found_it = 1; break; } } lim_free (0, branch); lim_free (0, version); rel_free_table (versions); return found_it; } /** * @brief Checks whether the specified item (and all its components) exist * @param arch The archive to look in * @param type The type of name being queried * @param package The name being queried */ void arch_check_for (struct arch_archive * arch, enum arch_valid_package_name_types type, t_uchar const * const package) { t_uchar * spec = arch_parse_package_name (arch_ret_non_archive, "", package); int missing = -1; /* note fall-through behavior */ switch (type) { case arch_req_patch_level: if (arch_revision_exists (arch, spec)) break; else missing = arch_req_patch_level; default: if (!arch_category_exists (arch, spec)) { missing=arch_req_category; break; } if (type == arch_req_category) break; if (!arch_package_exists (arch, spec)) { missing = arch_req_package; break; } if (type == arch_req_package) break; if (!arch_version_exists (arch, spec)) missing = arch_req_version; }; if (missing != -1) { arch_print_missing (arch, missing, type, spec); exit (2); } lim_free (0, spec); } void arch_print_missing (struct arch_archive * arch, enum arch_valid_package_name_types type, enum arch_valid_package_name_types supplied_type, t_uchar * spec) { t_uchar * name = missing_string (type); t_uchar * supplied_name = name_string (supplied_type); t_uchar * portion = arch_parse_package_name (valid_to_parse(type), arch->official_name, spec); t_uchar * nonarch = arch_parse_package_name (arch_ret_non_archive, "", spec); safe_printfmt (2, "No such %s (%s)\n", name, portion); safe_printfmt (2, " name: %s\n location: %s\n %s: %s\n", arch->official_name, arch->location, supplied_name, nonarch); lim_free (0, portion); lim_free (0, nonarch); } static t_uchar * missing_string (enum arch_valid_package_name_types type) { switch (type) { case arch_req_category: return "category"; break; case arch_req_package: return "package"; break; case arch_req_version: return "version"; break; case arch_req_patch_level: return "patchlevel"; break; default: panic ("missing_string: bad argument."); return 0; }; } static t_uchar * name_string (enum arch_valid_package_name_types type) { switch (type) { case arch_req_category: return "category"; break; case arch_req_package: return "package"; break; case arch_req_version: return "package-version"; break; case arch_req_patch_level: return "revision"; break; default: panic ("name_string: bad argument."); return 0; }; } static enum arch_parse_package_name_type valid_to_parse (enum arch_valid_package_name_types type) { switch (type) { case arch_req_category: return arch_ret_category; break; case arch_req_package: return arch_ret_package; break; case arch_req_version: return arch_ret_version; break; case arch_req_patch_level: return arch_ret_patch_level; break; default: panic ("valid_to_parse: bad argument."); return 0; }; } void arch_check_library_for_revision (t_uchar * archive, t_uchar * revision) { arch_patch_id patch_id; arch_project_tree_t * loc; arch_patch_id_init_archive (&patch_id, archive,revision); loc = arch_library_find (0, &patch_id, 0); if (loc) { arch_project_tree_delete (loc); } else { safe_printfmt (2, "Could not find revision in any library:\n%s/%s\n", archive, revision); exit (2); } arch_patch_id_finalise (&patch_id); } t_uchar * safe_tree_version (t_uchar const * const cmd_name) { arch_project_tree_t * tree = arch_project_tree_new (talloc_context, "."); t_uchar * tree_version = 0; if (!tree->root) { safe_printfmt (2, "%s: not in a project tree\n dir: %s\n", cmd_name, directory_as_cwd (".")); exit (2); } if (!tree->fqversion) { safe_printfmt (2, "%s: no tree-version set\n tree: %s\n", cmd_name, tree->root); exit (2); } tree_version = tree->fqversion; tree->fqversion = NULL; arch_project_tree_delete (tree); return tree_version; } static t_uchar * arch_determine_fqrevision_safe_latest_revision (struct arch_archive *arch, t_uchar *version_spec, t_uchar const *cmd_name) { t_uchar * version; t_uchar * revision; arch_check_for (arch, arch_req_version, version_spec); version = arch_parse_package_name (arch_ret_package_version, 0, version_spec); version_spec = arch_archive_latest_revision (arch, version, 2); if (!version_spec) { safe_printfmt (1, "%s: version has no revisions (%s/%s)\n", cmd_name, arch->official_name, version); exit (1); } /* FIXME: why deliberately not? * RBC 20050312 - becayse lock-revision connects by name so you can unlock revisions in -MIRROR etc * thus lock-revision needs to accept URL based input as an option, when then will * propogate down to here. */ revision = arch_fully_qualify ((t_uchar *)arch->official_name /*deliberately not official_name */, version_spec); lim_free (0, version); lim_free (0, version_spec); return revision; } static t_uchar * arch_determine_fqrevision_common (struct arch_archive ** arch, t_uchar * default_archive, t_uchar * revision_spec, t_uchar const * const cmd_name) { t_uchar * new_revision_spec = 0; if (!arch_valid_package_name (revision_spec, arch_maybe_archive, arch_req_version, 1)) { /* url or patch-level */ if (!arch_valid_patch_level_name (revision_spec)) { /* url ? */ if (!*arch) *arch = arch_archive_connect_branch (revision_spec, &new_revision_spec); if (!*arch || !arch_valid_package_name (new_revision_spec, arch_maybe_archive, arch_req_version, 1)) { safe_printfmt (2, "%s: illegal revision spec (%s)\n", cmd_name, revision_spec); exit (1); } } else { /* given a patch-level */ t_uchar * tree_version = safe_tree_version (cmd_name); new_revision_spec = str_alloc_cat_many (0, tree_version, "--", revision_spec, str_end); } } else if (!arch_valid_package_name (revision_spec, arch_req_archive, arch_req_version, 1)) { new_revision_spec = arch_fully_qualify (default_archive, revision_spec); } else { new_revision_spec = str_save (0, revision_spec); } if (!*arch) { *arch = arch_archive_connect_branch (new_revision_spec, NULL); if (!*arch) { safe_printfmt (2, "Can't connect to %s.\n", new_revision_spec); exit(1); } } return new_revision_spec; } t_uchar * arch_determine_fqrevision (struct arch_archive ** arch, t_uchar * default_archive, t_uchar * revision_spec, t_uchar const * const cmd_name) { t_uchar * revision = 0; t_uchar * new_revision_spec = arch_determine_fqrevision_common (arch, default_archive, revision_spec, cmd_name); if (arch_valid_package_name (new_revision_spec, arch_maybe_archive, arch_req_patch_level, 0)) { arch_check_for (*arch, arch_req_patch_level, new_revision_spec); revision = str_save (0, new_revision_spec); } else { revision = arch_determine_fqrevision_safe_latest_revision (*arch, new_revision_spec, cmd_name); } lim_free (0, new_revision_spec); return revision; } /** * \brief this function determines the next revision in a namespace * * note that its API is broken - it needs to operate in such a way that * it can disambiguate between mirrors. * i.e. it needs to accept a location as an option, and look for * revision spec in that location, falling back to heuristics as appropriate */ t_uchar * arch_determine_fqrevision_next (struct arch_archive ** arch, t_uchar * default_archive, t_uchar * revision_spec, t_uchar const * const cmd_name) { t_uchar * fqrevision_next; t_uchar * current; t_uchar * new_revision_spec = arch_determine_fqrevision_common (arch, default_archive, revision_spec, cmd_name); if (arch_valid_package_name (new_revision_spec, arch_maybe_archive, arch_req_patch_level, 0)) /* FIXME-REMOVENAME: this must stay as -name until lock-revision accepts url input, * when the archive to qualify from can be probed from the url. * RBC 20050312 */ current = arch_fully_qualify ((*arch)->registered_name, new_revision_spec); else current = arch_determine_fqrevision_safe_latest_revision (*arch, new_revision_spec, cmd_name); { t_uchar * revision = arch_parse_package_name (arch_ret_non_archive, "", current); t_uchar * spec = arch_parse_package_name (arch_ret_package_version, "", current); t_uchar * patchlevel = arch_parse_package_name (arch_ret_patch_level, "", current); if (arch_revision_exists (*arch, revision)) { t_uchar * revision_next = arch_next_revision (spec,patchlevel,0,0,cmd_name); /* FIXME-REMOVENAME rbc 20050312 url awareness allows us to change this */ fqrevision_next = arch_fully_qualify ((*arch)->registered_name, revision_next); lim_free (0, revision); lim_free (0, revision_next); } else fqrevision_next = str_save(0, current); lim_free (0, spec); lim_free (0, patchlevel); } lim_free (0, current); lim_free (0, new_revision_spec); return fqrevision_next; } /* * @brief Determine the specified revision using the local tree-> * * Uses the local tree if any, the default archive, and the revision spec. * Leaves arch connected to the archive within which this revision should be * found * @return a newly-allocated fully-qualified revision name */ t_uchar * arch_determine_revision (struct arch_archive ** arch, t_uchar * default_archive, t_uchar * revision_spec, t_uchar const * const cmd_name) { t_uchar * fqrevision = arch_determine_fqrevision (arch, default_archive, revision_spec, cmd_name); t_uchar * revision = arch_parse_package_name (arch_ret_non_archive, 0, fqrevision); lim_free (0, fqrevision); return revision; } /** * @brief as arch_determine_revision, but return the patch level above the one * requested. * * If the one requested doesn't exist, it will be returned. * in a present branch, permit it */ t_uchar * arch_determine_revision_next (struct arch_archive ** arch, t_uchar * default_archive, t_uchar * revision_spec, t_uchar const * const cmd_name) { t_uchar * fqrevision = arch_determine_fqrevision_next (arch, default_archive, revision_spec, cmd_name); t_uchar * revision = arch_parse_package_name (arch_ret_non_archive, 0, fqrevision); lim_free (0, fqrevision); return revision; } /** * \brief check that a directory is accessible and optionally writable * \param path The path to check * \param check_write If true, check for writability * \param soft_errors if true, don't report or exit on errors * \return 0 on success * */ int arch_check_directory (t_uchar const * const path, int check_write, int soft_errors) { int errn; int mode = R_OK+X_OK; struct stat statb; if (check_write) mode+=W_OK; if (vu_stat (&errn, (t_uchar *)path, &statb) == -1) { if (soft_errors) return -1; if (errn == ENOENT) safe_printfmt (2, "Specified directory does not exist\nPath: %s\n", path); else safe_printfmt (2, "Error encountered accessing directory (%s)\nPath: %s\n", errno_to_string (errn), path); exit(2); } if (!S_ISDIR(statb.st_mode)) { if (soft_errors) return -1; safe_printfmt (2, "Specified path is not a directory\nPath: %s\n", path); exit (2); } if (access (path, mode) == -1) { if (soft_errors) return -1; safe_printfmt (2, "Error accessing specified directory (%s)\nDirectory: %s\n", errno_to_string (errno), path); exit (2); } return 0; } void arch_check_uri (t_uchar * uri) { /* hackish, I know - should be a any_of search RBC20041202 */ if (!str_chr_index (uri, '\n') && !str_chr_index (uri, '\r') && arch_valid_uri (uri)) return; safe_printfmt (2, "URL invalid or unsupported: %s\n", uri); exit (2); } /** * @brief Check whether the revision exists, using local data first, before * trying the archive * @param archive the archive containg the revision * @param revision the unqualified revision */ extern void arch_check_revision_local (t_uchar * archive, t_uchar * revision) { struct arch_archive * arch = 0; arch_patch_id patch_id; arch_project_tree_t * loc; arch_patch_id_init_archive (&patch_id, archive,revision); loc = arch_library_find (0, &patch_id, 0); arch_patch_id_finalise (&patch_id); if (loc) { arch_project_tree_delete (loc); return; } arch = arch_archive_connect_branch (archive, NULL); if (!arch) { safe_printfmt (2, _("cannot connect to archive '%s' to verify revision '%s'\n"), archive, revision); exit (2); } arch_check_for (arch, arch_req_patch_level, revision); arch_archive_close (arch); } /** * @brief Check the archive to make sure it's suitable for normal use, and not * just for mirroring. * @param arch The archive to check */ extern void arch_check_arch (struct arch_archive *arch) { /* FIXME-REMOVENAMES: this goes in baz 1.4 with registered names */ if (str_cmp (arch->registered_name, arch->official_name) != 0) { safe_printfmt (2, _("This archive can only be used as a mirror source or target, because it is \nregistered with the wrong name. To use it for other purposes, you should\nregister it using the official name.\n")); safe_printfmt (2, _("name: %s\nofficial name: %s\nlocation: %s\n"), arch->official_name, arch->official_name, arch->location); exit (2); } } t_uchar * arch_project_tree_revision (t_uchar const * name, t_uchar const * tree_root) { t_uchar * result; arch_project_tree_t * tree = arch_project_tree_new (talloc_context, tree_root); if (!tree->fqversion) { safe_printfmt (2, "%s: no tree-version set\n tree: %s\n", name, tree_root); exit (2); } result = tree->fqrevision; tree->fqrevision=NULL; arch_project_tree_delete (tree); return result; } void arch_cmd_fail (t_uchar const *name, char const * format, ...) { va_list ap; safe_printfmt (2, "%s :", name); va_start (ap, format); safe_printfmt_va_list (2, format, ap); va_end (ap); safe_flush (2); exit (2); } t_uchar * arch_archive_last_level (struct arch_archive * arch, t_uchar *version) { t_uchar * last_level = 0; rel_table revisions = arch_archive_revisions (arch, version, 0); if (revisions) { last_level = str_save (0, revisions[rel_n_records (revisions) - 1][0]); } rel_free_table (revisions); return last_level; } t_uchar * arch_next_revision (t_uchar * version, t_uchar * last_level, int seal, int fix, t_uchar const * const argv0) { enum arch_patch_level_type last_level_type; enum arch_patch_level_type desired_level_type; t_ulong last_n; t_ulong desired_n; t_uchar * desired_level = 0; t_uchar * revision = 0; last_level_type = arch_analyze_patch_level (&last_n, last_level); switch (last_level_type) { default: panic ("NOT IMPLEMENTED YET"); panic ("internal error"); break; case arch_is_base0_level: { if (seal) { desired_level_type = arch_is_version_level; desired_n = 0; } else if (fix) { safe_printfmt (2, "%s: can not --fix before --seal\n", argv0); exit (2); } else { desired_level_type = arch_is_patch_level; desired_n = 1; } break; } case arch_is_patch_level: { if (seal) { desired_level_type = arch_is_version_level; desired_n = 0; } else if (fix) { safe_printfmt (2, "%s: can not --fix before --seal\n", argv0); exit (2); } else { desired_level_type = arch_is_patch_level; desired_n = last_n + 1; } break; } case arch_is_version_level: { if (seal) { safe_printfmt (2, "%s: version already sealed\n", argv0); exit (2); } else if (fix) { desired_level_type = arch_is_versionfix_level; desired_n = 1; } else { safe_printfmt (2, "%s: cannot commit to sealed version without --fix\n", argv0); exit (2); } break; } case arch_is_versionfix_level: { if (seal) { safe_printfmt (2, "%s: version already sealed\n", argv0); exit (2); } else if (fix) { desired_level_type = arch_is_versionfix_level; desired_n = last_n + 1; } else { safe_printfmt (2, "%s: cannot commit to sealed version without --fix\n", argv0); exit (2); } break; } } desired_level = arch_form_patch_level (desired_level_type, desired_n); revision = str_alloc_cat_many (0, version, "--", desired_level, str_end); lim_free (0, desired_level); return revision; } t_uchar * arch_version_spec_to_fq_version(t_uchar * version_spec) { t_uchar * archive; t_uchar * version; t_uchar * fqversion; archive = arch_parse_package_name (arch_ret_archive, NULL, version_spec); version = arch_parse_package_name (arch_ret_package_version, 0, version_spec); fqversion = arch_fully_qualify (archive, version); return fqversion; } void arch_assert_in_tree(t_uchar * program_name, t_uchar * dir) { t_uchar * tree_root; tree_root = arch_tree_root (0, dir, 0); if (!tree_root) { safe_printfmt (2, "%s: not in project tree (%s)\n", program_name, dir); exit (1); } } /** * @brief Does arch_tree_root(dir) have any uncommited changes? * @param program_name The program name to emit in errors * @param tree The path to the directory to examine * @return patch to a changeset containing the changes if there are any */ t_uchar * arch_any_local_changes (t_uchar * program_name, arch_project_tree_t * tree) { arch_project_tree_t *orig; struct arch_make_changeset_report make_report = {0, }; struct arch_changeset_report report = {0, }; assoc_table inode_shortcut = 0; rel_table limits = 0; t_uchar * result; { t_uchar * tmp = arch_diff_default_output_dir (talloc_context, tree->root, NULL); result = str_save (0, tmp); talloc_free (tmp); } orig = arch_find_or_make_local_tree_copy (1, tree, 0, 0, tree->archive, tree->revision); /* Is this neccessary? -rjw 20050109 */ if (!orig) { safe_printfmt (2, "%s: no local copies to compare to (%s/%s)\n consider `add-pristine --help'\n", program_name, tree->archive, tree->revision); exit (2); } arch_read_inode_sig_ids (0, &inode_shortcut, tree->root, tree->archive, tree->revision); arch_make_changeset (&make_report, orig, tree, result, arch_unspecified_id_tagging, arch_inventory_unrecognized, limits, inode_shortcut, 0, arch_escape_classes); arch_evaluate_changeset (&report, result); if (!arch_any_changes (&report)) { rmrf_file (result); lim_free (0, result); result = NULL; } arch_project_tree_delete (orig); arch_free_make_changeset_report_data (&make_report); return result; } /** * \brief factoring out from interpret_delta_path */ static t_uchar * arch_interpret_delta_make (t_uchar **arch_out, t_uchar **rev_out, 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 const * const scratch_if_no_root) { t_uchar * answer; safe_printfmt (1, "* finding or making %s/%s\n", archive, revision); safe_flush (1); answer = arch_find_or_make_tmp_local_copy (1, tree->root ? tree->root: scratch_if_no_root, tree, cache, arch, archive, revision); if (arch_out) *arch_out = str_save (0, archive); if (rev_out) *rev_out = str_save (0, revision); return answer; } /** * \brief return a tree for use in delta and related commands */ arch_project_tree_t * arch_interpret_delta_path (t_uchar ** arch, t_uchar ** rev, t_uchar * scratch_dir, t_uchar * spec, arch_project_tree_t * cache) { /* give local paths priority */ if (!arch_check_directory (spec, 0, 1)) return arch_project_tree_new_ext (talloc_context, directory_as_cwd (spec), 1, 0); /* patch level or RL-or-official-name */ else { arch_project_tree_t * answer; t_uchar * archive = 0; t_uchar * revision = 0; t_uchar * maybe_revision = 0; t_uchar * fqrn = 0; struct arch_archive *arch_struct = 0; t_uchar * official_namespace = NULL; /* try tree relative validation */ arch_project_tree_t * tree = arch_project_tree_new (talloc_context, "."); arch_project_tree_check_name (tree, &arch_struct, &official_namespace, spec); if (!arch_struct) /* if we haven't errored and have reached here it * must be a local path, so error with diagnostics * if we can't use it. */ arch_check_directory (spec, 0, 0); archive = arch_parse_package_name (arch_ret_archive, NULL, official_namespace); maybe_revision = arch_parse_package_name (arch_ret_non_archive, NULL, official_namespace); /* Here, we check to see if a revision is specified. If so, then * we use that. If not, then lets hunt for the lastest one, because * we may have been givine just a package or a version */ if (arch_valid_package_name (maybe_revision, arch_no_archive, arch_req_patch_level, 0)) { fqrn = str_save (0, maybe_revision); } else { fqrn = arch_archive_latest_revision(arch_struct, maybe_revision, 1); } revision = arch_parse_package_name(arch_ret_non_archive, NULL, fqrn); answer = arch_project_tree_new (talloc_context, arch_interpret_delta_make (arch, rev, tree, cache, arch_struct, archive, revision, scratch_dir)); arch_archive_close (arch_struct); lim_free (0, archive); lim_free (0, revision); lim_free (0, maybe_revision); lim_free (0, fqrn); arch_project_tree_delete (tree); return answer; } } /** * \brief generate a list of file paths and ids from a user input list of names * \throw EINVAL on missing or invalid paths. * \param context the talloc context to allocate against * \param program_name for errors * \param tree the tree to look in * \param count the number of strings * \param first a pointer to a pointer to the first string * \return a rel_table */ rel_table arch_paths_from_user (void * context, t_uchar const * program_name, arch_project_tree_t * tree, int count, char **first) { rel_table result = NULL; rel_table tmp; rel_table full_source_files; rel_table filter_paths = NULL; int index; if (count) { tmp = rel_unflatten (count, 1, first); rel_for_each (tmp, index) { t_uchar * relpath = arch_project_tree_rel_path_from_user_input (tree,tmp[index][0]); rel_add_records (&filter_paths, rel_make_record (relpath, NULL), NULL); lim_free (0, relpath); } rel_free_table (tmp); } full_source_files = arch_source_files_inventory (tree, 0, 0); result = arch_inventory_included (full_source_files, filter_paths); rel_free_table (full_source_files); if ((rel_n_records(filter_paths) != 0) && (rel_n_records(result) != rel_n_records(filter_paths))) { rel_free_table (filter_paths); rel_free_table (result); Throw (exception (EINVAL, _("Some files specified do not exist or are not source files."))); } rel_free_table (filter_paths); talloc_steal (context, ar_base (result)); return result; } /** * }@ */ /* tag: Aaron Bentley Tue Dec 23 10:46:00 2003 (cmdutils.c) */