Fossil

Check-in [72fdb21ae8]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Refactored unaddremove into (add|rm|addremove --reset).
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | unaddremove-command
Files: files | file ages | folders
SHA3-256: 72fdb21ae8cffc16ce8239cfa3c766e009f2ff4c09bb76eb11741be990903819
User & Date: stephan 2020-04-23 11:30:52.865
Context
2020-04-23
13:49
Added --dry-run support to add/rm/addremove --reset. ... (check-in: a7a75e7d41 user: stephan tags: unaddremove-command)
11:30
Refactored unaddremove into (add|rm|addremove --reset). ... (check-in: 72fdb21ae8 user: stephan tags: unaddremove-command)
00:06
Pedantic cosmetic change: do un-rm before un-add. ... (check-in: 6e21c7d706 user: stephan tags: unaddremove-command)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/add.c.
238
239
240
241
242
243
244
















































































245
246
247
248
249
250
251
    if( zReserved ) continue;
    nAdd += add_one_file(zToAdd, vid);
  }
  db_finalize(&loop);
  blob_reset(&repoName);
  return nAdd;
}

















































































/*
** COMMAND: add
**
** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
**
** Make arrangements to add one or more files or directories to the







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
    if( zReserved ) continue;
    nAdd += add_one_file(zToAdd, vid);
  }
  db_finalize(&loop);
  blob_reset(&repoName);
  return nAdd;
}

/*
** Resets the ADD/REMOVE state of a checkout, such that all newly-added
** (but not yet committed) files are no longer added and newly-removed
** (but not yet committed) files are no longer removed. If fIsAdd is true,
** it operates on the "add" state, else it operates on the "rm" state.
**
** If fVerbose is true it outputs the name of each reset entry.
**
** This is intended to be called only in the context of the add/rm
** commands, after the call to verify_all_options().
**
** Un-added files are not modified but any un-rm'd files which are
** missing from the checkout are restored from the repo. un-rm'd files
** which exist in the checkout are left as-is, rather than restoring
** them using vfile_to_disk(), to avoid overwriting any local changes
** made to those files.
*/
static void addremove_reset(int fIsAdd, int fVerbose){
  int nReset = 0; /* # of entries which get reset */
  Stmt stmt;      /* vfile loop query */

  db_begin_transaction();
  db_prepare(&stmt, "SELECT id, pathname FROM vfile "
                    "WHERE %s ORDER BY pathname",
                    fIsAdd==0 ? "deleted<>0" : "rid=0"/*safe-for-%s*/);
  while( db_step(&stmt)==SQLITE_ROW ){
    /* This loop exists only so we can restore the contents of un-rm'd
    ** files and support verbose mode. All manipulation of vfile's
    ** contents happens after the loop. For the ADD case in non-verbose
    ** mode we "could" skip this loop entirely.
    */
    int const id = db_column_int(&stmt, 0);
    char const * zPathname = db_column_text(&stmt, 1);
    Blob relName = empty_blob;
    if(fIsAdd==0 || fVerbose!=0){
      /* Make filename relative... */
      char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
      file_relative_name(zFullName, &relName, 0);
      fossil_free(zFullName);
    }
    if(fIsAdd==0){
      /* Restore contents of missing un-rm'd files. We don't do this
      ** unconditionally because we might cause data loss if a file
      ** is modified, rm'd, then un-rm'd.
      */
      ++nReset;
      if(!file_isfile_or_link(blob_str(&relName))){
        vfile_to_disk(0, id, 0, 0);
      }
      /* *Potential* corner case: relName refers to a directory,
      ** meaning the user rm'd the file and replaced it with a
      ** directory. In that case, vfile_to_disk() will fail fatally,
      ** which is arguably the best course of action.
      */
      if(fVerbose){
        fossil_print("Un-removed: %b\n", &relName);
      }
    }else{
      /* un-add... */
      ++nReset;
      if(fVerbose){
        fossil_print("Un-added: %b\n", &relName);
      }
    }
    blob_reset(&relName);
  }
  db_finalize(&stmt);
  if(nReset>0){
    if(fIsAdd==0){
      db_exec_sql("UPDATE vfile SET deleted=0 WHERE deleted<>0");
      fossil_print("Un-removed %d file(s).\n", nReset);
    }else{
      db_exec_sql("DELETE FROM vfile WHERE rid=0");
      fossil_print("Un-added %d file(s).\n", nReset);
    }
  }
  db_end_transaction(0);
}


/*
** COMMAND: add
**
** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
**
** Make arrangements to add one or more files or directories to the
274
275
276
277
278
279
280






281
282
283
284
285
286
287
288
289
290
291
292








293
294
295
296
297
298
299
**    --case-sensitive <BOOL> Override the case-sensitive setting.
**    --dotfiles              include files beginning with a dot (".")
**    -f|--force              Add files without prompting
**    --ignore <CSG>          Ignore unmanaged files matching patterns from
**                            the comma separated list of glob patterns.
**    --clean <CSG>           Also ignore files matching patterns from
**                            the comma separated list of glob patterns.






**
** See also: addremove, rm
*/
void add_cmd(void){
  int i;                     /* Loop counter */
  int vid;                   /* Currently checked out version */
  int nRoot;                 /* Full path characters in g.zLocalRoot */
  const char *zCleanFlag;    /* The --clean option or clean-glob setting */
  const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */
  Glob *pIgnore, *pClean;    /* Ignore everything matching the glob patterns */
  unsigned scanFlags = 0;    /* Flags passed to vfile_scan() */
  int forceFlag;









  zCleanFlag = find_option("clean",0,1);
  zIgnoreFlag = find_option("ignore",0,1);
  forceFlag = find_option("force","f",0)!=0;
  if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;

  /* We should be done with options.. */







>
>
>
>
>
>












>
>
>
>
>
>
>
>







354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
**    --case-sensitive <BOOL> Override the case-sensitive setting.
**    --dotfiles              include files beginning with a dot (".")
**    -f|--force              Add files without prompting
**    --ignore <CSG>          Ignore unmanaged files matching patterns from
**                            the comma separated list of glob patterns.
**    --clean <CSG>           Also ignore files matching patterns from
**                            the comma separated list of glob patterns.
**    --reset                 Reset the ADD state of a checkout, such that
**                            all newly-added (but not yet committed) files
**                            are no longer added. No flags other than
**                            --verbose may be used with --reset.
**    --verbose|-v            Outputs information about each --reset file.
**                            Only usable with --reset.
**
** See also: addremove, rm
*/
void add_cmd(void){
  int i;                     /* Loop counter */
  int vid;                   /* Currently checked out version */
  int nRoot;                 /* Full path characters in g.zLocalRoot */
  const char *zCleanFlag;    /* The --clean option or clean-glob setting */
  const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */
  Glob *pIgnore, *pClean;    /* Ignore everything matching the glob patterns */
  unsigned scanFlags = 0;    /* Flags passed to vfile_scan() */
  int forceFlag;

  if(0!=find_option("reset",0,0)){
    int const verboseFlag = find_option("verbose","v",0)!=0;
    db_must_be_within_tree();
    verify_all_options();
    addremove_reset(1, verboseFlag);
    return;
  }

  zCleanFlag = find_option("clean",0,1);
  zIgnoreFlag = find_option("ignore",0,1);
  forceFlag = find_option("force","f",0)!=0;
  if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;

  /* We should be done with options.. */
440
441
442
443
444
445
446






447
448
449
450
451
452
453
454
455
456








457
458
459
460
461
462
463
**
** Options:
**   --soft                  Skip removing files from the checkout.
**                           This supersedes the --hard option.
**   --hard                  Remove files from the checkout.
**   --case-sensitive <BOOL> Override the case-sensitive setting.
**   -n|--dry-run            If given, display instead of run actions.






**
** See also: addremove, add
*/
void delete_cmd(void){
  int i;
  int removeFiles;
  int dryRunFlag;
  int softFlag;
  int hardFlag;
  Stmt loop;









  dryRunFlag = find_option("dry-run","n",0)!=0;
  softFlag = find_option("soft",0,0)!=0;
  hardFlag = find_option("hard",0,0)!=0;

  /* We should be done with options.. */
  verify_all_options();







>
>
>
>
>
>










>
>
>
>
>
>
>
>







534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
**
** Options:
**   --soft                  Skip removing files from the checkout.
**                           This supersedes the --hard option.
**   --hard                  Remove files from the checkout.
**   --case-sensitive <BOOL> Override the case-sensitive setting.
**   -n|--dry-run            If given, display instead of run actions.
**   --reset                 Reset the DELETED state of a checkout, such
**                           that all newly-rm'd (but not yet committed)
**                           files are no longer removed. No flags other
**                           than --verbose may be used with --reset.
**   --verbose|-v            Outputs information about each --reset file.
**                           Only usable with --reset.
**
** See also: addremove, add
*/
void delete_cmd(void){
  int i;
  int removeFiles;
  int dryRunFlag;
  int softFlag;
  int hardFlag;
  Stmt loop;

  if(0!=find_option("reset",0,0)){
    int const verboseFlag = find_option("verbose","v",0)!=0;
    db_must_be_within_tree();
    verify_all_options();
    addremove_reset(0, verboseFlag);
    return;
  }

  dryRunFlag = find_option("dry-run","n",0)!=0;
  softFlag = find_option("soft",0,0)!=0;
  hardFlag = find_option("hard",0,0)!=0;

  /* We should be done with options.. */
  verify_all_options();
621
622
623
624
625
626
627








628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643













644
645
646
647
648
649
650
**   --case-sensitive <BOOL> Override the case-sensitive setting.
**   --dotfiles              Include files beginning with a dot (".")
**   --ignore <CSG>          Ignore unmanaged files matching patterns from
**                           the comma separated list of glob patterns.
**   --clean <CSG>           Also ignore files matching patterns from
**                           the comma separated list of glob patterns.
**   -n|--dry-run            If given, display instead of run actions.








**
** See also: add, rm
*/
void addremove_cmd(void){
  Blob path;
  const char *zCleanFlag = find_option("clean",0,1);
  const char *zIgnoreFlag = find_option("ignore",0,1);
  unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
  int dryRunFlag = find_option("dry-run","n",0)!=0;
  int n;
  Stmt q;
  int vid;
  int nAdd = 0;
  int nDelete = 0;
  Glob *pIgnore, *pClean;














  if( !dryRunFlag ){
    dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
  }

  /* We should be done with options.. */
  verify_all_options();








>
>
>
>
>
>
>
>





|
|
|
|







>
>
>
>
>
>
>
>
>
>
>
>
>







729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
**   --case-sensitive <BOOL> Override the case-sensitive setting.
**   --dotfiles              Include files beginning with a dot (".")
**   --ignore <CSG>          Ignore unmanaged files matching patterns from
**                           the comma separated list of glob patterns.
**   --clean <CSG>           Also ignore files matching patterns from
**                           the comma separated list of glob patterns.
**   -n|--dry-run            If given, display instead of run actions.
**   --reset                 Reset the ADDED/DELETED state of a checkout,
**                           such that all newly-added (but not yet committed)
**                           files are no longer added and all newly-removed
**                           (but not yet committed) flags are no longer
**                           removed. No flags other than --verbose may be
**                           used with --reset.
**   --verbose|-v            Outputs information about each --reset file.
**                           Only usable with --reset.
**
** See also: add, rm
*/
void addremove_cmd(void){
  Blob path;
  const char *zCleanFlag;
  const char *zIgnoreFlag;
  unsigned scanFlags;
  int dryRunFlag;
  int n;
  Stmt q;
  int vid;
  int nAdd = 0;
  int nDelete = 0;
  Glob *pIgnore, *pClean;

  if(0!=find_option("reset",0,0)){
    int const verboseFlag = find_option("verbose","v",0)!=0;
    db_must_be_within_tree();
    verify_all_options();
    addremove_reset(0, verboseFlag);
    addremove_reset(1, verboseFlag);
    return;
  }

  zCleanFlag = find_option("clean",0,1);
  zIgnoreFlag = find_option("ignore",0,1);
  scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
  dryRunFlag = find_option("dry-run","n",0)!=0;
  if( !dryRunFlag ){
    dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
  }

  /* We should be done with options.. */
  verify_all_options();

709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
  db_finalize(&q);
  /* show command summary */
  fossil_print("added %d files, deleted %d files\n", nAdd, nDelete);

  db_end_transaction(dryRunFlag);
}

/*
** COMMAND: unaddremove*
**
** Resets the ADD/REMOVE state of a checkout, such that all newly-added
** (but not yet committed) files are no longer added and newly-removed
** (but not yet committed) files are no longer removed.
**
** This command does not touch un-added files but restores any un-rm'd
** files which are missing from the checkout.
**
** Options:
**
**    -v|--verbose      Output name of each un-added/un-removed file.
**
*/
void unaddremove_cmd(void){
  int nDeleted = 0; /* # of files which get un-rm'd */
  int nAdded = 0;   /* # of files which get un-added */
  int fVerbose;     /* true if --verbose */
  Stmt stmt;        /* vfile loop query */

  db_must_be_within_tree();
  fVerbose = find_option("verbose", "v", 0)!=0;
  verify_all_options();

  db_begin_transaction();
  db_prepare(&stmt, "SELECT id, rid, deleted, pathname FROM vfile "
                    "ORDER BY deleted=0, pathname");
  while( db_step(&stmt)==SQLITE_ROW ){
    /* This loop exists only so we can restore the contents of un-rm'd
    ** files. All manipulation of vfile's contents happens after the
    ** loop. */
    int const rid = db_column_int(&stmt, 1);
    int const deleted = db_column_int(&stmt, 2);
    if(deleted!=0 || rid==0){
      int const id = db_column_int(&stmt, 0);
      char const * zPathname = db_column_text(&stmt, 3);
      char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
      Blob relName = empty_blob;
      file_relative_name(zFullName, &relName, 0);
      fossil_free(zFullName);
      zFullName = 0;
      if(deleted!=0){
        /* Restore contents of missing un-rm'd files. We don't do this
        ** unconditionally because we might cause data loss if a file
        ** is modified, rm'd, then un-rm'd.
        */
        ++nDeleted;
        if(!file_isfile_or_link(blob_str(&relName))){
          vfile_to_disk(0, id, 0, 0);
        }
        /* *Potential* corner case: relName refers to a directory,
        ** meaning the user rm'd the file and replaced it with a
        ** directory. In that case, vfile_to_disk() will fail fatally,
        ** which is arguably the best course of action.
        */
        if(fVerbose){
          fossil_print("Un-removed: %b\n", &relName);
        }
      }else if(rid==0){
        ++nAdded;
        if(fVerbose){
          fossil_print("Un-added: %b\n", &relName);
        }
      }
      blob_reset(&relName);
    }
  }
  db_finalize(&stmt);
  if(nDeleted>0){
    db_multi_exec("UPDATE vfile SET deleted=0 WHERE deleted<>0");
    fossil_print("Un-removed %d file(s).\n", nDeleted);
  }
  if(nAdded>0){
    db_multi_exec("DELETE FROM vfile WHERE rid=0");
    fossil_print("Un-added %d file(s).\n", nAdded);
  }
  db_end_transaction(0);
}

/*
** Rename a single file.
**
** The original name of the file is zOrig.  The new filename is zNew.
*/
static void mv_one_file(
  int vid,







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







838
839
840
841
842
843
844
















































































845
846
847
848
849
850
851
  db_finalize(&q);
  /* show command summary */
  fossil_print("added %d files, deleted %d files\n", nAdd, nDelete);

  db_end_transaction(dryRunFlag);
}

















































































/*
** Rename a single file.
**
** The original name of the file is zOrig.  The new filename is zNew.
*/
static void mv_one_file(
  int vid,