Browse Source

support for MOVE command in the whole stack

MOVE is more efficient than COPY + DELETE, especially on COW file systems
Enrico Tassi 6 years ago
parent
commit
bd2e387b02

+ 3
- 2
DESIGN View File

@@ -209,8 +209,9 @@ and bsha to the sha1 sum of its body.
209 209
 - `ADD name hsha bsha` is generated whenever a new mail message is found,
210 210
   and there is no mail message with a different name but the same body.
211 211
 - `COPY name hsha bsha TO newname` is generated if a new message is found,
212
-  that the mailbox contains a copy of it. In case mail has been moved,
213
-  this message is followed by a `DELETE` command.
212
+  and the mailbox contains a copy of it.
213
+- `MOVE name hsha bsha TO newname` is generated if a new message is found,
214
+  and the mailbox does not contain a copy of it but it used do.
214 215
 - `COPYBODY name bsha TO newname newhsha` is generated when a new file is 
215 216
   created, and that file has the same body of an already existent file. 
216 217
   In case mail has been moved, this message is followed by a `DELETE` command.

+ 2
- 1
mddiff.1.txt View File

@@ -3,7 +3,7 @@ NAME
3 3
 SYNOPSIS
4 4
   mddiff [--max-mailno mno] [--db-file dbf] [-l|--list] [-s|--symlink]
5 5
          [--exclude globexpr] [-v|--verbose] [-d|--dry-run] 
6
-         [-n|--no-delete] [--help] [--sha1sum] paths
6
+         [-n|--no-delete] [--no-move] [--help] [--sha1sum] paths
7 7
 DESCRIPTION
8 8
   mddiff computes the delta from an old status of a maildir (previously
9 9
   recorded in a support file, called db file) and the current status, 
@@ -75,6 +75,7 @@ OPTIONS
75 75
   -v --verbose          Increase program verbosity (printed on stderr)
76 76
   -d --dry-run          Do not generate a new db-file
77 77
   -n --no-delete        Do not track deleted files
78
+  --no-move             Do not generate MOVE (only COPY + DELETE)
78 79
   --help                This help screen
79 80
 
80 81
 NOTES

+ 79
- 7
mddiff.c View File

@@ -191,6 +191,7 @@ STATIC int only_mkfifo;
191 191
 STATIC int n_excludes;
192 192
 STATIC char **excludes;
193 193
 STATIC int no_delete;
194
+STATIC int no_move;
194 195
 
195 196
 // ============================ helpers =====================================
196 197
 
@@ -514,6 +515,12 @@ STATIC void load_db(const char* dbname){
514 515
 		txtsha(mail(m)->bsha, tmpbuff_2),\
515 516
 		URLtxt(mail_name(n),tmpbuff_6))
516 517
 
518
+#define COMMAND_MOVE(m,n) \
519
+	fprintf(stdout, "MOVE %s %s %s TO %s\n", URLtxt(mail_name(m),tmpbuff_5),\
520
+		txtsha(mail(m)->hsha, tmpbuff_1),\
521
+		txtsha(mail(m)->bsha, tmpbuff_2),\
522
+		URLtxt(mail_name(n),tmpbuff_6))
523
+
517 524
 #define COMMAND_COPYBODY(m,n) \
518 525
 	fprintf(stdout, "COPYBODY %s %s TO %s %s\n",\
519 526
 		URLtxt(mail_name(m),tmpbuff_5),txtsha(mail(m)->bsha, tmpbuff_1),\
@@ -535,6 +542,46 @@ STATIC void load_db(const char* dbname){
535 542
 		txtsha(mail(m)->bsha,tmpbuff_2), \
536 543
 		txtsha(mail(n)->hsha,tmpbuff_3))
537 544
 
545
+STATIC int is_old_file_still_there(const char* file){
546
+	int fd;
547
+	struct stat sb;
548
+	mail_t alias, m;
549
+
550
+	m = alloc_mail();
551
+	snprintf(next_name(), MAX_EMAIL_NAME_LEN,"%s",file);
552
+	set_mail_name(m,alloc_name());
553
+
554
+	fd = open_rdonly_noatime(mail_name(m));
555
+	if (fd == -1) {
556
+			goto err_alloc_cleanup;
557
+	}
558
+	if (fstat(fd, &sb) == -1) {
559
+			goto err_alloc_fd_cleanup;
560
+	}
561
+
562
+	alias = MAIL(g_hash_table_lookup(filename2mail,GPTR(m)));
563
+
564
+	if (alias != 0 && lastcheck >= sb.st_mtime) {
565
+		// we cache that it has been seen already
566
+		mail(alias)->seen=SEEN;
567
+
568
+		close(fd);
569
+		dealloc_name();
570
+		dealloc_mail();
571
+
572
+		return 1;
573
+	}
574
+
575
+err_alloc_fd_cleanup:
576
+	close(fd);
577
+
578
+err_alloc_cleanup:
579
+	dealloc_name();
580
+	dealloc_mail();
581
+
582
+	return 0;
583
+}
584
+
538 585
 // the heart
539 586
 STATIC void analyze_file(const char* dir,const char* file) {    
540 587
 	unsigned char *addr,*next;
@@ -543,7 +590,7 @@ STATIC void analyze_file(const char* dir,const char* file) {
543 590
 	mail_t alias, m;
544 591
 	GChecksum* ctx;
545 592
 	gsize ctx_len;
546
-	GSList *bodyaliases = NULL;
593
+	GSList *bodyaliases = NULL, *bodyaliases_orig = NULL;
547 594
 
548 595
 	m = alloc_mail();
549 596
 	snprintf(next_name(), MAX_EMAIL_NAME_LEN,"%s/%s",dir,file);
@@ -626,7 +673,7 @@ STATIC void analyze_file(const char* dir,const char* file) {
626 673
 		}
627 674
 	}
628 675
 
629
-	bodyaliases = g_hash_table_lookup(bsha2mail,GPTR(m));
676
+	bodyaliases_orig = bodyaliases = g_hash_table_lookup(bsha2mail,GPTR(m));
630 677
 
631 678
 	// some messages with the same body are there
632 679
 	if (bodyaliases != NULL) {
@@ -635,9 +682,28 @@ STATIC void analyze_file(const char* dir,const char* file) {
635 682
 			mail_t bodyalias = MAIL(bodyaliases->data);
636 683
 			if (hsha_equal(GPTR(bodyalias), GPTR(m))) {
637 684
 				// this one has the same header too
638
-				COMMAND_COPY(bodyalias,m);
639
-				PROMOTE(mail(bodyalias)->seen, NOT_SEEN, MOVED);
640
-				mail(m)->seen=SEEN;
685
+
686
+				// absurd, see the else case
687
+				g_assert(mail(bodyalias)->seen != MOVED || no_move);
688
+				if (mail(bodyalias)->seen == SEEN ||
689
+					is_old_file_still_there(mail_name(bodyalias)) ||
690
+					no_move) {
691
+					// a real copy
692
+					COMMAND_COPY(bodyalias,m);
693
+					PROMOTE(mail(bodyalias)->seen, NOT_SEEN, MOVED);
694
+					mail(m)->seen=SEEN;
695
+				} else {
696
+					// a real move
697
+					COMMAND_MOVE(bodyalias,m);
698
+
699
+					// the new file is the source for such body so that if the
700
+					// file was copied twice and then removed we generate a
701
+					// MOVE x -> y and a COPY y -> z
702
+					g_hash_table_insert(bsha2mail,GPTR(m),
703
+						g_slist_prepend(bodyaliases_orig,GPTR(m)));
704
+					mail(bodyalias)->seen=MOVED;
705
+					mail(m)->seen=SEEN;
706
+				}
641 707
 				return;
642 708
 			}
643 709
 		}
@@ -742,10 +808,11 @@ STATIC void generate_deletions(){
742 808
 	size_t m;
743 809
 
744 810
 	for(m=1; m < mailno; m++){
745
-		if (!no_delete && (mail(m)->seen == NOT_SEEN || mail(m)->seen == MOVED))
811
+		if (!no_delete &&
812
+			(mail(m)->seen == NOT_SEEN || (no_move && mail(m)->seen == MOVED)))
746 813
 			// normally moved or removed mails are deleted
747 814
 			COMMAND_DELETE(m);
748
-		else if (no_delete && mail(m)->seen == MOVED)
815
+		else if (no_delete && no_move && mail(m)->seen == MOVED)
749 816
 			// if --no-delete only moved mails should be deleted
750 817
 			COMMAND_DELETE(m);
751 818
 		else 
@@ -854,6 +921,7 @@ STATIC void extra_sha1sum_file(const char* file) {
854 921
 #define OPT_SHA1SUM    303
855 922
 #define OPT_MKDIRP     304
856 923
 #define OPT_MKFIFO     305
924
+#define OPT_NOMOVE     306
857 925
 
858 926
 // command line options
859 927
 STATIC struct option long_options[] = {
@@ -868,6 +936,7 @@ STATIC struct option long_options[] = {
868 936
 	{"verbose"   , no_argument      , NULL, 'v'},
869 937
 	{"dry-run"   , no_argument      , NULL, 'd'},
870 938
 	{"no-delete" , no_argument      , NULL, 'n'},
939
+	{"no-move"   , no_argument      , NULL, OPT_NOMOVE},
871 940
 	{"help"      , no_argument      , NULL, 'h'},
872 941
 	{NULL        , no_argument      , NULL, 0},
873 942
 };
@@ -970,6 +1039,9 @@ int main(int argc, char *argv[]) {
970 1039
 			case OPT_MKFIFO:
971 1040
 				only_mkfifo = 1;
972 1041
 			break;
1042
+			case OPT_NOMOVE:
1043
+				no_move = 1;
1044
+			break;
973 1045
 			case 'v':
974 1046
 				verbose = 1;
975 1047
 			break;

+ 97
- 8
smd-client View File

@@ -265,7 +265,8 @@ function execute_copy(name_src, hsha, bsha, name_tgt)
265 265
 	local ex_src, hsha_src, bsha_src = exists_and_sha(name_src)
266 266
 	local ex_tgt, hsha_tgt, bsha_tgt = exists_and_sha(name_tgt)
267 267
 	if ex_src and ex_tgt then
268
-		if hsha_src == hsha_tgt and bsha_src == bsha_tgt then
268
+		if hsha_src == hsha_tgt and bsha_src == bsha_tgt and
269
+		   hsha_src == hsha and bsha_src == bsha then
269 270
 			return (trace(true)) -- skip copy, already there
270 271
 		else
271 272
 			log_error('Failed to copy '..name_src..' to '..name_tgt)
@@ -292,7 +293,7 @@ function execute_copy(name_src, hsha, bsha, name_tgt)
292 293
 				else
293 294
 					ok = 0 -- we do not copy for real (--dry-run)
294 295
 				end
295
-				if ok == 0 then 
296
+				if ok == 0 then
296 297
 					return (trace(true)) -- copy successful
297 298
 				else 
298 299
 					log_error('Failed to copy '..name_src..' to '..name_tgt..
@@ -303,7 +304,7 @@ function execute_copy(name_src, hsha, bsha, name_tgt)
303 304
 					return (trace(false)) -- copy failed (cp command failed)
304 305
 				end
305 306
 		else
306
-				-- sub-optimal, we may reuse body or header 
307
+				-- sub-optimal, we may reuse body or header
307 308
 				return (get_full_email(name_tgt,hsha,bsha))
308 309
 		end
309 310
 	elseif not ex_src and ex_tgt then
@@ -334,6 +335,84 @@ function execute_copy(name_src, hsha, bsha, name_tgt)
334 335
 	end
335 336
 end
336 337
 
338
+function execute_move(name_src, hsha, bsha, name_tgt)
339
+	local ex_src, hsha_src, bsha_src = exists_and_sha(name_src)
340
+	local ex_tgt, hsha_tgt, bsha_tgt = exists_and_sha(name_tgt)
341
+	if ex_src and ex_tgt then
342
+		if hsha_tgt == hsha and bsha_tgt == bsha then
343
+			-- the target is already in place
344
+			if hsha_src == hsha and bsha_src == bsha then
345
+				return (execute_delete(name_src,hsha,bsha))
346
+			else
347
+				return (trace(true)) -- the source has changes, nothing to do
348
+			end
349
+		else
350
+			log_error('Failed to move '..name_src..' to '..name_tgt)
351
+			log_error('The destination already exists but its content differs.')
352
+			log_error('To fix this problem you have two options:')
353
+			log_error('- rename '..name_tgt..' by hand so that '..name_src)
354
+			log_error('  can be copied without replacing it.')
355
+			log_error('  Executing `cd; mv -n '..quote(name_tgt)..' '..
356
+				quote(tmp_for(name_tgt,false))..'` should work.')
357
+			log_error('- run @@INVERSECOMMAND@@ so that your changes to '..
358
+				name_tgt)
359
+			log_error('  are propagated to the other mailbox')
360
+
361
+			log_tags("move-message","concurrent-mailbox-edit",true,
362
+				mk_act('mv',name_tgt),
363
+				"run(@@INVERSECOMMAND@@ @@ENDPOINT@@)")
364
+			return (trace(false)) -- fail move, already there but !=
365
+		end
366
+	elseif ex_src and not ex_tgt then
367
+		if hsha_src == hsha and bsha_src == bsha then
368
+			local ok, err
369
+			if not dry_run() then
370
+				ok, err = os.rename(name_src,name_tgt)
371
+			else
372
+				ok = true -- we do not move for real (--dry-run)
373
+			end
374
+			if ok then
375
+				return (trace(true)) -- move successful
376
+			else
377
+				log_error('Failed to move '..name_src..' to '..name_tgt..
378
+					' : '..(err or 'unknown error'))
379
+
380
+				log_tags("move-message","bad-directory-permission",true,
381
+					mk_act('display', name_tgt))
382
+				return (trace(false)) -- copy failed (cp command failed)
383
+			end
384
+		else
385
+			-- sub-optimal, we may reuse body or header
386
+			return (get_full_email(name_tgt,hsha,bsha))
387
+		end
388
+	elseif not ex_src and ex_tgt then
389
+		if hsha == hsha_tgt and bsha == bsha_tgt then
390
+			return (trace(true)) -- skip move, already there (and no source)
391
+		else
392
+			log_error('Failed to move '..name_src..' to '..name_tgt)
393
+			log_error('The source file has been locally removed.')
394
+			log_error('The destination file already exists but its '..
395
+				'content differs.')
396
+			log_error('To fix this problem you have two options:')
397
+			log_error('- rename '..name_tgt..' by hand so that '..
398
+				name_src..' can be')
399
+			log_error('  copied without replacing it.')
400
+			log_error('  Executing `cd; mv -n '..quote(name_tgt)..' '..
401
+				quote(tmp_for(name_tgt,false))..'` should work.')
402
+			log_error('- run @@INVERSECOMMAND@@ so that your changes to '..
403
+				name_tgt..' are')
404
+			log_error('  propagated to the other mailbox')
405
+
406
+			log_tags("copy-message","concurrent-mailbox-edit",true,
407
+				mk_act('mv', name_tgt),
408
+				"run(@@INVERSECOMMAND@@ @@ENDPOINT@@)")
409
+			return (trace(false)) -- skip copy, already there and !=, no source
410
+		end
411
+	else
412
+		return (get_full_email(name_tgt,hsha,bsha))
413
+	end
414
+end
415
+
337 416
 function execute_replaceheader(name, hsha, bsha, hsha_new)
338 417
 	if exists(name) then
339 418
 		local hsha_l, bsha_l = sha_file(name)
@@ -367,7 +446,7 @@ function execute_copybody(name, bsha, newname, hsha)
367 446
 			else
368 447
 				ok = 0 -- we do not copy the body for merging (--dry-run)
369 448
 			end
370
-			if ok == 0 then 
449
+			if ok == 0 then
371 450
 				ok = get_header_and_merge(newname,hsha)
372 451
 				if ok then
373 452
 					return (trace(true)) -- copybody OK
@@ -442,21 +521,21 @@ end
442 521
 function execute(cmd)
443 522
 	local opcode = parse(cmd, '^(%S+)')
444 523
 
445
-	if opcode == "ADD" then 
524
+	if opcode == "ADD" then
446 525
 		local name, hsha, bsha = parse(cmd, '^ADD (%S+) (%S+) (%S+)$')
447 526
 		name = url_decode(name)
448 527
 		mkdir_p(name)
449 528
 		return (execute_add(name, hsha, bsha))
450 529
 	end
451 530
 
452
-	if opcode == "DELETE" then 
531
+	if opcode == "DELETE" then
453 532
 		local name, hsha, bsha = parse(cmd, '^DELETE (%S+) (%S+) (%S+)$')
454 533
 		name = url_decode(name)
455 534
 		mkdir_p(name)
456 535
 		return (execute_delete(name, hsha, bsha))
457 536
 	end
458 537
 
459
-	if opcode == "COPY" then 
538
+	if opcode == "COPY" then
460 539
 		local name_src, hsha, bsha, name_tgt = 
461 540
 			parse(cmd, '^COPY (%S+) (%S+) (%S+) TO (%S+)$')
462 541
 		name_src = url_decode(name_src)
@@ -465,6 +544,16 @@ function execute(cmd)
465 544
 		mkdir_p(name_tgt)
466 545
 		return (execute_copy(name_src, hsha, bsha, name_tgt))
467 546
 	end
547
+
548
+	if opcode == "MOVE" then
549
+		local name_src, hsha, bsha, name_tgt =
550
+			parse(cmd, '^MOVE (%S+) (%S+) (%S+) TO (%S+)$')
551
+		name_src = url_decode(name_src)
552
+		name_tgt = url_decode(name_tgt)
553
+		mkdir_p(name_src)
554
+		mkdir_p(name_tgt)
555
+		return (execute_move(name_src, hsha, bsha, name_tgt))
556
+	end
468 557
 	
469 558
 	if opcode == "REPLACEHEADER" then
470 559
 		local name, hsha, bsha, hsha_new = 
@@ -672,7 +761,7 @@ function main()
672 761
 	statistics.xdelta = receive(io.stdin, xdelta)
673 762
 
674 763
 	local rc
675
-	if not dry_run() and apply_xdelta then 
764
+	if not dry_run() and apply_xdelta then
676 765
 		rc = os.execute(XDELTA..' patch '..xdelta..' '..dbfile..' '..newdb)
677 766
 	else
678 767
 		rc = 0 -- the xdelta transmitted with --dry-run is dummy

+ 8
- 1
smd-server View File

@@ -19,6 +19,7 @@ function main()
19 19
 	-- argument parsing
20 20
 	local exclude = {}
21 21
 	local no_delete = false
22
+	local no_move = false
22 23
 	local just_mddiff = false
23 24
 	local stop_after_diff = false
24 25
 	local override_db = nil
@@ -35,6 +36,9 @@ function main()
35 36
 		elseif arg[1] == '-n' or arg[1] == '--no-delete' then
36 37
 			no_delete = true
37 38
 			table.remove(arg,1)
39
+		elseif arg[1] == '--no-move' then
40
+			no_move = true
41
+			table.remove(arg,1)
38 42
 		elseif arg[1] == '--exclude' then
39 43
 			exclude[#exclude + 1] = arg[1]
40 44
 			exclude[#exclude + 1] = arg[2]
@@ -94,11 +98,14 @@ function main()
94 98
 	local mailbox_opt = table.concat(arg,' ')
95 99
 	local no_delete_opt = ''
96 100
 	if no_delete then no_delete_opt = '-n' end
101
+	local no_move_opt = ''
102
+	if no_move then no_move_opt = '--no-move' end
97 103
 	local dry_opt = ''
98 104
 	if dry_run() then dry_opt = '-d' end
99 105
 	local exclude_opt = table.concat(exclude, ' ')
100 106
 	local mddiff = MDDIFF..' '..dry_opt..' '..database_opt..' '..
101
-		exclude_opt..' '..no_delete_opt..' '..mailbox_opt
107
+		exclude_opt..' '..no_delete_opt..' '..no_move_opt..' '..
108
+		mailbox_opt
102 109
 	
103 110
 	-- to call mddiff from another tool with the same cmdline
104 111
 	if just_mddiff then

+ 1
- 1
smd-uniform-names View File

@@ -88,7 +88,7 @@ CHILDSARGS="$ORIG_CHILDARGS --rename-only --override-db ~/$RENAMEDB"
88 88
 CLIENT=$!
89 89
 atexit_kill $CLIENT
90 90
 
91
-CHILDSARGS="$ORIG_CHILDARGS --stop-after-diff --override-db ~/$RENAMEDB"
91
+CHILDSARGS="$ORIG_CHILDARGS --no-move --stop-after-diff --override-db ~/$RENAMEDB"
92 92
 (run_remote_server < $LtS 2> $SL) > $StL  || EXITCODE=1
93 93
 
94 94
 wait $CLIENT || EXITCODE=1 

+ 2
- 5
tests.d/client-server/02-move-mail View File

@@ -9,11 +9,8 @@ msync 2
9 9
 
10 10
 test_eq Mail target/Mail 
11 11
 
12
-X=`grep '^DELETE ' log.s2c | wc -l`
13
-assert $X 1 "missing DELETE in s2c"
14
-
15
-X=`grep '^COPY ' log.s2c | wc -l`
16
-assert $X 1 "missing COPY in s2c"
12
+X=`grep '^MOVE ' log.s2c | wc -l`
13
+assert $X 1 "missing MOVE in s2c"
17 14
 
18 15
 X=`grep '^COMMIT$' log.c2s | wc -l`
19 16
 assert $X 1 "missing COMMIT in c2s"

+ 19
- 0
tests.d/client-server/33-move-fail1 View File

@@ -0,0 +1,19 @@
1
+#!/bin/bash
2
+
3
+
4
+msync 1
5
+
6
+M=Mail/cur/`ls Mail/cur/ | head -n 1`
7
+
8
+mv $M Mail/cur/copied_here
9
+echo -e 'foo\n\nbar' > target/Mail/cur/copied_here
10
+
11
+msync 2
12
+
13
+test_eq target/$M Mail/cur/copied_here
14
+
15
+X=`grep '^MOVE ' log.s2c | wc -l`
16
+assert $X 1 "missing MOVE in s2c"
17
+
18
+X=`grep '^COMMIT$' log.c2s | wc -l`
19
+assert $X 0 "missing COMMIT in c2s"

+ 19
- 0
tests.d/client-server/34-move-fail2 View File

@@ -0,0 +1,19 @@
1
+#!/bin/bash
2
+
3
+
4
+msync 1
5
+
6
+M=Mail/cur/`ls Mail/cur/ | head -n 1`
7
+
8
+mv $M Mail/cur/copied_here
9
+mv target/$M target/Mail/cur/copied_here
10
+
11
+msync 2
12
+
13
+test_eq target/Mail Mail
14
+
15
+X=`grep '^MOVE ' log.s2c | wc -l`
16
+assert $X 1 "missing MOVE in s2c"
17
+
18
+X=`grep '^COMMIT$' log.c2s | wc -l`
19
+assert $X 1 "missing COMMIT in c2s"

+ 18
- 0
tests.d/client-server/35-delete View File

@@ -0,0 +1,18 @@
1
+#!/bin/bash
2
+
3
+
4
+msync 1
5
+
6
+M=Mail/cur/`ls Mail/cur/ | head -n 1`
7
+
8
+rm $M
9
+
10
+msync 2
11
+
12
+test_eq target/Mail Mail
13
+
14
+X=`grep '^DELETE ' log.s2c | wc -l`
15
+assert $X 1 "missing DELETE in s2c"
16
+
17
+X=`grep '^COMMIT$' log.c2s | wc -l`
18
+assert $X 1 "missing COMMIT in c2s"

+ 18
- 0
tests.d/client-server/36-move-fail3 View File

@@ -0,0 +1,18 @@
1
+#!/bin/bash
2
+
3
+
4
+msync 1
5
+
6
+M=Mail/cur/`ls Mail/cur/ | head -n 1`
7
+
8
+mv $M Mail/cur/copied_here
9
+cp target/$M target/Mail/cur/copied_here
10
+sed -i 's/a/z/' target/$M
11
+
12
+msync 2
13
+
14
+X=`grep '^MOVE ' log.s2c | wc -l`
15
+assert $X 1 "missing MOVE in s2c"
16
+
17
+X=`grep '^COMMIT$' log.c2s | wc -l`
18
+assert $X 1 "missing COMMIT in c2s"

+ 9
- 7
tests.d/mddiff/09-no-delete View File

@@ -17,13 +17,15 @@ mv Mail/cur/$MAIL2 Mail/cur/foo
17 17
 
18 18
 mdiff Mail
19 19
 N=`cat log.mddiff | wc -l`
20
-assert $N 3 "too many commands: $N"
21
-N=`cat log.mddiff | grep ^DELETE | wc -l`
22
-assert $N 2 "too few DELETE commands: $N"
20
+assert $N 2 "too many commands: $N"
21
+N=`cat log.mddiff | grep ^DELETE | grep $MAIL1 | wc -l`
22
+assert $N 1 "no DELETE command for $MAIL1"
23 23
 N=`cat log.mddiff | grep ^COPY | wc -l`
24
-assert $N 1 "not 1 COPY command: $N"
24
+assert $N 0 "COPY command"
25
+N=`cat log.mddiff | grep ^MOVE | grep $MAIL2 | wc -l`
26
+assert $N 1 "no MOVE command for $MAIL2"
25 27
 mdiff -n Mail
26 28
 N=`cat log.mddiff | grep ^DELETE | wc -l`
27
-assert $N 1 "too many DELETE commands: $N"
28
-N=`cat log.mddiff | grep ^DELETE | grep $MAIL1 | wc -l`
29
-assert $N 0 "deletes aven if -n"
29
+assert $N 0 "a DELETE command: $N"
30
+N=`cat log.mddiff | grep ^MOVE | grep $MAIL2 | wc -l`
31
+assert $N 1 "no MOVE command for $MAIL2"

+ 27
- 0
tests.d/mddiff/10-move View File

@@ -0,0 +1,27 @@
1
+#!/bin/sh
2
+
3
+mdiff Mail
4
+assert $? 0 "mdiff failed"
5
+
6
+mv db.txt.new db.txt
7
+mv db.txt.mtime.new db.txt.mtime
8
+
9
+ls Mail/cur | head -n 2 > mails
10
+exec 7<mails
11
+read MAIL1 <&7
12
+read MAIL2 <&7
13
+exec 7<&-
14
+
15
+mv Mail/cur/$MAIL1 Mail/cur/foo
16
+cp Mail/cur/$MAIL2 Mail/cur/bar1
17
+mv Mail/cur/$MAIL2 Mail/cur/bar2
18
+
19
+mdiff Mail
20
+N=`cat log.mddiff | wc -l`
21
+assert $N 3 "too many commands: $N"
22
+N=`cat log.mddiff | grep ^DELETE | wc -l`
23
+assert $N 0 "DELETE command"
24
+N=`cat log.mddiff | grep ^COPY | grep Mail/cur/bar1 | wc -l`
25
+assert $N 1 "missing COPY command"
26
+N=`cat log.mddiff | grep ^MOVE | wc -l`
27
+assert $N 2 "wrong number of MOVE command: $N"

+ 25
- 0
tests.d/mddiff/11-move-copy View File

@@ -0,0 +1,25 @@
1
+#!/bin/sh
2
+
3
+mdiff Mail
4
+assert $? 0 "mdiff failed"
5
+
6
+mv db.txt.new db.txt
7
+mv db.txt.mtime.new db.txt.mtime
8
+
9
+ls Mail/cur | head -n 2 > mails
10
+exec 7<mails
11
+read MAIL1 <&7
12
+read MAIL2 <&7
13
+exec 7<&-
14
+
15
+cp Mail/cur/$MAIL2 Mail/cur/bar1
16
+
17
+mdiff Mail
18
+N=`cat log.mddiff | wc -l`
19
+assert $N 1 "too many commands: $N"
20
+N=`cat log.mddiff | grep ^DELETE | wc -l`
21
+assert $N 0 "DELETE command"
22
+N=`cat log.mddiff | grep ^COPY | grep Mail/cur/bar1 | wc -l`
23
+assert $N 1 "missing COPY command"
24
+N=`cat log.mddiff | grep ^MOVE | wc -l`
25
+assert $N 0 "wrong number of MOVE command: $N"

+ 25
- 0
tests.d/mddiff/12-move-nodelete View File

@@ -0,0 +1,25 @@
1
+#!/bin/sh
2
+
3
+mdiff Mail
4
+assert $? 0 "mdiff failed"
5
+
6
+mv db.txt.new db.txt
7
+mv db.txt.mtime.new db.txt.mtime
8
+
9
+ls Mail/cur | head -n 2 > mails
10
+exec 7<mails
11
+read MAIL1 <&7
12
+read MAIL2 <&7
13
+exec 7<&-
14
+
15
+mv Mail/cur/$MAIL2 Mail/cur/bar1
16
+
17
+mdiff --no-delete Mail
18
+N=`cat log.mddiff | wc -l`
19
+assert $N 1 "too many commands: $N"
20
+N=`cat log.mddiff | grep ^DELETE | wc -l`
21
+assert $N 0 "DELETE command"
22
+N=`cat log.mddiff | grep ^COPY | grep Mail/cur/bar1 | wc -l`
23
+assert $N 0 "missing COPY command"
24
+N=`cat log.mddiff | grep ^MOVE | wc -l`
25
+assert $N 1 "wrong number of MOVE command: $N"

+ 26
- 0
tests.d/mddiff/13-move-copy-nomove View File

@@ -0,0 +1,26 @@
1
+#!/bin/sh
2
+
3
+mdiff Mail
4
+assert $? 0 "mdiff failed"
5
+
6
+mv db.txt.new db.txt
7
+mv db.txt.mtime.new db.txt.mtime
8
+
9
+ls Mail/cur | head -n 2 > mails
10
+exec 7<mails
11
+read MAIL1 <&7
12
+read MAIL2 <&7
13
+exec 7<&-
14
+
15
+cp Mail/cur/$MAIL2 Mail/cur/bar0
16
+mv Mail/cur/$MAIL2 Mail/cur/bar1
17
+
18
+mdiff --no-move Mail
19
+N=`cat log.mddiff | wc -l`
20
+assert $N 3 "too many commands: $N"
21
+N=`cat log.mddiff | grep ^DELETE | wc -l`
22
+assert $N 1 "no DELETE command"
23
+N=`cat log.mddiff | grep ^COPY | grep Mail/cur/bar1 | wc -l`
24
+assert $N 1 "missing COPY command"
25
+N=`cat log.mddiff | grep ^MOVE | wc -l`
26
+assert $N 0 "wrong number of MOVE command: $N"

+ 26
- 0
tests.d/mddiff/14-move-copy View File

@@ -0,0 +1,26 @@
1
+#!/bin/sh
2
+
3
+mdiff Mail
4
+assert $? 0 "mdiff failed"
5
+
6
+mv db.txt.new db.txt
7
+mv db.txt.mtime.new db.txt.mtime
8
+
9
+ls Mail/cur | head -n 2 > mails
10
+exec 7<mails
11
+read MAIL1 <&7
12
+read MAIL2 <&7
13
+exec 7<&-
14
+
15
+cp Mail/cur/$MAIL2 Mail/cur/bar0
16
+mv Mail/cur/$MAIL2 Mail/cur/bar1
17
+
18
+mdiff Mail
19
+N=`cat log.mddiff | wc -l`
20
+assert $N 2 "too many commands: $N"
21
+N=`cat log.mddiff | grep ^DELETE | wc -l`
22
+assert $N 0 "DELETE command"
23
+N=`cat log.mddiff | grep ^COPY | grep Mail/cur/bar1 | wc -l`
24
+assert $N 1 "missing COPY command"
25
+N=`cat log.mddiff | grep ^MOVE | wc -l`
26
+assert $N 1 "wrong number of MOVE command: $N"

+ 26
- 0
tests.d/mddiff/15-move-copy-nodelete View File

@@ -0,0 +1,26 @@
1
+#!/bin/sh
2
+
3
+mdiff Mail
4
+assert $? 0 "mdiff failed"
5
+
6
+mv db.txt.new db.txt
7
+mv db.txt.mtime.new db.txt.mtime
8
+
9
+ls Mail/cur | head -n 2 > mails
10
+exec 7<mails
11
+read MAIL1 <&7
12
+read MAIL2 <&7
13
+exec 7<&-
14
+
15
+cp Mail/cur/$MAIL2 Mail/cur/bar0
16
+mv Mail/cur/$MAIL2 Mail/cur/bar1
17
+
18
+mdiff --no-delete Mail
19
+N=`cat log.mddiff | wc -l`
20
+assert $N 2 "too many commands: $N"
21
+N=`cat log.mddiff | grep ^DELETE | wc -l`
22
+assert $N 0 "DELETE command"
23
+N=`cat log.mddiff | grep ^COPY | grep Mail/cur/bar1 | wc -l`
24
+assert $N 1 "missing COPY command"
25
+N=`cat log.mddiff | grep ^MOVE | wc -l`
26
+assert $N 1 "wrong number of MOVE command: $N"

Loading…
Cancel
Save