bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: patch: new 'cvs import -X' option.


From: cgd
Subject: Re: patch: new 'cvs import -X' option.
Date: 26 Jun 2004 22:23:20 -0700
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

At Sat, 26 Jun 2004 10:47:38 -0700, Mark D. Baushke wrote:
> Per our private e-mail exchange, your update patch with better comments
> and an updated sanity.sh importX test has been committed to the feature
> branch.

Cool.  For the edification of other list readers, i've included the
last version of the patch as sent to you, below.


thanks,

chris
--
New-feature entry for the NEWS file:

* `cvs import' now has a new option, `-X', which causes new files to be
  imported in a way that they appear only on the vendor branch, and do not
  automatically appear on the main trunk.

[ src/ChangeLog ]
2004-06-24  Chris Demetriou  <cgd@broadcom.com>

        * import.c (import_usage): Add new -X flag.
        (import): Handle new -X flag.
        (process_import_file): Handle new -X flag.
        (killnew): New static flag variable to indicate use of -X flag.
        (preserve_initial_permissions): New function, extracted from
        add_rcs_file().
        (expand_and_copy_contents): Likewise.
        (add_rcs_file): New argument, do_killnew, to cause "import -X" flag
        processing.  Implement -X flag, and use newly abstracted functions.
        * rcs.h (add_rcs_file): Update prototype for do_killnew argument.
        * commit.c (checkaddfile): Update for add_rcs_file function change.
        * mkmodules.c (init): Likewise.
        * client.c (handle_mt): Handle an importmergecmd tag without
        any conflicts (for 'import -X' support).
        * sanity.sh (importX): New test.

[ doc/ChangeLog ]
2004-06-24  Chris Demetriou  <cgd@broadcom.com>

        * cvs.texinfo (Vendor branch): Document that sometimes
        the default branch won't be set to the vendor branch.
        (import options): Add -X.
        * cvsclient.texi (MT importmergecmd tag): Document that this
        can also be used with the 'cvs import -X' command, and
        that it can occur when there are no conflicts.

Index: cvs/doc/cvs.texinfo
diff -u cvs/doc/cvs.texinfo:1.1.1.1 cvs/doc/cvs.texinfo:1.4
--- cvs/doc/cvs.texinfo:1.1.1.1 Wed Jun 23 21:34:10 2004
+++ cvs/doc/cvs.texinfo Wed Jun 23 21:39:25 2004
@@ -7418,7 +7418,7 @@
 
 Use the @code{import} command to create and update
 the vendor branch.  When you import a new file,
-the vendor branch is made the `head' revision, so
+(usually) the vendor branch is made the `head' revision, so
 anyone that checks out a copy of the file gets that
 revision.  When a local modification is committed it is
 placed on the main trunk, and made the `head'
@@ -10470,6 +10470,17 @@
 @var{spec} can be a file name pattern of the same type
 that you can specify in the @file{.cvswrappers}
 file. @xref{Wrappers}.
+
+@item -X
+Modify the algorithm used by @sc{cvs} when importing new files
+so that new files do not immediately appear on the main trunk.
+
+Specifically, this flag causes @sc{cvs} to mark new files as
+if they were deleted on the main trunk, by taking the following
+steps for each file in addition to those normally taken on import:
+creating a new revision on the main trunk indicating that
+the new file is @code{dead}, resetting the new file's default branch,
+and placing the file in the Attic (@pxref{Attic}) directory.
 @end table
 
 @c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Index: cvs/doc/cvsclient.texi
diff -u cvs/doc/cvsclient.texi:1.1.1.1 cvs/doc/cvsclient.texi:1.4
--- cvs/doc/cvsclient.texi:1.1.1.1      Wed Jun 23 21:34:10 2004
+++ cvs/doc/cvsclient.texi      Wed Jun 23 21:39:25 2004
@@ -1823,8 +1823,11 @@
 @end example
 
 The @code{importmergecmd} tag is used when doing an import which has
-conflicts.  The client can use it to report how to merge in the newly
-imported changes.  The @var{count} is the number of conflicts.  The
+conflicts, or when doing an import with the @samp{-X} flag.
+The client can use it to report how to merge in the newly
+imported changes.  The @var{count} is the number of conflicts, or the
+string @code{No} if no conflicts occurred.  (The latter will only be
+sent for imports run with the @samp{-X} flag.)  The
 newly imported changes can be merged by running the following command:
 @smallexample
 cvs checkout -j @var{tag1} -j @var{tag2} @var{repository}
Index: cvs/src/client.c
diff -u cvs/src/client.c:1.1.1.1 cvs/src/client.c:1.4
--- cvs/src/client.c:1.1.1.1    Wed Jun 23 21:34:11 2004
+++ cvs/src/client.c    Wed Jun 23 21:39:25 2004
@@ -2663,8 +2663,11 @@
                    break;
                }
 
-               sprintf (buf, "\n%d conflicts created by this import.\n",
-                        importmergecmd.conflicts);
+               if (importmergecmd.conflicts == -1)
+                   sprintf (buf, "\nNo conflicts created by this import.\n");
+               else
+                   sprintf (buf, "\n%d conflicts created by this import.\n",
+                            importmergecmd.conflicts);
                cvs_output (buf, 0);
                cvs_output ("Use the following command to help the merge:\n\n",
                            0);
@@ -2720,7 +2723,12 @@
            else if (importmergecmd.seen)
            {
                if (strcmp (tag, "conflicts") == 0)
-                   importmergecmd.conflicts = atoi (text);
+               {
+                   if (strcmp (text, "No") == 0)
+                       importmergecmd.conflicts = -1;
+                   else
+                       importmergecmd.conflicts = atoi (text);
+               }
                else if (strcmp (tag, "mergetag1") == 0)
                    importmergecmd.mergetag1 = xstrdup (text);
                else if (strcmp (tag, "mergetag2") == 0)
Index: cvs/src/commit.c
diff -u cvs/src/commit.c:1.1.1.1 cvs/src/commit.c:1.4
--- cvs/src/commit.c:1.1.1.1    Wed Jun 23 21:34:11 2004
+++ cvs/src/commit.c    Wed Jun 23 21:39:25 2004
@@ -2000,7 +2000,7 @@
 
        if (add_rcs_file (NULL, rcsname, file, NULL, opt,
                          NULL, NULL, 0, NULL,
-                         desc, desclen, NULL) != 0)
+                         desc, desclen, NULL, 0) != 0)
        {
            if (rcsname != NULL)
                free (rcsname);
Index: cvs/src/import.c
diff -u cvs/src/import.c:1.1.1.1 cvs/src/import.c:1.5
--- cvs/src/import.c:1.1.1.1    Wed Jun 23 21:34:11 2004
+++ cvs/src/import.c    Wed Jun 23 22:16:21 2004
@@ -31,6 +31,12 @@
                                int targc, char *targv[]);
 static int update_rcs_file (char *message, char *vfile, char *vtag, int targc,
                            char *targv[], int inattic);
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+static int preserve_initial_permissions (FILE *fprcs, const char *userfile,
+                                        mode_t file_type, struct stat *sbp);
+#endif
+static int expand_and_copy_contents (FILE *fprcs, mode_t file_type,
+                                    const char *user, FILE *fpuser);
 static void add_log (int ch, char *fname);
 
 static int repos_len;
@@ -41,12 +47,14 @@
 static int conflicts;
 static int use_file_modtime;
 static char *keyword_opt = NULL;
+static int killnew;
 
 static const char *const import_usage[] =
 {
-    "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n",
+    "Usage: %s %s [-dX] [-k subst] [-I ign] [-m msg] [-b branch]\n",
     "    [-W spec] repository vendor-tag release-tags...\n",
     "\t-d\tUse the file's modification time as the time of import.\n",
+    "\t-X\tWhen importing new files, mark their trunk revisions as dead.\n",
     "\t-k sub\tSet default RCS keyword substitution mode.\n",
     "\t-I ign\tMore files to ignore (! to reset).\n",
     "\t-b bra\tVendor branch id.\n",
@@ -75,7 +83,7 @@
 
     vbranch = xstrdup (CVSBRANCH);
     optind = 0;
-    while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1)
+    while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:X")) != -1)
     {
        switch (c)
        {
@@ -129,6 +137,9 @@
            case 'W':
                wrap_add (optarg, 0);
                break;
+           case 'X':
+               killnew = 1;
+               break;
            case '?':
            default:
                usage (import_usage);
@@ -265,6 +276,8 @@
        option_with_arg ("-m", message ? message : "");
        if (keyword_opt != NULL)
            option_with_arg ("-k", keyword_opt);
+       if (killnew)
+           send_arg ("-X");
        /* The only ignore processing which takes place on the server side
           is the CVSROOT/cvsignore file.  But if the user specified -I !,
           the documented behavior is to not process said file.  */
@@ -324,7 +337,7 @@
 
     /* Just Do It.  */
     err = import_descend (message, argv[1], argc - 2, argv + 2);
-    if (conflicts)
+    if (conflicts || killnew)
     {
        if (!really_quiet)
        {
@@ -332,7 +345,10 @@
 
            cvs_output_tagged ("+importmergecmd", NULL);
            cvs_output_tagged ("newline", NULL);
-           sprintf (buf, "%d", conflicts);
+           if (conflicts)
+               sprintf (buf, "%d", conflicts);
+           else
+               sprintf (buf, "%s", "No");
            cvs_output_tagged ("conflicts", buf);
            cvs_output_tagged ("text", " conflicts created by this import.");
            cvs_output_tagged ("newline", NULL);
@@ -363,7 +379,11 @@
            report any required -d option.  There is no particularly
            clean way to tell the server about the -d option used by
            the client.  */
-       (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
+       if (conflicts)
+           (void) fprintf (logfp, "\n%d", conflicts);
+       else
+           (void) fprintf (logfp, "\nNo");
+       (void) fprintf (logfp, " conflicts created by this import.\n",
                        conflicts);
        (void) fprintf (logfp,
                        "Use the following command to help the merge:\n\n");
@@ -551,7 +571,27 @@
            char *free_opt = NULL;
            char *our_opt = keyword_opt;
 
-           free (attic_name);
+           /* If marking newly-imported files as dead, they must be
+              created in the attic!  */
+           if (! killnew)
+               free (attic_name);
+           else 
+           {
+               free (rcs);
+               rcs = attic_name;
+
+               /* Attempt to make the Attic directory, in case it
+                  does not exist.  */
+               (void) sprintf (rcs, "%s/%s", repository, CVSATTIC);
+               if (CVS_MKDIR (rcs, 0777 ) != 0 && errno != EEXIST)
+                   error (1, errno, "cannot make directory `%s'", rcs);
+
+               /* Note that the above clobbered the path name, so we
+                  recreate it here.  */
+               (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC,
+                               vfile, RCSEXT);
+           }
+
            /*
             * A new import source file; it doesn't exist as a ,v within the
             * repository nor in the Attic -- create it anew.
@@ -591,7 +631,7 @@
 
            retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
                                   vbranch, vtag, targc, targv,
-                                  NULL, 0, logfp);
+                                  NULL, 0, logfp, killnew);
            if (free_opt != NULL)
                free (free_opt);
            free (rcs);
@@ -973,7 +1013,9 @@
  *
  * INPUTS
  *   message    Log message for the addition.  Not used if add_vhead == NULL.
- *   rcs        Filename of the RCS file to create.
+ *   rcs        Filename of the RCS file to create.  Note that if 'do_killnew'
+ *             is set, this file should be in the Attic directory, and the
+ *             Attic directory must already exist.
  *   user       Filename of the file to serve as the contents of the initial
  *              revision.  Even if add_vhead is NULL, we use this to determine
  *              the modes to give the new RCS file.
@@ -994,6 +1036,8 @@
  *   desclen    The number of bytes in desctext.
  *   add_logfp  Write errors to here as well as via error (), or NULL if we
  *              should use only error ().
+ *   do_killnew        Mark newly-imported files as being dead on the trunk, 
i.e.,
+ *             as being imported only to the vendor branch.
  *
  * RETURNS
  *   Return value is 0 for success, or nonzero for failure (in which
@@ -1004,7 +1048,7 @@
               const char *add_vhead, const char *key_opt,
               const char *add_vbranch, const char *vtag, int targc,
               char **targv, const char *desctext, size_t desclen,
-              FILE *add_logfp)
+              FILE *add_logfp, int do_killnew)
 {
     FILE *fprcs, *fpuser;
     struct stat sb;
@@ -1018,10 +1062,39 @@
     const char *userfile;
     char *free_opt = NULL;
     mode_t file_type;
+    char *dead_revision = NULL;
 
     if (noexec)
        return (0);
 
+    if (do_killnew)
+    {
+       char *last_place;
+       int last_number;
+
+       /* If we are marking the newly imported file as dead, we must
+          have a head revision.  */
+       if (add_vhead == NULL)
+           error (1, 0, "killing new file attempted when no head revision is 
being added");
+
+       /* One extra byte for NUL, plus one for carry generated by adding
+          one to the last number in the add_vhead revision.  */
+       dead_revision = xmalloc (strlen (add_vhead) + 2);
+       strcpy (dead_revision, add_vhead);
+
+       /* Find the loacation of the last number, which we will increment
+          and overwrite.  Note that this handles single numbers (w/o
+          dots), which is probably unnecessary.  */
+       if ((last_place = strrchr (dead_revision, '.')) != NULL)
+           last_place++;
+       else
+           last_place = dead_revision;
+       last_number = atoi (last_place);
+       if (++last_number <= 0)
+         error (1, 0, "invalid revision number %s", add_vhead);
+       sprintf (last_place, "%d", last_number);
+    }
+
     /* Note that as the code stands now, the -k option overrides any
        settings in wrappers (whether CVSROOT/cvswrappers, -W, or
        whatever).  Some have suggested this should be the other way
@@ -1097,7 +1170,8 @@
      */
     if (add_vhead != NULL)
     {
-       if (fprintf (fprcs, "head     %s;\012", add_vhead) < 0)
+       if (fprintf (fprcs, "head     %s;\012",
+                    do_killnew ? dead_revision : add_vhead) < 0)
            goto write_error;
     }
     else
@@ -1106,7 +1180,10 @@
            goto write_error;
     }
 
-    if (add_vbranch != NULL)
+    /* This sets the default branch.  If using the 'do_killnew' functionality,
+       where imports don't show up until merged, no default branch should
+       be set.  */
+    if (add_vbranch != NULL && ! do_killnew)
     {
        if (fprintf (fprcs, "branch   %s;\012", add_vbranch) < 0)
            goto write_error;
@@ -1153,19 +1230,43 @@
 
     /* Write the revision(s), with the date and author and so on
        (that is "delta" rather than "deltatext" from rcsfile(5)).  */
+
+    if (use_file_modtime)
+       now = sb.st_mtime;
+    else
+       (void) time (&now);
+    ftm = gmtime (&now);
+    (void) sprintf (altdate1, DATEFORM,
+                   ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+                   ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
+                   ftm->tm_min, ftm->tm_sec);
+    author = getcaller ();
+
+    if (do_killnew)
+    {
+       if (fprintf (fprcs, "\012%s\012", dead_revision) < 0 ||
+       fprintf (fprcs, "date     %s;  author %s;  state %s;\012",
+                altdate1, author, RCSDEAD) < 0)
+       goto write_error;
+
+       if (fprintf (fprcs, "branches;\012") < 0)
+           goto write_error;
+       if (fprintf (fprcs, "next    %s;\012", add_vhead) < 0)
+           goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+       /* Store initial permissions if necessary. */
+       if (preserve_perms)
+       {
+           if (preserve_initial_permissions (fprcs, userfile,
+                                             file_type, sbp))
+               goto write_error;
+       }
+#endif
+    }
+
     if (add_vhead != NULL)
     {
-       if (use_file_modtime)
-           now = sb.st_mtime;
-       else
-           (void) time (&now);
-       ftm = gmtime (&now);
-       (void) sprintf (altdate1, DATEFORM,
-                       ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
-                       ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
-                       ftm->tm_min, ftm->tm_sec);
-       author = getcaller ();
-
        if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
        fprintf (fprcs, "date     %s;  author %s;  state Exp;\012",
                 altdate1, author) < 0)
@@ -1188,48 +1289,9 @@
        /* Store initial permissions if necessary. */
        if (preserve_perms)
        {
-           if (file_type == S_IFLNK)
-           {
-               char *link = xreadlink (userfile);
-               if (fprintf (fprcs, "symlink\t@") < 0 ||
-                   expand_at_signs (link, strlen (link), fprcs) < 0 ||
-                   fprintf (fprcs, "@;\012") < 0)
-                   goto write_error;
-               free (link);
-           }
-           else
-           {
-               if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
-                   goto write_error;
-               if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
-                   goto write_error;
-               if (fprintf (fprcs, "permissions\t%o;\012",
-                            sb.st_mode & 07777) < 0)
-                   goto write_error;
-               switch (file_type)
-               {
-                   case S_IFREG: break;
-                   case S_IFCHR:
-                   case S_IFBLK:
-#ifdef HAVE_STRUCT_STAT_ST_RDEV
-                       if (fprintf (fprcs, "special\t%s %lu;\012",
-                                    (file_type == S_IFCHR
-                                     ? "character"
-                                     : "block"),
-                                    (unsigned long) sb.st_rdev) < 0)
-                           goto write_error;
-#else
-                       error (0, 0,
-"can't import %s: unable to import device files on this system",
-userfile);
-#endif
-                       break;
-                   default:
-                       error (0, 0,
-                              "can't import %s: unknown kind of special file",
-                              userfile);
-               }
-           }
+           if (preserve_initial_permissions (fprcs, userfile,
+                                             file_type, sbp))
+               goto write_error;
        }
 #endif
 
@@ -1246,47 +1308,9 @@
            /* Store initial permissions if necessary. */
            if (preserve_perms)
            {
-               if (file_type == S_IFLNK)
-               {
-                   char *link = xreadlink (userfile);
-                   if (fprintf (fprcs, "symlink\t@") < 0 ||
-                       expand_at_signs (link, strlen (link), fprcs) < 0 ||
-                       fprintf (fprcs, "@;\012") < 0)
-                       goto write_error;
-                   free (link);
-               }
-               else
-               {
-                   if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
-                       fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
-                       fprintf (fprcs, "permissions\t%o;\012",
-                                sb.st_mode & 07777) < 0)
-                       goto write_error;
-           
-                   switch (file_type)
-                   {
-                       case S_IFREG: break;
-                       case S_IFCHR:
-                       case S_IFBLK:
-#ifdef HAVE_STRUCT_STAT_ST_RDEV
-                           if (fprintf (fprcs, "special\t%s %lu;\012",
-                                        (file_type == S_IFCHR
-                                         ? "character"
-                                         : "block"),
-                                        (unsigned long) sb.st_rdev) < 0)
-                               goto write_error;
-#else
-                           error (0, 0,
-"can't import %s: unable to import device files on this system",
-userfile);
-#endif
-                           break;
-                       default:
-                           error (0, 0,
-                             "cannot import %s: special file of unknown type",
-                              userfile);
-                   }
-               }
+               if (preserve_initial_permissions (fprcs, userfile,
+                                                 file_type, sbp))
+                   goto write_error;
            }
 #endif
 
@@ -1312,6 +1336,29 @@
 
     /* Now write the log messages and contents for the revision(s) (that
        is, "deltatext" rather than "delta" from rcsfile(5)).  */
+
+    if (do_killnew)
+    {
+       if (fprintf (fprcs, "\012%s\012", dead_revision) < 0 ||
+           fprintf (fprcs, "log\012@") < 0)
+           goto write_error;
+       if (fprintf (fprcs, "Revision %s was added on the vendor branch.\012",
+                    add_vhead) < 0)
+           goto write_error;
+       if (fprintf (fprcs, "@\012") < 0 ||
+           fprintf (fprcs, "text\012@") < 0)
+       {
+           goto write_error;
+       }
+
+       /* Now copy over the contents of the file, expanding at signs.  */
+       if (expand_and_copy_contents (fprcs, file_type, user, fpuser))
+           goto write_error;
+
+       if (fprintf (fprcs, "@\012\012") < 0)
+           goto write_error;
+    }
+
     if (add_vhead != NULL)
     {
        if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
@@ -1338,27 +1385,17 @@
 
        /* Now copy over the contents of the file, expanding at signs.
           If preserve_perms is set, do this only for regular files. */
-       if (!preserve_perms || file_type == S_IFREG)
+       if (! do_killnew)
        {
-           char buf[8192];
-           unsigned int len;
-
-           while (1)
-           {
-               len = fread (buf, 1, sizeof buf, fpuser);
-               if (len == 0)
-               {
-                   if (ferror (fpuser))
-                       error (1, errno, "cannot read file %s for copying",
-                              user);
-                   break;
-               }
-               if (expand_at_signs (buf, len, fprcs) < 0)
-                   goto write_error;
-           }
+            /* Now copy over the contents of the file, expanding at signs,
+              if not done as part of do_killnew handling above.  */
+           if (expand_and_copy_contents (fprcs, file_type, user, fpuser))
+               goto write_error;
        }
+
        if (fprintf (fprcs, "@\012\012") < 0)
            goto write_error;
+
        if (add_vbranch != NULL)
        {
            if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
@@ -1439,7 +1476,127 @@
     return (err + 1);
 }
 
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+/* Write file permissions and symlink information for a file being
+ * added into its RCS file.
+ *
+ * INPUTS
+ *   fprcs     FILE pointer for the (newly-created) RCS file.  Permisisons
+ *             and symlink information should be written here.
+ *   userfile  Filename of the file being added.  (Used to read symbolic
+ *             link contents, for symlinks.)
+ *   file_type File type of userfile, extracted from sbp->st_mode.
+ *   sbp       'stat' information for userfile.
+ *
+ * RETURNS
+ *   Return value is 0 for success, or nonzero for failure (in which case
+ *   no error message has yet been printed).
+ */
+static int
+preserve_initial_permissions (fprcs, userfile, file_type, sbp)
+    FILE *fprcs;
+    const char *userfile;
+    mode_t file_type;
+    struct stat *sbp;
+{
+    if (file_type == S_IFLNK)
+    {
+       char *link = xreadlink (userfile);
+       if (fprintf (fprcs, "symlink\t@") < 0 ||
+           expand_at_signs (link, strlen (link), fprcs) < 0 ||
+           fprintf (fprcs, "@;\012") < 0)
+           goto write_error;
+       free (link);
+    }
+    else
+    {
+       if (fprintf (fprcs, "owner\t%u;\012", sbp->st_uid) < 0)
+           goto write_error;
+       if (fprintf (fprcs, "group\t%u;\012", sbp->st_gid) < 0)
+           goto write_error;
+       if (fprintf (fprcs, "permissions\t%o;\012",
+                    sbp->st_mode & 07777) < 0)
+           goto write_error;
+       switch (file_type)
+       {
+           case S_IFREG: break;
+           case S_IFCHR:
+           case S_IFBLK:
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+               if (fprintf (fprcs, "special\t%s %lu;\012",
+                            (file_type == S_IFCHR
+                             ? "character"
+                             : "block"),
+                            (unsigned long) sbp->st_rdev) < 0)
+                   goto write_error;
+#else
+               error (0, 0,
+"can't import %s: unable to import device files on this system",
+userfile);
+#endif
+               break;
+           default:
+               error (0, 0,
+                      "can't import %s: unknown kind of special file",
+                      userfile);
+       }
+    }
+    return 0;
+
+write_error:
+    return 1;
+}
+#endif /* PRESERVE_PERMISSIONS_SUPPORT */
+
+/* Copy file contents into an RCS file, expanding at signs.
+ *
+ * If preserve_perms is set, nothing is copied if the source is not
+ * a regular file.
+ *
+ * INPUTS
+ *   fprcs     FILE pointer for the (newly-created) RCS file.  The expanded
+ *             contents should be written here.
+ *   file_type File type of the data source.  No data is copied if
+ *             preserve_permissions is set and the source is not a
+ *             regular file.
+ *   user      Filename of the data source (used to print error messages).
+ *   fpuser    FILE pointer for the data source, whose data is being
+ *             copied into the RCS file.
+ *
+ * RETURNS
+ *   Return value is 0 for success, or nonzero for failure (in which case
+ *   no error message has yet been printed).
+ */
+static int
+expand_and_copy_contents (fprcs, file_type, user, fpuser)
+    FILE *fprcs, *fpuser;
+    mode_t file_type;
+    const char *user;
+{
+    if (!preserve_perms || file_type == S_IFREG)
+    {
+       char buf[8192];
+       unsigned int len;
+
+       while (1)
+       {
+           len = fread (buf, 1, sizeof buf, fpuser);
+           if (len == 0)
+           {
+               if (ferror (fpuser))
+                   error (1, errno, "cannot read file %s for copying",
+                          user);
+               break;
+           }
+           if (expand_at_signs (buf, len, fprcs) < 0)
+               goto write_error;
+       }
+    }
+    return 0;
 
+write_error:
+    return 1;
+}
 
 /*
  * Write SIZE bytes at BUF to FP, expanding @ signs into double @
Index: cvs/src/mkmodules.c
diff -u cvs/src/mkmodules.c:1.1.1.1 cvs/src/mkmodules.c:1.4
--- cvs/src/mkmodules.c:1.1.1.1 Wed Jun 23 21:34:12 2004
+++ cvs/src/mkmodules.c Wed Jun 23 21:39:25 2004
@@ -961,7 +961,7 @@
                                    /* No vendor branch.  */
                                    NULL, NULL, 0, NULL,
 
-                                   NULL, 0, NULL);
+                                   NULL, 0, NULL, 0);
            if (retcode != 0)
                /* add_rcs_file already printed an error message.  */
                err = 1;
Index: cvs/src/rcs.h
diff -u cvs/src/rcs.h:1.1.1.1 cvs/src/rcs.h:1.4
--- cvs/src/rcs.h:1.1.1.1       Wed Jun 23 21:34:12 2004
+++ cvs/src/rcs.h       Wed Jun 23 21:39:25 2004
@@ -248,4 +248,4 @@
 extern int add_rcs_file (const char *, const char *, const char *,
                          const char *, const char *, const char *,
                          const char *, int, char **, const char *, size_t,
-                         FILE *);
+                         FILE *, int);
Index: cvs/src/sanity.sh
diff -u cvs/src/sanity.sh:1.1.1.1 cvs/src/sanity.sh:1.4.2.1
--- cvs/src/sanity.sh:1.1.1.1   Wed Jun 23 21:34:13 2004
+++ cvs/src/sanity.sh   Thu Jun 24 22:35:46 2004
@@ -1061,7 +1061,8 @@
        tests="${tests} rm-update-message rmadd rmadd2 rmadd3 resurrection"
        tests="${tests} dirs dirs2 branches branches2 branches3"
        tests="${tests} branches4 tagc tagf"
-       tests="${tests} rcslib multibranch import importb importc import-CVS"
+       tests="${tests} rcslib multibranch import importb importc importX"
+       tests="${tests} import-CVS"
        tests="${tests} update-p import-after-initial branch-after-import"
        tests="${tests} join join2 join3 join4 join5 join6"
        tests="${tests} join-readonly-conflict join-admin join-admin-2"
@@ -7886,6 +7887,7 @@
                # import  -- more tests of imports with keywords
                # importb  -- -b option.
                # importc -- bunch o' files in bunch o' directories
+               # importX  -- -X option.
                # modules3
                # mflag -- various -m messages
                # ignore  -- import and cvsignore
@@ -8339,6 +8341,149 @@
 
 
 
+       importX)
+         # More cvs import tests, especially -X option.
+
+         # OK, first we get some sources from the Munger version 0.9,
+         # and import them into the 1.1.1 vendor branch (w/o -X).  (This
+         # will be used to test subsequent imports of the same file
+         # with -X.)
+         mkdir imp-dir
+         cd imp-dir
+         echo 'Munger sources 0.9' >file0
+         dotest_sort importX-1 \
+"${testcvs} import -m add first-dir munger munger-0_9" \
+"
+
+N first-dir/file0
+No conflicts created by this import"
+         cd ..
+         rm -r imp-dir
+
+         # Now we put the sources we get from Munger version 1.0 on
+         # to the 1.1.1 vendor branch using -X.  (This imports a new
+         # version of file0, and imports all-new files file1 and file2.)
+         mkdir imp-dir
+         cd imp-dir
+         echo 'Munger sources' >file0
+         echo 'Munger sources' >file1
+         echo 'Munger sources' >file2
+         dotest_sort importX-2 \
+"${testcvs} import -X -m add first-dir munger munger-1_0" \
+"
+
+
+ ${CPROG} checkout -j<prev_rel_tag> -jmunger-1_0 first-dir
+N first-dir/file1
+N first-dir/file2
+No conflicts created by this import.
+U first-dir/file0
+Use the following command to help the merge:"
+         cd ..
+         rm -r imp-dir
+
+         # Now we put the sources we get from Munger version 1.1 on
+         # to the 1.1.1 vendor branch using -X.  (This imports unchanged
+         # versions of file0 and file2, a changed version of file1, and
+         # an all-new file3.)
+         mkdir imp-dir
+         cd imp-dir
+         echo 'Munger sources' >file0
+         echo 'Munger sources 1.1' >file1
+         echo 'Munger sources' >file2
+         echo 'Munger sources 1.1' >file3
+         dotest_sort importX-3 \
+"${testcvs} -d ${CVSROOT} import -X -m add first-dir munger munger-1_1" \
+"
+
+
+ ${CPROG} -d ${CVSROOT} checkout -j<prev_rel_tag> -jmunger-1_1 first-dir
+1 conflicts created by this import.
+C first-dir/file1
+N first-dir/file3
+U first-dir/file0
+U first-dir/file2
+Use the following command to help the merge:"
+         cd ..
+         rm -r imp-dir
+
+         mkdir 1
+         cd 1
+         # only file0 should be checked out
+         dotest importX-4 "${testcvs} -q co first-dir" \
+"U first-dir/file0"
+         cd first-dir
+
+         dotest importX-5 "${testcvs} -q log file0" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/file0,v
+Working file: file0
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+       munger-1_1: 1\.1\.1\.2
+       munger-1_0: 1\.1\.1\.2
+       munger-0_9: 1\.1\.1\.1
+       munger: 1\.1\.1
+keyword substitution: kv
+total revisions: 3;    selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE};  author: ${username};  state: Exp;
+branches:  1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.2
+date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1
+add
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0
+add
+============================================================================="
+
+         dotest importX-6 "${testcvs} -q log file1" "
+RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
+Working file: file1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+       munger-1_1: 1\.1\.1\.2
+       munger-1_0: 1\.1\.1\.1
+       munger: 1\.1\.1
+keyword substitution: kv
+total revisions: 4;    selected revisions: 4
+description:
+----------------------------
+revision 1\.2
+date: ${ISO8601DATE};  author: ${username};  state: dead;  lines: ${PLUS}0 -0
+Revision 1\.1 was added on the vendor branch\.
+----------------------------
+revision 1\.1
+date: ${ISO8601DATE};  author: ${username};  state: Exp;
+branches:  1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.2
+date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1
+add
+----------------------------
+revision 1\.1\.1\.1
+date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0
+add
+============================================================================="
+
+         cd ../..
+         rm -r 1
+         rm -rf ${CVSROOT_DIRNAME}/first-dir
+         ;;
+
+
+
        import-CVS)
          mkdir import-CVS
          cd import-CVS





reply via email to

[Prev in Thread] Current Thread [Next in Thread]