Overview
SHA1 Hash: | 28e56282c91556de4dde4860cf2618e5fca42314 |
---|---|
Date: | 2008-05-23 19:21:03 |
User: | drh |
Comment: | Finish implementing the configuration command by adding method implementations for "import", "reset", and "pull". |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/clone.c from [ebfd80e735] to [06872ed5c0].
@@ -75,11 +75,11 @@ } db_finalize(&q); }else{ url_enable_proxy(0); g.xlinkClusterOnly = 1; - client_sync(0,0,1); + client_sync(0,0,1,CONFIGSET_ALL); g.xlinkClusterOnly = 0; } verify_cancel(); db_end_transaction(0); db_close();
Modified src/configure.c from [bd69dac967] to [ee8a3cb48e].
@@ -61,29 +61,50 @@ ** transfer. */ static struct { const char *zName; /* Name of the configuration parameter */ int groupMask; /* Which config groups is it part of */ -} aSafeConfig[] = { +} aConfig[] = { { "css", CONFIGSET_SKIN }, { "header", CONFIGSET_SKIN }, { "footer", CONFIGSET_SKIN }, { "project-name", CONFIGSET_PROJ }, { "project-description", CONFIGSET_PROJ }, { "index-page", CONFIGSET_SKIN }, { "timeline-block-markup", CONFIGSET_SKIN }, { "timeline-max-comment", CONFIGSET_SKIN }, }; +static int iConfig = 0; + +/* +** Return name of first configuration property matching the given mask. +*/ +const char *configure_first_name(int iMask){ + iConfig = 0; + return configure_next_name(iMask); +} +const char *configure_next_name(int iMask){ + while( iConfig<count(aConfig) ){ + if( aConfig[iConfig].groupMask & iMask ){ + return aConfig[iConfig++].zName; + }else{ + iConfig++; + } + } + return 0; +} /* ** Return TRUE if a particular configuration parameter zName is ** safely exportable. */ int configure_is_exportable(const char *zName){ int i; - for(i=0; i<count(aSafeConfig); i++){ - if( strcmp(zName, aSafeConfig[i].zName)==0 ) return 1; + for(i=0; i<count(aConfig); i++){ + if( strcmp(zName, aConfig[i].zName)==0 ){ + return aConfig[i].groupMask; + } } return 0; } /* @@ -102,39 +123,39 @@ return 0; } /* -** COMMAND: configure +** COMMAND: configuration ** ** Usage: %fossil configure METHOD ... ** ** Where METHOD is one of: export import pull reset. All methods ** accept the -R or --repository option to specific a repository. ** -** %fossil config export AREA FILENAME +** %fossil configuration export AREA FILENAME ** ** Write to FILENAME exported configuraton information for AREA. ** AREA can be one of: all ticket skin project ** -** %fossil config import FILENAME +** %fossil configuration import FILENAME ** ** Read a configuration from FILENAME, overwriting the current ** configuration. Warning: Do not read a configuration from ** an untrusted source since the configuration is not checked ** for safety and can introduce security threats. ** -** %fossil config pull AREA URL +** %fossil configuration pull AREA URL ** ** Pull and install the configuration from a different server ** identified by URL. AREA is as in "export". ** -** %fossil configure reset AREA +** %fossil configuration reset AREA ** ** Restore the configuration to the default. AREA as above. */ -void configure_cmd(void){ +void configuration_cmd(void){ int n; const char *zMethod; if( g.argc<3 ){ usage("METHOD ..."); } @@ -158,39 +179,63 @@ "SELECT 'REPLACE INTO config(name,value) VALUES('''" " || name || ''',' || quote(value) || ');'" " FROM config WHERE name IN " ); zSep = "("; - for(i=0; i<count(aSafeConfig); i++){ - if( aSafeConfig[i].groupMask & mask ){ - blob_appendf(&sql, "%s'%s'", zSep, aSafeConfig[i].zName); + for(i=0; i<count(aConfig); i++){ + if( aConfig[i].groupMask & mask ){ + blob_appendf(&sql, "%s'%s'", zSep, aConfig[i].zName); zSep = ","; } } blob_appendf(&sql, ") ORDER BY name"); db_prepare(&q, blob_str(&sql)); blob_reset(&sql); blob_appendf(&out, "-- The \"%s\" configuration exported from\n" "-- repository \"%s\"\n" - "-- on %s\nBEGIN;\n", + "-- on %s\n", g.argv[3], g.zRepositoryName, db_text(0, "SELECT datetime('now')") ); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&out, "%s\n", db_column_text(&q, 0)); } db_finalize(&q); - blob_appendf(&out, "COMMIT;\n"); blob_write_to_file(&out, g.argv[4]); blob_reset(&out); }else if( strncmp(zMethod, "import", n)==0 ){ + Blob in; + if( g.argc!=4 ) usage("import FILENAME"); + blob_read_from_file(&in, g.argv[3]); + db_begin_transaction(); + db_multi_exec("%s", blob_str(&in)); + db_end_transaction(0); }else if( strncmp(zMethod, "pull", n)==0 ){ + int mask; + url_proxy_options(); + if( g.argc!=5 ) usage("pull AREA URL"); + mask = find_area(g.argv[3]); + url_parse(g.argv[4]); + if( g.urlIsFile ){ + fossil_fatal("network sync only"); + } + user_select(); + client_sync(0,0,0,mask); }else if( strncmp(zMethod, "reset", n)==0 ){ + int mask, i; + if( g.argc!=4 ) usage("reset AREA"); + mask = find_area(g.argv[3]); + db_begin_transaction(); + for(i=0; i<count(aConfig); i++){ + if( (aConfig[i].groupMask & mask)==0 ) continue; + db_multi_exec("DELETE FROM config WHERE name=%Q", aConfig[i].zName); + } + db_end_transaction(0); }else { fossil_fatal("METHOD should be one of: export import pull reset"); } }
Modified src/sync.c from [64b6ad3096] to [4404bbdd39].
@@ -61,20 +61,20 @@ printf("Autosync: http://%s:%d%s\n", g.urlName, g.urlPort, g.urlPath); }else{ printf("Autosync: http://%s%s\n", g.urlName, g.urlPath); } url_enable_proxy("via proxy: "); - client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0); + client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0); } /* ** This routine processes the command-line argument for push, pull, ** and sync. If a command-line argument is given, that is the URL ** of a server to sync against. If no argument is given, use the ** most recently synced URL. Remember the current URL for next time. */ -static void process_sync_args(void){ +void process_sync_args(void){ const char *zUrl = 0; url_proxy_options(); db_find_and_open_repository(1); if( g.argc==2 ){ zUrl = db_get("last-sync-url", 0); @@ -122,11 +122,11 @@ ** specifies the TCP port of the server. The default port is ** 80. */ void pull_cmd(void){ process_sync_args(); - client_sync(0,1,0); + client_sync(0,1,0,0); } /* ** COMMAND: push ** @@ -135,11 +135,11 @@ ** Push changes in the local repository over into a remote repository. ** See the "pull" command for additional information. */ void push_cmd(void){ process_sync_args(); - client_sync(1,0,0); + client_sync(1,0,0,0); } /* ** COMMAND: sync @@ -150,7 +150,7 @@ ** the equivalent of running both "push" and "pull" at the same time. ** See the "pull" command for additional information. */ void sync_cmd(void){ process_sync_args(); - client_sync(1,1,0); + client_sync(1,1,0,0); }
Modified src/xfer.c from [c1b226ecc2] to [5b389cafaa].
@@ -24,39 +24,10 @@ ** This file contains code to implement the file transfer protocol. */ #include "config.h" #include "xfer.h" -#if INTERFACE -/* -** Configuration transfers occur in groups. These are the allowed -** groupings: -*/ -#define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ -#define CONFIGSET_TKT 0x000002 /* Ticket configuration */ -#define CONFIGSET_PROJ 0x000004 /* Project name */ - -#endif /* INTERFACE */ - -/* -** The following is a list of settings that we are willing to -** transfer. -*/ -static struct { - const char *zName; /* Name of the configuration parameter */ - int groupMask; /* Which config groups is it part of */ -} aSafeConfig[] = { - { "css", CONFIGSET_SKIN }, - { "header", CONFIGSET_SKIN }, - { "footer", CONFIGSET_SKIN }, - { "project-name", CONFIGSET_PROJ }, - { "project-description", CONFIGSET_PROJ }, - { "index-page", CONFIGSET_SKIN }, - { "timeline-block-markup", CONFIGSET_SKIN }, - { "timeline-max-comment", CONFIGSET_SKIN }, -}; - /* ** This structure holds information about the current state of either ** a client or a server that is participating in xfer. */ typedef struct Xfer Xfer; @@ -680,20 +651,16 @@ if( blob_eq(&xfer.aToken[0], "reqconfig") && xfer.nToken==2 ){ if( g.okRead ){ char *zName = blob_str(&xfer.aToken[1]); - int i; - for(i=0; i<count(aSafeConfig); i++){ - if( strcmp(aSafeConfig[i].zName, zName)==0 ){ - char *zValue = db_get(zName, 0); - if( zValue ){ - blob_appendf(xfer.pOut, "config %s %d\n%s\n", zName, - strlen(zValue), zValue); - free(zValue); - } - break; + if( configure_is_exportable(zName) ){ + char *zValue = db_get(zName, 0); + if( zValue ){ + blob_appendf(xfer.pOut, "config %s %d\n%s\n", zName, + strlen(zValue), zValue); + free(zValue); } } } }else @@ -791,17 +758,19 @@ ** ** Records are pushed to the server if pushFlag is true. Records ** are pulled if pullFlag is true. A full sync occurs if both are ** true. */ -void client_sync(int pushFlag, int pullFlag, int cloneFlag){ +void client_sync(int pushFlag, int pullFlag, int cloneFlag, int configMask){ int go = 1; /* Loop until zero */ const char *zSCode = db_get("server-code", "x"); const char *zPCode = db_get("project-code", 0); int nCard = 0; /* Number of cards sent or received */ int nCycle = 0; /* Number of round trips to the server */ + int size; /* Size of a config value */ int nFileSend = 0; + int origConfigMask; /* Original value of configMask */ int nFileRecv; /* Number of files received */ int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ const char *zCookie; /* Server cookie */ Blob send; /* Text we are sending to the server */ Blob recv; /* Reply we got back from the server */ @@ -810,11 +779,11 @@ memset(&xfer, 0, sizeof(xfer)); xfer.pIn = &recv; xfer.pOut = &send; xfer.mxSend = db_get_int("max-upload", 250000); - assert( pushFlag || pullFlag || cloneFlag ); + assert( pushFlag || pullFlag || cloneFlag || configMask ); assert( !g.urlIsFile ); /* This only works for networking */ db_begin_transaction(); db_multi_exec( "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" @@ -822,10 +791,11 @@ blobarray_zero(xfer.aToken, count(xfer.aToken)); blob_zero(&send); blob_zero(&recv); blob_zero(&xfer.err); blob_zero(&xfer.line); + origConfigMask = configMask; /* ** Always begin with a clone, pull, or push message */ if( cloneFlag ){ @@ -862,10 +832,21 @@ request_phantoms(&xfer, mxPhantomReq); } if( pushFlag ){ send_unsent(&xfer); nCard += send_unclustered(&xfer); + } + + /* Send configuration parameter requests */ + if( configMask ){ + const char *zName; + zName = configure_first_name(configMask); + while( zName ){ + blob_appendf(&send, "reqconfig %s\n", zName); + zName = configure_next_name(configMask); + } + configMask = 0; } /* Exchange messages with the server */ nFileSend = xfer.nFileSent + xfer.nDeltaSent; printf(zValueFormat, "Send:", @@ -976,14 +957,24 @@ /* config NAME SIZE \n CONTENT ** ** Receive a configuration value from the server. */ - if( blob_eq(&xfer.aToken[0],"config") ){ - /* TBD: Extract name and content */ - /* Check to see if configuration name is authorized */ - /* Store content in the config table */ + if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 + && blob_is_int(&xfer.aToken[2], &size) ){ + const char *zName = blob_str(&xfer.aToken[1]); + Blob content; + blob_zero(&content); + blob_extract(xfer.pIn, size, &content); + if( configure_is_exportable(zName) & origConfigMask ){ + db_multi_exec( + "REPLACE INTO config(name,value) VALUES(%Q,%Q)", + zName, blob_str(&content) + ); + } + blob_reset(&content); + blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else /* cookie TEXT **