2 * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 * Release: "cancel" a checkout in the history log.
18 * - Enter a line in the history log indicating the "release". - If asked to,
19 * delete the local working directory.
26 static const char *const release_usage[] =
28 "Usage: %s %s [-d] directories...\n",
29 "\t-d\tDelete the given directory.\n",
30 "(Specify the --help global option for a list of other help options)\n",
35 static int release_server PROTO ((int argc, char **argv));
37 /* This is the server side of cvs release. */
39 release_server (argc, argv)
45 /* Note that we skip argv[0]. */
46 for (i = 1; i < argc; ++i)
47 history_write ('F', argv[i], "", argv[i], "");
51 #endif /* SERVER_SUPPORT */
53 /* There are various things to improve about this implementation:
55 1. Using run_popen to run "cvs update" could be replaced by a
56 fairly simple start_recursion/classify_file loop--a win for
57 portability, performance, and cleanliness. In particular, there is
58 no particularly good way to find the right "cvs".
60 2. The fact that "cvs update" contacts the server slows things down;
61 it undermines the case for using "cvs release" rather than "rm -rf".
62 However, for correctly printing "? foo" and correctly handling
63 CVSROOTADM_IGNORE, we currently need to contact the server. (One
64 idea for how to fix this is to stash a copy of CVSROOTADM_IGNORE in
65 the working directories; see comment at base_* in entries.c for a
66 few thoughts on that).
68 3. Would be nice to take processing things on the client side one step
69 further, and making it like edit/unedit in terms of working well if
70 disconnected from the network, and then sending a delayed
73 4. Having separate network turnarounds for the "Notify" request
74 which we do as part of unedit, and for the "release" itself, is slow
85 size_t line_allocated = 0;
90 short delete_flag = 0;
95 return release_server (argc, argv);
98 /* Everything from here on is client or local. */
100 usage (release_usage);
102 while ((c = getopt (argc, argv, "+Qdq")) != -1)
109 "-q or -Q must be specified before \"%s\"",
117 usage (release_usage);
124 /* We're going to run "cvs -n -q update" and check its output; if
125 * the output is sufficiently unalarming, then we release with no
126 * questions asked. Else we prompt, then maybe release.
127 * (Well, actually we ask no matter what. Our notion of "sufficiently
128 * unalarming" doesn't take into account "? foo.c" files, so it is
129 * up to the user to take note of them, at least currently
130 * (ignore-193 in testsuite)).
132 /* Construct the update command. Be sure to add authentication and
133 encryption if we are using them currently, else our child process may
134 not be able to communicate with the server. */
135 update_cmd = xmalloc (strlen (program_path)
136 + strlen (current_parsed_root->original)
137 + 1 + 3 + 3 + 16 + 1);
138 sprintf (update_cmd, "%s %s%s-n -q -d %s update",
140 #if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
141 cvsauthenticate ? "-a " : "",
142 cvsencrypt ? "-x " : "",
146 current_parsed_root->original);
148 #ifdef CLIENT_SUPPORT
149 /* Start the server; we'll close it after looping. */
150 if (current_parsed_root->isremote)
155 #endif /* CLIENT_SUPPORT */
157 /* Remember the directory where "cvs release" was invoked because
158 all args are relative to this directory and we chdir around.
165 for (i = arg_start_idx; i < argc; i++)
171 if (CVS_CHDIR (thisarg) < 0)
174 error (0, errno, "can't chdir to: %s", thisarg);
180 error (0, 0, "no repository directory: %s", thisarg);
181 if (restore_cwd (&cwd, NULL))
189 error (0, 0, "no such directory: %s", thisarg);
195 int line_length, status;
197 /* The "release" command piggybacks on "update", which
198 does the real work of finding out if anything is not
199 up-to-date with the repository. Then "release" prompts
200 the user, telling her how many files have been
201 modified, and asking if she still wants to do the
203 fp = run_popen (update_cmd, "r");
205 error (1, 0, "cannot run command %s", update_cmd);
209 while ((line_length = getline (&line, &line_allocated, fp)) >= 0)
211 if (strchr ("MARCZ", *line))
213 (void) fputs (line, stdout);
215 if (line_length < 0 && !feof (fp))
216 error (0, errno, "cannot read from subprocess");
218 /* If the update exited with an error, then we just want to
219 complain and go on to the next arg. Especially, we do
220 not want to delete the local copy, since it's obviously
221 not what the user thinks it is. */
222 status = pclose (fp);
225 error (0, 0, "unable to release `%s' (%d)", thisarg, status);
226 if (restore_cwd (&cwd, NULL))
231 printf ("You have [%d] altered files in this repository.\n",
233 printf ("Are you sure you want to release %sdirectory `%s': ",
234 delete_flag ? "(and delete) " : "", thisarg);
238 (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
240 if (restore_cwd (&cwd, NULL))
246 /* Note: client.c doesn't like to have other code
247 changing the current directory on it. So a fair amount
248 of effort is needed to make sure it doesn't get confused
249 about the directory and (for example) overwrite
250 CVS/Entries file in the wrong directory. See release-17
251 through release-23. */
253 if (restore_cwd (&cwd, NULL))
257 #ifdef CLIENT_SUPPORT
258 && !(current_parsed_root->isremote
259 && (!supported_request ("noop")
260 || !supported_request ("Notify")))
269 err += unedit (argc, argv);
270 if (restore_cwd (&cwd, NULL))
274 #ifdef CLIENT_SUPPORT
275 if (current_parsed_root->isremote)
277 send_to_server ("Argument ", 0);
278 send_to_server (thisarg, 0);
279 send_to_server ("\012", 1);
280 send_to_server ("release\012", 0);
283 #endif /* CLIENT_SUPPORT */
285 history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
290 /* FIXME? Shouldn't this just delete the CVS-controlled
291 files and, perhaps, the files that would normally be
292 ignored and leave everything else? */
294 if (unlink_file_dir (thisarg) < 0)
295 error (0, errno, "deletion of directory %s failed", thisarg);
298 #ifdef CLIENT_SUPPORT
299 if (current_parsed_root->isremote)
302 * Is there a good reason why get_server_responses() isn't
303 * responsible for restoring its initial directory itself when
306 err += get_server_responses ();
308 if (restore_cwd (&cwd, NULL))
311 #endif /* CLIENT_SUPPORT */
314 if (restore_cwd (&cwd, NULL))
318 #ifdef CLIENT_SUPPORT
319 if (current_parsed_root->isremote)
321 /* Unfortunately, client.c doesn't offer a way to close
322 the connection without waiting for responses. The extra
323 network turnaround here is quite unnecessary other than
325 send_to_server ("noop\012", 0);
326 err += get_responses_and_close ();
328 #endif /* CLIENT_SUPPORT */