Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch diffBinExternal Excluding Merge-Ins
This is equivalent to a diff from 97f68e61da to 064afb225a
2012-10-02
| ||
22:59 | Merge the enhancements that adds the "diff-binary" setting for passing binary files to the external diff program. check-in: f8339c2743 user: drh tags: trunk | |
2012-09-30
| ||
09:29 | The 'binary-glob' setting is a versionable project setting and should be listed with the others. check-in: 6ef41eeffe user: mistachkin tags: trunk | |
07:39 | Make sure the new command line options are always processed; however, wait until after the settings are available. Closed-Leaf check-in: 064afb225a user: mistachkin tags: diffBinExternal | |
06:25 | Add support for skipping binary files when using an external diff program. The existing 'binary-glob' setting and new 'diff-binary' boolean setting control this feature. check-in: c50eb50718 user: mistachkin tags: diffBinExternal | |
01:43 | Fix typo in comment. check-in: 97f68e61da user: mistachkin tags: trunk | |
2012-09-29
| ||
14:08 | Make the "--tk" option to the "diff" command also imply the "-i" option to force the use of the internal diff engine. check-in: 5a4fbb0a28 user: drh tags: trunk | |
Changes to src/db.c.
2012 2012 { "auto-shun", 0, 0, 0, "on" }, 2013 2013 { "autosync", 0, 0, 0, "on" }, 2014 2014 { "binary-glob", 0, 32, 1, "" }, 2015 2015 { "clearsign", 0, 0, 0, "off" }, 2016 2016 { "case-sensitive",0, 0, 0, "on" }, 2017 2017 { "crnl-glob", 0, 16, 1, "" }, 2018 2018 { "default-perms", 0, 16, 0, "u" }, 2019 + { "diff-binary", 0, 0, 0, "on" }, 2019 2020 { "diff-command", 0, 16, 0, "" }, 2020 2021 { "dont-push", 0, 0, 0, "off" }, 2021 2022 { "editor", 0, 16, 0, "" }, 2022 2023 { "gdiff-command", 0, 16, 0, "gdiff" }, 2023 2024 { "gmerge-command",0, 40, 0, "" }, 2024 2025 { "https-login", 0, 0, 0, "off" }, 2025 2026 { "ignore-glob", 0, 40, 1, "" }, ................................................................................ 2104 2105 ** crnl-glob A comma or newline-separated list of GLOB patterns for 2105 2106 ** (versionable) text files in which it is ok to have CR+NL line endings. 2106 2107 ** Set to "*" to disable CR+NL checking. 2107 2108 ** 2108 2109 ** default-perms Permissions given automatically to new users. For more 2109 2110 ** information on permissions see Users page in Server 2110 2111 ** Administration of the HTTP UI. Default: u. 2112 +** 2113 +** diff-binary If TRUE (the default), permit files that may be binary 2114 +** or that match the "binary-glob" setting to be used with 2115 +** external diff programs. If FALSE, skip these files. 2111 2116 ** 2112 2117 ** diff-command External command to run when performing a diff. 2113 2118 ** If undefined, the internal text diff will be used. 2114 2119 ** 2115 2120 ** dont-push Prevent this repository from pushing from client to 2116 2121 ** server. Useful when setting up a private branch. 2117 2122 **
Changes to src/diff.c.
36 36 #define DIFF_INLINE ((u64)0x00000000) /* Inline (not side-by-side) diff */ 37 37 #define DIFF_HTML ((u64)0x10000000) /* Render for HTML */ 38 38 #define DIFF_LINENO ((u64)0x20000000) /* Show line numbers */ 39 39 #define DIFF_WS_WARNING ((u64)0x40000000) /* Warn about whitespace */ 40 40 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */ 41 41 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ 42 42 43 +/* 44 +** These error messages are shared in multiple locations. They are defined 45 +** here for consistency. 46 +*/ 47 +#define DIFF_CANNOT_COMPUTE_BINARY \ 48 + "cannot compute difference between binary files\n" 49 + 50 +#define DIFF_CANNOT_COMPUTE_SYMLINK \ 51 + "cannot compute difference between symlink and regular file\n" 52 + 43 53 #endif /* INTERFACE */ 44 54 45 55 /* 46 56 ** Maximum length of a line in a text file. (8192) 47 57 */ 48 58 #define LENGTH_MASK_SZ 13 49 59 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) ................................................................................ 155 165 z += j+1; 156 166 } 157 167 158 168 /* Return results */ 159 169 *pnLine = nLine; 160 170 return a; 161 171 } 172 + 173 +/* 174 +** Returns non-zero if the specified content appears to be binary or 175 +** contains a line that is too long. 176 +*/ 177 +int looks_like_binary(const char *z, int n){ 178 + int nLine; 179 + DLine *aContent = break_into_lines(z, n, &nLine, 0); 180 + if( aContent ){ 181 + fossil_free(aContent); 182 + return 0; 183 + }else{ 184 + return 1; 185 + } 186 +} 162 187 163 188 /* 164 189 ** Return true if two DLine elements are identical. 165 190 */ 166 191 static int same_dline(DLine *pA, DLine *pB){ 167 192 return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0; 168 193 } ................................................................................ 1497 1522 /* Prepare the input files */ 1498 1523 memset(&c, 0, sizeof(c)); 1499 1524 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), 1500 1525 &c.nFrom, ignoreEolWs); 1501 1526 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), 1502 1527 &c.nTo, ignoreEolWs); 1503 1528 if( c.aFrom==0 || c.aTo==0 ){ 1504 - free(c.aFrom); 1505 - free(c.aTo); 1529 + fossil_free(c.aFrom); 1530 + fossil_free(c.aTo); 1506 1531 if( pOut ){ 1507 - blob_appendf(pOut, "cannot compute difference between binary files\n"); 1532 + blob_appendf(pOut, DIFF_CANNOT_COMPUTE_BINARY); 1508 1533 } 1509 1534 return 0; 1510 1535 } 1511 1536 1512 1537 /* Compute the difference */ 1513 1538 diff_all(&c); 1514 1539 if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c); ................................................................................ 1519 1544 if( diffFlags & DIFF_SIDEBYSIDE ){ 1520 1545 int width = diff_width(diffFlags); 1521 1546 sbsDiff(&c, pOut, nContext, width, escHtml); 1522 1547 }else{ 1523 1548 int showLn = (diffFlags & DIFF_LINENO)!=0; 1524 1549 contextDiff(&c, pOut, nContext, showLn, escHtml); 1525 1550 } 1526 - free(c.aFrom); 1527 - free(c.aTo); 1528 - free(c.aEdit); 1551 + fossil_free(c.aFrom); 1552 + fossil_free(c.aTo); 1553 + fossil_free(c.aEdit); 1529 1554 return 0; 1530 1555 }else{ 1531 1556 /* If a context diff is not requested, then return the 1532 1557 ** array of COPY/DELETE/INSERT triples. 1533 1558 */ 1534 1559 free(c.aFrom); 1535 1560 free(c.aTo); ................................................................................ 1700 1725 x->iLevel = iThisLevel; 1701 1726 } 1702 1727 } 1703 1728 lnTo += p->c.aEdit[i+2]; 1704 1729 } 1705 1730 1706 1731 /* Clear out the diff results */ 1707 - free(p->c.aEdit); 1732 + fossil_free(p->c.aEdit); 1708 1733 p->c.aEdit = 0; 1709 1734 p->c.nEdit = 0; 1710 1735 p->c.nEditAlloc = 0; 1711 1736 1712 1737 /* Clear out the from file */ 1713 1738 free(p->c.aFrom); 1714 1739
Changes to src/diffcmd.c.
67 67 ** Show the difference between two files, one in memory and one on disk. 68 68 ** 69 69 ** The difference is the set of edits needed to transform pFile1 into 70 70 ** zFile2. The content of pFile1 is in memory. zFile2 exists on disk. 71 71 ** 72 72 ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 73 73 ** command zDiffCmd to do the diffing. 74 +** 75 +** When using an external diff program, zBinGlob contains the GLOB patterns 76 +** for file names to treat as binary. If fIncludeBinary is zero, these files 77 +** will be skipped in addition to files that may contain binary content. 74 78 */ 75 79 void diff_file( 76 80 Blob *pFile1, /* In memory content to compare from */ 81 + int isBin1, /* Does the 'from' content appear to be binary */ 77 82 const char *zFile2, /* On disk content to compare to */ 78 83 const char *zName, /* Display name of the file */ 79 84 const char *zDiffCmd, /* Command for comparison */ 85 + const char *zBinGlob, /* Treat file names matching this as binary */ 86 + int fIncludeBinary, /* Include binary files for external diff */ 80 87 u64 diffFlags /* Flags to control the diff */ 81 88 ){ 82 89 if( zDiffCmd==0 ){ 83 90 Blob out; /* Diff output text */ 84 91 Blob file2; /* Content of zFile2 */ 85 92 const char *zName2; /* Name of zFile2 for display */ 86 93 ................................................................................ 114 121 115 122 /* Release memory resources */ 116 123 blob_reset(&file2); 117 124 }else{ 118 125 int cnt = 0; 119 126 Blob nameFile1; /* Name of temporary file to old pFile1 content */ 120 127 Blob cmd; /* Text of command to run */ 128 + 129 + if( !fIncludeBinary ){ 130 + Blob file2; 131 + if( isBin1 ){ 132 + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); 133 + return; 134 + } 135 + if( zBinGlob ){ 136 + Glob *pBinary = glob_create(zBinGlob); 137 + if( glob_match(pBinary, zName) ){ 138 + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); 139 + glob_free(pBinary); 140 + return; 141 + } 142 + glob_free(pBinary); 143 + } 144 + blob_zero(&file2); 145 + if( file_wd_size(zFile2)>=0 ){ 146 + if( file_wd_islink(zFile2) ){ 147 + blob_read_link(&file2, zFile2); 148 + }else{ 149 + blob_read_from_file(&file2, zFile2); 150 + } 151 + } 152 + if( looks_like_binary(blob_str(&file2), blob_size(&file2)) ){ 153 + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); 154 + blob_reset(&file2); 155 + return; 156 + } 157 + blob_reset(&file2); 158 + } 121 159 122 160 /* Construct a temporary file to hold pFile1 based on the name of 123 161 ** zFile2 */ 124 162 blob_zero(&nameFile1); 125 163 do{ 126 164 blob_reset(&nameFile1); 127 165 blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++); ................................................................................ 149 187 ** Show the difference between two files, both in memory. 150 188 ** 151 189 ** The difference is the set of edits needed to transform pFile1 into 152 190 ** pFile2. 153 191 ** 154 192 ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 155 193 ** command zDiffCmd to do the diffing. 194 +** 195 +** When using an external diff program, zBinGlob contains the GLOB patterns 196 +** for file names to treat as binary. If fIncludeBinary is zero, these files 197 +** will be skipped in addition to files that may contain binary content. 156 198 */ 157 199 void diff_file_mem( 158 200 Blob *pFile1, /* In memory content to compare from */ 159 201 Blob *pFile2, /* In memory content to compare to */ 202 + int isBin1, /* Does the 'from' content appear to be binary */ 203 + int isBin2, /* Does the 'to' content appear to be binary */ 160 204 const char *zName, /* Display name of the file */ 161 205 const char *zDiffCmd, /* Command for comparison */ 206 + const char *zBinGlob, /* Treat file names matching this as binary */ 207 + int fIncludeBinary, /* Include binary files for external diff */ 162 208 u64 diffFlags /* Diff flags */ 163 209 ){ 164 210 if( diffFlags & DIFF_BRIEF ) return; 165 211 if( zDiffCmd==0 ){ 166 212 Blob out; /* Diff output text */ 167 213 168 214 blob_zero(&out); ................................................................................ 172 218 173 219 /* Release memory resources */ 174 220 blob_reset(&out); 175 221 }else{ 176 222 Blob cmd; 177 223 char zTemp1[300]; 178 224 char zTemp2[300]; 225 + 226 + if( !fIncludeBinary ){ 227 + if( isBin1 || isBin2 ){ 228 + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); 229 + return; 230 + } 231 + if( zBinGlob ){ 232 + Glob *pBinary = glob_create(zBinGlob); 233 + if( glob_match(pBinary, zName) ){ 234 + fossil_print(DIFF_CANNOT_COMPUTE_BINARY); 235 + glob_free(pBinary); 236 + return; 237 + } 238 + glob_free(pBinary); 239 + } 240 + } 179 241 180 242 /* Construct a temporary file names */ 181 243 file_tempname(sizeof(zTemp1), zTemp1); 182 244 file_tempname(sizeof(zTemp2), zTemp2); 183 245 blob_write_to_file(pFile1, zTemp1); 184 246 blob_write_to_file(pFile2, zTemp2); 185 247 ................................................................................ 199 261 blob_reset(&cmd); 200 262 } 201 263 } 202 264 203 265 /* 204 266 ** Do a diff against a single file named in zFileTreeName from version zFrom 205 267 ** against the same file on disk. 268 +** 269 +** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 270 +** command zDiffCmd to do the diffing. 271 +** 272 +** When using an external diff program, zBinGlob contains the GLOB patterns 273 +** for file names to treat as binary. If fIncludeBinary is zero, these files 274 +** will be skipped in addition to files that may contain binary content. 206 275 */ 207 276 static void diff_one_against_disk( 208 277 const char *zFrom, /* Name of file */ 209 278 const char *zDiffCmd, /* Use this "diff" command */ 279 + const char *zBinGlob, /* Treat file names matching this as binary */ 280 + int fIncludeBinary, /* Include binary files for external diff */ 210 281 u64 diffFlags, /* Diff control flags */ 211 282 const char *zFileTreeName 212 283 ){ 213 284 Blob fname; 214 285 Blob content; 215 286 int isLink; 287 + int isBin; 216 288 file_tree_name(zFileTreeName, &fname, 1); 217 - historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0); 289 + historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 290 + fIncludeBinary ? 0 : &isBin, 0); 218 291 if( !isLink != !file_wd_islink(zFrom) ){ 219 - fossil_print("cannot compute difference between " 220 - "symlink and regular file\n"); 292 + fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK); 221 293 }else{ 222 - diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags); 294 + diff_file(&content, isBin, zFileTreeName, zFileTreeName, 295 + zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); 223 296 } 224 297 blob_reset(&content); 225 298 blob_reset(&fname); 226 299 } 227 300 228 301 /* 229 302 ** Run a diff between the version zFrom and files on disk. zFrom might 230 303 ** be NULL which means to simply show the difference between the edited 231 304 ** files on disk and the check-out on which they are based. 305 +** 306 +** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 307 +** command zDiffCmd to do the diffing. 308 +** 309 +** When using an external diff program, zBinGlob contains the GLOB patterns 310 +** for file names to treat as binary. If fIncludeBinary is zero, these files 311 +** will be skipped in addition to files that may contain binary content. 232 312 */ 233 313 static void diff_all_against_disk( 234 314 const char *zFrom, /* Version to difference from */ 235 315 const char *zDiffCmd, /* Use this diff command. NULL for built-in */ 316 + const char *zBinGlob, /* Treat file names matching this as binary */ 317 + int fIncludeBinary, /* Treat file names matching this as binary */ 236 318 u64 diffFlags /* Flags controlling diff output */ 237 319 ){ 238 320 int vid; 239 321 Blob sql; 240 322 Stmt q; 241 323 int asNewFile; /* Treat non-existant files as empty files */ 242 324 ................................................................................ 305 387 }else if( isChnged==3 ){ 306 388 fossil_print("ADDED_BY_MERGE %s\n", zPathname); 307 389 srcid = 0; 308 390 if( !asNewFile ){ showDiff = 0; } 309 391 } 310 392 if( showDiff ){ 311 393 Blob content; 394 + int isBin; 312 395 if( !isLink != !file_wd_islink(zFullName) ){ 313 396 diff_print_index(zPathname, diffFlags); 314 397 diff_print_filenames(zPathname, zPathname, diffFlags); 315 - fossil_print("cannot compute difference between " 316 - "symlink and regular file\n"); 398 + fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK); 317 399 continue; 318 400 } 319 401 if( srcid>0 ){ 320 402 content_get(srcid, &content); 321 403 }else{ 322 404 blob_zero(&content); 323 405 } 406 + isBin = fIncludeBinary ? 0 : looks_like_binary(blob_str(&content), 407 + blob_size(&content)); 324 408 diff_print_index(zPathname, diffFlags); 325 - diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags); 409 + diff_file(&content, isBin, zFullName, zPathname, zDiffCmd, 410 + zBinGlob, fIncludeBinary, diffFlags); 326 411 blob_reset(&content); 327 412 } 328 413 free(zToFree); 329 414 } 330 415 db_finalize(&q); 331 416 db_end_transaction(1); /* ROLLBACK */ 332 417 } 333 418 334 419 /* 335 420 ** Output the differences between two versions of a single file. 336 421 ** zFrom and zTo are the check-ins containing the two file versions. 422 +** 423 +** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 424 +** command zDiffCmd to do the diffing. 425 +** 426 +** When using an external diff program, zBinGlob contains the GLOB patterns 427 +** for file names to treat as binary. If fIncludeBinary is zero, these files 428 +** will be skipped in addition to files that may contain binary content. 337 429 */ 338 430 static void diff_one_two_versions( 339 431 const char *zFrom, 340 432 const char *zTo, 341 433 const char *zDiffCmd, 434 + const char *zBinGlob, 435 + int fIncludeBinary, 342 436 u64 diffFlags, 343 437 const char *zFileTreeName 344 438 ){ 345 439 char *zName; 346 440 Blob fname; 347 441 Blob v1, v2; 348 442 int isLink1, isLink2; 443 + int isBin1, isBin2; 349 444 if( diffFlags & DIFF_BRIEF ) return; 350 445 file_tree_name(zFileTreeName, &fname, 1); 351 446 zName = blob_str(&fname); 352 - historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0); 353 - historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0); 447 + historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 448 + fIncludeBinary ? 0 : &isBin1, 0); 449 + historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 450 + fIncludeBinary ? 0 : &isBin2, 0); 354 451 if( isLink1 != isLink2 ){ 355 452 diff_print_filenames(zName, zName, diffFlags); 356 - fossil_print("cannot compute difference " 357 - " between symlink and regular file\n"); 453 + fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK); 358 454 }else{ 359 - diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags); 455 + diff_file_mem(&v1, &v2, isBin1, isBin2, zName, zDiffCmd, 456 + zBinGlob, fIncludeBinary, diffFlags); 360 457 } 361 458 blob_reset(&v1); 362 459 blob_reset(&v2); 363 460 blob_reset(&fname); 364 461 } 365 462 366 463 /* 367 464 ** Show the difference between two files identified by ManifestFile 368 465 ** entries. 466 +** 467 +** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 468 +** command zDiffCmd to do the diffing. 469 +** 470 +** When using an external diff program, zBinGlob contains the GLOB patterns 471 +** for file names to treat as binary. If fIncludeBinary is zero, these files 472 +** will be skipped in addition to files that may contain binary content. 369 473 */ 370 474 static void diff_manifest_entry( 371 475 struct ManifestFile *pFrom, 372 476 struct ManifestFile *pTo, 373 477 const char *zDiffCmd, 478 + const char *zBinGlob, 479 + int fIncludeBinary, 374 480 u64 diffFlags 375 481 ){ 376 482 Blob f1, f2; 483 + int isBin1, isBin2; 377 484 int rid; 378 485 const char *zName = pFrom ? pFrom->zName : pTo->zName; 379 486 if( diffFlags & DIFF_BRIEF ) return; 380 487 diff_print_index(zName, diffFlags); 381 488 if( pFrom ){ 382 489 rid = uuid_to_rid(pFrom->zUuid, 0); 383 490 content_get(rid, &f1); ................................................................................ 386 493 } 387 494 if( pTo ){ 388 495 rid = uuid_to_rid(pTo->zUuid, 0); 389 496 content_get(rid, &f2); 390 497 }else{ 391 498 blob_zero(&f2); 392 499 } 393 - diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags); 500 + isBin1 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&f1), 501 + blob_size(&f1)); 502 + isBin2 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&f2), 503 + blob_size(&f2)); 504 + diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd, 505 + zBinGlob, fIncludeBinary, diffFlags); 394 506 blob_reset(&f1); 395 507 blob_reset(&f2); 396 508 } 397 509 398 510 /* 399 511 ** Output the differences between two check-ins. 512 +** 513 +** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the 514 +** command zDiffCmd to do the diffing. 515 +** 516 +** When using an external diff program, zBinGlob contains the GLOB patterns 517 +** for file names to treat as binary. If fIncludeBinary is zero, these files 518 +** will be skipped in addition to files that may contain binary content. 400 519 */ 401 520 static void diff_all_two_versions( 402 521 const char *zFrom, 403 522 const char *zTo, 404 523 const char *zDiffCmd, 524 + const char *zBinGlob, 525 + int fIncludeBinary, 405 526 u64 diffFlags 406 527 ){ 407 528 Manifest *pFrom, *pTo; 408 529 ManifestFile *pFromFile, *pToFile; 409 530 int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0; 410 531 411 532 pFrom = manifest_get_by_name(zFrom, 0); ................................................................................ 423 544 cmp = -1; 424 545 }else{ 425 546 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); 426 547 } 427 548 if( cmp<0 ){ 428 549 fossil_print("DELETED %s\n", pFromFile->zName); 429 550 if( asNewFlag ){ 430 - diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags); 551 + diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, 552 + fIncludeBinary, diffFlags); 431 553 } 432 554 pFromFile = manifest_file_next(pFrom,0); 433 555 }else if( cmp>0 ){ 434 556 fossil_print("ADDED %s\n", pToFile->zName); 435 557 if( asNewFlag ){ 436 - diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags); 558 + diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, 559 + fIncludeBinary, diffFlags); 437 560 } 438 561 pToFile = manifest_file_next(pTo,0); 439 562 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ 440 563 /* No changes */ 441 564 pFromFile = manifest_file_next(pFrom,0); 442 565 pToFile = manifest_file_next(pTo,0); 443 566 }else{ 444 567 if( diffFlags & DIFF_BRIEF ){ 445 568 fossil_print("CHANGED %s\n", pFromFile->zName); 446 569 }else{ 447 - diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags); 570 + diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, 571 + fIncludeBinary, diffFlags); 448 572 } 449 573 pFromFile = manifest_file_next(pFrom,0); 450 574 pToFile = manifest_file_next(pTo,0); 451 575 } 452 576 } 453 577 manifest_destroy(pFrom); 454 578 manifest_destroy(pTo); ................................................................................ 542 666 } 543 667 blob_appendf(&script, "}\n%s", zDiffScript); 544 668 zTempFile = write_blob_to_temp_file(&script); 545 669 zCmd = mprintf("tclsh \"%s\"", zTempFile); 546 670 fossil_system(zCmd); 547 671 file_delete(zTempFile); 548 672 } 673 + 674 +/* 675 +** Returns non-zero if files that may be binary should be used with external 676 +** diff programs. 677 +*/ 678 +int diff_include_binary_files(void){ 679 + if( is_truth(find_option("diff-binary", 0, 1)) ){ 680 + return 1; 681 + } 682 + if( db_get_boolean("diff-binary", 1) ){ 683 + return 1; 684 + } 685 + return 0; 686 +} 687 + 688 +/* 689 +** Returns the GLOB pattern for file names that should be treated as binary 690 +** by the diff subsystem, if any. 691 +*/ 692 +const char *diff_get_binary_glob(void){ 693 + const char *zBinGlob = find_option("binary", 0, 1); 694 + if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); 695 + return zBinGlob; 696 +} 549 697 550 698 /* 551 699 ** COMMAND: diff 552 700 ** COMMAND: gdiff 553 701 ** 554 702 ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? 555 703 ** ................................................................................ 571 719 ** rather than any external diff program that might be configured using 572 720 ** the "setting" command. If no external diff program is configured, then 573 721 ** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff". 574 722 ** 575 723 ** The "-N" or "--new-file" option causes the complete text of added or 576 724 ** deleted files to be displayed. 577 725 ** 726 +** The "--diff-binary" option enables or disables the inclusion of binary files 727 +** when using an external diff program. 728 +** 729 +** The "--binary" option causes files matching the glob PATTERN to be treated 730 +** as binary when considering if they should be used with external diff program. 731 +** This option overrides the "binary-glob" setting. 732 +** 578 733 ** Options: 579 734 ** --branch BRANCH Show diff of all changes on BRANCH 580 735 ** --brief Show filenames only 581 736 ** --context|-c N Use N lines of context 582 737 ** --from|-r VERSION select VERSION as source for the diff 583 738 ** -i use internal diff logic 584 739 ** --new-file|-N output complete text of added or deleted files 585 740 ** --tk Launch a Tcl/Tk GUI for display 586 741 ** --to VERSION select VERSION as target for the diff 587 742 ** --side-by-side|-y side-by-side diff 588 743 ** --unified unified diff 589 744 ** --width|-W N Width of lines in side-by-side diff 745 +** --diff-binary BOOL Include binary files when using external commands 746 +** --binary PATTERN Treat files that match the glob PATTERN as binary 590 747 */ 591 748 void diff_cmd(void){ 592 749 int isGDiff; /* True for gdiff. False for normal diff */ 593 750 int isInternDiff; /* True for internal diff */ 594 751 int hasNFlag; /* True if -N or --new-file flag is used */ 595 752 const char *zFrom; /* Source version number */ 596 753 const char *zTo; /* Target version number */ 597 754 const char *zBranch; /* Branch to diff */ 598 755 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ 756 + const char *zBinGlob = 0; /* Treat file names matching this as binary */ 757 + int fIncludeBinary = 0; /* Include binary files for external diff */ 599 758 u64 diffFlags = 0; /* Flags to control the DIFF */ 600 759 int f; 601 760 602 761 if( find_option("tk",0,0)!=0 ){ 603 762 diff_tk(); 604 763 return; 605 764 } ................................................................................ 617 776 fossil_fatal("cannot use --from or --to with --branch"); 618 777 } 619 778 zTo = zBranch; 620 779 zFrom = mprintf("root:%s", zBranch); 621 780 } 622 781 if( zTo==0 ){ 623 782 db_must_be_within_tree(); 624 - verify_all_options(); 625 783 if( !isInternDiff ){ 626 784 zDiffCmd = diff_command_external(isGDiff); 627 785 } 786 + zBinGlob = diff_get_binary_glob(); 787 + fIncludeBinary = diff_include_binary_files(); 788 + verify_all_options(); 628 789 if( g.argc>=3 ){ 629 790 for(f=2; f<g.argc; ++f){ 630 - diff_one_against_disk(zFrom, zDiffCmd, diffFlags, g.argv[f]); 791 + diff_one_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, 792 + diffFlags, g.argv[f]); 631 793 } 632 794 }else{ 633 - diff_all_against_disk(zFrom, zDiffCmd, diffFlags); 795 + diff_all_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, 796 + diffFlags); 634 797 } 635 798 }else if( zFrom==0 ){ 636 799 fossil_fatal("must use --from if --to is present"); 637 800 }else{ 638 801 db_find_and_open_repository(0, 0); 639 - verify_all_options(); 640 802 if( !isInternDiff ){ 641 803 zDiffCmd = diff_command_external(isGDiff); 642 804 } 805 + zBinGlob = diff_get_binary_glob(); 806 + fIncludeBinary = diff_include_binary_files(); 807 + verify_all_options(); 643 808 if( g.argc>=3 ){ 644 809 for(f=2; f<g.argc; ++f){ 645 - diff_one_two_versions(zFrom, zTo, zDiffCmd, diffFlags, g.argv[f]); 810 + diff_one_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, 811 + diffFlags, g.argv[f]); 646 812 } 647 813 }else{ 648 - diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags); 814 + diff_all_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, 815 + diffFlags); 649 816 } 650 817 } 651 818 } 652 819 653 820 /* 654 821 ** WEBPAGE: vpatch 655 822 ** URL vpatch?from=UUID&to=UUID ................................................................................ 658 825 const char *zFrom = P("from"); 659 826 const char *zTo = P("to"); 660 827 login_check_credentials(); 661 828 if( !g.perm.Read ){ login_needed(); return; } 662 829 if( zFrom==0 || zTo==0 ) fossil_redirect_home(); 663 830 664 831 cgi_set_content_type("text/plain"); 665 - diff_all_two_versions(zFrom, zTo, 0, DIFF_NEWFILE); 832 + diff_all_two_versions(zFrom, zTo, 0, 0, 0, DIFF_NEWFILE); 666 833 }
Changes to src/finfo.c.
113 113 }else if( find_option("print","p",0) ){ 114 114 Blob record; 115 115 Blob fname; 116 116 const char *zRevision = find_option("revision", "r", 1); 117 117 118 118 file_tree_name(g.argv[2], &fname, 1); 119 119 if( zRevision ){ 120 - historical_version_of_file(zRevision, blob_str(&fname), &record, 0, 0, 0); 120 + historical_version_of_file(zRevision, blob_str(&fname), &record, 0,0,0,0); 121 121 }else{ 122 122 int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s", 123 123 &fname, filename_collation()); 124 124 if( rid==0 ){ 125 125 fossil_fatal("no history for file: %b", &fname); 126 126 } 127 127 content_get(rid, &record);
Changes to src/stash.c.
265 265 nConflict); 266 266 } 267 267 } 268 268 269 269 /* 270 270 ** Show the diffs associate with a single stash. 271 271 */ 272 -static void stash_diff(int stashid, const char *zDiffCmd, u64 diffFlags){ 272 +static void stash_diff( 273 + int stashid, 274 + const char *zDiffCmd, 275 + const char *zBinGlob, 276 + int fIncludeBinary, 277 + u64 diffFlags 278 +){ 273 279 Stmt q; 274 280 Blob empty; 275 281 blob_zero(&empty); 276 282 db_prepare(&q, 277 283 "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" 278 284 " FROM stashfile WHERE stashid=%d", 279 285 stashid 280 286 ); 281 287 while( db_step(&q)==SQLITE_ROW ){ 282 288 int rid = db_column_int(&q, 0); 283 289 int isRemoved = db_column_int(&q, 1); 284 290 int isLink = db_column_int(&q, 3); 291 + int isBin1, isBin2; 285 292 const char *zOrig = db_column_text(&q, 4); 286 293 const char *zNew = db_column_text(&q, 5); 287 294 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); 288 295 Blob delta; 289 296 if( rid==0 ){ 290 297 db_ephemeral_blob(&q, 6, &delta); 291 298 fossil_print("ADDED %s\n", zNew); 292 299 diff_print_index(zNew, diffFlags); 293 - diff_file_mem(&empty, &delta, zNew, zDiffCmd, diffFlags); 300 + isBin1 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&empty), 301 + blob_size(&empty)); 302 + isBin2 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&delta), 303 + blob_size(&delta)); 304 + diff_file_mem(&empty, &delta, isBin1, isBin2, zNew, zDiffCmd, 305 + zBinGlob, fIncludeBinary, diffFlags); 294 306 }else if( isRemoved ){ 295 307 fossil_print("DELETE %s\n", zOrig); 296 308 if( file_wd_islink(zOPath) ){ 297 309 blob_read_link(&delta, zOPath); 298 310 }else{ 299 311 blob_read_from_file(&delta, zOPath); 300 312 } 301 313 diff_print_index(zNew, diffFlags); 302 - diff_file_mem(&delta, &empty, zOrig, zDiffCmd, diffFlags); 314 + isBin1 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&delta), 315 + blob_size(&delta)); 316 + isBin2 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&empty), 317 + blob_size(&empty)); 318 + diff_file_mem(&delta, &empty, isBin1, isBin2, zOrig, zDiffCmd, 319 + zBinGlob, fIncludeBinary, diffFlags); 303 320 }else{ 304 321 Blob a, b, disk; 305 322 int isOrigLink = file_wd_islink(zOPath); 306 323 db_ephemeral_blob(&q, 6, &delta); 307 324 if( isOrigLink ){ 308 325 blob_read_link(&disk, zOPath); 309 326 }else{ 310 327 blob_read_from_file(&disk, zOPath); 311 328 } 312 329 fossil_print("CHANGED %s\n", zNew); 313 330 if( !isOrigLink != !isLink ){ 314 331 diff_print_index(zNew, diffFlags); 315 332 diff_print_filenames(zOrig, zNew, diffFlags); 316 - printf("cannot compute difference between symlink and regular file\n"); 333 + printf(DIFF_CANNOT_COMPUTE_SYMLINK); 317 334 }else{ 318 335 content_get(rid, &a); 319 336 blob_delta_apply(&a, &delta, &b); 320 - diff_file_mem(&disk, &b, zNew, zDiffCmd, diffFlags); 337 + isBin1 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&disk), 338 + blob_size(&disk)); 339 + isBin2 = fIncludeBinary ? 0 : looks_like_binary(blob_str(&b), 340 + blob_size(&b)); 341 + diff_file_mem(&disk, &b, isBin1, isBin2, zNew, zDiffCmd, 342 + zBinGlob, fIncludeBinary, diffFlags); 321 343 blob_reset(&a); 322 344 blob_reset(&b); 323 345 } 324 346 blob_reset(&disk); 325 347 } 326 348 blob_reset(&delta); 327 349 } ................................................................................ 411 433 const char *zDb; 412 434 const char *zCmd; 413 435 int nCmd; 414 436 int stashid; 415 437 416 438 undo_capture_command_line(); 417 439 db_must_be_within_tree(); 440 + db_open_config(0); 418 441 db_begin_transaction(); 419 442 zDb = db_name("localdb"); 420 443 db_multi_exec(zStashInit, zDb, zDb); 421 444 if( g.argc<=2 ){ 422 445 zCmd = "save"; 423 446 }else{ 424 447 zCmd = g.argv[2]; ................................................................................ 548 571 db_multi_exec("UPDATE vfile SET mtime=0 WHERE pathname IN " 549 572 "(SELECT origname FROM stashfile WHERE stashid=%d)", 550 573 stashid); 551 574 undo_finish(); 552 575 }else 553 576 if( memcmp(zCmd, "diff", nCmd)==0 ){ 554 577 const char *zDiffCmd = diff_command_external(0); 578 + const char *zBinGlob = 0; 579 + int fIncludeBinary = 0; 555 580 u64 diffFlags = diff_options(); 556 581 if( g.argc>4 ) usage("diff STASHID"); 582 + if( zDiffCmd ){ 583 + zBinGlob = diff_get_binary_glob(); 584 + fIncludeBinary = diff_include_binary_files(); 585 + } 557 586 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); 558 - stash_diff(stashid, zDiffCmd, diffFlags); 587 + stash_diff(stashid, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); 559 588 }else 560 589 if( memcmp(zCmd, "gdiff", nCmd)==0 ){ 561 590 const char *zDiffCmd = diff_command_external(1); 591 + const char *zBinGlob = 0; 592 + int fIncludeBinary = 0; 562 593 u64 diffFlags = diff_options(); 563 594 if( g.argc>4 ) usage("gdiff STASHID"); 595 + if( zDiffCmd ){ 596 + zBinGlob = diff_get_binary_glob(); 597 + fIncludeBinary = diff_include_binary_files(); 598 + } 564 599 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); 565 - stash_diff(stashid, zDiffCmd, diffFlags); 600 + stash_diff(stashid, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); 566 601 }else 567 602 if( memcmp(zCmd, "help", nCmd)==0 ){ 568 603 g.argv[1] = "help"; 569 604 g.argv[2] = "stash"; 570 605 g.argc = 3; 571 606 help_cmd(); 572 607 }else 573 608 { 574 609 usage("SUBCOMMAND ARGS..."); 575 610 } 576 611 db_end_transaction(0); 577 612 }
Changes to src/update.c.
593 593 ** Get the contents of a file within the checking "revision". If 594 594 ** revision==NULL then get the file content for the current checkout. 595 595 */ 596 596 int historical_version_of_file( 597 597 const char *revision, /* The checkin containing the file */ 598 598 const char *file, /* Full treename of the file */ 599 599 Blob *content, /* Put the content here */ 600 - int *pIsLink, /* Set to true if file is link. */ 600 + int *pIsLink, /* Set to true if file is link. */ 601 601 int *pIsExe, /* Set to true if file is executable */ 602 + int *pIsBin, /* Set to true if file is binary */ 602 603 int errCode /* Error code if file not found. Panic if 0. */ 603 604 ){ 604 605 Manifest *pManifest; 605 606 ManifestFile *pFile; 606 607 int rid=0; 607 608 608 609 if( revision ){ ................................................................................ 615 616 fossil_fatal("no such checkin: %s", revision); 616 617 } 617 618 pManifest = manifest_get(rid, CFTYPE_MANIFEST); 618 619 619 620 if( pManifest ){ 620 621 pFile = manifest_file_find(pManifest, file); 621 622 if( pFile ){ 623 + int rc; 622 624 rid = uuid_to_rid(pFile->zUuid, 0); 623 625 if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE ); 624 626 if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK ); 625 627 manifest_destroy(pManifest); 626 - return content_get(rid, content); 628 + rc = content_get(rid, content); 629 + if( rc && pIsBin ){ 630 + *pIsBin = looks_like_binary(blob_str(content), blob_size(content)); 631 + } 632 + return rc; 627 633 } 628 634 manifest_destroy(pManifest); 629 635 if( errCode<=0 ){ 630 636 fossil_fatal("file %s does not exist in checkin: %s", file, revision); 631 637 } 632 638 }else if( errCode<=0 ){ 633 639 if( revision==0 ){ ................................................................................ 710 716 while( db_step(&q)==SQLITE_ROW ){ 711 717 int isExe = 0; 712 718 int isLink = 0; 713 719 char *zFull; 714 720 zFile = db_column_text(&q, 0); 715 721 zFull = mprintf("%/%/", g.zLocalRoot, zFile); 716 722 errCode = historical_version_of_file(zRevision, zFile, &record, 717 - &isLink, &isExe,2); 723 + &isLink, &isExe, 0, 2); 718 724 if( errCode==2 ){ 719 725 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){ 720 726 fossil_print("UNMANAGE: %s\n", zFile); 721 727 }else{ 722 728 undo_save(zFile); 723 729 file_delete(zFull); 724 730 fossil_print("DELETE: %s\n", zFile);