Check-in [28e56282c9]
Not logged in
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
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
       **