// // aegis - project change supervisor // Copyright (C) 2004-2014 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #ifndef LIBAEGIS_CHANGE_IDENTIFIER_H #define LIBAEGIS_CHANGE_IDENTIFIER_H #include #include #include #include /** * The change_identifier class is used to represent a change and its * context, as identified by all the different command line options used * to specify a change set. * * This class is a compound of the change_identifier_subset class and * the project_identifier_subset class, because they are most commonly * used together. The various methods are proxied to the appropriate * instance variables. */ class change_identifier { public: /** * The destructor. * It isn't virtual; thou shalt not derive from this class. */ ~change_identifier(); /** * The default constructor. */ change_identifier(); /** * The is_set method is used to determine if this change ID has been * set yet (via any of several command line options). */ bool is_set(void) const { return change_id.is_set(); } /** * The project_is_set method is used to determine if the project name * has been set yet (via any of several command line options). */ bool project_is_set(void) const { return project_id.is_set(); } /** * The command_line_parse method is used to parse command line * options (via the arglex() function) to set the change ID. The * current token is expected to be meaningful for identifying a * change. The position will be advanced past all relevant tokens. * * It understands all of the following command line options: * -BaseLine * [ -Change] number * -Change_From_Delta number * -BRanch number * -TRunk * -GrandParent * -DELta number * -DELta name * -DELta_Date when * -Development_Directory * [ -Project ] string * * @par * The command line parsing looks something like this: * @code * change_identifier cid; * while (arglex_token != arglex_token_eoln) * { * switch (arglex_token) * { * default: * generic_argument(usage); * continue; * * case arglex_token_baseline: * case arglex_token_branch: * case arglex_token_change: * case arglex_token_delta: * case arglex_token_delta_date: * case arglex_token_delta_from_change: * case arglex_token_development_directory: * case arglex_token_grandparent: * case arglex_token_number: * case arglex_token_project: * case arglex_token_string: * case arglex_token_trunk: * cid.command_line_parse(usage); * continue; * * ...other.options... * } * arglex(); * } * cid.command_line_check(usage); * @endcode * * @note * There is no need to pass all of these command line options to * this function for processing. Only pass those options which * make sense. It is often the case that there are actually * *two* changes being identified, and they will split the * arguments between them. */ void command_line_parse(void (*usage)(void)) { change_id.command_line_parse(usage); } /** * The command_line_parse_rest method is used to parse the rest of * the command line. It will call arglex(), #command_line_parse, * #command_line_check, and generic_argument() to perform this * processing. */ void command_line_parse_rest(void (*usage)(void)); bool get_devdir(void) { return change_id.get_devdir(); } /** * The command_line_check method is used to verify that sensible * command line options have been specified, once the parse has * completed. */ void command_line_check(void (*usage)(void)) { change_id.command_line_check(usage); } /** * The set_baseline method is used to specify that the baseline is * the change being identified. */ void set_baseline(void) { change_id.set_baseline(); } /** * The get_baseline method is used to determine whether the * --baseline option has been specified. */ bool get_baseline(void) { return change_id.get_baseline(); } /** * The get_file_revision is used to determine the path to the given * file at the time specified by the change ID. It must be called * after the set_change method has been called. * * @param filename * the name of the file of interest * @param bad_state * what to do if the change is not in an appropriate state */ file_revision get_file_revision(const nstring &filename, change_functor &bad_state) { return change_id.get_file_revision(filename, bad_state); } /** * The get_file_revision is used to determine the path to the given * file at the time specified by the change ID. It must be called * after the set_change method has been called. * * @param src * The meta data identifying the file (revison data, if set, * will be ignored) * @param bad_state * what to do if the change is not in an appropriate state */ file_revision get_file_revision(fstate_src_ty *src, change_functor &bad_state) { return change_id.get_file_revision(src, bad_state); } /** * The get_project_file_names method is used to obtain the list of * project file names, taking into account and --delta* options. */ void get_project_file_names(nstring_list &results) { change_id.get_project_file_names(results); } /** * The get_project_file method is used to obtain the details about * a named file, taking any --delta* options into account. * * @param file_name * The name of the file of interest. * @returns * pointer to file details, or NULL of the file does not exist. */ fstate_src_ty * get_project_file(const nstring &file_name) { return change_id.get_project_file(file_name); } /** * The get_historian method is used to obtain the location of the * historical file records reconstruction. * * @param detailed * true if you want a detailed history (recurse into branch * contents), or false if the simple report is enough. * The default is not to provide a detailed listing. * * @note * This function is a failure of the API to conceal this. * Eventually it would be nice if all the users of this could * be refactored to hide it again. */ project_file_roll_forward * get_historian(bool detailed = false) { return change_id.get_historian(detailed); } /** * The get_change_version_string method is used to get the version * string for the change. */ nstring get_change_version_string(void) { return change_id.get_change_version_string(); } /** * The get_pp method is used to get the project pointer for the * change identified. */ project * get_pp(void) { return branch_id.get_pp(); } /** * The get_up method is used to get the user pointer for the * change identified. */ user_ty::pointer get_up(void) { return branch_id.get_up(); } /** * The set_user_by_name method is used to set the user name by * name. This is useful for the small set of command which accept * a user name on the command line. * * @param login * The login name of the user. */ void set_user_by_name(nstring &login) { branch_id.set_user_by_name(login); } /** * The get_cp method is used to get the change pointer for the * change identified. */ change::pointer get_cp(void) { return change_id.get_cp(); } /** * The get_bogus_cp method is used to get the change pointer for * the change identified. It is an error if the use specified a * real change. */ change::pointer get_bogus_cp(void) { return change_id.get_bogus_cp(); } /** * The get_change_number method is used to obtain the change * number for the identified change. * * @note * There is no need to call magic_zero_decode(). */ long get_change_number(void) { return change_id.get_change_number(); } /** * The error_if_no_explicit_change_number is used to emit a * fatal_intl error if no change number was specified on the * command line. */ void error_if_no_explicit_change_number(void) { change_id.error_if_no_explicit_change_number(); } /** * The error_if_no_explicit_delta is used to emit a fatal_intl * error if no delta number was specified on the command line (in * any of the several forms). */ void error_if_no_explicit_delta(void) { change_id.error_if_no_explicit_delta(); } /** * The invalidate_change_meta_data method is used to discard cached * information about the change. This is usually necessary when a * sub-command is run and that subcommand would update the change * meta-data. */ void invalidate_change_meta_data(void) { change_id.invalidate_meta_data(); } /** * The set_delta_from_baseline method may be used to set the * change from the the change of the branch (the baseline). * * @note * Only call if the #is_set method returns false. */ void set_delta_from_baseline(void) { change_id.set_delta_from_baseline(); } /** * The set_delta_from_branch_head method may be used to set the * change from the current head revision of the branch. * * @note * Only call if the #is_set method returns false. */ void set_delta_from_branch_head(void) { change_id.set_delta_from_branch_head(); } /** * The create_new_change_set method is use to cause it to crete a * new change set, rather than binding to an existing chnage set. */ void create_new_change_set(void) { change_id.create_new_change_set(); } private: /** * The branch_id instance variable is used to remember the project subset * of identifying a change. */ project_identifier_subset_plain project_id; /** * The branch_id instance variable is used to remember the branch subset * of identifying a change. */ project_identifier_subset_branch branch_id; /** * The change_id instance variable is used to remember the change subset * of identifying a change. */ change_identifier_subset change_id; /** * The copy constructor. Do not use. */ change_identifier(const change_identifier &); /** * The assignment operator. Do not use. */ change_identifier &operator=(const change_identifier &); }; #endif // LIBAEGIS_CHANGE_IDENTIFIER_H // vim: set ts=8 sw=4 et :