Fossil SCM

Work toward improving the "diff" command. Get the "-r" or "--from" option working.

drh 2009-11-06 01:59 trunk
Commit a51808c0a514480020084bb848abdb869a41aab8
2 files changed +229 -170 +8 -1
+229 -170
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -46,180 +46,10 @@
4646
}
4747
}
4848
blob_append(pBlob, zIn, -1);
4949
}
5050
51
-/*
52
-** Run the fossil diff command separately for every file in the current
53
-** checkout that has changed.
54
-*/
55
-static void diff_all(int internalDiff, const char *zRevision){
56
- Stmt q;
57
- Blob cmd;
58
- int nCmdBase;
59
- int vid;
60
-
61
- vid = db_lget_int("checkout", 0);
62
- vfile_check_signature(vid);
63
- blob_zero(&cmd);
64
- shell_escape(&cmd, g.argv[0]);
65
- blob_append(&cmd, " diff ", -1);
66
- if( internalDiff ){
67
- blob_append(&cmd, "-i ", -1);
68
- }
69
- if( zRevision ){
70
- blob_append(&cmd, "-r ", -1);
71
- shell_escape(&cmd, zRevision);
72
- blob_append(&cmd, " ", 1);
73
- }
74
- nCmdBase = blob_size(&cmd);
75
- db_prepare(&q,
76
- "SELECT pathname, deleted, chnged, rid FROM vfile "
77
- "WHERE chnged OR deleted OR rid=0 ORDER BY 1"
78
- );
79
-
80
- while( db_step(&q)==SQLITE_ROW ){
81
- const char *zPathname = db_column_text(&q,0);
82
- int isDeleted = db_column_int(&q, 1);
83
- int isChnged = db_column_int(&q,2);
84
- int isNew = db_column_int(&q,3)==0;
85
- char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
86
- cmd.nUsed = nCmdBase;
87
- if( isDeleted ){
88
- printf("DELETED %s\n", zPathname);
89
- }else if( access(zFullName, 0) ){
90
- printf("MISSING %s\n", zPathname);
91
- }else if( isNew ){
92
- printf("ADDED %s\n", zPathname);
93
- }else if( isDeleted ){
94
- printf("DELETED %s\n", zPathname);
95
- }else if( isChnged==3 ){
96
- printf("ADDED_BY_MERGE %s\n", zPathname);
97
- }else{
98
- printf("Index: %s\n======================================="
99
- "============================\n",
100
- zPathname
101
- );
102
- shell_escape(&cmd, zFullName);
103
- printf("%s\n", blob_str(&cmd));
104
- fflush(stdout);
105
- portable_system(blob_str(&cmd));
106
- }
107
- free(zFullName);
108
- }
109
- db_finalize(&q);
110
-}
111
-
112
-/*
113
-** COMMAND: diff
114
-** COMMAND: gdiff
115
-**
116
-** Usage: %fossil diff|gdiff ?-i? ?-r REVISION? FILE...
117
-**
118
-** Show the difference between the current version of a file (as it
119
-** exists on disk) and that same file as it was checked out.
120
-**
121
-** diff will show a textual diff while gdiff will attempt to run a
122
-** graphical diff command that you have setup. If the choosen command
123
-** is not yet configured, the internal textual diff command will be
124
-** used.
125
-**
126
-** If -i is supplied for either diff or gdiff, the internal textual
127
-** diff command will be executed.
128
-**
129
-** Here are a few external diff command settings, for example:
130
-**
131
-** %fossil setting diff-command diff
132
-**
133
-** %fossil setting gdiff-command tkdiff
134
-** %fossil setting gdiff-command eskill22
135
-** %fossil setting gdiff-command tortoisemerge
136
-** %fossil setting gdiff-command meld
137
-** %fossil setting gdiff-command xxdiff
138
-** %fossil setting gdiff-command kdiff3
139
-*/
140
-void diff_cmd(void){
141
- int isGDiff; /* True for gdiff. False for normal diff */
142
- const char *zFile; /* Name of file to diff */
143
- const char *zRevision; /* Version of file to diff against current */
144
- Blob cmd; /* The diff command-line for external diff */
145
- Blob fname; /* */
146
- Blob vname;
147
- Blob record;
148
- int cnt=0;
149
- int internalDiff; /* True to use the internal diff engine */
150
-
151
- isGDiff = g.argv[1][0]=='g';
152
- internalDiff = find_option("internal","i",0)!=0;
153
- zRevision = find_option("revision", "r", 1);
154
- verify_all_options();
155
- db_must_be_within_tree();
156
-
157
- if( !isGDiff && g.argc==2 ){
158
- diff_all(internalDiff, zRevision);
159
- return;
160
- }
161
- if( g.argc<3 ){
162
- usage("?OPTIONS? FILE");
163
- }
164
-
165
- if( internalDiff==0 ){
166
- const char *zExternalCommand;
167
- if( !isGDiff ){
168
- zExternalCommand = db_get("diff-command", 0);
169
- }else{
170
- zExternalCommand = db_get("gdiff-command", 0);
171
- }
172
- if( zExternalCommand==0 ){
173
- internalDiff=1;
174
- }else{
175
- blob_zero(&cmd);
176
- blob_appendf(&cmd,"%s ",zExternalCommand);
177
- }
178
- }
179
- zFile = g.argv[g.argc-1];
180
- file_tree_name(zFile, &fname, 1);
181
-
182
- blob_zero(&vname);
183
- do{
184
- blob_reset(&vname);
185
- blob_appendf(&vname, "%s~%d", zFile, cnt++);
186
- }while( access(blob_str(&vname),0)==0 );
187
-
188
- if( zRevision==0 ){
189
- int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B", &fname);
190
- if( rid==0 ){
191
- fossil_fatal("no history for file: %b", &fname);
192
- }
193
- content_get(rid, &record);
194
- }else{
195
- historical_version_of_file(zRevision, blob_str(&fname), &record);
196
- }
197
- if( internalDiff ){
198
- Blob out;
199
- Blob current;
200
- blob_zero(&current);
201
- blob_read_from_file(&current, zFile);
202
- blob_zero(&out);
203
- text_diff(&record, &current, &out, 5);
204
- printf("--- %s\n+++ %s\n", blob_str(&fname), blob_str(&fname));
205
- printf("%s\n", blob_str(&out));
206
- blob_reset(&current);
207
- blob_reset(&out);
208
- }else{
209
- blob_write_to_file(&record, blob_str(&vname));
210
- blob_reset(&record);
211
- blob_appendf(&cmd, "%s ", blob_str(&vname));
212
- shell_escape(&cmd, zFile);
213
- portable_system(blob_str(&cmd));
214
- unlink(blob_str(&vname));
215
- blob_reset(&vname);
216
- blob_reset(&cmd);
217
- }
218
- blob_reset(&fname);
219
-}
220
-
22151
/*
22252
** This function implements a cross-platform "system()" interface.
22353
*/
22454
int portable_system(char *zOrigCmd){
22555
int rc;
@@ -235,5 +65,234 @@
23565
*/
23666
rc = system(zOrigCmd);
23767
#endif
23868
return rc;
23969
}
70
+
71
+/*
72
+** Show the difference between two files, one in memory and one on disk.
73
+**
74
+** The difference is the set of edits needed to transform pFile1 into
75
+** zFile2. The content of pFile1 is in memory. zFile2 exists on disk.
76
+**
77
+** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the
78
+** command zDiffCmd to do the diffing.
79
+*/
80
+static void diff_file(
81
+ Blob *pFile1, /* In memory content to compare from */
82
+ const char *zFile2, /* On disk content to compare to */
83
+ const char *zName, /* Display name of the file */
84
+ const char *zDiffCmd /* Command for comparison */
85
+){
86
+ if( zDiffCmd==0 ){
87
+ Blob out; /* Diff output text */
88
+ Blob file2; /* Content of zFile2 */
89
+
90
+ /* Read content of zFile2 into memory */
91
+ blob_zero(&file2);
92
+ blob_read_from_file(&file2, zFile2);
93
+
94
+ /* Compute and output the differences */
95
+ blob_zero(&out);
96
+ text_diff(pFile1, &file2, &out, 5);
97
+ printf("--- %s\n+++ %s\n", zName, zName);
98
+ printf("%s\n", blob_str(&out));
99
+
100
+ /* Release memory resources */
101
+ blob_reset(&file2);
102
+ blob_reset(&out);
103
+ }else{
104
+ int cnt = 0;
105
+ Blob nameFile1; /* Name of temporary file to old pFile1 content */
106
+ Blob cmd; /* Text of command to run */
107
+
108
+ /* Construct a temporary file to hold pFile1 based on the name of
109
+ ** zFile2 */
110
+ blob_zero(&nameFile1);
111
+ do{
112
+ blob_reset(&nameFile1);
113
+ blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++);
114
+ }while( access(blob_str(&nameFile1),0)==0 );
115
+ blob_write_to_file(pFile1, blob_str(&nameFile1));
116
+
117
+ /* Construct the external diff command */
118
+ blob_zero(&cmd);
119
+ blob_appendf(&cmd, "%s ", zDiffCmd);
120
+ shell_escape(&cmd, blob_str(&nameFile1));
121
+ blob_append(&cmd, " ", 1);
122
+ shell_escape(&cmd, zFile2);
123
+
124
+ /* Run the external diff command */
125
+ portable_system(blob_str(&cmd));
126
+
127
+ /* Delete the temporary file and clean up memory used */
128
+ unlink(blob_str(&nameFile1));
129
+ blob_reset(&nameFile1);
130
+ blob_reset(&cmd);
131
+ }
132
+}
133
+
134
+/*
135
+** Do a diff against a single file named in g.argv[2] from version zFrom
136
+** against the same file on disk.
137
+*/
138
+static void diff_one_against_disk(const char *zFrom, const char *zDiffCmd){
139
+ Blob fname;
140
+ Blob content;
141
+ file_tree_name(g.argv[2], &fname, 1);
142
+ historical_version_of_file(zFrom, blob_str(&fname), &content);
143
+ diff_file(&content, g.argv[2], g.argv[2], zDiffCmd);
144
+ blob_reset(&content);
145
+ blob_reset(&fname);
146
+}
147
+
148
+/*
149
+** Run a diff between the version zFrom and files on disk. zFrom might
150
+** be NULL which means to simply show the difference between the edited
151
+** files on disk and the check-out on which they are based.
152
+*/
153
+static void diff_all_against_disk(const char *zFrom, const char *zDiffCmd){
154
+ int vid;
155
+ Blob sql;
156
+ Stmt q;
157
+
158
+ vid = db_lget_int("checkout", 0);
159
+ blob_zero(&sql);
160
+ db_begin_transaction();
161
+ if( zFrom ){
162
+ int rid = name_to_rid(zFrom);
163
+ if( !is_a_version(rid) ){
164
+ fossil_fatal("no such check-in: %s", zFrom);
165
+ }
166
+ load_vfile_from_rid(rid);
167
+ blob_appendf(&sql,
168
+ "SELECT v2.pathname, v2.deleted, v2.chnged, v2.rid==0, v1.rid"
169
+ " FROM vfile v1, vfile v2 "
170
+ " WHERE v1.pathname=v2.pathname AND v1.vid=%d AND v2.vid=%d"
171
+ " AND (v2.deleted OR v2.chnged OR v2.rid==0)"
172
+ "UNION "
173
+ "SELECT pathname, 1, 0, 0, 0"
174
+ " FROM vfile v1"
175
+ " WHERE v1.vid=%d"
176
+ " AND NOT EXISTS(SELECT 1 FROM vfile v2"
177
+ " WHERE v2.vid=%d AND v2.pathname=v1.pathname)"
178
+ "UNION "
179
+ "SELECT pathname, 0, 0, 1, 0"
180
+ " FROM vfile v2"
181
+ " WHERE v2.vid=%d"
182
+ " AND NOT EXISTS(SELECT 1 FROM vfile v1"
183
+ " WHERE v1.vid=%d AND v1.pathname=v2.pathname)"
184
+ " ORDER BY 1",
185
+ rid, vid, rid, vid, vid, rid
186
+ );
187
+ }else{
188
+ blob_appendf(&sql,
189
+ "SELECT pathname, deleted, chnged , rid==0, rid"
190
+ " FROM vfile"
191
+ " WHERE vid=%d"
192
+ " AND (deleted OR chnged OR rid==0)"
193
+ " ORDER BY pathname",
194
+ vid
195
+ );
196
+ }
197
+ db_prepare(&q, blob_str(&sql));
198
+ while( db_step(&q)==SQLITE_ROW ){
199
+ const char *zPathname = db_column_text(&q,0);
200
+ int isDeleted = db_column_int(&q, 1);
201
+ int isChnged = db_column_int(&q,2);
202
+ int isNew = db_column_int(&q,3);
203
+ char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
204
+ if( isDeleted ){
205
+ printf("DELETED %s\n", zPathname);
206
+ }else if( access(zFullName, 0) ){
207
+ printf("MISSING %s\n", zPathname);
208
+ }else if( isNew ){
209
+ printf("ADDED %s\n", zPathname);
210
+ }else if( isDeleted ){
211
+ printf("DELETED %s\n", zPathname);
212
+ }else if( isChnged==3 ){
213
+ printf("ADDED_BY_MERGE %s\n", zPathname);
214
+ }else{
215
+ int srcid = db_column_int(&q, 4);
216
+ Blob content;
217
+ content_get(srcid, &content);
218
+ printf("Index: %s\n======================================="
219
+ "============================\n",
220
+ zPathname
221
+ );
222
+ diff_file(&content, zFullName, zPathname, zDiffCmd);
223
+ blob_reset(&content);
224
+ }
225
+ free(zFullName);
226
+ }
227
+ db_finalize(&q);
228
+ db_end_transaction(1);
229
+}
230
+
231
+
232
+
233
+/*
234
+** COMMAND: diff
235
+** COMMAND: gdiff
236
+**
237
+** Usage: %fossil diff|gdiff ?options? ?FILE?
238
+**
239
+** Show the difference between the current version of FILE (as it
240
+** exists on disk) and that same file as it was checked out. Or
241
+** if the FILE argument is omitted, show the unsaved changed currently
242
+** in the working check-out.
243
+**
244
+** If the "--from VERSION" or "-r VERSION" option is used it specifies
245
+** the source check-in for the diff operation. If not specified, the
246
+** source check-in is the base check-in for the current check-out.
247
+**
248
+** If the "--to VERSION" option appears, it specifies the check-in from
249
+** which the second version of the file or files is taken. If there is
250
+** no "--to" option then the (possibly edited) files in the current check-out
251
+** are used.
252
+**
253
+** The "-i" command-line option forces the use of the internal diff logic
254
+** rather than any external diff program that might be configured using
255
+** the "setting" command. If no external diff program is configured, then
256
+** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff".
257
+*/
258
+void diff_cmd(void){
259
+ int isGDiff; /* True for gdiff. False for normal diff */
260
+ int isInternDiff; /* True for internal diff */
261
+ const char *zFrom; /* Source version number */
262
+ const char *zTo; /* Target version number */
263
+ const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
264
+
265
+ isGDiff = g.argv[1][0]=='g';
266
+ isInternDiff = find_option("internal","i",0)!=0;
267
+ zFrom = find_option("from", "r", 1);
268
+ zTo = find_option("to", 0, 1);
269
+
270
+ if( zTo==0 ){
271
+ db_must_be_within_tree();
272
+ if( !isInternDiff ){
273
+ zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
274
+ }
275
+ verify_all_options();
276
+ if( g.argc==3 ){
277
+ diff_one_against_disk(zFrom, zDiffCmd);
278
+ }else{
279
+ diff_all_against_disk(zFrom, zDiffCmd);
280
+ }
281
+ }else if( zFrom==0 ){
282
+ fossil_fatal("must use --from if --to is present");
283
+ }else{
284
+ db_find_and_open_repository(1);
285
+ if( !isInternDiff ){
286
+ zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
287
+ }
288
+ verify_all_options();
289
+ fossil_fatal("--to not yet implemented");
290
+#if 0
291
+ if( g.argc==3 ){
292
+ diff_one_two_versions(zFrom, zTo, zDiffCmd);
293
+ }else{
294
+ diff_all_two_versions(zFrom, zTo, zDiffCmd);
295
+ }
296
+#endif
297
+ }
298
+}
240299
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -46,180 +46,10 @@
46 }
47 }
48 blob_append(pBlob, zIn, -1);
49 }
50
51 /*
52 ** Run the fossil diff command separately for every file in the current
53 ** checkout that has changed.
54 */
55 static void diff_all(int internalDiff, const char *zRevision){
56 Stmt q;
57 Blob cmd;
58 int nCmdBase;
59 int vid;
60
61 vid = db_lget_int("checkout", 0);
62 vfile_check_signature(vid);
63 blob_zero(&cmd);
64 shell_escape(&cmd, g.argv[0]);
65 blob_append(&cmd, " diff ", -1);
66 if( internalDiff ){
67 blob_append(&cmd, "-i ", -1);
68 }
69 if( zRevision ){
70 blob_append(&cmd, "-r ", -1);
71 shell_escape(&cmd, zRevision);
72 blob_append(&cmd, " ", 1);
73 }
74 nCmdBase = blob_size(&cmd);
75 db_prepare(&q,
76 "SELECT pathname, deleted, chnged, rid FROM vfile "
77 "WHERE chnged OR deleted OR rid=0 ORDER BY 1"
78 );
79
80 while( db_step(&q)==SQLITE_ROW ){
81 const char *zPathname = db_column_text(&q,0);
82 int isDeleted = db_column_int(&q, 1);
83 int isChnged = db_column_int(&q,2);
84 int isNew = db_column_int(&q,3)==0;
85 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
86 cmd.nUsed = nCmdBase;
87 if( isDeleted ){
88 printf("DELETED %s\n", zPathname);
89 }else if( access(zFullName, 0) ){
90 printf("MISSING %s\n", zPathname);
91 }else if( isNew ){
92 printf("ADDED %s\n", zPathname);
93 }else if( isDeleted ){
94 printf("DELETED %s\n", zPathname);
95 }else if( isChnged==3 ){
96 printf("ADDED_BY_MERGE %s\n", zPathname);
97 }else{
98 printf("Index: %s\n======================================="
99 "============================\n",
100 zPathname
101 );
102 shell_escape(&cmd, zFullName);
103 printf("%s\n", blob_str(&cmd));
104 fflush(stdout);
105 portable_system(blob_str(&cmd));
106 }
107 free(zFullName);
108 }
109 db_finalize(&q);
110 }
111
112 /*
113 ** COMMAND: diff
114 ** COMMAND: gdiff
115 **
116 ** Usage: %fossil diff|gdiff ?-i? ?-r REVISION? FILE...
117 **
118 ** Show the difference between the current version of a file (as it
119 ** exists on disk) and that same file as it was checked out.
120 **
121 ** diff will show a textual diff while gdiff will attempt to run a
122 ** graphical diff command that you have setup. If the choosen command
123 ** is not yet configured, the internal textual diff command will be
124 ** used.
125 **
126 ** If -i is supplied for either diff or gdiff, the internal textual
127 ** diff command will be executed.
128 **
129 ** Here are a few external diff command settings, for example:
130 **
131 ** %fossil setting diff-command diff
132 **
133 ** %fossil setting gdiff-command tkdiff
134 ** %fossil setting gdiff-command eskill22
135 ** %fossil setting gdiff-command tortoisemerge
136 ** %fossil setting gdiff-command meld
137 ** %fossil setting gdiff-command xxdiff
138 ** %fossil setting gdiff-command kdiff3
139 */
140 void diff_cmd(void){
141 int isGDiff; /* True for gdiff. False for normal diff */
142 const char *zFile; /* Name of file to diff */
143 const char *zRevision; /* Version of file to diff against current */
144 Blob cmd; /* The diff command-line for external diff */
145 Blob fname; /* */
146 Blob vname;
147 Blob record;
148 int cnt=0;
149 int internalDiff; /* True to use the internal diff engine */
150
151 isGDiff = g.argv[1][0]=='g';
152 internalDiff = find_option("internal","i",0)!=0;
153 zRevision = find_option("revision", "r", 1);
154 verify_all_options();
155 db_must_be_within_tree();
156
157 if( !isGDiff && g.argc==2 ){
158 diff_all(internalDiff, zRevision);
159 return;
160 }
161 if( g.argc<3 ){
162 usage("?OPTIONS? FILE");
163 }
164
165 if( internalDiff==0 ){
166 const char *zExternalCommand;
167 if( !isGDiff ){
168 zExternalCommand = db_get("diff-command", 0);
169 }else{
170 zExternalCommand = db_get("gdiff-command", 0);
171 }
172 if( zExternalCommand==0 ){
173 internalDiff=1;
174 }else{
175 blob_zero(&cmd);
176 blob_appendf(&cmd,"%s ",zExternalCommand);
177 }
178 }
179 zFile = g.argv[g.argc-1];
180 file_tree_name(zFile, &fname, 1);
181
182 blob_zero(&vname);
183 do{
184 blob_reset(&vname);
185 blob_appendf(&vname, "%s~%d", zFile, cnt++);
186 }while( access(blob_str(&vname),0)==0 );
187
188 if( zRevision==0 ){
189 int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B", &fname);
190 if( rid==0 ){
191 fossil_fatal("no history for file: %b", &fname);
192 }
193 content_get(rid, &record);
194 }else{
195 historical_version_of_file(zRevision, blob_str(&fname), &record);
196 }
197 if( internalDiff ){
198 Blob out;
199 Blob current;
200 blob_zero(&current);
201 blob_read_from_file(&current, zFile);
202 blob_zero(&out);
203 text_diff(&record, &current, &out, 5);
204 printf("--- %s\n+++ %s\n", blob_str(&fname), blob_str(&fname));
205 printf("%s\n", blob_str(&out));
206 blob_reset(&current);
207 blob_reset(&out);
208 }else{
209 blob_write_to_file(&record, blob_str(&vname));
210 blob_reset(&record);
211 blob_appendf(&cmd, "%s ", blob_str(&vname));
212 shell_escape(&cmd, zFile);
213 portable_system(blob_str(&cmd));
214 unlink(blob_str(&vname));
215 blob_reset(&vname);
216 blob_reset(&cmd);
217 }
218 blob_reset(&fname);
219 }
220
221 /*
222 ** This function implements a cross-platform "system()" interface.
223 */
224 int portable_system(char *zOrigCmd){
225 int rc;
@@ -235,5 +65,234 @@
235 */
236 rc = system(zOrigCmd);
237 #endif
238 return rc;
239 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -46,180 +46,10 @@
46 }
47 }
48 blob_append(pBlob, zIn, -1);
49 }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51 /*
52 ** This function implements a cross-platform "system()" interface.
53 */
54 int portable_system(char *zOrigCmd){
55 int rc;
@@ -235,5 +65,234 @@
65 */
66 rc = system(zOrigCmd);
67 #endif
68 return rc;
69 }
70
71 /*
72 ** Show the difference between two files, one in memory and one on disk.
73 **
74 ** The difference is the set of edits needed to transform pFile1 into
75 ** zFile2. The content of pFile1 is in memory. zFile2 exists on disk.
76 **
77 ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the
78 ** command zDiffCmd to do the diffing.
79 */
80 static void diff_file(
81 Blob *pFile1, /* In memory content to compare from */
82 const char *zFile2, /* On disk content to compare to */
83 const char *zName, /* Display name of the file */
84 const char *zDiffCmd /* Command for comparison */
85 ){
86 if( zDiffCmd==0 ){
87 Blob out; /* Diff output text */
88 Blob file2; /* Content of zFile2 */
89
90 /* Read content of zFile2 into memory */
91 blob_zero(&file2);
92 blob_read_from_file(&file2, zFile2);
93
94 /* Compute and output the differences */
95 blob_zero(&out);
96 text_diff(pFile1, &file2, &out, 5);
97 printf("--- %s\n+++ %s\n", zName, zName);
98 printf("%s\n", blob_str(&out));
99
100 /* Release memory resources */
101 blob_reset(&file2);
102 blob_reset(&out);
103 }else{
104 int cnt = 0;
105 Blob nameFile1; /* Name of temporary file to old pFile1 content */
106 Blob cmd; /* Text of command to run */
107
108 /* Construct a temporary file to hold pFile1 based on the name of
109 ** zFile2 */
110 blob_zero(&nameFile1);
111 do{
112 blob_reset(&nameFile1);
113 blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++);
114 }while( access(blob_str(&nameFile1),0)==0 );
115 blob_write_to_file(pFile1, blob_str(&nameFile1));
116
117 /* Construct the external diff command */
118 blob_zero(&cmd);
119 blob_appendf(&cmd, "%s ", zDiffCmd);
120 shell_escape(&cmd, blob_str(&nameFile1));
121 blob_append(&cmd, " ", 1);
122 shell_escape(&cmd, zFile2);
123
124 /* Run the external diff command */
125 portable_system(blob_str(&cmd));
126
127 /* Delete the temporary file and clean up memory used */
128 unlink(blob_str(&nameFile1));
129 blob_reset(&nameFile1);
130 blob_reset(&cmd);
131 }
132 }
133
134 /*
135 ** Do a diff against a single file named in g.argv[2] from version zFrom
136 ** against the same file on disk.
137 */
138 static void diff_one_against_disk(const char *zFrom, const char *zDiffCmd){
139 Blob fname;
140 Blob content;
141 file_tree_name(g.argv[2], &fname, 1);
142 historical_version_of_file(zFrom, blob_str(&fname), &content);
143 diff_file(&content, g.argv[2], g.argv[2], zDiffCmd);
144 blob_reset(&content);
145 blob_reset(&fname);
146 }
147
148 /*
149 ** Run a diff between the version zFrom and files on disk. zFrom might
150 ** be NULL which means to simply show the difference between the edited
151 ** files on disk and the check-out on which they are based.
152 */
153 static void diff_all_against_disk(const char *zFrom, const char *zDiffCmd){
154 int vid;
155 Blob sql;
156 Stmt q;
157
158 vid = db_lget_int("checkout", 0);
159 blob_zero(&sql);
160 db_begin_transaction();
161 if( zFrom ){
162 int rid = name_to_rid(zFrom);
163 if( !is_a_version(rid) ){
164 fossil_fatal("no such check-in: %s", zFrom);
165 }
166 load_vfile_from_rid(rid);
167 blob_appendf(&sql,
168 "SELECT v2.pathname, v2.deleted, v2.chnged, v2.rid==0, v1.rid"
169 " FROM vfile v1, vfile v2 "
170 " WHERE v1.pathname=v2.pathname AND v1.vid=%d AND v2.vid=%d"
171 " AND (v2.deleted OR v2.chnged OR v2.rid==0)"
172 "UNION "
173 "SELECT pathname, 1, 0, 0, 0"
174 " FROM vfile v1"
175 " WHERE v1.vid=%d"
176 " AND NOT EXISTS(SELECT 1 FROM vfile v2"
177 " WHERE v2.vid=%d AND v2.pathname=v1.pathname)"
178 "UNION "
179 "SELECT pathname, 0, 0, 1, 0"
180 " FROM vfile v2"
181 " WHERE v2.vid=%d"
182 " AND NOT EXISTS(SELECT 1 FROM vfile v1"
183 " WHERE v1.vid=%d AND v1.pathname=v2.pathname)"
184 " ORDER BY 1",
185 rid, vid, rid, vid, vid, rid
186 );
187 }else{
188 blob_appendf(&sql,
189 "SELECT pathname, deleted, chnged , rid==0, rid"
190 " FROM vfile"
191 " WHERE vid=%d"
192 " AND (deleted OR chnged OR rid==0)"
193 " ORDER BY pathname",
194 vid
195 );
196 }
197 db_prepare(&q, blob_str(&sql));
198 while( db_step(&q)==SQLITE_ROW ){
199 const char *zPathname = db_column_text(&q,0);
200 int isDeleted = db_column_int(&q, 1);
201 int isChnged = db_column_int(&q,2);
202 int isNew = db_column_int(&q,3);
203 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
204 if( isDeleted ){
205 printf("DELETED %s\n", zPathname);
206 }else if( access(zFullName, 0) ){
207 printf("MISSING %s\n", zPathname);
208 }else if( isNew ){
209 printf("ADDED %s\n", zPathname);
210 }else if( isDeleted ){
211 printf("DELETED %s\n", zPathname);
212 }else if( isChnged==3 ){
213 printf("ADDED_BY_MERGE %s\n", zPathname);
214 }else{
215 int srcid = db_column_int(&q, 4);
216 Blob content;
217 content_get(srcid, &content);
218 printf("Index: %s\n======================================="
219 "============================\n",
220 zPathname
221 );
222 diff_file(&content, zFullName, zPathname, zDiffCmd);
223 blob_reset(&content);
224 }
225 free(zFullName);
226 }
227 db_finalize(&q);
228 db_end_transaction(1);
229 }
230
231
232
233 /*
234 ** COMMAND: diff
235 ** COMMAND: gdiff
236 **
237 ** Usage: %fossil diff|gdiff ?options? ?FILE?
238 **
239 ** Show the difference between the current version of FILE (as it
240 ** exists on disk) and that same file as it was checked out. Or
241 ** if the FILE argument is omitted, show the unsaved changed currently
242 ** in the working check-out.
243 **
244 ** If the "--from VERSION" or "-r VERSION" option is used it specifies
245 ** the source check-in for the diff operation. If not specified, the
246 ** source check-in is the base check-in for the current check-out.
247 **
248 ** If the "--to VERSION" option appears, it specifies the check-in from
249 ** which the second version of the file or files is taken. If there is
250 ** no "--to" option then the (possibly edited) files in the current check-out
251 ** are used.
252 **
253 ** The "-i" command-line option forces the use of the internal diff logic
254 ** rather than any external diff program that might be configured using
255 ** the "setting" command. If no external diff program is configured, then
256 ** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff".
257 */
258 void diff_cmd(void){
259 int isGDiff; /* True for gdiff. False for normal diff */
260 int isInternDiff; /* True for internal diff */
261 const char *zFrom; /* Source version number */
262 const char *zTo; /* Target version number */
263 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
264
265 isGDiff = g.argv[1][0]=='g';
266 isInternDiff = find_option("internal","i",0)!=0;
267 zFrom = find_option("from", "r", 1);
268 zTo = find_option("to", 0, 1);
269
270 if( zTo==0 ){
271 db_must_be_within_tree();
272 if( !isInternDiff ){
273 zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
274 }
275 verify_all_options();
276 if( g.argc==3 ){
277 diff_one_against_disk(zFrom, zDiffCmd);
278 }else{
279 diff_all_against_disk(zFrom, zDiffCmd);
280 }
281 }else if( zFrom==0 ){
282 fossil_fatal("must use --from if --to is present");
283 }else{
284 db_find_and_open_repository(1);
285 if( !isInternDiff ){
286 zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
287 }
288 verify_all_options();
289 fossil_fatal("--to not yet implemented");
290 #if 0
291 if( g.argc==3 ){
292 diff_one_two_versions(zFrom, zTo, zDiffCmd);
293 }else{
294 diff_all_two_versions(zFrom, zTo, zDiffCmd);
295 }
296 #endif
297 }
298 }
299
+8 -1
--- src/update.c
+++ src/update.c
@@ -245,11 +245,18 @@
245245
){
246246
Blob mfile;
247247
Manifest m;
248248
int i, rid=0;
249249
250
- rid = name_to_rid(revision);
250
+ if( revision ){
251
+ rid = name_to_rid(revision);
252
+ }else{
253
+ rid = db_lget_int("checkout", 0);
254
+ }
255
+ if( !is_a_version(rid) ){
256
+ fossil_fatal("no such check-out: %s", revision);
257
+ }
251258
content_get(rid, &mfile);
252259
253260
if( manifest_parse(&m, &mfile) ){
254261
for(i=0; i<m.nFile; i++){
255262
if( strcmp(m.aFile[i].zName, file)==0 ){
256263
--- src/update.c
+++ src/update.c
@@ -245,11 +245,18 @@
245 ){
246 Blob mfile;
247 Manifest m;
248 int i, rid=0;
249
250 rid = name_to_rid(revision);
 
 
 
 
 
 
 
251 content_get(rid, &mfile);
252
253 if( manifest_parse(&m, &mfile) ){
254 for(i=0; i<m.nFile; i++){
255 if( strcmp(m.aFile[i].zName, file)==0 ){
256
--- src/update.c
+++ src/update.c
@@ -245,11 +245,18 @@
245 ){
246 Blob mfile;
247 Manifest m;
248 int i, rid=0;
249
250 if( revision ){
251 rid = name_to_rid(revision);
252 }else{
253 rid = db_lget_int("checkout", 0);
254 }
255 if( !is_a_version(rid) ){
256 fossil_fatal("no such check-out: %s", revision);
257 }
258 content_get(rid, &mfile);
259
260 if( manifest_parse(&m, &mfile) ){
261 for(i=0; i<m.nFile; i++){
262 if( strcmp(m.aFile[i].zName, file)==0 ){
263

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button