Fossil SCM

First attempt to get "fossil patch apply" working. There are probably still bugs. Certainly much more testing is needed.

drh 2021-06-22 00:04 patch-cmd
Commit 5865739195db36684e6a7b8d01e8879e9803b1581ca734155a71e4bd5e07f0e2
1 file changed +189 -9
+189 -9
--- src/patch.c
+++ src/patch.c
@@ -19,10 +19,17 @@
1919
*/
2020
#include "config.h"
2121
#include "patch.h"
2222
#include <assert.h>
2323
24
+/*
25
+** Flags passed from the main patch_cmd() routine into subfunctions used
26
+** to implement the various subcommands.
27
+*/
28
+#define PATCH_DRYRUN 0x0001
29
+#define PATCH_VERBOSE 0x0002
30
+
2431
/*
2532
** Implementation of the "readfile(X)" SQL function. The entire content
2633
** of the checkout file named X is read and returned as a BLOB.
2734
*/
2835
static void readfileFunc(
@@ -152,16 +159,18 @@
152159
" SELECT pathname, NULL, isexe, islink,"
153160
" compress(read_co_file(%Q||pathname))"
154161
" FROM vfile WHERE rid==0;",
155162
g.zLocalRoot
156163
);
164
+
157165
/* Deleted files */
158166
db_multi_exec(
159167
"INSERT INTO patch.chng(pathname,hash,isexe,islink,delta)"
160168
" SELECT pathname, NULL, 0, 0, NULL"
161169
" FROM vfile WHERE deleted;"
162170
);
171
+
163172
/* Changed files */
164173
db_multi_exec(
165174
"INSERT INTO patch.chng(pathname,origname,hash,isexe,islink,delta)"
166175
" SELECT pathname, nullif(origname,pathname), blob.uuid, isexe, islink,"
167176
" mkdelta(blob.rid, %Q||pathname)"
@@ -169,10 +178,11 @@
169178
" WHERE blob.rid=vfile.rid"
170179
" AND NOT deleted AND (chnged OR origname<>pathname);",
171180
g.zLocalRoot
172181
);
173182
183
+ /* Merges */
174184
if( db_exists("SELECT 1 FROM localdb.vmerge WHERE id<=0") ){
175185
db_multi_exec(
176186
"CREATE TABLE patch.patchmerge(type TEXT,mhash TEXT);\n"
177187
"WITH tmap(id,type) AS (VALUES(0,'merge'),(-1,'cherrypick'),"
178188
"(-2,'backout'),(-4,'integrate'))"
@@ -226,12 +236,12 @@
226236
}
227237
db_finalize(&q);
228238
}
229239
db_prepare(&q,
230240
"SELECT pathname,"
231
- " hash IS NULL AND delta IS NOT NULL,"
232
- " delta IS NULL,"
241
+ " hash IS NULL AND delta IS NOT NULL," /* isNew */
242
+ " delta IS NULL," /* delete if origname NULL */
233243
" origname"
234244
" FROM patch.chng ORDER BY 1");
235245
while( db_step(&q)==SQLITE_ROW ){
236246
const char *zClass = "EDIT";
237247
const char *zName = db_column_text(&q,0);
@@ -255,14 +265,15 @@
255265
** Apply the patch currently attached as database "patch".
256266
**
257267
** First update the check-out to be at "baseline". Then loop through
258268
** and update all files.
259269
*/
260
-void patch_apply(void){
270
+void patch_apply(unsigned mFlags){
261271
Stmt q;
262272
Blob cmd;
263273
blob_init(&cmd, 0, 0);
274
+ file_chdir(g.zLocalRoot, 0);
264275
db_prepare(&q,
265276
"SELECT patch.cfg.value"
266277
" FROM patch.cfg, localdb.vvar"
267278
" WHERE patch.cfg.key='baseline'"
268279
" AND localdb.vvar.name='checkout-hash'"
@@ -269,21 +280,185 @@
269280
" AND patch.cfg.key<>localdb.vvar.name"
270281
);
271282
if( db_step(&q)==SQLITE_ROW ){
272283
blob_append_escaped_arg(&cmd, g.nameOfExe);
273284
blob_appendf(&cmd, " update %s", db_column_text(&q, 0));
285
+ if( mFlags & PATCH_VERBOSE ){
286
+ fossil_print("%-10s %s\n", "BASELINE", db_column_text(&q,0));
287
+ }
274288
}
275289
db_finalize(&q);
276290
if( blob_size(&cmd)>0 ){
277
- int rc = fossil_system(blob_str(&cmd));
278
- if( rc ){
279
- fossil_fatal("unable to update to the baseline check-out: %s",
280
- blob_str(&cmd));
291
+ if( mFlags & PATCH_DRYRUN ){
292
+ fossil_print("%s\n", blob_str(&cmd));
293
+ }else{
294
+ int rc = fossil_system(blob_str(&cmd));
295
+ if( rc ){
296
+ fossil_fatal("unable to update to the baseline check-out: %s",
297
+ blob_str(&cmd));
298
+ }
281299
}
282300
}
283301
blob_reset(&cmd);
284
-
302
+ if( db_table_exists("patch","patchmerge") ){
303
+ db_prepare(&q,
304
+ "SELECT type, mhash, upper(type) FROM patch.patchmerge"
305
+ " WHERE type IN ('merge','cherrypick','backout','integrate')"
306
+ " AND mhash NOT GLOB '*[^a-fA-F0-9]*';"
307
+ );
308
+ while( db_step(&q)==SQLITE_ROW ){
309
+ blob_append_escaped_arg(&cmd, g.nameOfExe);
310
+ blob_appendf(&cmd, " --%s %s\n", db_column_text(&q,0),
311
+ db_column_text(&q,1));
312
+ if( mFlags & PATCH_VERBOSE ){
313
+ fossil_print("%-10s %s\n", db_column_text(&q,2),
314
+ db_column_text(&q,0));
315
+ }
316
+ }
317
+ db_finalize(&q);
318
+ if( mFlags & PATCH_DRYRUN ){
319
+ fossil_print("%s", blob_str(&cmd));
320
+ }else{
321
+ int rc = fossil_system(blob_str(&cmd));
322
+ if( rc ){
323
+ fossil_fatal("unable to do merges:\n%s",
324
+ blob_str(&cmd));
325
+ }
326
+ }
327
+ blob_reset(&cmd);
328
+ }
329
+
330
+ /* Deletions */
331
+ db_prepare(&q, "SELECT pathname FROM patch.chng"
332
+ " WHERE origname IS NULL AND delta IS NULL");
333
+ while( db_step(&q)==SQLITE_ROW ){
334
+ blob_append_escaped_arg(&cmd, g.nameOfExe);
335
+ blob_appendf(&cmd, " rm --hard %$\n", db_column_text(&q,0));
336
+ if( mFlags & PATCH_VERBOSE ){
337
+ fossil_print("%-10s %s\n", "DELETE", db_column_text(&q,0));
338
+ }
339
+ }
340
+ db_finalize(&q);
341
+ if( blob_size(&cmd)>0 ){
342
+ if( mFlags & PATCH_DRYRUN ){
343
+ fossil_print("%s", blob_str(&cmd));
344
+ }else{
345
+ int rc = fossil_system(blob_str(&cmd));
346
+ if( rc ){
347
+ fossil_fatal("unable to do merges:\n%s",
348
+ blob_str(&cmd));
349
+ }
350
+ }
351
+ blob_reset(&cmd);
352
+ }
353
+
354
+ /* Renames */
355
+ db_prepare(&q,
356
+ "SELECT origname, pathname FROM patch.chng"
357
+ " WHERE origname IS NOT NULL"
358
+ " AND origname<>pathname"
359
+ );
360
+ while( db_step(&q)==SQLITE_ROW ){
361
+ blob_append_escaped_arg(&cmd, g.nameOfExe);
362
+ blob_appendf(&cmd, " mv --hard %$ %$\n",
363
+ db_column_text(&q,0), db_column_text(&q,1));
364
+ if( mFlags & PATCH_VERBOSE ){
365
+ fossil_print("%-10s %s -> %s\n", "RENAME",
366
+ db_column_text(&q,0), db_column_text(&q,1));
367
+ }
368
+ }
369
+ db_finalize(&q);
370
+ if( blob_size(&cmd)>0 ){
371
+ if( mFlags & PATCH_DRYRUN ){
372
+ fossil_print("%s", blob_str(&cmd));
373
+ }else{
374
+ int rc = fossil_system(blob_str(&cmd));
375
+ if( rc ){
376
+ fossil_fatal("unable to rename files:\n%s",
377
+ blob_str(&cmd));
378
+ }
379
+ }
380
+ blob_reset(&cmd);
381
+ }
382
+
383
+ /* Edits and new files */
384
+ db_prepare(&q,
385
+ "SELECT pathname, hash, isexe, islink, delta FROM patch.chng"
386
+ " WHERE delta IS NOT NULL"
387
+ );
388
+ while( db_step(&q)==SQLITE_ROW ){
389
+ const char *zPathname = db_column_text(&q,0);
390
+ const char *zHash = db_column_text(&q,1);
391
+ int isExe = db_column_int(&q,2);
392
+ int isLink = db_column_int(&q,3);
393
+ Blob data;
394
+
395
+ blob_init(&data, 0, 0);
396
+ db_column_blob(&q, 4, &data);
397
+ blob_uncompress(&data, &data);
398
+ if( zHash ){
399
+ Blob basis;
400
+ int rid = fast_uuid_to_rid(zHash);
401
+ int outSize, sz;
402
+ char *aOut;
403
+ if( rid==0 ){
404
+ fossil_fatal("cannot locate basis artifact %s for %s",
405
+ zHash, zPathname);
406
+ }
407
+ if( !content_get(rid, &basis) ){
408
+ fossil_fatal("cannot load basis artifact %d for %s", rid, zPathname);
409
+ }
410
+ outSize = delta_output_size(blob_buffer(&data),blob_size(&data));
411
+ if( outSize<=0 ){
412
+ fossil_fatal("malformed delta for %s", zPathname);
413
+ }
414
+ aOut = sqlite3_malloc64( outSize+1 );
415
+ if( aOut==0 ){
416
+ fossil_fatal("out of memory");
417
+ }
418
+ sz = delta_apply(blob_buffer(&basis), blob_size(&basis),
419
+ blob_buffer(&data), blob_size(&data), aOut);
420
+ if( sz<0 ){
421
+ fossil_fatal("malformed delta for %s", zPathname);
422
+ }
423
+ blob_reset(&basis);
424
+ blob_reset(&data);
425
+ blob_append(&data, aOut, sz);
426
+ sqlite3_free(aOut);
427
+ if( mFlags & PATCH_VERBOSE ){
428
+ fossil_print("%-10s %s\n", "EDIT", zPathname);
429
+ }
430
+ }else{
431
+ blob_append_escaped_arg(&cmd, g.nameOfExe);
432
+ blob_appendf(&cmd, " add %$\n", zPathname);
433
+ if( mFlags & PATCH_VERBOSE ){
434
+ fossil_print("%-10s %s\n", "NEW", zPathname);
435
+ }
436
+ }
437
+ if( (mFlags & PATCH_DRYRUN)==0 ){
438
+ if( isLink ){
439
+ symlink_create(blob_str(&data), zPathname);
440
+ }else{
441
+ blob_write_to_file(&data, zPathname);
442
+ }
443
+ file_setexe(zPathname, isExe);
444
+ blob_reset(&data);
445
+ }
446
+ }
447
+ db_finalize(&q);
448
+ if( blob_size(&cmd)>0 ){
449
+ if( mFlags & PATCH_DRYRUN ){
450
+ fossil_print("%s", blob_str(&cmd));
451
+ }else{
452
+ int rc = fossil_system(blob_str(&cmd));
453
+ if( rc ){
454
+ fossil_fatal("unable to add new files:\n%s",
455
+ blob_str(&cmd));
456
+ }
457
+ }
458
+ blob_reset(&cmd);
459
+ }
285460
}
286461
287462
288463
/*
289464
** COMMAND: patch
@@ -304,10 +479,12 @@
304479
**
305480
** Apply the changes in FILENAME to the current check-out. Options:
306481
**
307482
** -f|--force Apply the patch even though there are unsaved
308483
** changes in the current check-out.
484
+** -n|--dryrun Do nothing, but print what would have happened.
485
+** -v|--verbose Extra output explaining what happens.
309486
**
310487
** > fossil patch diff [DIFF-FLAGS] FILENAME
311488
**
312489
** View the changes specified by the binary patch FILENAME in a
313490
** human-readable format. The usual diff flags apply.
@@ -336,20 +513,23 @@
336513
}
337514
zCmd = g.argv[2];
338515
n = strlen(zCmd);
339516
if( strncmp(zCmd, "apply", n)==0 ){
340517
int forceFlag = find_option("force","f",0)!=0;
518
+ unsigned flags = 0;
519
+ if( find_option("dryrun","n",0) ) flags |= PATCH_DRYRUN;
520
+ if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
341521
db_must_be_within_tree();
342522
verify_all_options();
343523
if( g.argc!=4 ){
344524
usage("apply FILENAME");
345525
}
346526
if( !forceFlag && unsaved_changes(0) ){
347527
fossil_fatal("there are unsaved changes in the current checkout");
348528
}
349529
patch_attach(g.argv[3]);
350
- patch_apply();
530
+ patch_apply(flags);
351531
}else
352532
if( strncmp(zCmd, "create", n)==0 ){
353533
db_must_be_within_tree();
354534
verify_all_options();
355535
if( g.argc!=4 ){
356536
--- src/patch.c
+++ src/patch.c
@@ -19,10 +19,17 @@
19 */
20 #include "config.h"
21 #include "patch.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
24 /*
25 ** Implementation of the "readfile(X)" SQL function. The entire content
26 ** of the checkout file named X is read and returned as a BLOB.
27 */
28 static void readfileFunc(
@@ -152,16 +159,18 @@
152 " SELECT pathname, NULL, isexe, islink,"
153 " compress(read_co_file(%Q||pathname))"
154 " FROM vfile WHERE rid==0;",
155 g.zLocalRoot
156 );
 
157 /* Deleted files */
158 db_multi_exec(
159 "INSERT INTO patch.chng(pathname,hash,isexe,islink,delta)"
160 " SELECT pathname, NULL, 0, 0, NULL"
161 " FROM vfile WHERE deleted;"
162 );
 
163 /* Changed files */
164 db_multi_exec(
165 "INSERT INTO patch.chng(pathname,origname,hash,isexe,islink,delta)"
166 " SELECT pathname, nullif(origname,pathname), blob.uuid, isexe, islink,"
167 " mkdelta(blob.rid, %Q||pathname)"
@@ -169,10 +178,11 @@
169 " WHERE blob.rid=vfile.rid"
170 " AND NOT deleted AND (chnged OR origname<>pathname);",
171 g.zLocalRoot
172 );
173
 
174 if( db_exists("SELECT 1 FROM localdb.vmerge WHERE id<=0") ){
175 db_multi_exec(
176 "CREATE TABLE patch.patchmerge(type TEXT,mhash TEXT);\n"
177 "WITH tmap(id,type) AS (VALUES(0,'merge'),(-1,'cherrypick'),"
178 "(-2,'backout'),(-4,'integrate'))"
@@ -226,12 +236,12 @@
226 }
227 db_finalize(&q);
228 }
229 db_prepare(&q,
230 "SELECT pathname,"
231 " hash IS NULL AND delta IS NOT NULL,"
232 " delta IS NULL,"
233 " origname"
234 " FROM patch.chng ORDER BY 1");
235 while( db_step(&q)==SQLITE_ROW ){
236 const char *zClass = "EDIT";
237 const char *zName = db_column_text(&q,0);
@@ -255,14 +265,15 @@
255 ** Apply the patch currently attached as database "patch".
256 **
257 ** First update the check-out to be at "baseline". Then loop through
258 ** and update all files.
259 */
260 void patch_apply(void){
261 Stmt q;
262 Blob cmd;
263 blob_init(&cmd, 0, 0);
 
264 db_prepare(&q,
265 "SELECT patch.cfg.value"
266 " FROM patch.cfg, localdb.vvar"
267 " WHERE patch.cfg.key='baseline'"
268 " AND localdb.vvar.name='checkout-hash'"
@@ -269,21 +280,185 @@
269 " AND patch.cfg.key<>localdb.vvar.name"
270 );
271 if( db_step(&q)==SQLITE_ROW ){
272 blob_append_escaped_arg(&cmd, g.nameOfExe);
273 blob_appendf(&cmd, " update %s", db_column_text(&q, 0));
 
 
 
274 }
275 db_finalize(&q);
276 if( blob_size(&cmd)>0 ){
277 int rc = fossil_system(blob_str(&cmd));
278 if( rc ){
279 fossil_fatal("unable to update to the baseline check-out: %s",
280 blob_str(&cmd));
 
 
 
 
281 }
282 }
283 blob_reset(&cmd);
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285 }
286
287
288 /*
289 ** COMMAND: patch
@@ -304,10 +479,12 @@
304 **
305 ** Apply the changes in FILENAME to the current check-out. Options:
306 **
307 ** -f|--force Apply the patch even though there are unsaved
308 ** changes in the current check-out.
 
 
309 **
310 ** > fossil patch diff [DIFF-FLAGS] FILENAME
311 **
312 ** View the changes specified by the binary patch FILENAME in a
313 ** human-readable format. The usual diff flags apply.
@@ -336,20 +513,23 @@
336 }
337 zCmd = g.argv[2];
338 n = strlen(zCmd);
339 if( strncmp(zCmd, "apply", n)==0 ){
340 int forceFlag = find_option("force","f",0)!=0;
 
 
 
341 db_must_be_within_tree();
342 verify_all_options();
343 if( g.argc!=4 ){
344 usage("apply FILENAME");
345 }
346 if( !forceFlag && unsaved_changes(0) ){
347 fossil_fatal("there are unsaved changes in the current checkout");
348 }
349 patch_attach(g.argv[3]);
350 patch_apply();
351 }else
352 if( strncmp(zCmd, "create", n)==0 ){
353 db_must_be_within_tree();
354 verify_all_options();
355 if( g.argc!=4 ){
356
--- src/patch.c
+++ src/patch.c
@@ -19,10 +19,17 @@
19 */
20 #include "config.h"
21 #include "patch.h"
22 #include <assert.h>
23
24 /*
25 ** Flags passed from the main patch_cmd() routine into subfunctions used
26 ** to implement the various subcommands.
27 */
28 #define PATCH_DRYRUN 0x0001
29 #define PATCH_VERBOSE 0x0002
30
31 /*
32 ** Implementation of the "readfile(X)" SQL function. The entire content
33 ** of the checkout file named X is read and returned as a BLOB.
34 */
35 static void readfileFunc(
@@ -152,16 +159,18 @@
159 " SELECT pathname, NULL, isexe, islink,"
160 " compress(read_co_file(%Q||pathname))"
161 " FROM vfile WHERE rid==0;",
162 g.zLocalRoot
163 );
164
165 /* Deleted files */
166 db_multi_exec(
167 "INSERT INTO patch.chng(pathname,hash,isexe,islink,delta)"
168 " SELECT pathname, NULL, 0, 0, NULL"
169 " FROM vfile WHERE deleted;"
170 );
171
172 /* Changed files */
173 db_multi_exec(
174 "INSERT INTO patch.chng(pathname,origname,hash,isexe,islink,delta)"
175 " SELECT pathname, nullif(origname,pathname), blob.uuid, isexe, islink,"
176 " mkdelta(blob.rid, %Q||pathname)"
@@ -169,10 +178,11 @@
178 " WHERE blob.rid=vfile.rid"
179 " AND NOT deleted AND (chnged OR origname<>pathname);",
180 g.zLocalRoot
181 );
182
183 /* Merges */
184 if( db_exists("SELECT 1 FROM localdb.vmerge WHERE id<=0") ){
185 db_multi_exec(
186 "CREATE TABLE patch.patchmerge(type TEXT,mhash TEXT);\n"
187 "WITH tmap(id,type) AS (VALUES(0,'merge'),(-1,'cherrypick'),"
188 "(-2,'backout'),(-4,'integrate'))"
@@ -226,12 +236,12 @@
236 }
237 db_finalize(&q);
238 }
239 db_prepare(&q,
240 "SELECT pathname,"
241 " hash IS NULL AND delta IS NOT NULL," /* isNew */
242 " delta IS NULL," /* delete if origname NULL */
243 " origname"
244 " FROM patch.chng ORDER BY 1");
245 while( db_step(&q)==SQLITE_ROW ){
246 const char *zClass = "EDIT";
247 const char *zName = db_column_text(&q,0);
@@ -255,14 +265,15 @@
265 ** Apply the patch currently attached as database "patch".
266 **
267 ** First update the check-out to be at "baseline". Then loop through
268 ** and update all files.
269 */
270 void patch_apply(unsigned mFlags){
271 Stmt q;
272 Blob cmd;
273 blob_init(&cmd, 0, 0);
274 file_chdir(g.zLocalRoot, 0);
275 db_prepare(&q,
276 "SELECT patch.cfg.value"
277 " FROM patch.cfg, localdb.vvar"
278 " WHERE patch.cfg.key='baseline'"
279 " AND localdb.vvar.name='checkout-hash'"
@@ -269,21 +280,185 @@
280 " AND patch.cfg.key<>localdb.vvar.name"
281 );
282 if( db_step(&q)==SQLITE_ROW ){
283 blob_append_escaped_arg(&cmd, g.nameOfExe);
284 blob_appendf(&cmd, " update %s", db_column_text(&q, 0));
285 if( mFlags & PATCH_VERBOSE ){
286 fossil_print("%-10s %s\n", "BASELINE", db_column_text(&q,0));
287 }
288 }
289 db_finalize(&q);
290 if( blob_size(&cmd)>0 ){
291 if( mFlags & PATCH_DRYRUN ){
292 fossil_print("%s\n", blob_str(&cmd));
293 }else{
294 int rc = fossil_system(blob_str(&cmd));
295 if( rc ){
296 fossil_fatal("unable to update to the baseline check-out: %s",
297 blob_str(&cmd));
298 }
299 }
300 }
301 blob_reset(&cmd);
302 if( db_table_exists("patch","patchmerge") ){
303 db_prepare(&q,
304 "SELECT type, mhash, upper(type) FROM patch.patchmerge"
305 " WHERE type IN ('merge','cherrypick','backout','integrate')"
306 " AND mhash NOT GLOB '*[^a-fA-F0-9]*';"
307 );
308 while( db_step(&q)==SQLITE_ROW ){
309 blob_append_escaped_arg(&cmd, g.nameOfExe);
310 blob_appendf(&cmd, " --%s %s\n", db_column_text(&q,0),
311 db_column_text(&q,1));
312 if( mFlags & PATCH_VERBOSE ){
313 fossil_print("%-10s %s\n", db_column_text(&q,2),
314 db_column_text(&q,0));
315 }
316 }
317 db_finalize(&q);
318 if( mFlags & PATCH_DRYRUN ){
319 fossil_print("%s", blob_str(&cmd));
320 }else{
321 int rc = fossil_system(blob_str(&cmd));
322 if( rc ){
323 fossil_fatal("unable to do merges:\n%s",
324 blob_str(&cmd));
325 }
326 }
327 blob_reset(&cmd);
328 }
329
330 /* Deletions */
331 db_prepare(&q, "SELECT pathname FROM patch.chng"
332 " WHERE origname IS NULL AND delta IS NULL");
333 while( db_step(&q)==SQLITE_ROW ){
334 blob_append_escaped_arg(&cmd, g.nameOfExe);
335 blob_appendf(&cmd, " rm --hard %$\n", db_column_text(&q,0));
336 if( mFlags & PATCH_VERBOSE ){
337 fossil_print("%-10s %s\n", "DELETE", db_column_text(&q,0));
338 }
339 }
340 db_finalize(&q);
341 if( blob_size(&cmd)>0 ){
342 if( mFlags & PATCH_DRYRUN ){
343 fossil_print("%s", blob_str(&cmd));
344 }else{
345 int rc = fossil_system(blob_str(&cmd));
346 if( rc ){
347 fossil_fatal("unable to do merges:\n%s",
348 blob_str(&cmd));
349 }
350 }
351 blob_reset(&cmd);
352 }
353
354 /* Renames */
355 db_prepare(&q,
356 "SELECT origname, pathname FROM patch.chng"
357 " WHERE origname IS NOT NULL"
358 " AND origname<>pathname"
359 );
360 while( db_step(&q)==SQLITE_ROW ){
361 blob_append_escaped_arg(&cmd, g.nameOfExe);
362 blob_appendf(&cmd, " mv --hard %$ %$\n",
363 db_column_text(&q,0), db_column_text(&q,1));
364 if( mFlags & PATCH_VERBOSE ){
365 fossil_print("%-10s %s -> %s\n", "RENAME",
366 db_column_text(&q,0), db_column_text(&q,1));
367 }
368 }
369 db_finalize(&q);
370 if( blob_size(&cmd)>0 ){
371 if( mFlags & PATCH_DRYRUN ){
372 fossil_print("%s", blob_str(&cmd));
373 }else{
374 int rc = fossil_system(blob_str(&cmd));
375 if( rc ){
376 fossil_fatal("unable to rename files:\n%s",
377 blob_str(&cmd));
378 }
379 }
380 blob_reset(&cmd);
381 }
382
383 /* Edits and new files */
384 db_prepare(&q,
385 "SELECT pathname, hash, isexe, islink, delta FROM patch.chng"
386 " WHERE delta IS NOT NULL"
387 );
388 while( db_step(&q)==SQLITE_ROW ){
389 const char *zPathname = db_column_text(&q,0);
390 const char *zHash = db_column_text(&q,1);
391 int isExe = db_column_int(&q,2);
392 int isLink = db_column_int(&q,3);
393 Blob data;
394
395 blob_init(&data, 0, 0);
396 db_column_blob(&q, 4, &data);
397 blob_uncompress(&data, &data);
398 if( zHash ){
399 Blob basis;
400 int rid = fast_uuid_to_rid(zHash);
401 int outSize, sz;
402 char *aOut;
403 if( rid==0 ){
404 fossil_fatal("cannot locate basis artifact %s for %s",
405 zHash, zPathname);
406 }
407 if( !content_get(rid, &basis) ){
408 fossil_fatal("cannot load basis artifact %d for %s", rid, zPathname);
409 }
410 outSize = delta_output_size(blob_buffer(&data),blob_size(&data));
411 if( outSize<=0 ){
412 fossil_fatal("malformed delta for %s", zPathname);
413 }
414 aOut = sqlite3_malloc64( outSize+1 );
415 if( aOut==0 ){
416 fossil_fatal("out of memory");
417 }
418 sz = delta_apply(blob_buffer(&basis), blob_size(&basis),
419 blob_buffer(&data), blob_size(&data), aOut);
420 if( sz<0 ){
421 fossil_fatal("malformed delta for %s", zPathname);
422 }
423 blob_reset(&basis);
424 blob_reset(&data);
425 blob_append(&data, aOut, sz);
426 sqlite3_free(aOut);
427 if( mFlags & PATCH_VERBOSE ){
428 fossil_print("%-10s %s\n", "EDIT", zPathname);
429 }
430 }else{
431 blob_append_escaped_arg(&cmd, g.nameOfExe);
432 blob_appendf(&cmd, " add %$\n", zPathname);
433 if( mFlags & PATCH_VERBOSE ){
434 fossil_print("%-10s %s\n", "NEW", zPathname);
435 }
436 }
437 if( (mFlags & PATCH_DRYRUN)==0 ){
438 if( isLink ){
439 symlink_create(blob_str(&data), zPathname);
440 }else{
441 blob_write_to_file(&data, zPathname);
442 }
443 file_setexe(zPathname, isExe);
444 blob_reset(&data);
445 }
446 }
447 db_finalize(&q);
448 if( blob_size(&cmd)>0 ){
449 if( mFlags & PATCH_DRYRUN ){
450 fossil_print("%s", blob_str(&cmd));
451 }else{
452 int rc = fossil_system(blob_str(&cmd));
453 if( rc ){
454 fossil_fatal("unable to add new files:\n%s",
455 blob_str(&cmd));
456 }
457 }
458 blob_reset(&cmd);
459 }
460 }
461
462
463 /*
464 ** COMMAND: patch
@@ -304,10 +479,12 @@
479 **
480 ** Apply the changes in FILENAME to the current check-out. Options:
481 **
482 ** -f|--force Apply the patch even though there are unsaved
483 ** changes in the current check-out.
484 ** -n|--dryrun Do nothing, but print what would have happened.
485 ** -v|--verbose Extra output explaining what happens.
486 **
487 ** > fossil patch diff [DIFF-FLAGS] FILENAME
488 **
489 ** View the changes specified by the binary patch FILENAME in a
490 ** human-readable format. The usual diff flags apply.
@@ -336,20 +513,23 @@
513 }
514 zCmd = g.argv[2];
515 n = strlen(zCmd);
516 if( strncmp(zCmd, "apply", n)==0 ){
517 int forceFlag = find_option("force","f",0)!=0;
518 unsigned flags = 0;
519 if( find_option("dryrun","n",0) ) flags |= PATCH_DRYRUN;
520 if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
521 db_must_be_within_tree();
522 verify_all_options();
523 if( g.argc!=4 ){
524 usage("apply FILENAME");
525 }
526 if( !forceFlag && unsaved_changes(0) ){
527 fossil_fatal("there are unsaved changes in the current checkout");
528 }
529 patch_attach(g.argv[3]);
530 patch_apply(flags);
531 }else
532 if( strncmp(zCmd, "create", n)==0 ){
533 db_must_be_within_tree();
534 verify_all_options();
535 if( g.argc!=4 ){
536

Keyboard Shortcuts

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