Fossil SCM
added output redirect and client force for hook
Commit
ccef28b54b3662d4b9dc9f556a3b35c9c4b6e8a4
Parent
9cf288de27c2eb7…
2 files changed
+15
-2
+25
-7
M
src/db.c
+15
-2
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1526,10 +1526,12 @@ | ||
| 1526 | 1526 | { "localauth", 0, 0, "0" }, |
| 1527 | 1527 | { "mtime-changes", 0, 0, "0" }, |
| 1528 | 1528 | { "pgp-command", 0, 32, "gpg --clearsign -o " }, |
| 1529 | 1529 | { "proxy", 0, 32, "off" }, |
| 1530 | 1530 | { "push-hook-cmd", 0, 32, "" }, |
| 1531 | + { "push-hook-force", | |
| 1532 | + 0, 0, "" }, | |
| 1531 | 1533 | { "push-hook-pattern-client", |
| 1532 | 1534 | 0, 32, "" }, |
| 1533 | 1535 | { "push-hook-pattern-server", |
| 1534 | 1536 | 0, 32, "" }, |
| 1535 | 1537 | { "ssh-command", 0, 32, "" }, |
| @@ -1605,12 +1607,23 @@ | ||
| 1605 | 1607 | ** then a direct HTTP connection is used. |
| 1606 | 1608 | ** |
| 1607 | 1609 | ** push-hook-cmd this is the command line, that will be activated |
| 1608 | 1610 | ** as push hook. Output redirects should be added to |
| 1609 | 1611 | ** this command line. |
| 1610 | -** The complete pattern, sent by the client will be | |
| 1611 | -** appended to the command line. | |
| 1612 | +** The complete command line looks like: | |
| 1613 | +** command name: the configured value for push-hook-cmd | |
| 1614 | +** argument 1: timestamp followed by random-number | |
| 1615 | +** argument 2: pattern sent by client | |
| 1616 | +** As fallback, stdin/stderr are redirected to files | |
| 1617 | +** hook-log-<timestamp followed by random-number> | |
| 1618 | +** | |
| 1619 | +** push-hook-force | |
| 1620 | +** if this is set on the client, it will request always | |
| 1621 | +** the hook activation, even if no files where pushed on | |
| 1622 | +** the sync. | |
| 1623 | +** if this is set on the server, it will accept hook | |
| 1624 | +** activiation, even if no files where pushed. | |
| 1612 | 1625 | ** |
| 1613 | 1626 | ** push-hook-pattern-client |
| 1614 | 1627 | ** if set, a client push will sent this message to the |
| 1615 | 1628 | ** server, to activate the push hook command. |
| 1616 | 1629 | ** |
| 1617 | 1630 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1526,10 +1526,12 @@ | |
| 1526 | { "localauth", 0, 0, "0" }, |
| 1527 | { "mtime-changes", 0, 0, "0" }, |
| 1528 | { "pgp-command", 0, 32, "gpg --clearsign -o " }, |
| 1529 | { "proxy", 0, 32, "off" }, |
| 1530 | { "push-hook-cmd", 0, 32, "" }, |
| 1531 | { "push-hook-pattern-client", |
| 1532 | 0, 32, "" }, |
| 1533 | { "push-hook-pattern-server", |
| 1534 | 0, 32, "" }, |
| 1535 | { "ssh-command", 0, 32, "" }, |
| @@ -1605,12 +1607,23 @@ | |
| 1605 | ** then a direct HTTP connection is used. |
| 1606 | ** |
| 1607 | ** push-hook-cmd this is the command line, that will be activated |
| 1608 | ** as push hook. Output redirects should be added to |
| 1609 | ** this command line. |
| 1610 | ** The complete pattern, sent by the client will be |
| 1611 | ** appended to the command line. |
| 1612 | ** |
| 1613 | ** push-hook-pattern-client |
| 1614 | ** if set, a client push will sent this message to the |
| 1615 | ** server, to activate the push hook command. |
| 1616 | ** |
| 1617 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1526,10 +1526,12 @@ | |
| 1526 | { "localauth", 0, 0, "0" }, |
| 1527 | { "mtime-changes", 0, 0, "0" }, |
| 1528 | { "pgp-command", 0, 32, "gpg --clearsign -o " }, |
| 1529 | { "proxy", 0, 32, "off" }, |
| 1530 | { "push-hook-cmd", 0, 32, "" }, |
| 1531 | { "push-hook-force", |
| 1532 | 0, 0, "" }, |
| 1533 | { "push-hook-pattern-client", |
| 1534 | 0, 32, "" }, |
| 1535 | { "push-hook-pattern-server", |
| 1536 | 0, 32, "" }, |
| 1537 | { "ssh-command", 0, 32, "" }, |
| @@ -1605,12 +1607,23 @@ | |
| 1607 | ** then a direct HTTP connection is used. |
| 1608 | ** |
| 1609 | ** push-hook-cmd this is the command line, that will be activated |
| 1610 | ** as push hook. Output redirects should be added to |
| 1611 | ** this command line. |
| 1612 | ** The complete command line looks like: |
| 1613 | ** command name: the configured value for push-hook-cmd |
| 1614 | ** argument 1: timestamp followed by random-number |
| 1615 | ** argument 2: pattern sent by client |
| 1616 | ** As fallback, stdin/stderr are redirected to files |
| 1617 | ** hook-log-<timestamp followed by random-number> |
| 1618 | ** |
| 1619 | ** push-hook-force |
| 1620 | ** if this is set on the client, it will request always |
| 1621 | ** the hook activation, even if no files where pushed on |
| 1622 | ** the sync. |
| 1623 | ** if this is set on the server, it will accept hook |
| 1624 | ** activiation, even if no files where pushed. |
| 1625 | ** |
| 1626 | ** push-hook-pattern-client |
| 1627 | ** if set, a client push will sent this message to the |
| 1628 | ** server, to activate the push hook command. |
| 1629 | ** |
| 1630 |
+25
-7
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -74,33 +74,48 @@ | ||
| 74 | 74 | ){ |
| 75 | 75 | fossil_fatal("push hook pattern '%s' doesn't match configuration '%s'\n", |
| 76 | 76 | g.argv[2],zPushHookPattern); |
| 77 | 77 | } |
| 78 | 78 | } |
| 79 | - post_push_hook(g.argv[2]); | |
| 79 | + post_push_hook(g.argv[2],'C'); | |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | /* |
| 83 | 83 | ** Let a server-side external agent know that a push has completed. /fatman |
| 84 | +** The second argument controls, how the command is called: | |
| 85 | +** P - client request with pushed files | |
| 86 | +** F - client request without pushed files(FORCE!) | |
| 87 | +** C - server side command line activation | |
| 84 | 88 | */ |
| 85 | -void post_push_hook(char const * const zPushHookLine){ | |
| 89 | +void post_push_hook(char const * const zPushHookLine, const char requestType){ | |
| 86 | 90 | /* |
| 87 | 91 | ** TO DO: get the string cmd from a config file? Or the database local |
| 88 | 92 | ** settings, as someone suggested? Ditto output and error logs. /fatman |
| 89 | 93 | */ |
| 90 | 94 | const char *zCmd = db_get("push-hook-cmd", ""); |
| 95 | + int allowForced = db_get_boolean("push-hook-force", 0); | |
| 91 | 96 | |
| 92 | - if( zCmd && zCmd[0] ){ | |
| 97 | + if( requestType=='P' && !allowForced){ | |
| 98 | + fossil_print("Forced push call from client not allowed," | |
| 99 | + " skipping call for '%s'\n", zPushHookLine); | |
| 100 | + }else if( zCmd && zCmd[0] ){ | |
| 93 | 101 | int rc; |
| 94 | 102 | char * zCalledCmd; |
| 103 | + char * zDate; | |
| 104 | + const char *zRnd; | |
| 105 | + | |
| 106 | + | |
| 107 | + zDate = db_text(0, "SELECT strftime('%%Y%%m%%d%%H%%M%%f','now')"); | |
| 108 | + zRnd = db_text(0, "SELECT lower(hex(randomblob(6)))"); | |
| 95 | 109 | |
| 96 | - zCalledCmd = mprintf("%s %s",zCmd,zPushHookLine); | |
| 110 | + zCalledCmd = mprintf("%s %s-%s %s >hook-log-%s-%s 2>&1",zCmd,zDate,zRnd,zPushHookLine,zDate,zRnd); | |
| 97 | 111 | rc = system(zCalledCmd); |
| 98 | 112 | if (rc != 0) { |
| 99 | 113 | fossil_print("The post-push-hook command \"%s\" failed.", zCalledCmd); |
| 100 | 114 | } |
| 101 | 115 | free(zCalledCmd); |
| 116 | + free(zDate); | |
| 102 | 117 | }else{ |
| 103 | 118 | fossil_print("No push hook configured, skipping call for '%s'\n", zPushHookLine); |
| 104 | 119 | } |
| 105 | 120 | } |
| 106 | 121 | |
| @@ -686,11 +701,11 @@ | ||
| 686 | 701 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 687 | 702 | if( lenPushHookPattern |
| 688 | 703 | && 0 == memcmp(blob_buffer(&xfer.line)+1, |
| 689 | 704 | zPushHookPattern, lenPushHookPattern) |
| 690 | 705 | ){ |
| 691 | - post_push_hook(blob_buffer(&xfer.line)+1); | |
| 706 | + post_push_hook(blob_buffer(&xfer.line)+2,blob_buffer(&xfer.line)[1]); | |
| 692 | 707 | } |
| 693 | 708 | continue; |
| 694 | 709 | } |
| 695 | 710 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| 696 | 711 | |
| @@ -1021,10 +1036,11 @@ | ||
| 1021 | 1036 | Blob recv; /* Reply we got back from the server */ |
| 1022 | 1037 | Xfer xfer; /* Transfer data */ |
| 1023 | 1038 | const char *zSCode = db_get("server-code", "x"); |
| 1024 | 1039 | const char *zPCode = db_get("project-code", 0); |
| 1025 | 1040 | const char *zPushHookPattern = db_get("push-hook-pattern-client", ""); |
| 1041 | + int allowForced = db_get_boolean("push-hook-force", 0); | |
| 1026 | 1042 | |
| 1027 | 1043 | |
| 1028 | 1044 | if( db_get_boolean("dont-push", 0) ) pushFlag = 0; |
| 1029 | 1045 | if( pushFlag + pullFlag + cloneFlag == 0 |
| 1030 | 1046 | && configRcvMask==0 && configSendMask==0 ) return; |
| @@ -1404,17 +1420,19 @@ | ||
| 1404 | 1420 | } |
| 1405 | 1421 | |
| 1406 | 1422 | /* If this is a clone, the go at least two rounds */ |
| 1407 | 1423 | if( cloneFlag && nCycle==1 ) go = 1; |
| 1408 | 1424 | }; |
| 1409 | - if (pushFlag && nFileSend > 0) { | |
| 1425 | + if( pushFlag && ( (nFileSend > 0) || allowForced ) ){ | |
| 1410 | 1426 | if( zPushHookPattern && zPushHookPattern[0] ){ |
| 1411 | - blob_appendf(&send, "#%s\n", zPushHookPattern); | |
| 1427 | + blob_appendf(&send, "#%c%s\n", | |
| 1428 | + ((nFileSend > 0)?'P':'F'), zPushHookPattern); | |
| 1412 | 1429 | http_exchange(&send, &recv, cloneFlag==0 || nCycle>0); |
| 1413 | 1430 | blob_reset(&send); |
| 1414 | 1431 | nCardSent++; |
| 1415 | 1432 | } |
| 1433 | + int allowForced = db_get_boolean("push-hook-force", 0); | |
| 1416 | 1434 | } |
| 1417 | 1435 | transport_stats(&nSent, &nRcvd, 1); |
| 1418 | 1436 | fossil_print("Total network traffic: %d bytes sent, %d bytes received\n", |
| 1419 | 1437 | nSent, nRcvd); |
| 1420 | 1438 | transport_close(); |
| 1421 | 1439 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -74,33 +74,48 @@ | |
| 74 | ){ |
| 75 | fossil_fatal("push hook pattern '%s' doesn't match configuration '%s'\n", |
| 76 | g.argv[2],zPushHookPattern); |
| 77 | } |
| 78 | } |
| 79 | post_push_hook(g.argv[2]); |
| 80 | } |
| 81 | |
| 82 | /* |
| 83 | ** Let a server-side external agent know that a push has completed. /fatman |
| 84 | */ |
| 85 | void post_push_hook(char const * const zPushHookLine){ |
| 86 | /* |
| 87 | ** TO DO: get the string cmd from a config file? Or the database local |
| 88 | ** settings, as someone suggested? Ditto output and error logs. /fatman |
| 89 | */ |
| 90 | const char *zCmd = db_get("push-hook-cmd", ""); |
| 91 | |
| 92 | if( zCmd && zCmd[0] ){ |
| 93 | int rc; |
| 94 | char * zCalledCmd; |
| 95 | |
| 96 | zCalledCmd = mprintf("%s %s",zCmd,zPushHookLine); |
| 97 | rc = system(zCalledCmd); |
| 98 | if (rc != 0) { |
| 99 | fossil_print("The post-push-hook command \"%s\" failed.", zCalledCmd); |
| 100 | } |
| 101 | free(zCalledCmd); |
| 102 | }else{ |
| 103 | fossil_print("No push hook configured, skipping call for '%s'\n", zPushHookLine); |
| 104 | } |
| 105 | } |
| 106 | |
| @@ -686,11 +701,11 @@ | |
| 686 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 687 | if( lenPushHookPattern |
| 688 | && 0 == memcmp(blob_buffer(&xfer.line)+1, |
| 689 | zPushHookPattern, lenPushHookPattern) |
| 690 | ){ |
| 691 | post_push_hook(blob_buffer(&xfer.line)+1); |
| 692 | } |
| 693 | continue; |
| 694 | } |
| 695 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| 696 | |
| @@ -1021,10 +1036,11 @@ | |
| 1021 | Blob recv; /* Reply we got back from the server */ |
| 1022 | Xfer xfer; /* Transfer data */ |
| 1023 | const char *zSCode = db_get("server-code", "x"); |
| 1024 | const char *zPCode = db_get("project-code", 0); |
| 1025 | const char *zPushHookPattern = db_get("push-hook-pattern-client", ""); |
| 1026 | |
| 1027 | |
| 1028 | if( db_get_boolean("dont-push", 0) ) pushFlag = 0; |
| 1029 | if( pushFlag + pullFlag + cloneFlag == 0 |
| 1030 | && configRcvMask==0 && configSendMask==0 ) return; |
| @@ -1404,17 +1420,19 @@ | |
| 1404 | } |
| 1405 | |
| 1406 | /* If this is a clone, the go at least two rounds */ |
| 1407 | if( cloneFlag && nCycle==1 ) go = 1; |
| 1408 | }; |
| 1409 | if (pushFlag && nFileSend > 0) { |
| 1410 | if( zPushHookPattern && zPushHookPattern[0] ){ |
| 1411 | blob_appendf(&send, "#%s\n", zPushHookPattern); |
| 1412 | http_exchange(&send, &recv, cloneFlag==0 || nCycle>0); |
| 1413 | blob_reset(&send); |
| 1414 | nCardSent++; |
| 1415 | } |
| 1416 | } |
| 1417 | transport_stats(&nSent, &nRcvd, 1); |
| 1418 | fossil_print("Total network traffic: %d bytes sent, %d bytes received\n", |
| 1419 | nSent, nRcvd); |
| 1420 | transport_close(); |
| 1421 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -74,33 +74,48 @@ | |
| 74 | ){ |
| 75 | fossil_fatal("push hook pattern '%s' doesn't match configuration '%s'\n", |
| 76 | g.argv[2],zPushHookPattern); |
| 77 | } |
| 78 | } |
| 79 | post_push_hook(g.argv[2],'C'); |
| 80 | } |
| 81 | |
| 82 | /* |
| 83 | ** Let a server-side external agent know that a push has completed. /fatman |
| 84 | ** The second argument controls, how the command is called: |
| 85 | ** P - client request with pushed files |
| 86 | ** F - client request without pushed files(FORCE!) |
| 87 | ** C - server side command line activation |
| 88 | */ |
| 89 | void post_push_hook(char const * const zPushHookLine, const char requestType){ |
| 90 | /* |
| 91 | ** TO DO: get the string cmd from a config file? Or the database local |
| 92 | ** settings, as someone suggested? Ditto output and error logs. /fatman |
| 93 | */ |
| 94 | const char *zCmd = db_get("push-hook-cmd", ""); |
| 95 | int allowForced = db_get_boolean("push-hook-force", 0); |
| 96 | |
| 97 | if( requestType=='P' && !allowForced){ |
| 98 | fossil_print("Forced push call from client not allowed," |
| 99 | " skipping call for '%s'\n", zPushHookLine); |
| 100 | }else if( zCmd && zCmd[0] ){ |
| 101 | int rc; |
| 102 | char * zCalledCmd; |
| 103 | char * zDate; |
| 104 | const char *zRnd; |
| 105 | |
| 106 | |
| 107 | zDate = db_text(0, "SELECT strftime('%%Y%%m%%d%%H%%M%%f','now')"); |
| 108 | zRnd = db_text(0, "SELECT lower(hex(randomblob(6)))"); |
| 109 | |
| 110 | zCalledCmd = mprintf("%s %s-%s %s >hook-log-%s-%s 2>&1",zCmd,zDate,zRnd,zPushHookLine,zDate,zRnd); |
| 111 | rc = system(zCalledCmd); |
| 112 | if (rc != 0) { |
| 113 | fossil_print("The post-push-hook command \"%s\" failed.", zCalledCmd); |
| 114 | } |
| 115 | free(zCalledCmd); |
| 116 | free(zDate); |
| 117 | }else{ |
| 118 | fossil_print("No push hook configured, skipping call for '%s'\n", zPushHookLine); |
| 119 | } |
| 120 | } |
| 121 | |
| @@ -686,11 +701,11 @@ | |
| 701 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 702 | if( lenPushHookPattern |
| 703 | && 0 == memcmp(blob_buffer(&xfer.line)+1, |
| 704 | zPushHookPattern, lenPushHookPattern) |
| 705 | ){ |
| 706 | post_push_hook(blob_buffer(&xfer.line)+2,blob_buffer(&xfer.line)[1]); |
| 707 | } |
| 708 | continue; |
| 709 | } |
| 710 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| 711 | |
| @@ -1021,10 +1036,11 @@ | |
| 1036 | Blob recv; /* Reply we got back from the server */ |
| 1037 | Xfer xfer; /* Transfer data */ |
| 1038 | const char *zSCode = db_get("server-code", "x"); |
| 1039 | const char *zPCode = db_get("project-code", 0); |
| 1040 | const char *zPushHookPattern = db_get("push-hook-pattern-client", ""); |
| 1041 | int allowForced = db_get_boolean("push-hook-force", 0); |
| 1042 | |
| 1043 | |
| 1044 | if( db_get_boolean("dont-push", 0) ) pushFlag = 0; |
| 1045 | if( pushFlag + pullFlag + cloneFlag == 0 |
| 1046 | && configRcvMask==0 && configSendMask==0 ) return; |
| @@ -1404,17 +1420,19 @@ | |
| 1420 | } |
| 1421 | |
| 1422 | /* If this is a clone, the go at least two rounds */ |
| 1423 | if( cloneFlag && nCycle==1 ) go = 1; |
| 1424 | }; |
| 1425 | if( pushFlag && ( (nFileSend > 0) || allowForced ) ){ |
| 1426 | if( zPushHookPattern && zPushHookPattern[0] ){ |
| 1427 | blob_appendf(&send, "#%c%s\n", |
| 1428 | ((nFileSend > 0)?'P':'F'), zPushHookPattern); |
| 1429 | http_exchange(&send, &recv, cloneFlag==0 || nCycle>0); |
| 1430 | blob_reset(&send); |
| 1431 | nCardSent++; |
| 1432 | } |
| 1433 | int allowForced = db_get_boolean("push-hook-force", 0); |
| 1434 | } |
| 1435 | transport_stats(&nSent, &nRcvd, 1); |
| 1436 | fossil_print("Total network traffic: %d bytes sent, %d bytes received\n", |
| 1437 | nSent, nRcvd); |
| 1438 | transport_close(); |
| 1439 |