Index: cvs.h =================================================================== RCS file: /home/mike/cvsr/ccvs/src/cvs.h,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 cvs.h --- cvs.h 25 Feb 2003 23:56:06 -0000 1.1.1.2 +++ cvs.h 26 Feb 2003 00:54:05 -0000 @@ -180,6 +180,7 @@ #define CVSROOTADM_RCSINFO "rcsinfo" #define CVSROOTADM_COMMITINFO "commitinfo" #define CVSROOTADM_TAGINFO "taginfo" +#define CVSROOTADM_POSTTAGINFO "posttaginfo" #define CVSROOTADM_EDITINFO "editinfo" #define CVSROOTADM_VERIFYMSG "verifymsg" #define CVSROOTADM_HISTORY "history" Index: mkmodules.c =================================================================== RCS file: /home/mike/cvsr/ccvs/src/mkmodules.c,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 mkmodules.c --- mkmodules.c 25 Feb 2003 23:56:01 -0000 1.1.1.2 +++ mkmodules.c 26 Feb 2003 00:54:05 -0000 @@ -186,6 +186,30 @@ NULL }; +static const char *const posttaginfo_contents[] = { + "# The \"taginfo\" file is used to control post-tag scripting.\n", + "# The filter on the right is invoked with the following arguments:\n", + "#\n", + "# $1 -- tagname\n", + "# $2 -- operation \"add\" for tag, \"mov\" for tag -F, and \"del\" for tag -d\n", + "# $3 -- repository\n", + "# $4-> file revision [file revision ...]\n", + "#\n", + "# A non-zero exit of the filter program will cause the tag to be aborted.\n", + "#\n", + "# The first entry on a line is a regular expression which is tested\n", + "# against the directory that the change is being committed to, relative\n", + "# to the $CVSROOT. For the first match that is found, then the remainder\n", + "# of the line is the name of the filter to run.\n", + "#\n", + "# If the repository name does not match any of the regular expressions in this\n", + "# file, the \"DEFAULT\" line is used, if it is specified.\n", + "#\n", + "# If the name \"ALL\" appears as a regular expression it is always used\n", + "# in addition to the first matching regex or \"DEFAULT\".\n", + NULL +}; + static const char *const checkoutlist_contents[] = { "# The \"checkoutlist\" file is used to support additional version controlled\n", "# administrative files in $CVSROOT/CVSROOT, such as template files.\n", @@ -329,6 +353,9 @@ {CVSROOTADM_TAGINFO, "a %s file can be used to configure 'cvs tag' checking", taginfo_contents}, + {CVSROOTADM_POSTTAGINFO, + "a %s file can be used to configure 'cvs tag' post tag scripting", + posttaginfo_contents}, {CVSROOTADM_IGNORE, "a %s file can be used to specify files to ignore", NULL}, Index: tag.c =================================================================== RCS file: /home/mike/cvsr/ccvs/src/tag.c,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 tag.c --- tag.c 25 Feb 2003 23:56:05 -0000 1.1.1.2 +++ tag.c 26 Feb 2003 00:54:05 -0000 @@ -33,6 +33,13 @@ static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo)); static int rtag_delete PROTO((RCSNode *rcsfile)); static int tag_fileproc PROTO ((void *callerdat, struct file_info *finfo)); +static int tag_filesdoneproc PROTO ((void *callerdat, int err, char *repos, + char *update_dir, List *entries)); +static int posttag_proc PROTO ((char *repository, char*filter)); +static int posttag_list_proc PROTO ((Node *p, void *closure)); + + + static char *numtag; /* specific revision to tag */ static int numtag_validated = 0; @@ -395,7 +402,7 @@ /* start the recursion processor */ err = start_recursion (is_rtag ? rtag_fileproc : tag_fileproc, - (FILESDONEPROC) NULL, tag_dirproc, + tag_filesdoneproc, tag_dirproc, (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1, local_specified, which, 0, CVS_LOCK_WRITE, where, 1); dellist (&mtlist); @@ -1370,4 +1377,83 @@ tag_check_valid (c, argc, argv, local, aflag, repository); free (c); +} +static int +tag_filesdoneproc (callerdat, err, repos, update_dir, entries) + void *callerdat; + int err; + char *repos; + char *update_dir; + List *entries; +{ + int n; + Node *p; + + p = findnode(mtlist, update_dir); + if (p != NULL) + { + tlist = ((struct master_lists *) p->data)->tlist; + } + else + { + tlist = (List *) NULL; + } + if ((tlist == NULL) || (tlist->list->next == tlist->list)) + { + return (err); + } + if ((n = Parse_Info(CVSROOTADM_POSTTAGINFO, repos, posttag_proc, 1)) > 0) + { + error (0, 0, "Post-tag script failed"); + err += n; + } + return (err); +} + +static int +posttag_proc(repository, filter) + char *repository; + char *filter; +{ + if (filter[0] == '/') + { + char *s, *cp; + + s = xstrdup(filter); + for (cp=s; *cp; cp++) + { + if (isspace ((unsigned char) *cp)) + { + *cp = '\0'; + break; + } + } + if (!isfile(s)) + { + error (0, errno, "cannot find post-tag filter '%s'", s); + free(s); + return (1); + } + free(s); + } + run_setup (filter); + run_arg (symtag); + run_arg (delete_flag ? "del" : force_tag_move ? "mov" : + branch_mode ? "add-branch" : "add"); + run_arg (repository); + walklist(tlist, posttag_list_proc, NULL); + return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)); +} + +static int +posttag_list_proc(p, closure) + Node *p; + void *closure; +{ + if (p->data != NULL) + { + run_arg(p->key); + run_arg(p->data); + } + return (0); }