Fossil SCM
The "diff" command now accepts a HOST:DIRECTORY argument when using --tk.
Commit
3daa780e2ccd1d04e1704057a5e73388544da28cfe0c7dc263294fd084632606
Parent
1ec45d0dea0fca9…
2 files changed
+72
-10
+52
-8
+72
-10
| --- src/diff.tcl | ||
| +++ src/diff.tcl | ||
| @@ -1,11 +1,25 @@ | ||
| 1 | -# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line | |
| 2 | -# to this file, then runs this file using "tclsh" in order to display the | |
| 3 | -# graphical diff in a separate window. A typical "set fossilcmd" line | |
| 4 | -# looks like this: | |
| 1 | +# Various diff commands ("fossil diff", "fossil stash diff", "fossil fdiff", | |
| 2 | +# "fossil patch diff", and others) that include the --tk option, or that use "gdiff" | |
| 3 | +# instead of diff, work by running a Tcl/Tk script which is just this script prepended | |
| 4 | +# with some variable initializations. The key variable is fossilcmd which is | |
| 5 | +# usually set something like this: | |
| 5 | 6 | # |
| 6 | 7 | # set fossilcmd {| "./fossil" diff --tcl -i -v} |
| 8 | +# | |
| 9 | +# If there are additional command-line options or arguments, those will be appended | |
| 10 | +# as well. This variable becomes the argument to "open" to gather the diff | |
| 11 | +# information that is to be displayed. | |
| 12 | +# | |
| 13 | +# Other variables initializations that might be prepended to this script include: | |
| 14 | +# | |
| 15 | +# set debug 1 | |
| 16 | +# set darkmode 1 | |
| 17 | +# set remotehost hostname | |
| 18 | +# set remotedir directory-on-hostname | |
| 19 | +# | |
| 20 | +# After prepending those "set" commands, the resulting script is run using "tclsh". | |
| 7 | 21 | # |
| 8 | 22 | # This header comment is stripped off by the "mkbuiltin.c" program. |
| 9 | 23 | # |
| 10 | 24 | set prog { |
| 11 | 25 | package require Tk |
| @@ -94,20 +108,24 @@ | ||
| 94 | 108 | |
| 95 | 109 | proc reloadDiff {} { |
| 96 | 110 | global fossilcmd difftxt |
| 97 | 111 | unset -nocomplain difftxt |
| 98 | 112 | set idx [.txtA index @0,0] |
| 99 | - readDiffs $fossilcmd 1 | |
| 113 | + readDiffs 1 | |
| 100 | 114 | update |
| 101 | 115 | viewDiff $idx |
| 102 | 116 | } |
| 103 | 117 | |
| 104 | -proc readDiffs {fossilcmd redo} { | |
| 105 | - global difftxt debug | |
| 106 | - if {![info exists difftxt]} { | |
| 118 | +# Populate the difftxt global variable by running the fossilcmd command | |
| 119 | +# and capturing the output. This is a reload if $redo is 1 and the initial | |
| 120 | +# load if $redo is 0. | |
| 121 | +# | |
| 122 | +proc fetchRawDiff {redo} { | |
| 123 | + global fossilcmd remotehost remotedir debug difftxt | |
| 124 | + if {![info exists remotehost] || $remotehost eq ""} { | |
| 107 | 125 | if {$debug} { |
| 108 | - puts "# [list open $fossilcmd r]" | |
| 126 | + puts "# [lrange $fossilcmd 1 end]" | |
| 109 | 127 | flush stdout |
| 110 | 128 | } |
| 111 | 129 | if {[catch { |
| 112 | 130 | set in [open $fossilcmd r] |
| 113 | 131 | fconfigure $in -encoding utf-8 |
| @@ -120,10 +138,54 @@ | ||
| 120 | 138 | } else { |
| 121 | 139 | puts $msg |
| 122 | 140 | exit 1 |
| 123 | 141 | } |
| 124 | 142 | } |
| 143 | + return 0 | |
| 144 | + } else { | |
| 145 | + set suffix [lrange $fossilcmd 2 end] | |
| 146 | + set cmd "| ssh $remotehost {cd $remotedir && fossil $suffix}" | |
| 147 | + if {$debug} { | |
| 148 | + puts "# [lrange $cmd 1 end]" | |
| 149 | + flush stdout | |
| 150 | + } | |
| 151 | + if {![catch { | |
| 152 | + set in [open $cmd r] | |
| 153 | + fconfigure $in -encoding utf-8 | |
| 154 | + set difftxt [split [read $in] \n] | |
| 155 | + close $in | |
| 156 | + }]} { | |
| 157 | + return 1 | |
| 158 | + } | |
| 159 | + set cmd "| ssh $remotehost {cd $remotedir && \ | |
| 160 | + PATH=\$HOME/bin:/usr/local/bin:/opt/homebrew/bin:\$PATH fossil $suffix}" | |
| 161 | + if {$debug} { | |
| 162 | + puts "# [lrange $cmd 1 end]" | |
| 163 | + flush stdout | |
| 164 | + } | |
| 165 | + if {![catch { | |
| 166 | + set in [open $cmd r] | |
| 167 | + fconfigure $in -encoding utf-8 | |
| 168 | + set difftxt [split [read $in] \n] | |
| 169 | + close $in | |
| 170 | + } msg]} { | |
| 171 | + return 1 | |
| 172 | + } | |
| 173 | + if {$redo} { | |
| 174 | + tk_messageBox -type ok -title Error -message "Unable to refresh:\n$msg" | |
| 175 | + return 0 | |
| 176 | + } else { | |
| 177 | + puts $msg | |
| 178 | + exit 1 | |
| 179 | + } | |
| 180 | + } | |
| 181 | +} | |
| 182 | + | |
| 183 | +proc readDiffs {redo} { | |
| 184 | + global fossilcmd difftxt debug | |
| 185 | + if {![info exists difftxt]} { | |
| 186 | + fetchRawDiff $redo | |
| 125 | 187 | } |
| 126 | 188 | set N [llength $difftxt] |
| 127 | 189 | set ii 0 |
| 128 | 190 | set nDiffs 0 |
| 129 | 191 | set n1 0 |
| @@ -487,11 +549,11 @@ | ||
| 487 | 549 | ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical |
| 488 | 550 | ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal |
| 489 | 551 | ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal |
| 490 | 552 | frame .spacer |
| 491 | 553 | |
| 492 | -if {[readDiffs $fossilcmd 0] == 0} { | |
| 554 | +if {[readDiffs 0] == 0} { | |
| 493 | 555 | tk_messageBox -type ok -title $CFG(TITLE) -message "No changes" |
| 494 | 556 | exit |
| 495 | 557 | } |
| 496 | 558 | update idletasks |
| 497 | 559 | |
| 498 | 560 |
| --- src/diff.tcl | |
| +++ src/diff.tcl | |
| @@ -1,11 +1,25 @@ | |
| 1 | # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line |
| 2 | # to this file, then runs this file using "tclsh" in order to display the |
| 3 | # graphical diff in a separate window. A typical "set fossilcmd" line |
| 4 | # looks like this: |
| 5 | # |
| 6 | # set fossilcmd {| "./fossil" diff --tcl -i -v} |
| 7 | # |
| 8 | # This header comment is stripped off by the "mkbuiltin.c" program. |
| 9 | # |
| 10 | set prog { |
| 11 | package require Tk |
| @@ -94,20 +108,24 @@ | |
| 94 | |
| 95 | proc reloadDiff {} { |
| 96 | global fossilcmd difftxt |
| 97 | unset -nocomplain difftxt |
| 98 | set idx [.txtA index @0,0] |
| 99 | readDiffs $fossilcmd 1 |
| 100 | update |
| 101 | viewDiff $idx |
| 102 | } |
| 103 | |
| 104 | proc readDiffs {fossilcmd redo} { |
| 105 | global difftxt debug |
| 106 | if {![info exists difftxt]} { |
| 107 | if {$debug} { |
| 108 | puts "# [list open $fossilcmd r]" |
| 109 | flush stdout |
| 110 | } |
| 111 | if {[catch { |
| 112 | set in [open $fossilcmd r] |
| 113 | fconfigure $in -encoding utf-8 |
| @@ -120,10 +138,54 @@ | |
| 120 | } else { |
| 121 | puts $msg |
| 122 | exit 1 |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | set N [llength $difftxt] |
| 127 | set ii 0 |
| 128 | set nDiffs 0 |
| 129 | set n1 0 |
| @@ -487,11 +549,11 @@ | |
| 487 | ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical |
| 488 | ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal |
| 489 | ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal |
| 490 | frame .spacer |
| 491 | |
| 492 | if {[readDiffs $fossilcmd 0] == 0} { |
| 493 | tk_messageBox -type ok -title $CFG(TITLE) -message "No changes" |
| 494 | exit |
| 495 | } |
| 496 | update idletasks |
| 497 | |
| 498 |
| --- src/diff.tcl | |
| +++ src/diff.tcl | |
| @@ -1,11 +1,25 @@ | |
| 1 | # Various diff commands ("fossil diff", "fossil stash diff", "fossil fdiff", |
| 2 | # "fossil patch diff", and others) that include the --tk option, or that use "gdiff" |
| 3 | # instead of diff, work by running a Tcl/Tk script which is just this script prepended |
| 4 | # with some variable initializations. The key variable is fossilcmd which is |
| 5 | # usually set something like this: |
| 6 | # |
| 7 | # set fossilcmd {| "./fossil" diff --tcl -i -v} |
| 8 | # |
| 9 | # If there are additional command-line options or arguments, those will be appended |
| 10 | # as well. This variable becomes the argument to "open" to gather the diff |
| 11 | # information that is to be displayed. |
| 12 | # |
| 13 | # Other variables initializations that might be prepended to this script include: |
| 14 | # |
| 15 | # set debug 1 |
| 16 | # set darkmode 1 |
| 17 | # set remotehost hostname |
| 18 | # set remotedir directory-on-hostname |
| 19 | # |
| 20 | # After prepending those "set" commands, the resulting script is run using "tclsh". |
| 21 | # |
| 22 | # This header comment is stripped off by the "mkbuiltin.c" program. |
| 23 | # |
| 24 | set prog { |
| 25 | package require Tk |
| @@ -94,20 +108,24 @@ | |
| 108 | |
| 109 | proc reloadDiff {} { |
| 110 | global fossilcmd difftxt |
| 111 | unset -nocomplain difftxt |
| 112 | set idx [.txtA index @0,0] |
| 113 | readDiffs 1 |
| 114 | update |
| 115 | viewDiff $idx |
| 116 | } |
| 117 | |
| 118 | # Populate the difftxt global variable by running the fossilcmd command |
| 119 | # and capturing the output. This is a reload if $redo is 1 and the initial |
| 120 | # load if $redo is 0. |
| 121 | # |
| 122 | proc fetchRawDiff {redo} { |
| 123 | global fossilcmd remotehost remotedir debug difftxt |
| 124 | if {![info exists remotehost] || $remotehost eq ""} { |
| 125 | if {$debug} { |
| 126 | puts "# [lrange $fossilcmd 1 end]" |
| 127 | flush stdout |
| 128 | } |
| 129 | if {[catch { |
| 130 | set in [open $fossilcmd r] |
| 131 | fconfigure $in -encoding utf-8 |
| @@ -120,10 +138,54 @@ | |
| 138 | } else { |
| 139 | puts $msg |
| 140 | exit 1 |
| 141 | } |
| 142 | } |
| 143 | return 0 |
| 144 | } else { |
| 145 | set suffix [lrange $fossilcmd 2 end] |
| 146 | set cmd "| ssh $remotehost {cd $remotedir && fossil $suffix}" |
| 147 | if {$debug} { |
| 148 | puts "# [lrange $cmd 1 end]" |
| 149 | flush stdout |
| 150 | } |
| 151 | if {![catch { |
| 152 | set in [open $cmd r] |
| 153 | fconfigure $in -encoding utf-8 |
| 154 | set difftxt [split [read $in] \n] |
| 155 | close $in |
| 156 | }]} { |
| 157 | return 1 |
| 158 | } |
| 159 | set cmd "| ssh $remotehost {cd $remotedir && \ |
| 160 | PATH=\$HOME/bin:/usr/local/bin:/opt/homebrew/bin:\$PATH fossil $suffix}" |
| 161 | if {$debug} { |
| 162 | puts "# [lrange $cmd 1 end]" |
| 163 | flush stdout |
| 164 | } |
| 165 | if {![catch { |
| 166 | set in [open $cmd r] |
| 167 | fconfigure $in -encoding utf-8 |
| 168 | set difftxt [split [read $in] \n] |
| 169 | close $in |
| 170 | } msg]} { |
| 171 | return 1 |
| 172 | } |
| 173 | if {$redo} { |
| 174 | tk_messageBox -type ok -title Error -message "Unable to refresh:\n$msg" |
| 175 | return 0 |
| 176 | } else { |
| 177 | puts $msg |
| 178 | exit 1 |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | proc readDiffs {redo} { |
| 184 | global fossilcmd difftxt debug |
| 185 | if {![info exists difftxt]} { |
| 186 | fetchRawDiff $redo |
| 187 | } |
| 188 | set N [llength $difftxt] |
| 189 | set ii 0 |
| 190 | set nDiffs 0 |
| 191 | set n1 0 |
| @@ -487,11 +549,11 @@ | |
| 549 | ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical |
| 550 | ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal |
| 551 | ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal |
| 552 | frame .spacer |
| 553 | |
| 554 | if {[readDiffs 0] == 0} { |
| 555 | tk_messageBox -type ok -title $CFG(TITLE) -message "No changes" |
| 556 | exit |
| 557 | } |
| 558 | update idletasks |
| 559 | |
| 560 |
+52
-8
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -1187,10 +1187,35 @@ | ||
| 1187 | 1187 | ){ |
| 1188 | 1188 | return 1; |
| 1189 | 1189 | } |
| 1190 | 1190 | return 0; |
| 1191 | 1191 | } |
| 1192 | + | |
| 1193 | +/* | |
| 1194 | +** A TCL list is being constructed in pBlob. Append a single list | |
| 1195 | +** element z[] to that list. Do all necessary quoting and escaping. | |
| 1196 | +** The content of z[] might be controlled by an attacker. | |
| 1197 | +*/ | |
| 1198 | +static void diff_tcl_lappend(Blob *pBlob, const char *z, int isFilename){ | |
| 1199 | + if( strchr(z,'{')==0 && strchr(z,'}')==0 ){ | |
| 1200 | + if( isFilename ){ | |
| 1201 | + blob_appendf(pBlob, " {%/}", z); | |
| 1202 | + }else{ | |
| 1203 | + blob_appendf(pBlob, " {%s}", z); | |
| 1204 | + } | |
| 1205 | + }else{ | |
| 1206 | + int j; | |
| 1207 | + blob_append_char(pBlob, ' '); | |
| 1208 | + for(j=0; z[j]; j++){ | |
| 1209 | + if( fossil_isalnum(z[j]) ){ | |
| 1210 | + blob_append_char(pBlob, z[j]); | |
| 1211 | + }else{ | |
| 1212 | + blob_appendf(pBlob, "\\%03o", (unsigned char)z[j]); | |
| 1213 | + } | |
| 1214 | + } | |
| 1215 | + } | |
| 1216 | +} | |
| 1192 | 1217 | |
| 1193 | 1218 | /* |
| 1194 | 1219 | ** Show diff output in a Tcl/Tk window, in response to the --tk option |
| 1195 | 1220 | ** to the diff command. |
| 1196 | 1221 | ** |
| @@ -1205,10 +1230,12 @@ | ||
| 1205 | 1230 | int i; |
| 1206 | 1231 | Blob script; |
| 1207 | 1232 | const char *zTempFile = 0; |
| 1208 | 1233 | char *zCmd; |
| 1209 | 1234 | const char *zTclsh; |
| 1235 | + const char *zHost = 0; | |
| 1236 | + const char *zDir = 0; | |
| 1210 | 1237 | int bDebug = find_option("tkdebug",0,0)!=0; |
| 1211 | 1238 | int bDarkMode = find_option("dark",0,0)!=0; |
| 1212 | 1239 | (void)find_option("debug",0,0); |
| 1213 | 1240 | blob_zero(&script); |
| 1214 | 1241 | /* Caution: When this routine is called from the merge-info command, |
| @@ -1232,20 +1259,28 @@ | ||
| 1232 | 1259 | ** be written into the FILENAME instead of being run. This is used |
| 1233 | 1260 | ** for testing and debugging. */ |
| 1234 | 1261 | zTempFile = find_option("script",0,1); |
| 1235 | 1262 | for(i=firstArg; i<g.argc; i++){ |
| 1236 | 1263 | const char *z = g.argv[i]; |
| 1237 | - if( sqlite3_strglob("*}*",z) ){ | |
| 1238 | - blob_appendf(&script, " {%/}", z); | |
| 1239 | - }else{ | |
| 1240 | - int j; | |
| 1241 | - blob_append(&script, " ", 1); | |
| 1242 | - for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]); | |
| 1264 | + if( zHost==0 | |
| 1265 | + && !file_isfile_or_link(z) | |
| 1266 | + && (zDir = file_skip_userhost(z))!=0 | |
| 1267 | + ){ | |
| 1268 | + zHost = mprintf("%.*s", (int)(zDir - z - 1), z); | |
| 1269 | + continue; | |
| 1243 | 1270 | } |
| 1271 | + diff_tcl_lappend(&script, z, 1); | |
| 1244 | 1272 | } |
| 1245 | 1273 | blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode); |
| 1246 | 1274 | blob_appendf(&script, "set debug %d\n", bDebug); |
| 1275 | + if( zHost ){ | |
| 1276 | + blob_appendf(&script, "set remotehost"); | |
| 1277 | + diff_tcl_lappend(&script, zHost, 0); | |
| 1278 | + blob_appendf(&script, "\nset remotedir"); | |
| 1279 | + diff_tcl_lappend(&script, zDir, 1); | |
| 1280 | + blob_append_char(&script, '\n'); | |
| 1281 | + } | |
| 1247 | 1282 | blob_appendf(&script, "%s", builtin_file("diff.tcl", 0)); |
| 1248 | 1283 | if( zTempFile ){ |
| 1249 | 1284 | blob_write_to_file(&script, zTempFile); |
| 1250 | 1285 | fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile); |
| 1251 | 1286 | }else{ |
| @@ -1288,13 +1323,15 @@ | ||
| 1288 | 1323 | ** |
| 1289 | 1324 | ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? |
| 1290 | 1325 | ** |
| 1291 | 1326 | ** Show the difference between the current version of each of the FILEs |
| 1292 | 1327 | ** specified (as they exist on disk) and that same file as it was checked- |
| 1293 | -** out. Or if the FILE arguments are omitted, show all unsaved changes | |
| 1328 | +** out. Or if the FILE arguments are omitted, show all committed changes | |
| 1294 | 1329 | ** currently in the working check-out. The "gdiff" variant means to |
| 1295 | -** use a GUI diff. | |
| 1330 | +** use a GUI diff specified by the "gdiff-command" setting. If | |
| 1331 | +** gdiff-command is unset or is an empty string, then "gdiff" behaves | |
| 1332 | +** like "diff --tk". | |
| 1296 | 1333 | ** |
| 1297 | 1334 | ** The default output format is a "unified patch" (the same as the |
| 1298 | 1335 | ** output of "diff -u" on most unix systems). Many alternative formats |
| 1299 | 1336 | ** are available. A few of the more useful alternatives: |
| 1300 | 1337 | ** |
| @@ -1328,10 +1365,17 @@ | ||
| 1328 | 1365 | ** when using an external diff program. |
| 1329 | 1366 | ** |
| 1330 | 1367 | ** The "--binary" option causes files matching the glob PATTERN to be treated |
| 1331 | 1368 | ** as binary when considering if they should be used with the external diff |
| 1332 | 1369 | ** program. This option overrides the "binary-glob" setting. |
| 1370 | +** | |
| 1371 | +** If the "--tk" option is used (or "gdiff" is used and no third-party | |
| 1372 | +** graphical diff tool is specified) then an additional argument of | |
| 1373 | +** the form "USER@HOST:DIRECTORY" or "HOST:DIRECTORY" can be added to specify | |
| 1374 | +** a remote host and directory from which the diff should be taken. If this | |
| 1375 | +** happens, Fossil will run the diff using SSH, capture the results, then | |
| 1376 | +** display the results locally using the Tcl/Tk diff GUI. | |
| 1333 | 1377 | ** |
| 1334 | 1378 | ** These commands show differences between managed files. Use the "fossil xdiff" |
| 1335 | 1379 | ** command to see differences in unmanaged files. |
| 1336 | 1380 | ** |
| 1337 | 1381 | ** Options: |
| 1338 | 1382 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -1187,10 +1187,35 @@ | |
| 1187 | ){ |
| 1188 | return 1; |
| 1189 | } |
| 1190 | return 0; |
| 1191 | } |
| 1192 | |
| 1193 | /* |
| 1194 | ** Show diff output in a Tcl/Tk window, in response to the --tk option |
| 1195 | ** to the diff command. |
| 1196 | ** |
| @@ -1205,10 +1230,12 @@ | |
| 1205 | int i; |
| 1206 | Blob script; |
| 1207 | const char *zTempFile = 0; |
| 1208 | char *zCmd; |
| 1209 | const char *zTclsh; |
| 1210 | int bDebug = find_option("tkdebug",0,0)!=0; |
| 1211 | int bDarkMode = find_option("dark",0,0)!=0; |
| 1212 | (void)find_option("debug",0,0); |
| 1213 | blob_zero(&script); |
| 1214 | /* Caution: When this routine is called from the merge-info command, |
| @@ -1232,20 +1259,28 @@ | |
| 1232 | ** be written into the FILENAME instead of being run. This is used |
| 1233 | ** for testing and debugging. */ |
| 1234 | zTempFile = find_option("script",0,1); |
| 1235 | for(i=firstArg; i<g.argc; i++){ |
| 1236 | const char *z = g.argv[i]; |
| 1237 | if( sqlite3_strglob("*}*",z) ){ |
| 1238 | blob_appendf(&script, " {%/}", z); |
| 1239 | }else{ |
| 1240 | int j; |
| 1241 | blob_append(&script, " ", 1); |
| 1242 | for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]); |
| 1243 | } |
| 1244 | } |
| 1245 | blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode); |
| 1246 | blob_appendf(&script, "set debug %d\n", bDebug); |
| 1247 | blob_appendf(&script, "%s", builtin_file("diff.tcl", 0)); |
| 1248 | if( zTempFile ){ |
| 1249 | blob_write_to_file(&script, zTempFile); |
| 1250 | fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile); |
| 1251 | }else{ |
| @@ -1288,13 +1323,15 @@ | |
| 1288 | ** |
| 1289 | ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? |
| 1290 | ** |
| 1291 | ** Show the difference between the current version of each of the FILEs |
| 1292 | ** specified (as they exist on disk) and that same file as it was checked- |
| 1293 | ** out. Or if the FILE arguments are omitted, show all unsaved changes |
| 1294 | ** currently in the working check-out. The "gdiff" variant means to |
| 1295 | ** use a GUI diff. |
| 1296 | ** |
| 1297 | ** The default output format is a "unified patch" (the same as the |
| 1298 | ** output of "diff -u" on most unix systems). Many alternative formats |
| 1299 | ** are available. A few of the more useful alternatives: |
| 1300 | ** |
| @@ -1328,10 +1365,17 @@ | |
| 1328 | ** when using an external diff program. |
| 1329 | ** |
| 1330 | ** The "--binary" option causes files matching the glob PATTERN to be treated |
| 1331 | ** as binary when considering if they should be used with the external diff |
| 1332 | ** program. This option overrides the "binary-glob" setting. |
| 1333 | ** |
| 1334 | ** These commands show differences between managed files. Use the "fossil xdiff" |
| 1335 | ** command to see differences in unmanaged files. |
| 1336 | ** |
| 1337 | ** Options: |
| 1338 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -1187,10 +1187,35 @@ | |
| 1187 | ){ |
| 1188 | return 1; |
| 1189 | } |
| 1190 | return 0; |
| 1191 | } |
| 1192 | |
| 1193 | /* |
| 1194 | ** A TCL list is being constructed in pBlob. Append a single list |
| 1195 | ** element z[] to that list. Do all necessary quoting and escaping. |
| 1196 | ** The content of z[] might be controlled by an attacker. |
| 1197 | */ |
| 1198 | static void diff_tcl_lappend(Blob *pBlob, const char *z, int isFilename){ |
| 1199 | if( strchr(z,'{')==0 && strchr(z,'}')==0 ){ |
| 1200 | if( isFilename ){ |
| 1201 | blob_appendf(pBlob, " {%/}", z); |
| 1202 | }else{ |
| 1203 | blob_appendf(pBlob, " {%s}", z); |
| 1204 | } |
| 1205 | }else{ |
| 1206 | int j; |
| 1207 | blob_append_char(pBlob, ' '); |
| 1208 | for(j=0; z[j]; j++){ |
| 1209 | if( fossil_isalnum(z[j]) ){ |
| 1210 | blob_append_char(pBlob, z[j]); |
| 1211 | }else{ |
| 1212 | blob_appendf(pBlob, "\\%03o", (unsigned char)z[j]); |
| 1213 | } |
| 1214 | } |
| 1215 | } |
| 1216 | } |
| 1217 | |
| 1218 | /* |
| 1219 | ** Show diff output in a Tcl/Tk window, in response to the --tk option |
| 1220 | ** to the diff command. |
| 1221 | ** |
| @@ -1205,10 +1230,12 @@ | |
| 1230 | int i; |
| 1231 | Blob script; |
| 1232 | const char *zTempFile = 0; |
| 1233 | char *zCmd; |
| 1234 | const char *zTclsh; |
| 1235 | const char *zHost = 0; |
| 1236 | const char *zDir = 0; |
| 1237 | int bDebug = find_option("tkdebug",0,0)!=0; |
| 1238 | int bDarkMode = find_option("dark",0,0)!=0; |
| 1239 | (void)find_option("debug",0,0); |
| 1240 | blob_zero(&script); |
| 1241 | /* Caution: When this routine is called from the merge-info command, |
| @@ -1232,20 +1259,28 @@ | |
| 1259 | ** be written into the FILENAME instead of being run. This is used |
| 1260 | ** for testing and debugging. */ |
| 1261 | zTempFile = find_option("script",0,1); |
| 1262 | for(i=firstArg; i<g.argc; i++){ |
| 1263 | const char *z = g.argv[i]; |
| 1264 | if( zHost==0 |
| 1265 | && !file_isfile_or_link(z) |
| 1266 | && (zDir = file_skip_userhost(z))!=0 |
| 1267 | ){ |
| 1268 | zHost = mprintf("%.*s", (int)(zDir - z - 1), z); |
| 1269 | continue; |
| 1270 | } |
| 1271 | diff_tcl_lappend(&script, z, 1); |
| 1272 | } |
| 1273 | blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode); |
| 1274 | blob_appendf(&script, "set debug %d\n", bDebug); |
| 1275 | if( zHost ){ |
| 1276 | blob_appendf(&script, "set remotehost"); |
| 1277 | diff_tcl_lappend(&script, zHost, 0); |
| 1278 | blob_appendf(&script, "\nset remotedir"); |
| 1279 | diff_tcl_lappend(&script, zDir, 1); |
| 1280 | blob_append_char(&script, '\n'); |
| 1281 | } |
| 1282 | blob_appendf(&script, "%s", builtin_file("diff.tcl", 0)); |
| 1283 | if( zTempFile ){ |
| 1284 | blob_write_to_file(&script, zTempFile); |
| 1285 | fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile); |
| 1286 | }else{ |
| @@ -1288,13 +1323,15 @@ | |
| 1323 | ** |
| 1324 | ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? |
| 1325 | ** |
| 1326 | ** Show the difference between the current version of each of the FILEs |
| 1327 | ** specified (as they exist on disk) and that same file as it was checked- |
| 1328 | ** out. Or if the FILE arguments are omitted, show all committed changes |
| 1329 | ** currently in the working check-out. The "gdiff" variant means to |
| 1330 | ** use a GUI diff specified by the "gdiff-command" setting. If |
| 1331 | ** gdiff-command is unset or is an empty string, then "gdiff" behaves |
| 1332 | ** like "diff --tk". |
| 1333 | ** |
| 1334 | ** The default output format is a "unified patch" (the same as the |
| 1335 | ** output of "diff -u" on most unix systems). Many alternative formats |
| 1336 | ** are available. A few of the more useful alternatives: |
| 1337 | ** |
| @@ -1328,10 +1365,17 @@ | |
| 1365 | ** when using an external diff program. |
| 1366 | ** |
| 1367 | ** The "--binary" option causes files matching the glob PATTERN to be treated |
| 1368 | ** as binary when considering if they should be used with the external diff |
| 1369 | ** program. This option overrides the "binary-glob" setting. |
| 1370 | ** |
| 1371 | ** If the "--tk" option is used (or "gdiff" is used and no third-party |
| 1372 | ** graphical diff tool is specified) then an additional argument of |
| 1373 | ** the form "USER@HOST:DIRECTORY" or "HOST:DIRECTORY" can be added to specify |
| 1374 | ** a remote host and directory from which the diff should be taken. If this |
| 1375 | ** happens, Fossil will run the diff using SSH, capture the results, then |
| 1376 | ** display the results locally using the Tcl/Tk diff GUI. |
| 1377 | ** |
| 1378 | ** These commands show differences between managed files. Use the "fossil xdiff" |
| 1379 | ** command to see differences in unmanaged files. |
| 1380 | ** |
| 1381 | ** Options: |
| 1382 |