diff options
author | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
commit | 8982e501c77217c860f79bba431f46a62b607a21 (patch) | |
tree | 70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/release.c | |
parent | 01ee40fd6a76f6ff7ef247fc1b2cf6e337f216c5 (diff) | |
download | FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.zip FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.tar.gz |
Import of slightly trimmed cvs-1.8 distribution. Generated files
and non-unix code has been left out.
Diffstat (limited to 'contrib/cvs/src/release.c')
-rw-r--r-- | contrib/cvs/src/release.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/contrib/cvs/src/release.c b/contrib/cvs/src/release.c new file mode 100644 index 0000000..b3ebb2b --- /dev/null +++ b/contrib/cvs/src/release.c @@ -0,0 +1,286 @@ +/* + * 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" + +static void release_delete PROTO((char *dir)); + +static const char *const release_usage[] = +{ + "Usage: %s %s [-d] modules...\n", + "\t-d\tDelete the given directory.\n", + NULL +}; + +static short delete_flag; + +/* FIXME: This implementation is cheezy in quite a few ways: + + 1. The whole "cvs update" junk could be checked locally with a + fairly simple start_recursion/classify_file loop--a win for + portability, performance, and cleanliness. + + 2. Should be like edit/unedit in terms of working well if disconnected + from the network, and then sending a delayed notification. + + 3. Way too many network turnarounds. More than one for each argument. + Puh-leeze. + + 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. */ + +int +release (argc, argv) + int argc; + char **argv; +{ + FILE *fp; + register int i, c; + char *repository, *srepos; + char line[PATH_MAX], update_cmd[PATH_MAX]; + char *thisarg; + int arg_start_idx; + int err = 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) +#endif + error (1, 0, + "-q or -Q must be specified before \"%s\"", + command_name); + break; + case 'd': + delete_flag++; + break; + case '?': + default: + usage (release_usage); + break; + } + } + argc -= optind; + argv += optind; +#ifdef SERVER_SUPPORT + } +#endif /* SERVER_SUPPORT */ + + /* 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. */ + sprintf (update_cmd, "%s -n -q -d %s update", + program_path, CVSroot); + +#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; + + 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. + */ + 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; + } + } + else + { + 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; + } + } + + if (1 +#ifdef SERVER_SUPPORT + && !server_active +#endif +#ifdef CLIENT_SUPPORT + && !(client_active + && (!supported_request ("noop") + || !supported_request ("Notify"))) +#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); + } + +#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); + } + else + { +#endif /* CLIENT_SUPPORT */ + history_write ('F', thisarg, "", thisarg, ""); /* F == Free */ +#ifdef CLIENT_SUPPORT + } /* else client not active */ +#endif /* CLIENT_SUPPORT */ + + free (repository); + if (delete_flag) release_delete (thisarg); + +#ifdef CLIENT_SUPPORT + if (client_active) + return get_responses_and_close (); + else +#endif /* CLIENT_SUPPORT */ + return (0); + +#ifdef SERVER_SUPPORT + } /* else server not active */ +#endif /* SERVER_SUPPORT */ + } /* `for' loop */ + return err; +} + + +/* We want to "rm -r" the working directory, but let us be a little + paranoid. */ +static void +release_delete (dir) + char *dir; +{ + struct stat st; + ino_t ino; + + (void) stat (".", &st); + ino = st.st_ino; + (void) chdir (".."); + (void) stat (dir, &st); + if (ino != st.st_ino) + { + error (0, 0, + "Parent dir on a different disk, delete of %s aborted", dir); + return; + } + /* + * XXX - shouldn't this just delete the CVS-controlled files and, perhaps, + * the files that would normally be ignored and leave everything else? + */ + if (unlink_file_dir (dir) < 0) + error (0, errno, "deletion of directory %s failed", dir); +} |