Fossil SCM

Extend the commit command so that specific files can be committed. There are still some problems with doing this after a merge.

dan 2007-08-03 15:31 trunk
Commit 22552fb803cfa78054677bef53d250e532e00832
+104 -14
--- src/checkin.c
+++ src/checkin.c
@@ -35,12 +35,14 @@
3535
** We assume that vfile_check_signature has been run.
3636
*/
3737
static void status_report(Blob *report, const char *zPrefix){
3838
Stmt q;
3939
int nPrefix = strlen(zPrefix);
40
- db_prepare(&q, "SELECT pathname, deleted, chnged, rid FROM vfile"
41
- " WHERE chnged OR deleted OR rid=0 ORDER BY 1");
40
+ db_prepare(&q,
41
+ "SELECT pathname, deleted, chnged, rid FROM vfile "
42
+ "WHERE file_is_selected(id) AND (chnged OR deleted OR rid=0) ORDER BY 1"
43
+ );
4244
while( db_step(&q)==SQLITE_ROW ){
4345
const char *zPathname = db_column_text(&q,0);
4446
int isDeleted = db_column_int(&q, 1);
4547
int isChnged = db_column_int(&q,2);
4648
int isNew = db_column_int(&q,3)==0;
@@ -209,16 +211,57 @@
209211
zComment = blob_str(pComment);
210212
i = strlen(zComment);
211213
while( i>0 && isspace(zComment[i-1]) ){ i--; }
212214
blob_resize(pComment, i);
213215
}
216
+
217
+/*
218
+** Populate the Global.aCommitFile[] based on the command line arguments
219
+** to a [commit] command. Global.aCommitFile is an array of integers
220
+** sized at (N+1), where N is the number of arguments passed to [commit].
221
+** The contents are the [id] values from the vfile table corresponding
222
+** to the filenames passed as arguments.
223
+**
224
+** The last element of aCommitFile[] is always 0 - indicating the end
225
+** of the array.
226
+**
227
+** If there were no arguments passed to [commit], aCommitFile is not
228
+** allocated and remains NULL. Other parts of the code interpret this
229
+** to mean "all files".
230
+*/
231
+void select_commit_files(void){
232
+ if( g.argc>2 ){
233
+ int ii;
234
+ Blob b;
235
+ memset(&b, 0, sizeof(Blob));
236
+ g.aCommitFile = malloc(sizeof(int)*(g.argc-1));
237
+
238
+ for(ii=2; ii<g.argc; ii++){
239
+ int iId;
240
+ if( !file_tree_name(g.argv[ii], &b) ){
241
+ fossil_fatal("file is not in tree: %s", g.argv[ii]);
242
+ }
243
+ iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
244
+ if( iId<0 ){
245
+ fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
246
+ }
247
+ g.aCommitFile[ii-2] = iId;
248
+ }
249
+ g.aCommitFile[ii-2] = 0;
250
+ }
251
+}
214252
215253
/*
216254
** COMMAND: commit
217255
**
218256
** Create a new version containing all of the changes in the current
219
-** checkout.
257
+** checkout. A commit is a three step process:
258
+**
259
+** 1) Add the new content to the blob table,
260
+** 2) Create and add the new manifest to the blob table,
261
+** 3) Update the vfile table,
262
+** 4) Run checks to make sure everything is still internally consistent.
220263
*/
221264
void commit_cmd(void){
222265
int rc;
223266
int vid, nrid, nvid;
224267
Blob comment;
@@ -228,37 +271,70 @@
228271
char *zManifestFile; /* Name of the manifest file */
229272
Blob manifest;
230273
Blob mcksum; /* Self-checksum on the manifest */
231274
Blob cksum1, cksum2; /* Before and after commit checksums */
232275
Blob cksum1b; /* Checksum recorded in the manifest */
233
-
276
+
234277
db_must_be_within_tree();
278
+
279
+ /* There are two ways this command may be executed. If there are
280
+ ** no arguments following the word "commit", then all modified files
281
+ ** in the checked out directory are committed. If one or more arguments
282
+ ** follows "commit", then only those files are committed.
283
+ **
284
+ ** After the following function call has returned, the Global.aCommitFile[]
285
+ ** array is allocated to contain the "id" field from the vfile table
286
+ ** for each file to be committed. Or, if aCommitFile is NULL, all files
287
+ ** should be committed.
288
+ */
289
+ select_commit_files();
290
+
235291
user_select();
236292
db_begin_transaction();
237293
rc = unsaved_changes();
238294
if( rc==0 ){
239295
fossil_panic("nothing has changed");
240296
}
297
+
298
+ /* If one or more files that were named on the command line have not
299
+ ** been modified, bail out now.
300
+ */
301
+ if( g.aCommitFile ){
302
+ Blob unmodified;
303
+ memset(&unmodified, 0, sizeof(Blob));
304
+ blob_init(&unmodified, 0, 0);
305
+ db_blob(&unmodified,
306
+ "SELECT pathname FROM vfile WHERE chnged = 0 AND file_is_selected(id)"
307
+ );
308
+ if( strlen(blob_str(&unmodified)) ){
309
+ fossil_panic("file %s has not changed", blob_str(&unmodified));
310
+ }
311
+ }
312
+
241313
vid = db_lget_int("checkout", 0);
242314
vfile_aggregate_checksum_disk(vid, &cksum1);
243315
prepare_commit_comment(&comment);
244316
317
+ /* Step 1: Insert records for all modified files into the blob
318
+ ** table. If there were arguments passed to this command, only
319
+ ** the identified fils are inserted (if they have been modified).
320
+ */
245321
db_prepare(&q,
246
- "SELECT id, %Q || pathname, mrid FROM vfile"
247
- " WHERE chnged==1 AND NOT deleted", g.zLocalRoot
322
+ "SELECT id, %Q || pathname, mrid FROM vfile "
323
+ "WHERE chnged==1 AND NOT deleted AND file_is_selected(id)"
324
+ , g.zLocalRoot
248325
);
249
- db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
250326
while( db_step(&q)==SQLITE_ROW ){
251327
int id, rid;
252328
const char *zFullname;
253329
Blob content;
254330
255331
id = db_column_int(&q, 0);
256332
zFullname = db_column_text(&q, 1);
257333
rid = db_column_int(&q, 2);
258334
259
- blob_zero(&content);
335
+ blob_zero(&content);
260336
blob_read_from_file(&content, zFullname);
261337
nrid = content_put(&content, 0);
262338
if( rid>0 ){
263339
content_deltify(rid, nrid, 0);
264340
}
@@ -265,11 +341,11 @@
265341
db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
266342
}
267343
db_finalize(&q);
268344
269345
/* Create the manifest */
270
- blob_zero(&manifest);
346
+ blob_zero(&manifest);
271347
blob_appendf(&manifest, "C %F\n", blob_str(&comment));
272348
zDate = db_text(0, "SELECT datetime('now')");
273349
zDate[10] = 'T';
274350
blob_appendf(&manifest, "D %s\n", zDate);
275351
db_prepare(&q,
@@ -282,10 +358,12 @@
282358
blob_appendf(&manifest, "F %F %s\n", zName, zUuid);
283359
}
284360
db_finalize(&q);
285361
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
286362
blob_appendf(&manifest, "P %s", zUuid);
363
+
364
+ db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
287365
db_bind_int(&q2, ":id", 0);
288366
while( db_step(&q2)==SQLITE_ROW ){
289367
int mid = db_column_int(&q2, 0);
290368
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
291369
if( zUuid ){
@@ -292,10 +370,11 @@
292370
blob_appendf(&manifest, " %s", zUuid);
293371
free(zUuid);
294372
}
295373
}
296374
db_reset(&q2);
375
+
297376
blob_appendf(&manifest, "\n");
298377
blob_appendf(&manifest, "R %b\n", &cksum1);
299378
blob_appendf(&manifest, "U %F\n", g.zLogin);
300379
md5sum_blob(&manifest, &mcksum);
301380
blob_appendf(&manifest, "Z %b\n", &mcksum);
@@ -320,33 +399,44 @@
320399
manifest_crosslink(nvid, &manifest);
321400
content_deltify(vid, nvid, 0);
322401
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
323402
printf("New_Version: %s\n", zUuid);
324403
325
- /* Update VFILE */
326
- db_multi_exec("DELETE FROM vfile WHERE vid!=%d OR deleted", vid);
327
- db_multi_exec("DELETE FROM vmerge");
328
- db_multi_exec("UPDATE vfile SET vid=%d, rid=mrid, chnged=0, deleted=0", nvid);
404
+ /* Update the vfile and vmerge tables */
405
+ db_multi_exec(
406
+ "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND file_is_selected(id);"
407
+ "DELETE FROM vmerge WHERE file_is_selected(id) OR id=0;"
408
+ "UPDATE vfile SET vid=%d;"
409
+ "UPDATE vfile SET rid=mrid, chnged=0, deleted=0 WHERE file_is_selected(id);"
410
+ , vid, nvid
411
+ );
329412
db_lset_int("checkout", nvid);
330413
331
- /* Verify that the tree checksum is unchanged */
414
+ /* Verify that the repository checksum matches the expected checksum
415
+ ** calculated before the checkin started (and stored as the R record
416
+ ** of the manifest file).
417
+ */
332418
vfile_aggregate_checksum_repository(nvid, &cksum2);
333419
if( blob_compare(&cksum1, &cksum2) ){
334420
fossil_panic("tree checksum does not match repository after commit");
335421
}
422
+
423
+ /* Verify that the manifest checksum matches the expected checksum */
336424
vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b);
337425
if( blob_compare(&cksum1, &cksum1b) ){
338426
fossil_panic("manifest checksum does not agree with manifest: "
339427
"%b versus %b", &cksum1, &cksum1b);
340428
}
341429
if( blob_compare(&cksum1, &cksum2) ){
342430
fossil_panic("tree checksum does not match manifest after commit: "
343431
"%b versus %b", &cksum1, &cksum2);
344432
}
433
+
434
+ /* Verify that the commit did not modify any disk images. */
345435
vfile_aggregate_checksum_disk(nvid, &cksum2);
346436
if( blob_compare(&cksum1, &cksum2) ){
347437
fossil_panic("tree checksums before and after commit do not match");
348438
}
349439
350440
/* Commit */
351441
db_end_transaction(0);
352442
}
353443
--- src/checkin.c
+++ src/checkin.c
@@ -35,12 +35,14 @@
35 ** We assume that vfile_check_signature has been run.
36 */
37 static void status_report(Blob *report, const char *zPrefix){
38 Stmt q;
39 int nPrefix = strlen(zPrefix);
40 db_prepare(&q, "SELECT pathname, deleted, chnged, rid FROM vfile"
41 " WHERE chnged OR deleted OR rid=0 ORDER BY 1");
 
 
42 while( db_step(&q)==SQLITE_ROW ){
43 const char *zPathname = db_column_text(&q,0);
44 int isDeleted = db_column_int(&q, 1);
45 int isChnged = db_column_int(&q,2);
46 int isNew = db_column_int(&q,3)==0;
@@ -209,16 +211,57 @@
209 zComment = blob_str(pComment);
210 i = strlen(zComment);
211 while( i>0 && isspace(zComment[i-1]) ){ i--; }
212 blob_resize(pComment, i);
213 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
215 /*
216 ** COMMAND: commit
217 **
218 ** Create a new version containing all of the changes in the current
219 ** checkout.
 
 
 
 
 
220 */
221 void commit_cmd(void){
222 int rc;
223 int vid, nrid, nvid;
224 Blob comment;
@@ -228,37 +271,70 @@
228 char *zManifestFile; /* Name of the manifest file */
229 Blob manifest;
230 Blob mcksum; /* Self-checksum on the manifest */
231 Blob cksum1, cksum2; /* Before and after commit checksums */
232 Blob cksum1b; /* Checksum recorded in the manifest */
233
234 db_must_be_within_tree();
 
 
 
 
 
 
 
 
 
 
 
 
 
235 user_select();
236 db_begin_transaction();
237 rc = unsaved_changes();
238 if( rc==0 ){
239 fossil_panic("nothing has changed");
240 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241 vid = db_lget_int("checkout", 0);
242 vfile_aggregate_checksum_disk(vid, &cksum1);
243 prepare_commit_comment(&comment);
244
 
 
 
 
245 db_prepare(&q,
246 "SELECT id, %Q || pathname, mrid FROM vfile"
247 " WHERE chnged==1 AND NOT deleted", g.zLocalRoot
 
248 );
249 db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
250 while( db_step(&q)==SQLITE_ROW ){
251 int id, rid;
252 const char *zFullname;
253 Blob content;
254
255 id = db_column_int(&q, 0);
256 zFullname = db_column_text(&q, 1);
257 rid = db_column_int(&q, 2);
258
259 blob_zero(&content);
260 blob_read_from_file(&content, zFullname);
261 nrid = content_put(&content, 0);
262 if( rid>0 ){
263 content_deltify(rid, nrid, 0);
264 }
@@ -265,11 +341,11 @@
265 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
266 }
267 db_finalize(&q);
268
269 /* Create the manifest */
270 blob_zero(&manifest);
271 blob_appendf(&manifest, "C %F\n", blob_str(&comment));
272 zDate = db_text(0, "SELECT datetime('now')");
273 zDate[10] = 'T';
274 blob_appendf(&manifest, "D %s\n", zDate);
275 db_prepare(&q,
@@ -282,10 +358,12 @@
282 blob_appendf(&manifest, "F %F %s\n", zName, zUuid);
283 }
284 db_finalize(&q);
285 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
286 blob_appendf(&manifest, "P %s", zUuid);
 
 
287 db_bind_int(&q2, ":id", 0);
288 while( db_step(&q2)==SQLITE_ROW ){
289 int mid = db_column_int(&q2, 0);
290 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
291 if( zUuid ){
@@ -292,10 +370,11 @@
292 blob_appendf(&manifest, " %s", zUuid);
293 free(zUuid);
294 }
295 }
296 db_reset(&q2);
 
297 blob_appendf(&manifest, "\n");
298 blob_appendf(&manifest, "R %b\n", &cksum1);
299 blob_appendf(&manifest, "U %F\n", g.zLogin);
300 md5sum_blob(&manifest, &mcksum);
301 blob_appendf(&manifest, "Z %b\n", &mcksum);
@@ -320,33 +399,44 @@
320 manifest_crosslink(nvid, &manifest);
321 content_deltify(vid, nvid, 0);
322 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
323 printf("New_Version: %s\n", zUuid);
324
325 /* Update VFILE */
326 db_multi_exec("DELETE FROM vfile WHERE vid!=%d OR deleted", vid);
327 db_multi_exec("DELETE FROM vmerge");
328 db_multi_exec("UPDATE vfile SET vid=%d, rid=mrid, chnged=0, deleted=0", nvid);
 
 
 
 
329 db_lset_int("checkout", nvid);
330
331 /* Verify that the tree checksum is unchanged */
 
 
 
332 vfile_aggregate_checksum_repository(nvid, &cksum2);
333 if( blob_compare(&cksum1, &cksum2) ){
334 fossil_panic("tree checksum does not match repository after commit");
335 }
 
 
336 vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b);
337 if( blob_compare(&cksum1, &cksum1b) ){
338 fossil_panic("manifest checksum does not agree with manifest: "
339 "%b versus %b", &cksum1, &cksum1b);
340 }
341 if( blob_compare(&cksum1, &cksum2) ){
342 fossil_panic("tree checksum does not match manifest after commit: "
343 "%b versus %b", &cksum1, &cksum2);
344 }
 
 
345 vfile_aggregate_checksum_disk(nvid, &cksum2);
346 if( blob_compare(&cksum1, &cksum2) ){
347 fossil_panic("tree checksums before and after commit do not match");
348 }
349
350 /* Commit */
351 db_end_transaction(0);
352 }
353
--- src/checkin.c
+++ src/checkin.c
@@ -35,12 +35,14 @@
35 ** We assume that vfile_check_signature has been run.
36 */
37 static void status_report(Blob *report, const char *zPrefix){
38 Stmt q;
39 int nPrefix = strlen(zPrefix);
40 db_prepare(&q,
41 "SELECT pathname, deleted, chnged, rid FROM vfile "
42 "WHERE file_is_selected(id) AND (chnged OR deleted OR rid=0) ORDER BY 1"
43 );
44 while( db_step(&q)==SQLITE_ROW ){
45 const char *zPathname = db_column_text(&q,0);
46 int isDeleted = db_column_int(&q, 1);
47 int isChnged = db_column_int(&q,2);
48 int isNew = db_column_int(&q,3)==0;
@@ -209,16 +211,57 @@
211 zComment = blob_str(pComment);
212 i = strlen(zComment);
213 while( i>0 && isspace(zComment[i-1]) ){ i--; }
214 blob_resize(pComment, i);
215 }
216
217 /*
218 ** Populate the Global.aCommitFile[] based on the command line arguments
219 ** to a [commit] command. Global.aCommitFile is an array of integers
220 ** sized at (N+1), where N is the number of arguments passed to [commit].
221 ** The contents are the [id] values from the vfile table corresponding
222 ** to the filenames passed as arguments.
223 **
224 ** The last element of aCommitFile[] is always 0 - indicating the end
225 ** of the array.
226 **
227 ** If there were no arguments passed to [commit], aCommitFile is not
228 ** allocated and remains NULL. Other parts of the code interpret this
229 ** to mean "all files".
230 */
231 void select_commit_files(void){
232 if( g.argc>2 ){
233 int ii;
234 Blob b;
235 memset(&b, 0, sizeof(Blob));
236 g.aCommitFile = malloc(sizeof(int)*(g.argc-1));
237
238 for(ii=2; ii<g.argc; ii++){
239 int iId;
240 if( !file_tree_name(g.argv[ii], &b) ){
241 fossil_fatal("file is not in tree: %s", g.argv[ii]);
242 }
243 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
244 if( iId<0 ){
245 fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
246 }
247 g.aCommitFile[ii-2] = iId;
248 }
249 g.aCommitFile[ii-2] = 0;
250 }
251 }
252
253 /*
254 ** COMMAND: commit
255 **
256 ** Create a new version containing all of the changes in the current
257 ** checkout. A commit is a three step process:
258 **
259 ** 1) Add the new content to the blob table,
260 ** 2) Create and add the new manifest to the blob table,
261 ** 3) Update the vfile table,
262 ** 4) Run checks to make sure everything is still internally consistent.
263 */
264 void commit_cmd(void){
265 int rc;
266 int vid, nrid, nvid;
267 Blob comment;
@@ -228,37 +271,70 @@
271 char *zManifestFile; /* Name of the manifest file */
272 Blob manifest;
273 Blob mcksum; /* Self-checksum on the manifest */
274 Blob cksum1, cksum2; /* Before and after commit checksums */
275 Blob cksum1b; /* Checksum recorded in the manifest */
276
277 db_must_be_within_tree();
278
279 /* There are two ways this command may be executed. If there are
280 ** no arguments following the word "commit", then all modified files
281 ** in the checked out directory are committed. If one or more arguments
282 ** follows "commit", then only those files are committed.
283 **
284 ** After the following function call has returned, the Global.aCommitFile[]
285 ** array is allocated to contain the "id" field from the vfile table
286 ** for each file to be committed. Or, if aCommitFile is NULL, all files
287 ** should be committed.
288 */
289 select_commit_files();
290
291 user_select();
292 db_begin_transaction();
293 rc = unsaved_changes();
294 if( rc==0 ){
295 fossil_panic("nothing has changed");
296 }
297
298 /* If one or more files that were named on the command line have not
299 ** been modified, bail out now.
300 */
301 if( g.aCommitFile ){
302 Blob unmodified;
303 memset(&unmodified, 0, sizeof(Blob));
304 blob_init(&unmodified, 0, 0);
305 db_blob(&unmodified,
306 "SELECT pathname FROM vfile WHERE chnged = 0 AND file_is_selected(id)"
307 );
308 if( strlen(blob_str(&unmodified)) ){
309 fossil_panic("file %s has not changed", blob_str(&unmodified));
310 }
311 }
312
313 vid = db_lget_int("checkout", 0);
314 vfile_aggregate_checksum_disk(vid, &cksum1);
315 prepare_commit_comment(&comment);
316
317 /* Step 1: Insert records for all modified files into the blob
318 ** table. If there were arguments passed to this command, only
319 ** the identified fils are inserted (if they have been modified).
320 */
321 db_prepare(&q,
322 "SELECT id, %Q || pathname, mrid FROM vfile "
323 "WHERE chnged==1 AND NOT deleted AND file_is_selected(id)"
324 , g.zLocalRoot
325 );
 
326 while( db_step(&q)==SQLITE_ROW ){
327 int id, rid;
328 const char *zFullname;
329 Blob content;
330
331 id = db_column_int(&q, 0);
332 zFullname = db_column_text(&q, 1);
333 rid = db_column_int(&q, 2);
334
335 blob_zero(&content);
336 blob_read_from_file(&content, zFullname);
337 nrid = content_put(&content, 0);
338 if( rid>0 ){
339 content_deltify(rid, nrid, 0);
340 }
@@ -265,11 +341,11 @@
341 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
342 }
343 db_finalize(&q);
344
345 /* Create the manifest */
346 blob_zero(&manifest);
347 blob_appendf(&manifest, "C %F\n", blob_str(&comment));
348 zDate = db_text(0, "SELECT datetime('now')");
349 zDate[10] = 'T';
350 blob_appendf(&manifest, "D %s\n", zDate);
351 db_prepare(&q,
@@ -282,10 +358,12 @@
358 blob_appendf(&manifest, "F %F %s\n", zName, zUuid);
359 }
360 db_finalize(&q);
361 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
362 blob_appendf(&manifest, "P %s", zUuid);
363
364 db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
365 db_bind_int(&q2, ":id", 0);
366 while( db_step(&q2)==SQLITE_ROW ){
367 int mid = db_column_int(&q2, 0);
368 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
369 if( zUuid ){
@@ -292,10 +370,11 @@
370 blob_appendf(&manifest, " %s", zUuid);
371 free(zUuid);
372 }
373 }
374 db_reset(&q2);
375
376 blob_appendf(&manifest, "\n");
377 blob_appendf(&manifest, "R %b\n", &cksum1);
378 blob_appendf(&manifest, "U %F\n", g.zLogin);
379 md5sum_blob(&manifest, &mcksum);
380 blob_appendf(&manifest, "Z %b\n", &mcksum);
@@ -320,33 +399,44 @@
399 manifest_crosslink(nvid, &manifest);
400 content_deltify(vid, nvid, 0);
401 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
402 printf("New_Version: %s\n", zUuid);
403
404 /* Update the vfile and vmerge tables */
405 db_multi_exec(
406 "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND file_is_selected(id);"
407 "DELETE FROM vmerge WHERE file_is_selected(id) OR id=0;"
408 "UPDATE vfile SET vid=%d;"
409 "UPDATE vfile SET rid=mrid, chnged=0, deleted=0 WHERE file_is_selected(id);"
410 , vid, nvid
411 );
412 db_lset_int("checkout", nvid);
413
414 /* Verify that the repository checksum matches the expected checksum
415 ** calculated before the checkin started (and stored as the R record
416 ** of the manifest file).
417 */
418 vfile_aggregate_checksum_repository(nvid, &cksum2);
419 if( blob_compare(&cksum1, &cksum2) ){
420 fossil_panic("tree checksum does not match repository after commit");
421 }
422
423 /* Verify that the manifest checksum matches the expected checksum */
424 vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b);
425 if( blob_compare(&cksum1, &cksum1b) ){
426 fossil_panic("manifest checksum does not agree with manifest: "
427 "%b versus %b", &cksum1, &cksum1b);
428 }
429 if( blob_compare(&cksum1, &cksum2) ){
430 fossil_panic("tree checksum does not match manifest after commit: "
431 "%b versus %b", &cksum1, &cksum2);
432 }
433
434 /* Verify that the commit did not modify any disk images. */
435 vfile_aggregate_checksum_disk(nvid, &cksum2);
436 if( blob_compare(&cksum1, &cksum2) ){
437 fossil_panic("tree checksums before and after commit do not match");
438 }
439
440 /* Commit */
441 db_end_transaction(0);
442 }
443
+34
--- src/db.c
+++ src/db.c
@@ -722,19 +722,53 @@
722722
}
723723
}
724724
static void db_sql_trace(void *notUsed, const char *zSql){
725725
printf("%s\n", zSql);
726726
}
727
+
728
+/*
729
+** This is used by the [commit] command.
730
+**
731
+** Return true if either:
732
+**
733
+** a) Global.aCommitFile is NULL, or
734
+** b) Global.aCommitFile contains the integer passed as an argument.
735
+**
736
+** Otherwise return false.
737
+*/
738
+static void file_is_selected(
739
+ sqlite3_context *context,
740
+ int argc,
741
+ sqlite3_value **argv
742
+){
743
+ assert(argc==1);
744
+ if( g.aCommitFile ){
745
+ int iId = sqlite3_value_int(argv[0]);
746
+ int ii;
747
+ for(ii=0; g.aCommitFile[ii]; ii++){
748
+ if( iId==g.aCommitFile[ii] ){
749
+ sqlite3_result_int(context, 1);
750
+ return;
751
+ }
752
+ }
753
+ sqlite3_result_int(context, 0);
754
+ }else{
755
+ sqlite3_result_int(context, 1);
756
+ }
757
+}
727758
728759
/*
729760
** This function registers auxiliary functions when the SQLite
730761
** database connection is first established.
731762
*/
732763
LOCAL void db_connection_init(void){
733764
static int once = 1;
734765
if( once ){
735766
sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
767
+ sqlite3_create_function(
768
+ g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
769
+ );
736770
if( g.fSqlTrace ){
737771
sqlite3_trace(g.db, db_sql_trace, 0);
738772
}
739773
once = 0;
740774
}
741775
--- src/db.c
+++ src/db.c
@@ -722,19 +722,53 @@
722 }
723 }
724 static void db_sql_trace(void *notUsed, const char *zSql){
725 printf("%s\n", zSql);
726 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
728 /*
729 ** This function registers auxiliary functions when the SQLite
730 ** database connection is first established.
731 */
732 LOCAL void db_connection_init(void){
733 static int once = 1;
734 if( once ){
735 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
 
 
 
736 if( g.fSqlTrace ){
737 sqlite3_trace(g.db, db_sql_trace, 0);
738 }
739 once = 0;
740 }
741
--- src/db.c
+++ src/db.c
@@ -722,19 +722,53 @@
722 }
723 }
724 static void db_sql_trace(void *notUsed, const char *zSql){
725 printf("%s\n", zSql);
726 }
727
728 /*
729 ** This is used by the [commit] command.
730 **
731 ** Return true if either:
732 **
733 ** a) Global.aCommitFile is NULL, or
734 ** b) Global.aCommitFile contains the integer passed as an argument.
735 **
736 ** Otherwise return false.
737 */
738 static void file_is_selected(
739 sqlite3_context *context,
740 int argc,
741 sqlite3_value **argv
742 ){
743 assert(argc==1);
744 if( g.aCommitFile ){
745 int iId = sqlite3_value_int(argv[0]);
746 int ii;
747 for(ii=0; g.aCommitFile[ii]; ii++){
748 if( iId==g.aCommitFile[ii] ){
749 sqlite3_result_int(context, 1);
750 return;
751 }
752 }
753 sqlite3_result_int(context, 0);
754 }else{
755 sqlite3_result_int(context, 1);
756 }
757 }
758
759 /*
760 ** This function registers auxiliary functions when the SQLite
761 ** database connection is first established.
762 */
763 LOCAL void db_connection_init(void){
764 static int once = 1;
765 if( once ){
766 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
767 sqlite3_create_function(
768 g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
769 );
770 if( g.fSqlTrace ){
771 sqlite3_trace(g.db, db_sql_trace, 0);
772 }
773 once = 0;
774 }
775
+2
--- src/main.c
+++ src/main.c
@@ -64,10 +64,12 @@
6464
const char *zContentType; /* The content type of the input HTTP request */
6565
int iErrPriority; /* Priority of current error message */
6666
char *zErrMsg; /* Text of an error message */
6767
Blob cgiIn; /* Input to an xfer www method */
6868
int cgiPanic; /* Write error messages to CGI */
69
+
70
+ int *aCommitFile;
6971
7072
int urlIsFile; /* True if a "file:" url */
7173
char *urlName; /* Hostname for http: or filename for file: */
7274
int urlPort; /* TCP port number for http: */
7375
char *urlPath; /* Pathname for http: */
7476
--- src/main.c
+++ src/main.c
@@ -64,10 +64,12 @@
64 const char *zContentType; /* The content type of the input HTTP request */
65 int iErrPriority; /* Priority of current error message */
66 char *zErrMsg; /* Text of an error message */
67 Blob cgiIn; /* Input to an xfer www method */
68 int cgiPanic; /* Write error messages to CGI */
 
 
69
70 int urlIsFile; /* True if a "file:" url */
71 char *urlName; /* Hostname for http: or filename for file: */
72 int urlPort; /* TCP port number for http: */
73 char *urlPath; /* Pathname for http: */
74
--- src/main.c
+++ src/main.c
@@ -64,10 +64,12 @@
64 const char *zContentType; /* The content type of the input HTTP request */
65 int iErrPriority; /* Priority of current error message */
66 char *zErrMsg; /* Text of an error message */
67 Blob cgiIn; /* Input to an xfer www method */
68 int cgiPanic; /* Write error messages to CGI */
69
70 int *aCommitFile;
71
72 int urlIsFile; /* True if a "file:" url */
73 char *urlName; /* Hostname for http: or filename for file: */
74 int urlPort; /* TCP port number for http: */
75 char *urlPath; /* Pathname for http: */
76
+43 -20
--- src/vfile.c
+++ src/vfile.c
@@ -253,43 +253,66 @@
253253
254254
/*
255255
** Compute an aggregate MD5 checksum over the disk image of every
256256
** file in vid. The file names are part of the checksum.
257257
**
258
+** This function operates differently if the Global.aCommitFile
259
+** variable is not NULL. In that case, the disk image is used for
260
+** each file in aCommitFile[] and the repository image (see
261
+** vfile_aggregate_checksum_repository() is used for all others).
262
+**
258263
** Return the resulting checksum in blob pOut.
259264
*/
260265
void vfile_aggregate_checksum_disk(int vid, Blob *pOut){
261266
FILE *in;
262267
Stmt q;
263268
char zBuf[4096];
264269
265270
db_must_be_within_tree();
266
- db_prepare(&q, "SELECT %Q || pathname, pathname FROM vfile"
267
- " WHERE NOT deleted AND vid=%d"
268
- " ORDER BY pathname",
269
- g.zLocalRoot, vid);
271
+ db_prepare(&q,
272
+ "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile"
273
+ " WHERE NOT deleted AND vid=%d"
274
+ " ORDER BY pathname",
275
+ g.zLocalRoot, vid
276
+ );
270277
md5sum_init();
271278
while( db_step(&q)==SQLITE_ROW ){
272279
const char *zFullpath = db_column_text(&q, 0);
273280
const char *zName = db_column_text(&q, 1);
281
+ int isSelected = db_column_int(&q, 2);
282
+
274283
md5sum_step_text(zName, -1);
275
- in = fopen(zFullpath,"rb");
276
- if( in==0 ){
277
- md5sum_step_text(" 0\n", -1);
278
- continue;
279
- }
280
- fseek(in, 0L, SEEK_END);
281
- sprintf(zBuf, " %ld\n", ftell(in));
282
- fseek(in, 0L, SEEK_SET);
283
- md5sum_step_text(zBuf, -1);
284
- for(;;){
285
- int n;
286
- n = fread(zBuf, 1, sizeof(zBuf), in);
287
- if( n<=0 ) break;
288
- md5sum_step_text(zBuf, n);
289
- }
290
- fclose(in);
284
+
285
+ if( isSelected ){
286
+ in = fopen(zFullpath,"rb");
287
+ if( in==0 ){
288
+ md5sum_step_text(" 0\n", -1);
289
+ continue;
290
+ }
291
+ fseek(in, 0L, SEEK_END);
292
+ sprintf(zBuf, " %ld\n", ftell(in));
293
+ fseek(in, 0L, SEEK_SET);
294
+ md5sum_step_text(zBuf, -1);
295
+ for(;;){
296
+ int n;
297
+ n = fread(zBuf, 1, sizeof(zBuf), in);
298
+ if( n<=0 ) break;
299
+ md5sum_step_text(zBuf, n);
300
+ }
301
+ fclose(in);
302
+ }else{
303
+ int rid = db_column_int(&q, 3);
304
+ char zBuf[100];
305
+ Blob file;
306
+
307
+ blob_zero(&file);
308
+ content_get(rid, &file);
309
+ sprintf(zBuf, " %d\n", blob_size(&file));
310
+ md5sum_step_text(zBuf, -1);
311
+ md5sum_step_blob(&file);
312
+ blob_reset(&file);
313
+ }
291314
}
292315
db_finalize(&q);
293316
md5sum_finish(pOut);
294317
}
295318
296319
--- src/vfile.c
+++ src/vfile.c
@@ -253,43 +253,66 @@
253
254 /*
255 ** Compute an aggregate MD5 checksum over the disk image of every
256 ** file in vid. The file names are part of the checksum.
257 **
 
 
 
 
 
258 ** Return the resulting checksum in blob pOut.
259 */
260 void vfile_aggregate_checksum_disk(int vid, Blob *pOut){
261 FILE *in;
262 Stmt q;
263 char zBuf[4096];
264
265 db_must_be_within_tree();
266 db_prepare(&q, "SELECT %Q || pathname, pathname FROM vfile"
267 " WHERE NOT deleted AND vid=%d"
268 " ORDER BY pathname",
269 g.zLocalRoot, vid);
 
 
270 md5sum_init();
271 while( db_step(&q)==SQLITE_ROW ){
272 const char *zFullpath = db_column_text(&q, 0);
273 const char *zName = db_column_text(&q, 1);
 
 
274 md5sum_step_text(zName, -1);
275 in = fopen(zFullpath,"rb");
276 if( in==0 ){
277 md5sum_step_text(" 0\n", -1);
278 continue;
279 }
280 fseek(in, 0L, SEEK_END);
281 sprintf(zBuf, " %ld\n", ftell(in));
282 fseek(in, 0L, SEEK_SET);
283 md5sum_step_text(zBuf, -1);
284 for(;;){
285 int n;
286 n = fread(zBuf, 1, sizeof(zBuf), in);
287 if( n<=0 ) break;
288 md5sum_step_text(zBuf, n);
289 }
290 fclose(in);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291 }
292 db_finalize(&q);
293 md5sum_finish(pOut);
294 }
295
296
--- src/vfile.c
+++ src/vfile.c
@@ -253,43 +253,66 @@
253
254 /*
255 ** Compute an aggregate MD5 checksum over the disk image of every
256 ** file in vid. The file names are part of the checksum.
257 **
258 ** This function operates differently if the Global.aCommitFile
259 ** variable is not NULL. In that case, the disk image is used for
260 ** each file in aCommitFile[] and the repository image (see
261 ** vfile_aggregate_checksum_repository() is used for all others).
262 **
263 ** Return the resulting checksum in blob pOut.
264 */
265 void vfile_aggregate_checksum_disk(int vid, Blob *pOut){
266 FILE *in;
267 Stmt q;
268 char zBuf[4096];
269
270 db_must_be_within_tree();
271 db_prepare(&q,
272 "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile"
273 " WHERE NOT deleted AND vid=%d"
274 " ORDER BY pathname",
275 g.zLocalRoot, vid
276 );
277 md5sum_init();
278 while( db_step(&q)==SQLITE_ROW ){
279 const char *zFullpath = db_column_text(&q, 0);
280 const char *zName = db_column_text(&q, 1);
281 int isSelected = db_column_int(&q, 2);
282
283 md5sum_step_text(zName, -1);
284
285 if( isSelected ){
286 in = fopen(zFullpath,"rb");
287 if( in==0 ){
288 md5sum_step_text(" 0\n", -1);
289 continue;
290 }
291 fseek(in, 0L, SEEK_END);
292 sprintf(zBuf, " %ld\n", ftell(in));
293 fseek(in, 0L, SEEK_SET);
294 md5sum_step_text(zBuf, -1);
295 for(;;){
296 int n;
297 n = fread(zBuf, 1, sizeof(zBuf), in);
298 if( n<=0 ) break;
299 md5sum_step_text(zBuf, n);
300 }
301 fclose(in);
302 }else{
303 int rid = db_column_int(&q, 3);
304 char zBuf[100];
305 Blob file;
306
307 blob_zero(&file);
308 content_get(rid, &file);
309 sprintf(zBuf, " %d\n", blob_size(&file));
310 md5sum_step_text(zBuf, -1);
311 md5sum_step_blob(&file);
312 blob_reset(&file);
313 }
314 }
315 db_finalize(&q);
316 md5sum_finish(pOut);
317 }
318
319

Keyboard Shortcuts

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