home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
cvs-1.8.7-src.tgz
/
tar.out
/
fsf
/
cvs
/
src
/
release.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
8KB
|
287 lines
/*
* 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_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;
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 ( CVS_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) CVS_STAT (".", &st);
ino = st.st_ino;
(void) CVS_CHDIR ("..");
(void) CVS_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);
}