File Annotation
Not logged in
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Copyright (c) 2008 D. Richard Hipp
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** This program is free software; you can redistribute it and/or
e06ae9f6d2 2008-05-22       drh: ** modify it under the terms of the GNU General Public
e06ae9f6d2 2008-05-22       drh: ** License version 2 as published by the Free Software Foundation.
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** This program is distributed in the hope that it will be useful,
e06ae9f6d2 2008-05-22       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
e06ae9f6d2 2008-05-22       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
e06ae9f6d2 2008-05-22       drh: ** General Public License for more details.
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** You should have received a copy of the GNU General Public
e06ae9f6d2 2008-05-22       drh: ** License along with this library; if not, write to the
e06ae9f6d2 2008-05-22       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
e06ae9f6d2 2008-05-22       drh: ** Boston, MA  02111-1307, USA.
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** Author contact information:
e06ae9f6d2 2008-05-22       drh: **   drh@hwaci.com
e06ae9f6d2 2008-05-22       drh: **   http://www.hwaci.com/drh/
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: *******************************************************************************
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** This file contains code used to manage repository configurations.
e06ae9f6d2 2008-05-22       drh: ** By "responsitory configure" we mean the local state of a repository
e06ae9f6d2 2008-05-22       drh: ** distinct from the versioned files.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: #include "config.h"
e06ae9f6d2 2008-05-22       drh: #include "configure.h"
e06ae9f6d2 2008-05-22       drh: #include <assert.h>
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: #if INTERFACE
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Configuration transfers occur in groups.  These are the allowed
e06ae9f6d2 2008-05-22       drh: ** groupings:
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_SKIN   0x000001     /* WWW interface appearance */
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_TKT    0x000002     /* Ticket configuration */
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_PROJ   0x000004     /* Project name */
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_ALL    0xffffff     /* Everything */
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: #endif /* INTERFACE */
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Names of the configuration sets
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: static struct {
e06ae9f6d2 2008-05-22       drh:   const char *zName;   /* Name of the configuration set */
e06ae9f6d2 2008-05-22       drh:   int groupMask;       /* Mask for that configuration set */
e06ae9f6d2 2008-05-22       drh: } aGroupName[] = {
e06ae9f6d2 2008-05-22       drh:   { "skin",         CONFIGSET_SKIN },
e06ae9f6d2 2008-05-22       drh:   { "ticket",       CONFIGSET_TKT  },
e06ae9f6d2 2008-05-22       drh:   { "project",      CONFIGSET_PROJ },
e06ae9f6d2 2008-05-22       drh:   { "all",          CONFIGSET_ALL  },
e06ae9f6d2 2008-05-22       drh: };
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** The following is a list of settings that we are willing to
e06ae9f6d2 2008-05-22       drh: ** transfer.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: static struct {
e06ae9f6d2 2008-05-22       drh:   const char *zName;   /* Name of the configuration parameter */
e06ae9f6d2 2008-05-22       drh:   int groupMask;       /* Which config groups is it part of */
28e56282c9 2008-05-23       drh: } aConfig[] = {
e06ae9f6d2 2008-05-22       drh:   { "css",                   CONFIGSET_SKIN },
e06ae9f6d2 2008-05-22       drh:   { "header",                CONFIGSET_SKIN },
e06ae9f6d2 2008-05-22       drh:   { "footer",                CONFIGSET_SKIN },
e06ae9f6d2 2008-05-22       drh:   { "project-name",          CONFIGSET_PROJ },
e06ae9f6d2 2008-05-22       drh:   { "project-description",   CONFIGSET_PROJ },
e06ae9f6d2 2008-05-22       drh:   { "index-page",            CONFIGSET_SKIN },
e06ae9f6d2 2008-05-22       drh:   { "timeline-block-markup", CONFIGSET_SKIN },
e06ae9f6d2 2008-05-22       drh:   { "timeline-max-comment",  CONFIGSET_SKIN },
86db6fa150 2008-05-28       drh:   { "ticket-table",          CONFIGSET_TKT  },
86db6fa150 2008-05-28       drh:   { "ticket-common",         CONFIGSET_TKT  },
86db6fa150 2008-05-28       drh:   { "ticket-newpage",        CONFIGSET_TKT  },
86db6fa150 2008-05-28       drh:   { "ticket-viewpage",       CONFIGSET_TKT  },
86db6fa150 2008-05-28       drh:   { "ticket-editpage",       CONFIGSET_TKT  },
e06ae9f6d2 2008-05-22       drh: };
28e56282c9 2008-05-23       drh: static int iConfig = 0;
28e56282c9 2008-05-23       drh: 
28e56282c9 2008-05-23       drh: /*
28e56282c9 2008-05-23       drh: ** Return name of first configuration property matching the given mask.
28e56282c9 2008-05-23       drh: */
28e56282c9 2008-05-23       drh: const char *configure_first_name(int iMask){
28e56282c9 2008-05-23       drh:   iConfig = 0;
28e56282c9 2008-05-23       drh:   return configure_next_name(iMask);
28e56282c9 2008-05-23       drh: }
28e56282c9 2008-05-23       drh: const char *configure_next_name(int iMask){
28e56282c9 2008-05-23       drh:   while( iConfig<count(aConfig) ){
28e56282c9 2008-05-23       drh:     if( aConfig[iConfig].groupMask & iMask ){
28e56282c9 2008-05-23       drh:       return aConfig[iConfig++].zName;
28e56282c9 2008-05-23       drh:     }else{
28e56282c9 2008-05-23       drh:       iConfig++;
28e56282c9 2008-05-23       drh:     }
28e56282c9 2008-05-23       drh:   }
28e56282c9 2008-05-23       drh:   return 0;
28e56282c9 2008-05-23       drh: }
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Return TRUE if a particular configuration parameter zName is
e06ae9f6d2 2008-05-22       drh: ** safely exportable.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: int configure_is_exportable(const char *zName){
e06ae9f6d2 2008-05-22       drh:   int i;
28e56282c9 2008-05-23       drh:   for(i=0; i<count(aConfig); i++){
28e56282c9 2008-05-23       drh:     if( strcmp(zName, aConfig[i].zName)==0 ){
28e56282c9 2008-05-23       drh:       return aConfig[i].groupMask;
28e56282c9 2008-05-23       drh:     }
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh:   return 0;
e06ae9f6d2 2008-05-22       drh: }
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Identify a configuration group by name.  Return its mask.
e06ae9f6d2 2008-05-22       drh: ** Throw an error if no match.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: static int find_area(const char *z){
e06ae9f6d2 2008-05-22       drh:   int i;
e06ae9f6d2 2008-05-22       drh:   int n = strlen(z);
e06ae9f6d2 2008-05-22       drh:   for(i=0; i<count(aGroupName); i++){
e06ae9f6d2 2008-05-22       drh:     if( strncmp(z, aGroupName[i].zName, n)==0 ){
e06ae9f6d2 2008-05-22       drh:       return aGroupName[i].groupMask;
e06ae9f6d2 2008-05-22       drh:     }
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh:   fossil_fatal("no such configuration area: \"%s\"", z);
e06ae9f6d2 2008-05-22       drh:   return 0;
e06ae9f6d2 2008-05-22       drh: }
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
28e56282c9 2008-05-23       drh: ** COMMAND: configuration
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** Usage: %fossil configure METHOD ...
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** Where METHOD is one of: export import pull reset.  All methods
e06ae9f6d2 2008-05-22       drh: ** accept the -R or --repository option to specific a repository.
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration export AREA FILENAME
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Write to FILENAME exported configuraton information for AREA.
e06ae9f6d2 2008-05-22       drh: **         AREA can be one of:  all ticket skin project
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration import FILENAME
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Read a configuration from FILENAME, overwriting the current
e06ae9f6d2 2008-05-22       drh: **         configuration.  Warning:  Do not read a configuration from
e06ae9f6d2 2008-05-22       drh: **         an untrusted source since the configuration is not checked
e06ae9f6d2 2008-05-22       drh: **         for safety and can introduce security threats.
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration pull AREA URL
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Pull and install the configuration from a different server
e06ae9f6d2 2008-05-22       drh: **         identified by URL.  AREA is as in "export".
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration reset AREA
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Restore the configuration to the default.  AREA as above.
e06ae9f6d2 2008-05-22       drh: */
28e56282c9 2008-05-23       drh: void configuration_cmd(void){
e06ae9f6d2 2008-05-22       drh:   int n;
e06ae9f6d2 2008-05-22       drh:   const char *zMethod;
e06ae9f6d2 2008-05-22       drh:   if( g.argc<3 ){
e06ae9f6d2 2008-05-22       drh:     usage("METHOD ...");
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh:   db_find_and_open_repository(1);
e06ae9f6d2 2008-05-22       drh:   zMethod = g.argv[2];
e06ae9f6d2 2008-05-22       drh:   n = strlen(zMethod);
e06ae9f6d2 2008-05-22       drh:   if( strncmp(zMethod, "export", n)==0 ){
e06ae9f6d2 2008-05-22       drh:     int i;
e06ae9f6d2 2008-05-22       drh:     int mask;
e06ae9f6d2 2008-05-22       drh:     const char *zSep;
e06ae9f6d2 2008-05-22       drh:     Blob sql;
e06ae9f6d2 2008-05-22       drh:     Stmt q;
e06ae9f6d2 2008-05-22       drh:     Blob out;
e06ae9f6d2 2008-05-22       drh:     if( g.argc!=5 ){
e06ae9f6d2 2008-05-22       drh:       usage("export AREA FILENAME");
e06ae9f6d2 2008-05-22       drh:     }
e06ae9f6d2 2008-05-22       drh:     mask = find_area(g.argv[3]);
e06ae9f6d2 2008-05-22       drh:     blob_zero(&sql);
e06ae9f6d2 2008-05-22       drh:     blob_zero(&out);
e06ae9f6d2 2008-05-22       drh:     blob_appendf(&sql,
e06ae9f6d2 2008-05-22       drh:        "SELECT 'REPLACE INTO config(name,value) VALUES('''"
e06ae9f6d2 2008-05-22       drh:        "         || name || ''',' || quote(value) || ');'"
e06ae9f6d2 2008-05-22       drh:        "  FROM config WHERE name IN "
e06ae9f6d2 2008-05-22       drh:     );
e06ae9f6d2 2008-05-22       drh:     zSep = "(";
28e56282c9 2008-05-23       drh:     for(i=0; i<count(aConfig); i++){
28e56282c9 2008-05-23       drh:       if( aConfig[i].groupMask & mask ){
28e56282c9 2008-05-23       drh:         blob_appendf(&sql, "%s'%s'", zSep, aConfig[i].zName);
e06ae9f6d2 2008-05-22       drh:         zSep = ",";
e06ae9f6d2 2008-05-22       drh:       }
e06ae9f6d2 2008-05-22       drh:     }
e06ae9f6d2 2008-05-22       drh:     blob_appendf(&sql, ") ORDER BY name");
e06ae9f6d2 2008-05-22       drh:     db_prepare(&q, blob_str(&sql));
e06ae9f6d2 2008-05-22       drh:     blob_reset(&sql);
e06ae9f6d2 2008-05-22       drh:     blob_appendf(&out,
e06ae9f6d2 2008-05-22       drh:         "-- The \"%s\" configuration exported from\n"
e06ae9f6d2 2008-05-22       drh:         "-- repository \"%s\"\n"
28e56282c9 2008-05-23       drh:         "-- on %s\n",
e06ae9f6d2 2008-05-22       drh:         g.argv[3], g.zRepositoryName,
e06ae9f6d2 2008-05-22       drh:         db_text(0, "SELECT datetime('now')")
e06ae9f6d2 2008-05-22       drh:     );
e06ae9f6d2 2008-05-22       drh:     while( db_step(&q)==SQLITE_ROW ){
e06ae9f6d2 2008-05-22       drh:       blob_appendf(&out, "%s\n", db_column_text(&q, 0));
e06ae9f6d2 2008-05-22       drh:     }
e06ae9f6d2 2008-05-22       drh:     db_finalize(&q);
e06ae9f6d2 2008-05-22       drh:     blob_write_to_file(&out, g.argv[4]);
e06ae9f6d2 2008-05-22       drh:     blob_reset(&out);
e06ae9f6d2 2008-05-22       drh:   }else
e06ae9f6d2 2008-05-22       drh:   if( strncmp(zMethod, "import", n)==0 ){
28e56282c9 2008-05-23       drh:     Blob in;
28e56282c9 2008-05-23       drh:     if( g.argc!=4 ) usage("import FILENAME");
28e56282c9 2008-05-23       drh:     blob_read_from_file(&in, g.argv[3]);
28e56282c9 2008-05-23       drh:     db_begin_transaction();
28e56282c9 2008-05-23       drh:     db_multi_exec("%s", blob_str(&in));
28e56282c9 2008-05-23       drh:     db_end_transaction(0);
e06ae9f6d2 2008-05-22       drh:   }else
e06ae9f6d2 2008-05-22       drh:   if( strncmp(zMethod, "pull", n)==0 ){
28e56282c9 2008-05-23       drh:     int mask;
28e56282c9 2008-05-23       drh:     url_proxy_options();
28e56282c9 2008-05-23       drh:     if( g.argc!=5 ) usage("pull AREA URL");
28e56282c9 2008-05-23       drh:     mask = find_area(g.argv[3]);
28e56282c9 2008-05-23       drh:     url_parse(g.argv[4]);
28e56282c9 2008-05-23       drh:     if( g.urlIsFile ){
28e56282c9 2008-05-23       drh:       fossil_fatal("network sync only");
28e56282c9 2008-05-23       drh:     }
28e56282c9 2008-05-23       drh:     user_select();
28e56282c9 2008-05-23       drh:     client_sync(0,0,0,mask);
e06ae9f6d2 2008-05-22       drh:   }else
e06ae9f6d2 2008-05-22       drh:   if( strncmp(zMethod, "reset", n)==0 ){
28e56282c9 2008-05-23       drh:     int mask, i;
28e56282c9 2008-05-23       drh:     if( g.argc!=4 ) usage("reset AREA");
28e56282c9 2008-05-23       drh:     mask = find_area(g.argv[3]);
28e56282c9 2008-05-23       drh:     db_begin_transaction();
28e56282c9 2008-05-23       drh:     for(i=0; i<count(aConfig); i++){
28e56282c9 2008-05-23       drh:       if( (aConfig[i].groupMask & mask)==0 ) continue;
28e56282c9 2008-05-23       drh:       db_multi_exec("DELETE FROM config WHERE name=%Q", aConfig[i].zName);
28e56282c9 2008-05-23       drh:     }
28e56282c9 2008-05-23       drh:     db_end_transaction(0);
e06ae9f6d2 2008-05-22       drh:   }else
e06ae9f6d2 2008-05-22       drh:   {
e06ae9f6d2 2008-05-22       drh:     fossil_fatal("METHOD should be one of:  export import pull reset");
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh: }