summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/release.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/release.c')
-rw-r--r--contrib/cvs/src/release.c333
1 files changed, 165 insertions, 168 deletions
diff --git a/contrib/cvs/src/release.c b/contrib/cvs/src/release.c
index b3ebb2b..f2f1edf 100644
--- a/contrib/cvs/src/release.c
+++ b/contrib/cvs/src/release.c
@@ -1,41 +1,61 @@
/*
* Release: "cancel" a checkout in the history log.
*
- * - Don't allow release if anything is active - Don't allow release if not
- * above or inside repository. - Don't allow release if ./CVS/Repository is
- * not the same as the directory specified in the module database.
- *
* - Enter a line in the history log indicating the "release". - If asked to,
* delete the local working directory.
*/
#include "cvs.h"
+#include "getline.h"
static void release_delete PROTO((char *dir));
static const char *const release_usage[] =
{
- "Usage: %s %s [-d] modules...\n",
+ "Usage: %s %s [-d] directories...\n",
"\t-d\tDelete the given directory.\n",
NULL
};
-static short delete_flag;
+#ifdef SERVER_SUPPORT
+static int release_server PROTO ((int argc, char **argv));
+
+/* This is the server side of cvs release. */
+static int
+release_server (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+ /* Note that we skip argv[0]. */
+ for (i = 1; i < argc; ++i)
+ history_write ('F', argv[i], "", argv[i], "");
+ return 0;
+}
+
+#endif /* SERVER_SUPPORT */
-/* FIXME: This implementation is cheezy in quite a few ways:
+/* There are various things to improve about this implementation:
- 1. The whole "cvs update" junk could be checked locally with a
+ 1. Using run_popen to run "cvs update" could be replaced by a
fairly simple start_recursion/classify_file loop--a win for
- portability, performance, and cleanliness.
+ portability, performance, and cleanliness. In particular, there is
+ no particularly good way to find the right "cvs".
- 2. Should be like edit/unedit in terms of working well if disconnected
- from the network, and then sending a delayed notification.
+ 2. The fact that "cvs update" contacts the server slows things down;
+ it undermines the case for using "cvs release" rather than "rm -rf".
+ However, for correctly printing "? foo" and correctly handling
+ CVSROOTADM_IGNORE, we currently need to contact the server.
- 3. Way too many network turnarounds. More than one for each argument.
- Puh-leeze.
+ 3. Would be nice to take processing things on the client side one step
+ further, and making it like edit/unedit in terms of working well if
+ disconnected from the network, and then sending a delayed
+ notification.
- 4. Oh, and as a purely stylistic nit, break this out into separate
- functions for client/local and for server. Those #ifdefs are a mess. */
+ 4. Having separate network turnarounds for the "Notify" request
+ which we do as part of unedit, and for the "release" itself, is slow
+ and unnecessary. */
int
release (argc, argv)
@@ -43,171 +63,140 @@ release (argc, argv)
char **argv;
{
FILE *fp;
- register int i, c;
- char *repository, *srepos;
- char line[PATH_MAX], update_cmd[PATH_MAX];
+ int i, c;
+ char *repository;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ char *update_cmd;
char *thisarg;
int arg_start_idx;
int err = 0;
+ short delete_flag = 0;
#ifdef SERVER_SUPPORT
- if (!server_active)
- {
-#endif /* SERVER_SUPPORT */
- if (argc == -1)
- usage (release_usage);
- optind = 1;
- while ((c = getopt (argc, argv, "Qdq")) != -1)
- {
- switch (c)
- {
- case 'Q':
- case 'q':
-#ifdef SERVER_SUPPORT
- /* The CVS 1.5 client sends these options (in addition to
- Global_option requests), so we must ignore them. */
- if (!server_active)
+ if (server_active)
+ return release_server (argc, argv);
#endif
- error (1, 0,
- "-q or -Q must be specified before \"%s\"",
- command_name);
+
+ /* Everything from here on is client or local. */
+ if (argc == -1)
+ usage (release_usage);
+ optind = 1;
+ while ((c = getopt (argc, argv, "+Qdq")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
break;
- case 'd':
+ case 'd':
delete_flag++;
break;
- case '?':
- default:
+ case '?':
+ default:
usage (release_usage);
break;
- }
- }
- argc -= optind;
- argv += optind;
-#ifdef SERVER_SUPPORT
- }
-#endif /* SERVER_SUPPORT */
+ }
+ }
+ argc -= optind;
+ argv += optind;
/* We're going to run "cvs -n -q update" and check its output; if
* the output is sufficiently unalarming, then we release with no
* questions asked. Else we prompt, then maybe release.
*/
/* Construct the update command. */
+ update_cmd = xmalloc (strlen (program_path)
+ + strlen (CVSroot_original)
+ + 20);
sprintf (update_cmd, "%s -n -q -d %s update",
- program_path, CVSroot);
+ program_path, CVSroot_original);
#ifdef CLIENT_SUPPORT
/* Start the server; we'll close it after looping. */
if (client_active)
- {
+ {
start_server ();
ign_setup ();
- }
+ }
#endif /* CLIENT_SUPPORT */
- /* If !server_active, we already skipped over argv[0] in the "argc
- -= optind;" statement above. But if server_active, we need to
- skip it now. */
-#ifdef SERVER_SUPPORT
- if (server_active)
- arg_start_idx = 1;
- else
-#endif /* SERVER_SUPPORT */
- arg_start_idx = 0;
+ arg_start_idx = 0;
for (i = arg_start_idx; i < argc; i++)
{
- thisarg = argv[i];
-
-#ifdef SERVER_SUPPORT
- if (server_active)
- {
- /* Just log the release -- all the interesting stuff happened
- * on the client.
- */
- history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
- }
- else
- {
-#endif /* SERVER_SUPPORT */
-
- /*
- * If we are in a repository, do it. Else if we are in the parent of
- * a directory with the same name as the module, "cd" into it and
- * look for a repository there.
- */
+ thisarg = argv[i];
+
if (isdir (thisarg))
{
- if (chdir (thisarg) < 0)
- {
- if (!really_quiet)
- error (0, 0, "can't chdir to: %s", thisarg);
- continue;
- }
- if (!isdir (CVSADM))
- {
- if (!really_quiet)
- error (0, 0, "no repository module: %s", thisarg);
- continue;
- }
+ if (CVS_CHDIR (thisarg) < 0)
+ {
+ if (!really_quiet)
+ error (0, errno, "can't chdir to: %s", thisarg);
+ continue;
+ }
+ if (!isdir (CVSADM))
+ {
+ if (!really_quiet)
+ error (0, 0, "no repository directory: %s", thisarg);
+ continue;
+ }
}
else
{
- if (!really_quiet)
- error (0, 0, "no such directory: %s", thisarg);
- continue;
+ if (!really_quiet)
+ error (0, 0, "no such directory: %s", thisarg);
+ continue;
}
repository = Name_Repository ((char *) NULL, (char *) NULL);
- srepos = Short_Repository (repository);
-
+
if (!really_quiet)
{
- /* The "release" command piggybacks on "update", which
- * does the real work of finding out if anything is not
- * up-to-date with the repository. Then "release" prompts
- * the user, telling her how many files have been
- * modified, and asking if she still wants to do the
- * release.
- */
- fp = run_popen (update_cmd, "r");
- c = 0;
-
- while (fgets (line, sizeof (line), fp))
- {
- if (strchr ("MARCZ", *line))
- c++;
- (void) printf (line);
- }
-
- /* If the update exited with an error, then we just want to
- * complain and go on to the next arg. Especially, we do
- * not want to delete the local copy, since it's obviously
- * not what the user thinks it is.
- */
- if ((pclose (fp)) != 0)
- {
- error (0, 0, "unable to release `%s'", thisarg);
- continue;
- }
-
- (void) printf ("You have [%d] altered files in this repository.\n",
- c);
- (void) printf ("Are you sure you want to release %smodule `%s': ",
- delete_flag ? "(and delete) " : "", thisarg);
- c = !yesno ();
- if (c) /* "No" */
- {
- (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
- command_name);
- free (repository);
- continue;
- }
+ /* The "release" command piggybacks on "update", which
+ does the real work of finding out if anything is not
+ up-to-date with the repository. Then "release" prompts
+ the user, telling her how many files have been
+ modified, and asking if she still wants to do the
+ release. */
+ fp = run_popen (update_cmd, "r");
+ c = 0;
+
+ while (getline (&line, &line_allocated, fp) >= 0)
+ {
+ if (strchr ("MARCZ", *line))
+ c++;
+ (void) printf (line);
+ }
+
+ /* If the update exited with an error, then we just want to
+ complain and go on to the next arg. Especially, we do
+ not want to delete the local copy, since it's obviously
+ not what the user thinks it is. */
+ if ((pclose (fp)) != 0)
+ {
+ error (0, 0, "unable to release `%s'", thisarg);
+ continue;
+ }
+
+ printf ("You have [%d] altered files in this repository.\n",
+ c);
+ printf ("Are you sure you want to release %sdirectory `%s': ",
+ delete_flag ? "(and delete) " : "", thisarg);
+ c = !yesno ();
+ if (c) /* "No" */
+ {
+ (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
+ command_name);
+ free (repository);
+ continue;
+ }
}
if (1
-#ifdef SERVER_SUPPORT
- && !server_active
-#endif
#ifdef CLIENT_SUPPORT
&& !(client_active
&& (!supported_request ("noop")
@@ -215,45 +204,53 @@ release (argc, argv)
#endif
)
{
- /* We are chdir'ed into the directory in question.
- So don't pass args to unedit. */
- int argc = 1;
- char *argv[3];
- argv[0] = "dummy";
- argv[1] = NULL;
- err += unedit (argc, argv);
+ /* We are chdir'ed into the directory in question.
+ So don't pass args to unedit. */
+ int argc = 1;
+ char *argv[3];
+ argv[0] = "dummy";
+ argv[1] = NULL;
+ err += unedit (argc, argv);
}
#ifdef CLIENT_SUPPORT
if (client_active)
{
- send_to_server ("Argument ", 0);
- send_to_server (thisarg, 0);
- send_to_server ("\012", 1);
- send_to_server ("release\012", 0);
- }
+ send_to_server ("Argument ", 0);
+ send_to_server (thisarg, 0);
+ send_to_server ("\012", 1);
+ send_to_server ("release\012", 0);
+ }
else
- {
#endif /* CLIENT_SUPPORT */
- history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
-#ifdef CLIENT_SUPPORT
- } /* else client not active */
-#endif /* CLIENT_SUPPORT */
-
+ {
+ history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
+ }
+
free (repository);
if (delete_flag) release_delete (thisarg);
-
+
#ifdef CLIENT_SUPPORT
if (client_active)
- return get_responses_and_close ();
- else
+ err += get_server_responses ();
#endif /* CLIENT_SUPPORT */
- return (0);
-
-#ifdef SERVER_SUPPORT
- } /* else server not active */
-#endif /* SERVER_SUPPORT */
- } /* `for' loop */
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* Unfortunately, client.c doesn't offer a way to close
+ the connection without waiting for responses. The extra
+ network turnaround here is quite unnecessary other than
+ that.... */
+ send_to_server ("noop\012", 0);
+ err += get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ free (update_cmd);
+ if (line != NULL)
+ free (line);
return err;
}
@@ -267,10 +264,10 @@ release_delete (dir)
struct stat st;
ino_t ino;
- (void) stat (".", &st);
+ (void) CVS_STAT (".", &st);
ino = st.st_ino;
- (void) chdir ("..");
- (void) stat (dir, &st);
+ (void) CVS_CHDIR ("..");
+ (void) CVS_STAT (dir, &st);
if (ino != st.st_ino)
{
error (0, 0,
OpenPOWER on IntegriCloud