Fossil SCM
Add the "fossil hook status" command. Embargo post-receive hooks for 60 seconds after an incomplete sync, to give an opportunity for the sync to complete.
Commit
3d191798a62507e5c765d4f992bfe7084903b4720359a01b5896364be7f29e1f
Parent
8e424389e02fa06…
2 files changed
+55
-8
+1
+55
-8
| --- src/hook.c | ||
| +++ src/hook.c | ||
| @@ -26,11 +26,12 @@ | ||
| 26 | 26 | ** "type": "after-receive", // type of hook |
| 27 | 27 | ** "cmd": "command-to-run", // command to run |
| 28 | 28 | ** "seq": 50 // run in this order |
| 29 | 29 | ** } |
| 30 | 30 | ** |
| 31 | -** hook-last-rcvid Number of last rcvid for which hooks were run | |
| 31 | +** hook-last-rcvid The last rcvid for which post-receive hooks were | |
| 32 | +** run. | |
| 32 | 33 | ** |
| 33 | 34 | ** hook-embargo Do not run hooks again before this julianday. |
| 34 | 35 | ** |
| 35 | 36 | ** For "after-receive" hooks, a list of the received artifacts is sent |
| 36 | 37 | ** into the command via standard input. Each line of input begins with |
| @@ -104,10 +105,31 @@ | ||
| 104 | 105 | } |
| 105 | 106 | } |
| 106 | 107 | blob_str(&r); |
| 107 | 108 | return r.aData; |
| 108 | 109 | } |
| 110 | + | |
| 111 | +/* | |
| 112 | +** Record the fact that new artifacts are expected within N seconds | |
| 113 | +** (N is normally a small number) and so post-receive hooks should | |
| 114 | +** probably be deferred until after the new artifacts arrive. | |
| 115 | +** | |
| 116 | +** If N==0, then there is no expectation of new artifacts arriving | |
| 117 | +** soon and so post-receive hooks can be run without delay. | |
| 118 | +*/ | |
| 119 | +void hook_expecting_more_artifacts(int N){ | |
| 120 | + if( N>0 ){ | |
| 121 | + db_multi_exec( | |
| 122 | + "REPLACE INTO config(name,value,mtime)" | |
| 123 | + "VALUES('hook-embargo',now()+%d,now())", | |
| 124 | + N | |
| 125 | + ); | |
| 126 | + }else{ | |
| 127 | + db_unset("hook-embargo",0); | |
| 128 | + } | |
| 129 | +} | |
| 130 | + | |
| 109 | 131 | |
| 110 | 132 | /* |
| 111 | 133 | ** Fill the Blob pOut with text that describes all artifacts |
| 112 | 134 | ** received after zBaseRcvid up to and including zNewRcvid. |
| 113 | 135 | ** Except, never include more than one days worth of changes. |
| @@ -122,16 +144,21 @@ | ||
| 122 | 144 | zBaseRcvid = db_get("hook-last-rcvid","0"); |
| 123 | 145 | } |
| 124 | 146 | if( zNewRcvid==0 ){ |
| 125 | 147 | zNewRcvid = db_text("0","SELECT max(rcvid) FROM rcvfrom"); |
| 126 | 148 | } |
| 149 | + | |
| 150 | + /* Adjust the baseline rcvid to omit change that are more than | |
| 151 | + ** 24 hours older than the most recent change. | |
| 152 | + */ | |
| 127 | 153 | zBaseRcvid = db_text(0, |
| 128 | 154 | "SELECT min(rcvid) FROM rcvfrom" |
| 129 | 155 | " WHERE rcvid>=%d" |
| 130 | 156 | " AND mtime>=(SELECT mtime FROM rcvfrom WHERE rcvid=%d)-1.0", |
| 131 | 157 | atoi(zBaseRcvid), atoi(zNewRcvid) |
| 132 | 158 | ); |
| 159 | + | |
| 133 | 160 | zWhere = mprintf("IN (SELECT rid FROM blob WHERE rcvid>%d AND rcvid<=%d)", |
| 134 | 161 | atoi(zBaseRcvid), atoi(zNewRcvid)); |
| 135 | 162 | describe_artifacts(zWhere); |
| 136 | 163 | fossil_free(zWhere); |
| 137 | 164 | db_prepare(&q, "SELECT uuid, summary FROM description"); |
| @@ -146,33 +173,38 @@ | ||
| 146 | 173 | ** |
| 147 | 174 | ** Usage: %fossil hook COMMAND ... |
| 148 | 175 | ** |
| 149 | 176 | ** Commands include: |
| 150 | 177 | ** |
| 151 | -** > fossil hook list | |
| 178 | +** > fossil hook add --command COMMAND --type TYPE --sequence NUMBER | |
| 152 | 179 | ** |
| 153 | -** Show all current hooks | |
| 180 | +** Create a new hook. The --command and --type arguments are | |
| 181 | +** required. --sequence is optional. | |
| 154 | 182 | ** |
| 155 | 183 | ** > fossil hook delete ID ... |
| 156 | 184 | ** |
| 157 | 185 | ** Delete one or more hooks by their IDs. ID can be "all" |
| 158 | 186 | ** to delete all hooks. Caution: There is no "undo" for |
| 159 | 187 | ** this operation. Deleted hooks are permanently lost. |
| 160 | 188 | ** |
| 161 | -** > fossil hook add --command COMMAND --type TYPE --sequence NUMBER | |
| 162 | -** | |
| 163 | -** Create a new hook. The --command and --type arguments are | |
| 164 | -** required. --sequence is optional. | |
| 165 | -** | |
| 166 | 189 | ** > fossil hook edit --command COMMAND --type TYPE --sequence NUMBER ID ... |
| 167 | 190 | ** |
| 168 | 191 | ** Make changes to one or more existing hooks. The ID argument |
| 169 | 192 | ** is either a hook-id, or a list of hook-ids, or the keyword |
| 170 | 193 | ** "all". For example, to disable hook number 2, use: |
| 171 | 194 | ** |
| 172 | 195 | ** fossil hook edit --type disabled 2 |
| 173 | 196 | ** |
| 197 | +** > fossil hook list | |
| 198 | +** | |
| 199 | +** Show all current hooks | |
| 200 | +** | |
| 201 | +** > fossil hook status | |
| 202 | +** | |
| 203 | +** Print the values of CONFIG table entries that are relevant to | |
| 204 | +** hook processing. Used for debugging. | |
| 205 | +** | |
| 174 | 206 | ** > fossil hook test [OPTIONS] ID |
| 175 | 207 | ** |
| 176 | 208 | ** Run the hook script given by ID for testing purposes. |
| 177 | 209 | ** Options: |
| 178 | 210 | ** |
| @@ -301,10 +333,21 @@ | ||
| 301 | 333 | fossil_print("%3d: type = %s\n", |
| 302 | 334 | db_column_int(&q,0), db_column_text(&q,3)); |
| 303 | 335 | fossil_print(" command = %s\n", db_column_text(&q,2)); |
| 304 | 336 | fossil_print(" sequence = %d\n", db_column_int(&q,1)); |
| 305 | 337 | } |
| 338 | + db_finalize(&q); | |
| 339 | + }else | |
| 340 | + if( strncmp(zCmd, "status", nCmd)==0 ){ | |
| 341 | + Stmt q; | |
| 342 | + db_prepare(&q, | |
| 343 | + "SELECT name, quote(value) FROM config WHERE name IN" | |
| 344 | + "('hooks','hook-embargo','hook-last-rcvid') ORDER BY name" | |
| 345 | + ); | |
| 346 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 347 | + fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1)); | |
| 348 | + } | |
| 306 | 349 | db_finalize(&q); |
| 307 | 350 | }else |
| 308 | 351 | if( strncmp(zCmd, "test", nCmd)==0 ){ |
| 309 | 352 | Stmt q; |
| 310 | 353 | int bDryRun = find_option("dry-run", "n", 0)!=0; |
| @@ -366,10 +409,14 @@ | ||
| 366 | 409 | int cnt = 0; |
| 367 | 410 | db_begin_write(); |
| 368 | 411 | if( !db_exists("SELECT 1 FROM config WHERE name='hooks'") ){ |
| 369 | 412 | goto hook_backoffice_done; /* No hooks */ |
| 370 | 413 | } |
| 414 | + if( db_int(0, "SELECT now()<value+0 FROM config" | |
| 415 | + " WHERE name='hook-embargo'") ){ | |
| 416 | + goto hook_backoffice_done; /* Within the embargo window */ | |
| 417 | + } | |
| 371 | 418 | zLastRcvid = db_get("hook-last-rcvid","0"); |
| 372 | 419 | zNewRcvid = db_text("0","SELECT max(rcvid) FROM rcvfrom"); |
| 373 | 420 | if( atoi(zLastRcvid)>=atoi(zNewRcvid) ){ |
| 374 | 421 | goto hook_backoffice_done; /* no new content */ |
| 375 | 422 | } |
| 376 | 423 |
| --- src/hook.c | |
| +++ src/hook.c | |
| @@ -26,11 +26,12 @@ | |
| 26 | ** "type": "after-receive", // type of hook |
| 27 | ** "cmd": "command-to-run", // command to run |
| 28 | ** "seq": 50 // run in this order |
| 29 | ** } |
| 30 | ** |
| 31 | ** hook-last-rcvid Number of last rcvid for which hooks were run |
| 32 | ** |
| 33 | ** hook-embargo Do not run hooks again before this julianday. |
| 34 | ** |
| 35 | ** For "after-receive" hooks, a list of the received artifacts is sent |
| 36 | ** into the command via standard input. Each line of input begins with |
| @@ -104,10 +105,31 @@ | |
| 104 | } |
| 105 | } |
| 106 | blob_str(&r); |
| 107 | return r.aData; |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | ** Fill the Blob pOut with text that describes all artifacts |
| 112 | ** received after zBaseRcvid up to and including zNewRcvid. |
| 113 | ** Except, never include more than one days worth of changes. |
| @@ -122,16 +144,21 @@ | |
| 122 | zBaseRcvid = db_get("hook-last-rcvid","0"); |
| 123 | } |
| 124 | if( zNewRcvid==0 ){ |
| 125 | zNewRcvid = db_text("0","SELECT max(rcvid) FROM rcvfrom"); |
| 126 | } |
| 127 | zBaseRcvid = db_text(0, |
| 128 | "SELECT min(rcvid) FROM rcvfrom" |
| 129 | " WHERE rcvid>=%d" |
| 130 | " AND mtime>=(SELECT mtime FROM rcvfrom WHERE rcvid=%d)-1.0", |
| 131 | atoi(zBaseRcvid), atoi(zNewRcvid) |
| 132 | ); |
| 133 | zWhere = mprintf("IN (SELECT rid FROM blob WHERE rcvid>%d AND rcvid<=%d)", |
| 134 | atoi(zBaseRcvid), atoi(zNewRcvid)); |
| 135 | describe_artifacts(zWhere); |
| 136 | fossil_free(zWhere); |
| 137 | db_prepare(&q, "SELECT uuid, summary FROM description"); |
| @@ -146,33 +173,38 @@ | |
| 146 | ** |
| 147 | ** Usage: %fossil hook COMMAND ... |
| 148 | ** |
| 149 | ** Commands include: |
| 150 | ** |
| 151 | ** > fossil hook list |
| 152 | ** |
| 153 | ** Show all current hooks |
| 154 | ** |
| 155 | ** > fossil hook delete ID ... |
| 156 | ** |
| 157 | ** Delete one or more hooks by their IDs. ID can be "all" |
| 158 | ** to delete all hooks. Caution: There is no "undo" for |
| 159 | ** this operation. Deleted hooks are permanently lost. |
| 160 | ** |
| 161 | ** > fossil hook add --command COMMAND --type TYPE --sequence NUMBER |
| 162 | ** |
| 163 | ** Create a new hook. The --command and --type arguments are |
| 164 | ** required. --sequence is optional. |
| 165 | ** |
| 166 | ** > fossil hook edit --command COMMAND --type TYPE --sequence NUMBER ID ... |
| 167 | ** |
| 168 | ** Make changes to one or more existing hooks. The ID argument |
| 169 | ** is either a hook-id, or a list of hook-ids, or the keyword |
| 170 | ** "all". For example, to disable hook number 2, use: |
| 171 | ** |
| 172 | ** fossil hook edit --type disabled 2 |
| 173 | ** |
| 174 | ** > fossil hook test [OPTIONS] ID |
| 175 | ** |
| 176 | ** Run the hook script given by ID for testing purposes. |
| 177 | ** Options: |
| 178 | ** |
| @@ -301,10 +333,21 @@ | |
| 301 | fossil_print("%3d: type = %s\n", |
| 302 | db_column_int(&q,0), db_column_text(&q,3)); |
| 303 | fossil_print(" command = %s\n", db_column_text(&q,2)); |
| 304 | fossil_print(" sequence = %d\n", db_column_int(&q,1)); |
| 305 | } |
| 306 | db_finalize(&q); |
| 307 | }else |
| 308 | if( strncmp(zCmd, "test", nCmd)==0 ){ |
| 309 | Stmt q; |
| 310 | int bDryRun = find_option("dry-run", "n", 0)!=0; |
| @@ -366,10 +409,14 @@ | |
| 366 | int cnt = 0; |
| 367 | db_begin_write(); |
| 368 | if( !db_exists("SELECT 1 FROM config WHERE name='hooks'") ){ |
| 369 | goto hook_backoffice_done; /* No hooks */ |
| 370 | } |
| 371 | zLastRcvid = db_get("hook-last-rcvid","0"); |
| 372 | zNewRcvid = db_text("0","SELECT max(rcvid) FROM rcvfrom"); |
| 373 | if( atoi(zLastRcvid)>=atoi(zNewRcvid) ){ |
| 374 | goto hook_backoffice_done; /* no new content */ |
| 375 | } |
| 376 |
| --- src/hook.c | |
| +++ src/hook.c | |
| @@ -26,11 +26,12 @@ | |
| 26 | ** "type": "after-receive", // type of hook |
| 27 | ** "cmd": "command-to-run", // command to run |
| 28 | ** "seq": 50 // run in this order |
| 29 | ** } |
| 30 | ** |
| 31 | ** hook-last-rcvid The last rcvid for which post-receive hooks were |
| 32 | ** run. |
| 33 | ** |
| 34 | ** hook-embargo Do not run hooks again before this julianday. |
| 35 | ** |
| 36 | ** For "after-receive" hooks, a list of the received artifacts is sent |
| 37 | ** into the command via standard input. Each line of input begins with |
| @@ -104,10 +105,31 @@ | |
| 105 | } |
| 106 | } |
| 107 | blob_str(&r); |
| 108 | return r.aData; |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** Record the fact that new artifacts are expected within N seconds |
| 113 | ** (N is normally a small number) and so post-receive hooks should |
| 114 | ** probably be deferred until after the new artifacts arrive. |
| 115 | ** |
| 116 | ** If N==0, then there is no expectation of new artifacts arriving |
| 117 | ** soon and so post-receive hooks can be run without delay. |
| 118 | */ |
| 119 | void hook_expecting_more_artifacts(int N){ |
| 120 | if( N>0 ){ |
| 121 | db_multi_exec( |
| 122 | "REPLACE INTO config(name,value,mtime)" |
| 123 | "VALUES('hook-embargo',now()+%d,now())", |
| 124 | N |
| 125 | ); |
| 126 | }else{ |
| 127 | db_unset("hook-embargo",0); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | |
| 132 | /* |
| 133 | ** Fill the Blob pOut with text that describes all artifacts |
| 134 | ** received after zBaseRcvid up to and including zNewRcvid. |
| 135 | ** Except, never include more than one days worth of changes. |
| @@ -122,16 +144,21 @@ | |
| 144 | zBaseRcvid = db_get("hook-last-rcvid","0"); |
| 145 | } |
| 146 | if( zNewRcvid==0 ){ |
| 147 | zNewRcvid = db_text("0","SELECT max(rcvid) FROM rcvfrom"); |
| 148 | } |
| 149 | |
| 150 | /* Adjust the baseline rcvid to omit change that are more than |
| 151 | ** 24 hours older than the most recent change. |
| 152 | */ |
| 153 | zBaseRcvid = db_text(0, |
| 154 | "SELECT min(rcvid) FROM rcvfrom" |
| 155 | " WHERE rcvid>=%d" |
| 156 | " AND mtime>=(SELECT mtime FROM rcvfrom WHERE rcvid=%d)-1.0", |
| 157 | atoi(zBaseRcvid), atoi(zNewRcvid) |
| 158 | ); |
| 159 | |
| 160 | zWhere = mprintf("IN (SELECT rid FROM blob WHERE rcvid>%d AND rcvid<=%d)", |
| 161 | atoi(zBaseRcvid), atoi(zNewRcvid)); |
| 162 | describe_artifacts(zWhere); |
| 163 | fossil_free(zWhere); |
| 164 | db_prepare(&q, "SELECT uuid, summary FROM description"); |
| @@ -146,33 +173,38 @@ | |
| 173 | ** |
| 174 | ** Usage: %fossil hook COMMAND ... |
| 175 | ** |
| 176 | ** Commands include: |
| 177 | ** |
| 178 | ** > fossil hook add --command COMMAND --type TYPE --sequence NUMBER |
| 179 | ** |
| 180 | ** Create a new hook. The --command and --type arguments are |
| 181 | ** required. --sequence is optional. |
| 182 | ** |
| 183 | ** > fossil hook delete ID ... |
| 184 | ** |
| 185 | ** Delete one or more hooks by their IDs. ID can be "all" |
| 186 | ** to delete all hooks. Caution: There is no "undo" for |
| 187 | ** this operation. Deleted hooks are permanently lost. |
| 188 | ** |
| 189 | ** > fossil hook edit --command COMMAND --type TYPE --sequence NUMBER ID ... |
| 190 | ** |
| 191 | ** Make changes to one or more existing hooks. The ID argument |
| 192 | ** is either a hook-id, or a list of hook-ids, or the keyword |
| 193 | ** "all". For example, to disable hook number 2, use: |
| 194 | ** |
| 195 | ** fossil hook edit --type disabled 2 |
| 196 | ** |
| 197 | ** > fossil hook list |
| 198 | ** |
| 199 | ** Show all current hooks |
| 200 | ** |
| 201 | ** > fossil hook status |
| 202 | ** |
| 203 | ** Print the values of CONFIG table entries that are relevant to |
| 204 | ** hook processing. Used for debugging. |
| 205 | ** |
| 206 | ** > fossil hook test [OPTIONS] ID |
| 207 | ** |
| 208 | ** Run the hook script given by ID for testing purposes. |
| 209 | ** Options: |
| 210 | ** |
| @@ -301,10 +333,21 @@ | |
| 333 | fossil_print("%3d: type = %s\n", |
| 334 | db_column_int(&q,0), db_column_text(&q,3)); |
| 335 | fossil_print(" command = %s\n", db_column_text(&q,2)); |
| 336 | fossil_print(" sequence = %d\n", db_column_int(&q,1)); |
| 337 | } |
| 338 | db_finalize(&q); |
| 339 | }else |
| 340 | if( strncmp(zCmd, "status", nCmd)==0 ){ |
| 341 | Stmt q; |
| 342 | db_prepare(&q, |
| 343 | "SELECT name, quote(value) FROM config WHERE name IN" |
| 344 | "('hooks','hook-embargo','hook-last-rcvid') ORDER BY name" |
| 345 | ); |
| 346 | while( db_step(&q)==SQLITE_ROW ){ |
| 347 | fossil_print("%s: %s\n", db_column_text(&q,0), db_column_text(&q,1)); |
| 348 | } |
| 349 | db_finalize(&q); |
| 350 | }else |
| 351 | if( strncmp(zCmd, "test", nCmd)==0 ){ |
| 352 | Stmt q; |
| 353 | int bDryRun = find_option("dry-run", "n", 0)!=0; |
| @@ -366,10 +409,14 @@ | |
| 409 | int cnt = 0; |
| 410 | db_begin_write(); |
| 411 | if( !db_exists("SELECT 1 FROM config WHERE name='hooks'") ){ |
| 412 | goto hook_backoffice_done; /* No hooks */ |
| 413 | } |
| 414 | if( db_int(0, "SELECT now()<value+0 FROM config" |
| 415 | " WHERE name='hook-embargo'") ){ |
| 416 | goto hook_backoffice_done; /* Within the embargo window */ |
| 417 | } |
| 418 | zLastRcvid = db_get("hook-last-rcvid","0"); |
| 419 | zNewRcvid = db_text("0","SELECT max(rcvid) FROM rcvfrom"); |
| 420 | if( atoi(zLastRcvid)>=atoi(zNewRcvid) ){ |
| 421 | goto hook_backoffice_done; /* no new content */ |
| 422 | } |
| 423 |
+1
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -1739,10 +1739,11 @@ | ||
| 1739 | 1739 | }else if( isPull ){ |
| 1740 | 1740 | create_cluster(); |
| 1741 | 1741 | send_unclustered(&xfer); |
| 1742 | 1742 | if( xfer.syncPrivate ) send_private(&xfer); |
| 1743 | 1743 | } |
| 1744 | + hook_expecting_more_artifacts(xfer.nGimmeSent?60:0); | |
| 1744 | 1745 | db_multi_exec("DROP TABLE onremote; DROP TABLE unk;"); |
| 1745 | 1746 | manifest_crosslink_end(MC_PERMIT_HOOKS); |
| 1746 | 1747 | |
| 1747 | 1748 | /* Send the server timestamp last, in case prior processing happened |
| 1748 | 1749 | ** to use up a significant fraction of our time window. |
| 1749 | 1750 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -1739,10 +1739,11 @@ | |
| 1739 | }else if( isPull ){ |
| 1740 | create_cluster(); |
| 1741 | send_unclustered(&xfer); |
| 1742 | if( xfer.syncPrivate ) send_private(&xfer); |
| 1743 | } |
| 1744 | db_multi_exec("DROP TABLE onremote; DROP TABLE unk;"); |
| 1745 | manifest_crosslink_end(MC_PERMIT_HOOKS); |
| 1746 | |
| 1747 | /* Send the server timestamp last, in case prior processing happened |
| 1748 | ** to use up a significant fraction of our time window. |
| 1749 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -1739,10 +1739,11 @@ | |
| 1739 | }else if( isPull ){ |
| 1740 | create_cluster(); |
| 1741 | send_unclustered(&xfer); |
| 1742 | if( xfer.syncPrivate ) send_private(&xfer); |
| 1743 | } |
| 1744 | hook_expecting_more_artifacts(xfer.nGimmeSent?60:0); |
| 1745 | db_multi_exec("DROP TABLE onremote; DROP TABLE unk;"); |
| 1746 | manifest_crosslink_end(MC_PERMIT_HOOKS); |
| 1747 | |
| 1748 | /* Send the server timestamp last, in case prior processing happened |
| 1749 | ** to use up a significant fraction of our time window. |
| 1750 |