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 >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  287 lines

  1. /*
  2.  * Release: "cancel" a checkout in the history log.
  3.  * 
  4.  * - Don't allow release if anything is active - Don't allow release if not
  5.  * above or inside repository. - Don't allow release if ./CVS/Repository is
  6.  * not the same as the directory specified in the module database.
  7.  * 
  8.  * - Enter a line in the history log indicating the "release". - If asked to,
  9.  * delete the local working directory.
  10.  */
  11.  
  12. #include "cvs.h"
  13.  
  14. static void release_delete PROTO((char *dir));
  15.  
  16. static const char *const release_usage[] =
  17. {
  18.     "Usage: %s %s [-d] modules...\n",
  19.     "\t-d\tDelete the given directory.\n",
  20.     NULL
  21. };
  22.  
  23. static short delete_flag;
  24.  
  25. /* FIXME: This implementation is cheezy in quite a few ways:
  26.  
  27.    1.  The whole "cvs update" junk could be checked locally with a
  28.    fairly simple start_recursion/classify_file loop--a win for
  29.    portability, performance, and cleanliness.
  30.  
  31.    2.  Should be like edit/unedit in terms of working well if disconnected
  32.    from the network, and then sending a delayed notification.
  33.  
  34.    3.  Way too many network turnarounds.  More than one for each argument.
  35.    Puh-leeze.
  36.  
  37.    4.  Oh, and as a purely stylistic nit, break this out into separate
  38.    functions for client/local and for server.  Those #ifdefs are a mess.  */
  39.  
  40. int
  41. release (argc, argv)
  42.     int argc;
  43.     char **argv;
  44. {
  45.     FILE *fp;
  46.     register int i, c;
  47.     char *repository, *srepos;
  48.     char line[PATH_MAX], update_cmd[PATH_MAX];
  49.     char *thisarg;
  50.     int arg_start_idx;
  51.     int err = 0;
  52.  
  53. #ifdef SERVER_SUPPORT
  54.     if (!server_active)
  55.       {
  56. #endif /* SERVER_SUPPORT */
  57.         if (argc == -1)
  58.           usage (release_usage);
  59.         optind = 1;
  60.         while ((c = getopt (argc, argv, "Qdq")) != -1)
  61.           {
  62.             switch (c)
  63.               {
  64.               case 'Q':
  65.               case 'q':
  66. #ifdef SERVER_SUPPORT
  67.         /* The CVS 1.5 client sends these options (in addition to
  68.            Global_option requests), so we must ignore them.  */
  69.         if (!server_active)
  70. #endif
  71.                   error (1, 0,
  72.                          "-q or -Q must be specified before \"%s\"",
  73.                          command_name);
  74.         break;
  75.               case 'd':
  76.         delete_flag++;
  77.         break;
  78.               case '?':
  79.               default:
  80.         usage (release_usage);
  81.         break;
  82.               }
  83.           }
  84.         argc -= optind;
  85.         argv += optind;
  86. #ifdef SERVER_SUPPORT
  87.       }
  88. #endif /* SERVER_SUPPORT */
  89.  
  90.     /* We're going to run "cvs -n -q update" and check its output; if
  91.      * the output is sufficiently unalarming, then we release with no
  92.      * questions asked.  Else we prompt, then maybe release.
  93.      */
  94.     /* Construct the update command. */
  95.     sprintf (update_cmd, "%s -n -q -d %s update",
  96.              program_path, CVSroot_original);
  97.  
  98. #ifdef CLIENT_SUPPORT
  99.     /* Start the server; we'll close it after looping. */
  100.     if (client_active)
  101.       {
  102.     start_server ();
  103.     ign_setup ();
  104.       }
  105. #endif /* CLIENT_SUPPORT */
  106.  
  107.     /* If !server_active, we already skipped over argv[0] in the "argc
  108.        -= optind;" statement above.  But if server_active, we need to
  109.        skip it now.  */
  110. #ifdef SERVER_SUPPORT
  111.     if (server_active)
  112.       arg_start_idx = 1;
  113.     else
  114. #endif /* SERVER_SUPPORT */
  115.       arg_start_idx = 0;
  116.  
  117.     for (i = arg_start_idx; i < argc; i++)
  118.     {
  119.       thisarg = argv[i];
  120.         
  121. #ifdef SERVER_SUPPORT
  122.       if (server_active)
  123.       {
  124.         /* Just log the release -- all the interesting stuff happened
  125.          * on the client.
  126.          */
  127.         history_write ('F', thisarg, "", thisarg, "");    /* F == Free */
  128.       }
  129.       else
  130.       {
  131. #endif /* SERVER_SUPPORT */
  132.         
  133.         /*
  134.          * If we are in a repository, do it.  Else if we are in the parent of
  135.          * a directory with the same name as the module, "cd" into it and
  136.          * look for a repository there.
  137.          */
  138.         if (isdir (thisarg))
  139.         {
  140.           if ( CVS_CHDIR (thisarg) < 0)
  141.           {
  142.             if (!really_quiet)
  143.               error (0, 0, "can't chdir to: %s", thisarg);
  144.             continue;
  145.           }
  146.           if (!isdir (CVSADM))
  147.           {
  148.             if (!really_quiet)
  149.               error (0, 0, "no repository module: %s", thisarg);
  150.             continue;
  151.           }
  152.     }
  153.     else
  154.         {
  155.           if (!really_quiet)
  156.             error (0, 0, "no such directory: %s", thisarg);
  157.           continue;
  158.     }
  159.  
  160.     repository = Name_Repository ((char *) NULL, (char *) NULL);
  161.     srepos = Short_Repository (repository);
  162.         
  163.     if (!really_quiet)
  164.     {
  165.           /* The "release" command piggybacks on "update", which
  166.            * does the real work of finding out if anything is not
  167.            * up-to-date with the repository.  Then "release" prompts
  168.            * the user, telling her how many files have been
  169.            * modified, and asking if she still wants to do the
  170.            * release.
  171.            */
  172.           fp = run_popen (update_cmd, "r");
  173.           c = 0;
  174.  
  175.           while (fgets (line, sizeof (line), fp))
  176.           {
  177.             if (strchr ("MARCZ", *line))
  178.               c++;
  179.             (void) printf (line);
  180.           }
  181.  
  182.           /* If the update exited with an error, then we just want to
  183.            * complain and go on to the next arg.  Especially, we do
  184.            * not want to delete the local copy, since it's obviously
  185.            * not what the user thinks it is.
  186.            */
  187.           if ((pclose (fp)) != 0)
  188.           {
  189.             error (0, 0, "unable to release `%s'", thisarg);
  190.             continue;
  191.           }
  192.  
  193.           (void) printf ("You have [%d] altered files in this repository.\n",
  194.                          c);
  195.           (void) printf ("Are you sure you want to release %smodule `%s': ",
  196.                          delete_flag ? "(and delete) " : "", thisarg);
  197.           c = !yesno ();
  198.           if (c)            /* "No" */
  199.           {
  200.             (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
  201.                             command_name);
  202.             free (repository);
  203.             continue;
  204.           }
  205.     }
  206.  
  207.     if (1
  208. #ifdef SERVER_SUPPORT
  209.         && !server_active
  210. #endif
  211. #ifdef CLIENT_SUPPORT
  212.         && !(client_active
  213.          && (!supported_request ("noop")
  214.              || !supported_request ("Notify")))
  215. #endif
  216.         )
  217.     {
  218.       /* We are chdir'ed into the directory in question.  
  219.          So don't pass args to unedit.  */
  220.       int argc = 1;
  221.       char *argv[3];
  222.       argv[0] = "dummy";
  223.       argv[1] = NULL;
  224.       err += unedit (argc, argv);
  225.     }
  226.  
  227. #ifdef CLIENT_SUPPORT
  228.         if (client_active)
  229.         {
  230.           send_to_server ("Argument ", 0);
  231.           send_to_server (thisarg, 0);
  232.           send_to_server ("\012", 1);
  233.           send_to_server ("release\012", 0);
  234.         }
  235.         else
  236.         {
  237. #endif /* CLIENT_SUPPORT */
  238.           history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
  239. #ifdef CLIENT_SUPPORT
  240.         } /* else client not active */
  241. #endif /* CLIENT_SUPPORT */
  242.         
  243.         free (repository);
  244.         if (delete_flag) release_delete (thisarg);
  245.         
  246. #ifdef CLIENT_SUPPORT
  247.         if (client_active)
  248.           return get_responses_and_close ();
  249.         else
  250. #endif /* CLIENT_SUPPORT */
  251.           return (0);
  252.         
  253. #ifdef SERVER_SUPPORT
  254.       } /* else server not active */
  255. #endif  /* SERVER_SUPPORT */
  256.     }   /* `for' loop */
  257.     return err;
  258. }
  259.  
  260.  
  261. /* We want to "rm -r" the working directory, but let us be a little
  262.    paranoid.  */
  263. static void
  264. release_delete (dir)
  265.     char *dir;
  266. {
  267.     struct stat st;
  268.     ino_t ino;
  269.  
  270.     (void) CVS_STAT (".", &st);
  271.     ino = st.st_ino;
  272.     (void) CVS_CHDIR ("..");
  273.     (void) CVS_STAT (dir, &st);
  274.     if (ino != st.st_ino)
  275.     {
  276.     error (0, 0,
  277.            "Parent dir on a different disk, delete of %s aborted", dir);
  278.     return;
  279.     }
  280.     /*
  281.      * XXX - shouldn't this just delete the CVS-controlled files and, perhaps,
  282.      * the files that would normally be ignored and leave everything else?
  283.      */
  284.     if (unlink_file_dir (dir) < 0)
  285.     error (0, errno, "deletion of directory %s failed", dir);
  286. }
  287.