Fossil SCM

Code to generate a patchfile.

drh 2021-06-21 19:09 patch-cmd
Commit 7333115dc28b51c52b52704ad4000b662f1b7df5e388644ab3a93abae2ac9abb
1 file changed +86 -1
+86 -1
--- src/patch.c
+++ src/patch.c
@@ -19,10 +19,95 @@
1919
*/
2020
#include "config.h"
2121
#include "patch.h"
2222
#include <assert.h>
2323
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(
29
+ sqlite3_context *context,
30
+ int argc,
31
+ sqlite3_value **argv
32
+){
33
+ const char *zName;
34
+ Blob x;
35
+ sqlite3_int64 sz;
36
+ (void)(argc); /* Unused parameter */
37
+ zName = (const char*)sqlite3_value_text(argv[0]);
38
+ if( zName==0 || (zName[0]=='-' && zName[1]==0) ) return;
39
+ sz = blob_read_from_file(&x, zName, RepoFILE);
40
+ sqlite3_result_blob64(context, x.aData, sz, SQLITE_TRANSIENT);
41
+ blob_reset(&x);
42
+}
43
+
44
+
45
+/*
46
+** Generate a binary patch file and store it into the file
47
+** named zOut.
48
+*/
49
+void patch_create(const char *zOut){
50
+ int vid;
51
+ if( file_isdir(zOut, ExtFILE)!=0 ){
52
+ fossil_fatal("patch file already exists: %s", zOut);
53
+ }
54
+ add_content_sql_commands(g.db);
55
+ deltafunc_init(g.db);
56
+ sqlite3_create_function(g.db, "read_co_file", 1, SQLITE_UTF8, 0,
57
+ readfileFunc, 0, 0);
58
+ db_multi_exec("ATTACH %Q AS patch;", zOut);
59
+ db_multi_exec(
60
+ "PRAGMA patch.journal_mode=OFF;\n"
61
+ "PRAGMA patch.page_size=512;\n"
62
+ "CREATE TABLE patch.chng(\n"
63
+ " fname TEXT,\n" /* Filename */
64
+ " hash TEXT,\n" /* Baseline hash. NULL for new files. */
65
+ " isexe BOOL,\n" /* True if executable */
66
+ " islink BOOL,\n" /* True if is a symbolic link */
67
+ " delta BLOB\n" /* Delta. NULL if file deleted */
68
+ ");"
69
+ "CREATE TABLE patch.cfg(\n"
70
+ " key TEXT,\n"
71
+ " value ANY\n"
72
+ ");"
73
+ );
74
+ vid = db_lget_int("checkout", 0);
75
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
76
+ db_multi_exec(
77
+ "INSERT INTO patch.cfg(key,value)"
78
+ "SELECT 'baseline',uuid FROM blob WHERE rid=%d", vid);
79
+ if( db_exists("SELECT 1 FROM vmerge") ){
80
+ db_multi_exec("INSERT INTO patch.cfg(key,value)VALUES('merged',1);");
81
+ }
82
+
83
+ /* New files */
84
+ db_multi_exec(
85
+ "INSERT INTO patch.chng(fname,hash,isexe,islink,delta)"
86
+ " SELECT pathname, NULL, isexe, islink,"
87
+ " compress(read_co_file(%Q||pathname))"
88
+ " FROM vfile WHERE rid==0;",
89
+ g.zLocalRoot
90
+ );
91
+ /* Deleted files */
92
+ db_multi_exec(
93
+ "INSERT INTO patch.chng(fname,hash,isexe,islink,delta)"
94
+ " SELECT pathname, NULL, 0, 0, NULL"
95
+ " FROM vfile WHERE deleted;"
96
+ );
97
+ /* Changed files */
98
+ db_multi_exec(
99
+ "INSERT INTO patch.chng(fname,hash,isexe,islink,delta)"
100
+ " SELECT pathname, blob.uuid, isexe, islink,"
101
+ " compress(delta_create(content(blob.uuid),"
102
+ "read_co_file(%Q||pathname)))"
103
+ " FROM vfile, blob"
104
+ " WHERE blob.rid=vfile.rid AND NOT deleted AND chnged;",
105
+ g.zLocalRoot
106
+ );
107
+}
108
+
24109
25110
/*
26111
** COMMAND: patch
27112
**
28113
** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
@@ -69,18 +154,18 @@
69154
db_must_be_within_tree();
70155
verify_all_options();
71156
if( g.argc!=4 ){
72157
usage("apply FILENAME");
73158
}
74
- fossil_print("TBD...\n");
75159
}else
76160
if( strncmp(zCmd, "create", n)==0 ){
77161
db_must_be_within_tree();
78162
verify_all_options();
79163
if( g.argc!=4 ){
80164
usage("create FILENAME");
81165
}
166
+ patch_create(g.argv[3]);
82167
}else
83168
if( strncmp(zCmd, "pull", n)==0 ){
84169
db_must_be_within_tree();
85170
verify_all_options();
86171
if( g.argc!=4 ){
87172
--- src/patch.c
+++ src/patch.c
@@ -19,10 +19,95 @@
19 */
20 #include "config.h"
21 #include "patch.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
25 /*
26 ** COMMAND: patch
27 **
28 ** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
@@ -69,18 +154,18 @@
69 db_must_be_within_tree();
70 verify_all_options();
71 if( g.argc!=4 ){
72 usage("apply FILENAME");
73 }
74 fossil_print("TBD...\n");
75 }else
76 if( strncmp(zCmd, "create", n)==0 ){
77 db_must_be_within_tree();
78 verify_all_options();
79 if( g.argc!=4 ){
80 usage("create FILENAME");
81 }
 
82 }else
83 if( strncmp(zCmd, "pull", n)==0 ){
84 db_must_be_within_tree();
85 verify_all_options();
86 if( g.argc!=4 ){
87
--- src/patch.c
+++ src/patch.c
@@ -19,10 +19,95 @@
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(
29 sqlite3_context *context,
30 int argc,
31 sqlite3_value **argv
32 ){
33 const char *zName;
34 Blob x;
35 sqlite3_int64 sz;
36 (void)(argc); /* Unused parameter */
37 zName = (const char*)sqlite3_value_text(argv[0]);
38 if( zName==0 || (zName[0]=='-' && zName[1]==0) ) return;
39 sz = blob_read_from_file(&x, zName, RepoFILE);
40 sqlite3_result_blob64(context, x.aData, sz, SQLITE_TRANSIENT);
41 blob_reset(&x);
42 }
43
44
45 /*
46 ** Generate a binary patch file and store it into the file
47 ** named zOut.
48 */
49 void patch_create(const char *zOut){
50 int vid;
51 if( file_isdir(zOut, ExtFILE)!=0 ){
52 fossil_fatal("patch file already exists: %s", zOut);
53 }
54 add_content_sql_commands(g.db);
55 deltafunc_init(g.db);
56 sqlite3_create_function(g.db, "read_co_file", 1, SQLITE_UTF8, 0,
57 readfileFunc, 0, 0);
58 db_multi_exec("ATTACH %Q AS patch;", zOut);
59 db_multi_exec(
60 "PRAGMA patch.journal_mode=OFF;\n"
61 "PRAGMA patch.page_size=512;\n"
62 "CREATE TABLE patch.chng(\n"
63 " fname TEXT,\n" /* Filename */
64 " hash TEXT,\n" /* Baseline hash. NULL for new files. */
65 " isexe BOOL,\n" /* True if executable */
66 " islink BOOL,\n" /* True if is a symbolic link */
67 " delta BLOB\n" /* Delta. NULL if file deleted */
68 ");"
69 "CREATE TABLE patch.cfg(\n"
70 " key TEXT,\n"
71 " value ANY\n"
72 ");"
73 );
74 vid = db_lget_int("checkout", 0);
75 vfile_check_signature(vid, CKSIG_ENOTFILE);
76 db_multi_exec(
77 "INSERT INTO patch.cfg(key,value)"
78 "SELECT 'baseline',uuid FROM blob WHERE rid=%d", vid);
79 if( db_exists("SELECT 1 FROM vmerge") ){
80 db_multi_exec("INSERT INTO patch.cfg(key,value)VALUES('merged',1);");
81 }
82
83 /* New files */
84 db_multi_exec(
85 "INSERT INTO patch.chng(fname,hash,isexe,islink,delta)"
86 " SELECT pathname, NULL, isexe, islink,"
87 " compress(read_co_file(%Q||pathname))"
88 " FROM vfile WHERE rid==0;",
89 g.zLocalRoot
90 );
91 /* Deleted files */
92 db_multi_exec(
93 "INSERT INTO patch.chng(fname,hash,isexe,islink,delta)"
94 " SELECT pathname, NULL, 0, 0, NULL"
95 " FROM vfile WHERE deleted;"
96 );
97 /* Changed files */
98 db_multi_exec(
99 "INSERT INTO patch.chng(fname,hash,isexe,islink,delta)"
100 " SELECT pathname, blob.uuid, isexe, islink,"
101 " compress(delta_create(content(blob.uuid),"
102 "read_co_file(%Q||pathname)))"
103 " FROM vfile, blob"
104 " WHERE blob.rid=vfile.rid AND NOT deleted AND chnged;",
105 g.zLocalRoot
106 );
107 }
108
109
110 /*
111 ** COMMAND: patch
112 **
113 ** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
@@ -69,18 +154,18 @@
154 db_must_be_within_tree();
155 verify_all_options();
156 if( g.argc!=4 ){
157 usage("apply FILENAME");
158 }
 
159 }else
160 if( strncmp(zCmd, "create", n)==0 ){
161 db_must_be_within_tree();
162 verify_all_options();
163 if( g.argc!=4 ){
164 usage("create FILENAME");
165 }
166 patch_create(g.argv[3]);
167 }else
168 if( strncmp(zCmd, "pull", n)==0 ){
169 db_must_be_within_tree();
170 verify_all_options();
171 if( g.argc!=4 ){
172

Keyboard Shortcuts

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