Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | Enhance the "fossil diff" command so that it accepts directories as arguments and shows diffs on all files contained within those directories. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c46f98055cf49687423e15a134ed1445 |
User & Date: | drh 2015-12-15 20:07:02 |
2015-12-15
| ||
20:18 | Minor fix to the previous "fossil diff" enhancement to avoid unnecessary warnings about directories not being found if the directory does not contain any files that were changed. ... (check-in: b789df4b user: drh tags: trunk) | |
20:07 | Enhance the "fossil diff" command so that it accepts directories as arguments and shows diffs on all files contained within those directories. ... (check-in: c46f9805 user: drh tags: trunk) | |
16:12 | Add the "bisect" query parameter the /timeline. Add the "fossil bisect ui" command that runs "fossil ui -page 'timeline?bisect'". ... (check-in: cbde2cf7 user: drh tags: trunk) | |
Changes to src/diffcmd.c.
36 37 38 39 40 41 42 | #define DIFF_NO_NAME "(unknown)" /* ** Use the "exec-rel-paths" setting and the --exec-abs-paths and ** --exec-rel-paths command line options to determine whether ** certain external commands are executed using relative paths. */ | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #define DIFF_NO_NAME "(unknown)" /* ** Use the "exec-rel-paths" setting and the --exec-abs-paths and ** --exec-rel-paths command line options to determine whether ** certain external commands are executed using relative paths. */ static int determine_exec_relative_option(int force){ static int relativePaths = -1; if( force || relativePaths==-1 ){ int relPathOption = find_option("exec-rel-paths", 0, 0)!=0; int absPathOption = find_option("exec-abs-paths", 0, 0)!=0; #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) relativePaths = db_get_boolean("exec-rel-paths", 1); #else relativePaths = db_get_boolean("exec-rel-paths", 0); #endif if( relPathOption ){ relativePaths = 1; } if( absPathOption ){ relativePaths = 0; } } return relativePaths; } #if INTERFACE /* ** An array of FileDirList objects describe the files and directories listed ** on the command line of a "diff" command. Only those objects listed are ** actually diffed. */ struct FileDirList { int nUsed; /* Number of times each entry is used */ int nName; /* Length of the entry */ char *zName; /* Text of the entry */ }; #endif /* ** Return true if zFile is a file named on the azInclude[] list or is ** a file in a directory named on the azInclude[] list. ** ** if azInclude is NULL, then always include zFile. */ static int file_dir_match(FileDirList *p, const char *zFile){ int i = 0; if( p==0 || strcmp(p->zName,".")==0 ) return 1; if( filenames_are_case_sensitive() ){ while( p->zName ){ if( strcmp(zFile, p->zName)==0 || (strncmp(zFile, p->zName, p->nName)==0 && zFile[p->nName]=='/') ){ break; } p++; } }else{ while( p->zName ){ if( fossil_stricmp(zFile, p->zName)==0 || (fossil_strnicmp(zFile, p->zName, p->nName)==0 && zFile[p->nName]=='/') ){ break; } p++; } } if( p->zName ){ p->nUsed++; return 1; } return 0; } /* ** Print the "Index:" message that patches wants to see at the top of a diff. */ void diff_print_index(const char *zFile, u64 diffFlags){ if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF))==0 ){ char *z = mprintf("Index: %s\n%.66c\n", zFile, '='); |
295 296 297 298 299 300 301 | /* Delete the temporary file and clean up memory used */ file_delete(zTemp1); file_delete(zTemp2); blob_reset(&cmd); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | /* Delete the temporary file and clean up memory used */ file_delete(zTemp1); file_delete(zTemp2); blob_reset(&cmd); } } /* ** Run a diff between the version zFrom and files on disk. zFrom might ** be NULL which means to simply show the difference between the edited ** files on disk and the check-out on which they are based. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_against_disk( const char *zFrom, /* Version to difference from */ const char *zDiffCmd, /* Use this diff command. NULL for built-in */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Treat file names matching this as binary */ u64 diffFlags, /* Flags controlling diff output */ FileDirList *pFileDir /* Which files to diff */ ){ int vid; Blob sql; Stmt q; int asNewFile; /* Treat non-existant files as empty files */ asNewFile = (diffFlags & DIFF_VERBOSE)!=0; |
408 409 410 411 412 413 414 415 416 417 418 419 420 421 | int isNew = db_column_int(&q,3); int srcid = db_column_int(&q, 4); int isLink = db_column_int(&q, 5); const char *zFullName; int showDiff = 1; Blob fname; if( determine_exec_relative_option(0) ){ blob_zero(&fname); file_relative_name(zPathname, &fname, 1); }else{ blob_set(&fname, g.zLocalRoot); blob_append(&fname, zPathname, -1); } | > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | int isNew = db_column_int(&q,3); int srcid = db_column_int(&q, 4); int isLink = db_column_int(&q, 5); const char *zFullName; int showDiff = 1; Blob fname; if( !file_dir_match(pFileDir, zPathname) ) continue; if( determine_exec_relative_option(0) ){ blob_zero(&fname); file_relative_name(zPathname, &fname, 1); }else{ blob_set(&fname, g.zLocalRoot); blob_append(&fname, zPathname, -1); } |
461 462 463 464 465 466 467 | } blob_reset(&fname); } db_finalize(&q); db_end_transaction(1); /* ROLLBACK */ } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | } blob_reset(&fname); } db_finalize(&q); db_end_transaction(1); /* ROLLBACK */ } /* ** Run a diff between the undo buffer and files on disk. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_against_undo( const char *zDiffCmd, /* Use this diff command. NULL for built-in */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Treat file names matching this as binary */ u64 diffFlags, /* Flags controlling diff output */ FileDirList *pFileDir /* List of files and directories to diff */ ){ Stmt q; Blob content; db_prepare(&q, "SELECT pathname, content FROM undo"); blob_init(&content, 0, 0); while( db_step(&q)==SQLITE_ROW ){ char *zFullName; const char *zFile = (const char*)db_column_text(&q, 0); if( !file_dir_match(pFileDir, zFile) ) continue; zFullName = mprintf("%s%s", g.zLocalRoot, zFile); db_column_blob(&q, 1, &content); diff_file(&content, 0, zFullName, zFile, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); fossil_free(zFullName); blob_reset(&content); } db_finalize(&q); } /* ** Show the difference between two files identified by ManifestFile ** entries. ** ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** |
632 633 634 635 636 637 638 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ | | | > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the ** command zDiffCmd to do the diffing. ** ** When using an external diff program, zBinGlob contains the GLOB patterns ** for file names to treat as binary. If fIncludeBinary is zero, these files ** will be skipped in addition to files that may contain binary content. */ static void diff_two_versions( const char *zFrom, const char *zTo, const char *zDiffCmd, const char *zBinGlob, int fIncludeBinary, u64 diffFlags, FileDirList *pFileDir ){ Manifest *pFrom, *pTo; ManifestFile *pFromFile, *pToFile; int asNewFlag = (diffFlags & DIFF_VERBOSE)!=0 ? 1 : 0; pFrom = manifest_get_by_name(zFrom, 0); manifest_file_rewind(pFrom); |
661 662 663 664 665 666 667 | cmp = +1; }else if( pToFile==0 ){ cmp = -1; }else{ cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); } if( cmp<0 ){ | > | | | | > > | | | | > > > | | | | | > | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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 | cmp = +1; }else if( pToFile==0 ){ cmp = -1; }else{ cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); } if( cmp<0 ){ if( file_dir_match(pFileDir, pFromFile->zName) ){ fossil_print("DELETED %s\n", pFromFile->zName); if( asNewFlag ){ diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } } pFromFile = manifest_file_next(pFrom,0); }else if( cmp>0 ){ if( file_dir_match(pFileDir, pToFile->zName) ){ fossil_print("ADDED %s\n", pToFile->zName); if( asNewFlag ){ diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } } pToFile = manifest_file_next(pTo,0); }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ /* No changes */ (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ pFromFile = manifest_file_next(pFrom,0); pToFile = manifest_file_next(pTo,0); }else{ if( file_dir_match(pFileDir, pToFile->zName) ){ if( diffFlags & DIFF_BRIEF ){ fossil_print("CHANGED %s\n", pFromFile->zName); }else{ diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); } } pFromFile = manifest_file_next(pFrom,0); pToFile = manifest_file_next(pTo,0); } } manifest_destroy(pFrom); manifest_destroy(pTo); |
803 804 805 806 807 808 809 810 811 812 813 814 815 816 | ** by the diff subsystem, if any. */ const char *diff_get_binary_glob(void){ const char *zBinGlob = find_option("binary", 0, 1); if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); return zBinGlob; } /* ** COMMAND: diff ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 803 804 805 806 807 808 | ** by the diff subsystem, if any. */ const char *diff_get_binary_glob(void){ const char *zBinGlob = find_option("binary", 0, 1); if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); return zBinGlob; } /* ** The input is a list of file and/or directory names either in the current ** checkout, or in the undo buffer if useUndo is true, or in check-outs ** zFrom and/or zTo if they are not null. Return a new list that consists ** of only filenames. Any directories on the input list are expected into ** multiple files in the output list. The output list uses space obtained ** from malloc() and is NULL terminated. */ static char **diff_expand_dirs( int argc, /* Number of entries in argv[] */ const char **argv, /* List of files and/or directories to be diffed */ const char *zFrom, /* Source check-in name, or NULL */ const char *zTo, /* Target check-in name, or NULL */ int useUndo /* True if diffing against the undo buffer */ ){ Stmt q; int i; db_multi_exec( "CREATE TEMP TABLE dfiles(" " name TEXT PRIMARY KEY," " path TEXT" ") WITHOUT ROWID;" "CREATE TEMP TABLE allowed(" " fn TEXT PRIMARY KEY" ") WITHOUT ROWID;" ); if( useUndo ){ db_multi_exec( "INSERT OR IGNORE INTO allowed(fn)" " SELECT pathname FROM undo INTERSECT SELECT pathname FROM vfile;" ); }else if( zTo ){ } db_prepare(&q, "INSERT OR IGNORE INTO dfiles(names) VALUES(:txt)"); for(i=0; i<argc; i++){ db_bind_text(&q, ":txt", argv[i]); db_step(&q); db_reset(&q); } db_finalize(&q); } /* ** COMMAND: diff ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** |
872 873 874 875 876 877 878 879 880 881 882 883 884 885 | const char *zTo; /* Target version number */ const char *zBranch; /* Branch to diff */ const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ const char *zBinGlob = 0; /* Treat file names matching this as binary */ int fIncludeBinary = 0; /* Include binary files for external diff */ int againstUndo = 0; /* Diff against files in the undo buffer */ u64 diffFlags = 0; /* Flags to control the DIFF */ if( find_option("tk",0,0)!=0 ){ diff_tk("diff", 2); return; } isGDiff = g.argv[1][0]=='g'; isInternDiff = find_option("internal","i",0)!=0; | > | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | const char *zTo; /* Target version number */ const char *zBranch; /* Branch to diff */ const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ const char *zBinGlob = 0; /* Treat file names matching this as binary */ int fIncludeBinary = 0; /* Include binary files for external diff */ int againstUndo = 0; /* Diff against files in the undo buffer */ u64 diffFlags = 0; /* Flags to control the DIFF */ FileDirList *pFileDir = 0; /* Restrict the diff to these files */ if( find_option("tk",0,0)!=0 ){ diff_tk("diff", 2); return; } isGDiff = g.argv[1][0]=='g'; isInternDiff = find_option("internal","i",0)!=0; |
913 914 915 916 917 918 919 920 921 922 923 924 | if( !isInternDiff ){ zDiffCmd = diff_command_external(isGDiff); } zBinGlob = diff_get_binary_glob(); fIncludeBinary = diff_include_binary_files(); determine_exec_relative_option(1); verify_all_options(); if( againstUndo ){ if( db_lget_int("undo_available",0)==0 ){ fossil_print("No undo or redo is available\n"); return; } | > > > > > > > > > > > > > > > > > > < < < | < < < < | < < < < | | < | | | | < | | | < > | < < < > > | | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 | if( !isInternDiff ){ zDiffCmd = diff_command_external(isGDiff); } zBinGlob = diff_get_binary_glob(); fIncludeBinary = diff_include_binary_files(); determine_exec_relative_option(1); verify_all_options(); if( g.argc>=3 ){ int i; Blob fname; pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) ); memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1)); for(i=2; i<g.argc; i++){ file_tree_name(g.argv[i], &fname, 0, 1); pFileDir[i-2].zName = fossil_strdup(blob_str(&fname)); if( strcmp(pFileDir[i-2].zName,".")==0 ){ pFileDir[0].zName[0] = '.'; pFileDir[0].zName[1] = 0; break; } pFileDir[i-2].nName = blob_size(&fname); pFileDir[i-2].nUsed = 0; blob_reset(&fname); } } if( againstUndo ){ if( db_lget_int("undo_available",0)==0 ){ fossil_print("No undo or redo is available\n"); return; } diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, pFileDir); }else if( zTo==0 ){ diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, pFileDir); }else{ diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, pFileDir); } if( pFileDir ){ int i; for(i=0; pFileDir[i].zName; i++){ if( pFileDir[i].nUsed==0 && strcmp(pFileDir[0].zName,".")!=0 ){ fossil_fatal("not found: '%s'", g.argv[i+2]); } fossil_free(pFileDir[i].zName); } fossil_free(pFileDir); } } /* ** WEBPAGE: vpatch ** URL: /vpatch?from=FROM&to=TO ** ** Show a patch that goes from check-in FROM to check-in TO. */ void vpatch_page(void){ const char *zFrom = P("from"); const char *zTo = P("to"); login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( zFrom==0 || zTo==0 ) fossil_redirect_home(); cgi_set_content_type("text/plain"); diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0); } |