Fossil

Check-in [473e08a6d1]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add check for win32/cygwin whether the config-db is writable in stead of checking that the $HOME directory is writable. Eliminate g.zHome and g.configOpen, in stead use a single g.configDbName. Then people no longer have to guess whether the config db name is ".fossil" or "_fossil". g.zHome was only used for locating the config db, nothing else.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 473e08a6d190a66c4fc9a44e0fa83010f23302d6
User & Date: jan.nijtmans 2013-03-05 12:17:13.037
Context
2013-03-05
12:25
style: use g.zConfigDbName in stead of g.configDbName, as all other strings. check-in: a5dc5332d4 user: jan.nijtmans tags: trunk
12:17
Add check for win32/cygwin whether the config-db is writable in stead of checking that the $HOME directory is writable. Eliminate g.zHome and g.configOpen, in stead use a single g.configDbName. Then people no longer have to guess whether the config db name is ".fossil" or "_fossil". g.zHome was only used for locating the config db, nothing else. check-in: 473e08a6d1 user: jan.nijtmans tags: trunk
09:24
Don't trigger the long-lines warning if the long line is followed by a null-byte: it's a normal binary file then. re-write looks_like_utf8/16 to handle crlf the same way as long lines (thanks, Joe, for the long-lines rewrite!) check-in: ab2920c2b9 user: jan.nijtmans tags: trunk
2013-03-04
20:06
Check on writability of the home directory appears too restricted. Writability of the $HOME/.fossil file should be sufficient for fossil to operate. Closed-Leaf check-in: 1e90d43d76 user: jan.nijtmans tags: home-check-too-restricted
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/checkin.c.
201
202
203
204
205
206
207



208
209
210
211
212
213
214
*/
void status_cmd(void){
  int vid;
  db_must_be_within_tree();
       /* 012345678901234 */
  fossil_print("repository:   %s\n", db_repository_filename());
  fossil_print("local-root:   %s\n", g.zLocalRoot);



  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  changes_cmd();
}







>
>
>







201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
*/
void status_cmd(void){
  int vid;
  db_must_be_within_tree();
       /* 012345678901234 */
  fossil_print("repository:   %s\n", db_repository_filename());
  fossil_print("local-root:   %s\n", g.zLocalRoot);
  if( g.configDbName ){
    fossil_print("config-db:    %s\n", g.configDbName);
  }
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  changes_cmd();
}
Changes to src/db.c.
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840



841
842
843
844
845





846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
** it is convenient for the ~/.fossil to be attached to the main database
** connection so that we can join between the various databases.  In that
** case, invoke this routine with useAttach as 1.
*/
void db_open_config(int useAttach){
  char *zDbName;
  char *zHome;
  if( g.configOpen ) return;
#if defined(_WIN32) || defined(__CYGWIN__)
  zHome = fossil_getenv("LOCALAPPDATA");
  if( zHome==0 ){
    zHome = fossil_getenv("APPDATA");
    if( zHome==0 ){
      char *zDrive = fossil_getenv("HOMEDRIVE");
      zHome = fossil_getenv("HOMEPATH");
      if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome);
    }
  }
#if defined(__CYGWIN__)
  if( zHome!=0 ){
    /* We now have the win32 path, but we need the Cygwin equivalent. */
    char *zPath = fossil_utf8_to_filename(zHome);
    fossil_filename_free(zHome);
    zHome = zPath;
  }
#endif
  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - "
                "please set the LOCALAPPDATA or APPDATA or HOMEPATH "
                "environment variables");
  }
#else
  zHome = fossil_getenv("HOME");
  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - "
                 "please set the HOME environment variable");
  }
#endif
  if( file_isdir(zHome)!=1 ){
    fossil_fatal("invalid home directory: %s", zHome);
  }
#if !defined(_WIN32)
  if( file_access(zHome, W_OK) ){
    fossil_fatal("home directory %s must be writeable", zHome);
  }
#endif
  g.zHome = mprintf("%/", zHome);
#if defined(_WIN32) || defined(__CYGWIN__)
  /* . filenames give some window systems problems and many apps problems */
  zDbName = mprintf("%//_fossil", zHome);
#else



  zDbName = mprintf("%s/.fossil", zHome);
#endif
  if( file_size(zDbName)<1024*3 ){
    db_init_database(zDbName, zConfigSchema, (char*)0);
  }





  if( useAttach ){
    db_open_or_attach(zDbName, "configdb", &g.useAttach);
    g.dbConfig = 0;
    g.zConfigDbType = 0;
  }else{
    g.useAttach = 0;
    g.dbConfig = db_open(zDbName);
    g.zConfigDbType = "configdb";
  }
  g.configOpen = 1;
  free(zDbName);
  fossil_filename_free(zHome);
}


/*
** Returns TRUE if zTable exists in the local database but lacks column
** zColumn
*/







|










<
<
<
<
<
<
<
<















<
<
<
<
<
<




>
>
>





>
>
>
>
>









|
<
<







790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807








808
809
810
811
812
813
814
815
816
817
818
819
820
821
822






823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849


850
851
852
853
854
855
856
** it is convenient for the ~/.fossil to be attached to the main database
** connection so that we can join between the various databases.  In that
** case, invoke this routine with useAttach as 1.
*/
void db_open_config(int useAttach){
  char *zDbName;
  char *zHome;
  if( g.configDbName ) return;
#if defined(_WIN32) || defined(__CYGWIN__)
  zHome = fossil_getenv("LOCALAPPDATA");
  if( zHome==0 ){
    zHome = fossil_getenv("APPDATA");
    if( zHome==0 ){
      char *zDrive = fossil_getenv("HOMEDRIVE");
      zHome = fossil_getenv("HOMEPATH");
      if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome);
    }
  }








  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - "
                "please set the LOCALAPPDATA or APPDATA or HOMEPATH "
                "environment variables");
  }
#else
  zHome = fossil_getenv("HOME");
  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - "
                 "please set the HOME environment variable");
  }
#endif
  if( file_isdir(zHome)!=1 ){
    fossil_fatal("invalid home directory: %s", zHome);
  }






#if defined(_WIN32) || defined(__CYGWIN__)
  /* . filenames give some window systems problems and many apps problems */
  zDbName = mprintf("%//_fossil", zHome);
#else
  if( file_access(zHome, W_OK) ){
    fossil_fatal("home directory %s must be writeable", zHome);
  }
  zDbName = mprintf("%s/.fossil", zHome);
#endif
  if( file_size(zDbName)<1024*3 ){
    db_init_database(zDbName, zConfigSchema, (char*)0);
  }
#if defined(_WIN32) || defined(__CYGWIN__)
  if( file_access(zDbName, W_OK) ){
    fossil_fatal("configuration file %s must be writeable", zDbName);
  }
#endif
  if( useAttach ){
    db_open_or_attach(zDbName, "configdb", &g.useAttach);
    g.dbConfig = 0;
    g.zConfigDbType = 0;
  }else{
    g.useAttach = 0;
    g.dbConfig = db_open(zDbName);
    g.zConfigDbType = "configdb";
  }
  g.configDbName = zDbName;


}


/*
** Returns TRUE if zTable exists in the local database but lacks column
** zColumn
*/
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  if( reportErrors ){
    while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
      fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
    }
  }
  g.repositoryOpen = 0;
  g.localOpen = 0;
  g.configOpen = 0;
  sqlite3_wal_checkpoint(g.db, 0);
  sqlite3_close(g.db);
  g.db = 0;
  g.zMainDbType = 0;
  if( g.dbConfig ){
    sqlite3_close(g.dbConfig);
    g.dbConfig = 0;







|







1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  if( reportErrors ){
    while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
      fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
    }
  }
  g.repositoryOpen = 0;
  g.localOpen = 0;
  g.configDbName = NULL;
  sqlite3_wal_checkpoint(g.db, 0);
  sqlite3_close(g.db);
  g.db = 0;
  g.zMainDbType = 0;
  if( g.dbConfig ){
    sqlite3_close(g.dbConfig);
    g.dbConfig = 0;
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
      ctrlSetting = &(ctrlSettings[i]);
      break;
    }
  }
  if( g.repositoryOpen ){
    z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
  }
  if( z==0 && g.configOpen ){
    db_swap_connections();
    z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
    /* This is a versionable setting, try and get the info from a
    ** checked out file */







|







1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
      ctrlSetting = &(ctrlSettings[i]);
      break;
    }
  }
  if( g.repositoryOpen ){
    z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
  }
  if( z==0 && g.configDbName ){
    db_swap_connections();
    z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){
    /* This is a versionable setting, try and get the info from a
    ** checked out file */
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
  if( globalFlag && g.repositoryOpen ){
    db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
  }
  db_end_transaction(0);
}
int db_is_global(const char *zName){
  int rc = 0;
  if( g.configOpen ){
    db_swap_connections();
    rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  return rc;
}
int db_get_int(const char *zName, int dflt){
  int v = dflt;
  int rc;
  if( g.repositoryOpen ){
    Stmt q;
    db_prepare(&q, "SELECT value FROM config WHERE name=%Q", zName);
    rc = db_step(&q);
    if( rc==SQLITE_ROW ){
      v = db_column_int(&q, 0);
    }
    db_finalize(&q);
  }else{
    rc = SQLITE_DONE;
  }
  if( rc==SQLITE_DONE && g.configOpen ){
    db_swap_connections();
    v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  return v;
}
void db_set_int(const char *zName, int value, int globalFlag){







|




















|







1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
  if( globalFlag && g.repositoryOpen ){
    db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
  }
  db_end_transaction(0);
}
int db_is_global(const char *zName){
  int rc = 0;
  if( g.configDbName ){
    db_swap_connections();
    rc = db_exists("SELECT 1 FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  return rc;
}
int db_get_int(const char *zName, int dflt){
  int v = dflt;
  int rc;
  if( g.repositoryOpen ){
    Stmt q;
    db_prepare(&q, "SELECT value FROM config WHERE name=%Q", zName);
    rc = db_step(&q);
    if( rc==SQLITE_ROW ){
      v = db_column_int(&q, 0);
    }
    db_finalize(&q);
  }else{
    rc = SQLITE_DONE;
  }
  if( rc==SQLITE_DONE && g.configDbName ){
    db_swap_connections();
    v = db_int(dflt, "SELECT value FROM global_config WHERE name=%Q", zName);
    db_swap_connections();
  }
  return v;
}
void db_set_int(const char *zName, int value, int globalFlag){
Changes to src/info.c.
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    db_record_repository_filename(0);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    if( g.localOpen ){
      fossil_print("repository:   %s\n", db_repository_filename());
      fossil_print("local-root:   %s\n", g.zLocalRoot);
    }
    if( bDetail ) extraRepoInfo();
#if defined(_WIN32)
    if( g.zHome ){
      fossil_print("user-home:    %s\n", g.zHome);
    }
#endif
    fossil_print("project-code: %s\n", db_get("project-code", ""));
    vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
    if( vid ){
      show_common_info(vid, "checkout:", 1, 1);
    }
    fossil_print("checkins:     %d\n",
                 db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));







<
|
|

<







196
197
198
199
200
201
202

203
204
205

206
207
208
209
210
211
212
    db_record_repository_filename(0);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    if( g.localOpen ){
      fossil_print("repository:   %s\n", db_repository_filename());
      fossil_print("local-root:   %s\n", g.zLocalRoot);
    }
    if( bDetail ) extraRepoInfo();

    if( g.configDbName ){
      fossil_print("config-db:    %s\n", g.configDbName);
    }

    fossil_print("project-code: %s\n", db_get("project-code", ""));
    vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
    if( vid ){
      show_common_info(vid, "checkout:", 1, 1);
    }
    fossil_print("checkins:     %d\n",
                 db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
Changes to src/json.c.
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
#define INT(OBJ,K) cson_object_set(o, #K, json_new_int(OBJ.K))
#define CSTR(OBJ,K) cson_object_set(o, #K, OBJ.K ? json_new_string(OBJ.K) : cson_value_null())
#define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null())
  VAL(capabilities, json_cap_value());
  INT(g, argc);
  INT(g, isConst);
  INT(g, useAttach);
  INT(g, configOpen);
  INT(g, repositoryOpen);
  INT(g, localOpen);
  INT(g, minPrefix);
  INT(g, fSqlTrace);
  INT(g, fSqlStats);
  INT(g, fSqlPrint);
  INT(g, fQuiet);







|







1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
#define INT(OBJ,K) cson_object_set(o, #K, json_new_int(OBJ.K))
#define CSTR(OBJ,K) cson_object_set(o, #K, OBJ.K ? json_new_string(OBJ.K) : cson_value_null())
#define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null())
  VAL(capabilities, json_cap_value());
  INT(g, argc);
  INT(g, isConst);
  INT(g, useAttach);
  CSTR(g, configDbName);
  INT(g, repositoryOpen);
  INT(g, localOpen);
  INT(g, minPrefix);
  INT(g, fSqlTrace);
  INT(g, fSqlStats);
  INT(g, fSqlPrint);
  INT(g, fQuiet);
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
  INT(g, thTrace);
  INT(g, isHome);
  INT(g, nAux);
  INT(g, allowSymlinks);

  CSTR(g, zMainDbType);
  CSTR(g, zConfigDbType);
  CSTR(g, zHome);
  CSTR(g, zLocalRoot);
  CSTR(g, zPath);
  CSTR(g, zExtra);
  CSTR(g, zBaseURL);
  CSTR(g, zTop);
  CSTR(g, zContentType);
  CSTR(g, zErrMsg);







<







1408
1409
1410
1411
1412
1413
1414

1415
1416
1417
1418
1419
1420
1421
  INT(g, thTrace);
  INT(g, isHome);
  INT(g, nAux);
  INT(g, allowSymlinks);

  CSTR(g, zMainDbType);
  CSTR(g, zConfigDbType);

  CSTR(g, zLocalRoot);
  CSTR(g, zPath);
  CSTR(g, zExtra);
  CSTR(g, zBaseURL);
  CSTR(g, zTop);
  CSTR(g, zContentType);
  CSTR(g, zErrMsg);
Changes to src/json_status.c.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
*/

/*
** Implementation of the /json/status page.
**
*/
cson_value * json_page_status(){
  char const * zSql = NULL;
  Stmt q = empty_Stmt;
  cson_object * oPay;
  /*cson_object * files;*/
  int vid, nErr = 0;
  cson_object * tmpO;
  char * zTmp;
  i64 iMtime;







<







35
36
37
38
39
40
41

42
43
44
45
46
47
48
*/

/*
** Implementation of the /json/status page.
**
*/
cson_value * json_page_status(){

  Stmt q = empty_Stmt;
  cson_object * oPay;
  /*cson_object * files;*/
  int vid, nErr = 0;
  cson_object * tmpO;
  char * zTmp;
  i64 iMtime;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
    "  FROM vfile "
    " WHERE is_selected(id)"
    "   AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q,0);
    const char *zDisplayName = zPathname;
    int isDeleted = db_column_int(&q, 1);
    int isChnged = db_column_int(&q,2);
    int isNew = db_column_int(&q,3)==0;
    int isRenamed = db_column_int(&q,4);
    cson_object * oFile;
    char const * zStatus = "???";
    char * zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);







<







98
99
100
101
102
103
104

105
106
107
108
109
110
111
    "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
    "  FROM vfile "
    " WHERE is_selected(id)"
    "   AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q,0);

    int isDeleted = db_column_int(&q, 1);
    int isChnged = db_column_int(&q,2);
    int isNew = db_column_int(&q,3)==0;
    int isRenamed = db_column_int(&q,4);
    cson_object * oFile;
    char const * zStatus = "???";
    char * zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
Changes to src/main.c.
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
struct Global {
  int argc; char **argv;  /* Command-line arguments to the program */
  char *nameOfExe;        /* Full path of executable. */
  int isConst;            /* True if the output is unchanging */
  sqlite3 *db;            /* The connection to the databases */
  sqlite3 *dbConfig;      /* Separate connection for global_config table */
  int useAttach;          /* True if global_config is attached to repository */
  int configOpen;         /* True if the config database is open */
  sqlite3_int64 now;      /* Seconds since 1970 */
  int repositoryOpen;     /* True if the main repository database is open */
  char *zRepositoryName;  /* Name of the repository database */
  const char *zMainDbType;/* "configdb", "localdb", or "repository" */
  const char *zConfigDbType;  /* "configdb", "localdb", or "repository" */
  const char *zHome;      /* Name of user home directory */
  int localOpen;          /* True if the local database is open */
  char *zLocalRoot;       /* The directory holding the  local database */
  int minPrefix;          /* Number of digits needed for a distinct UUID */
  int fSqlTrace;          /* True if --sqltrace flag is present */
  int fSqlStats;          /* True if --sqltrace or --sqlstats are present */
  int fSqlPrint;          /* True if -sqlprint flag is present */
  int fQuiet;             /* True if -quiet flag is present */







|





<







112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
struct Global {
  int argc; char **argv;  /* Command-line arguments to the program */
  char *nameOfExe;        /* Full path of executable. */
  int isConst;            /* True if the output is unchanging */
  sqlite3 *db;            /* The connection to the databases */
  sqlite3 *dbConfig;      /* Separate connection for global_config table */
  int useAttach;          /* True if global_config is attached to repository */
  const char *configDbName; /* Path of the config database. NULL if not open */
  sqlite3_int64 now;      /* Seconds since 1970 */
  int repositoryOpen;     /* True if the main repository database is open */
  char *zRepositoryName;  /* Name of the repository database */
  const char *zMainDbType;/* "configdb", "localdb", or "repository" */
  const char *zConfigDbType;  /* "configdb", "localdb", or "repository" */

  int localOpen;          /* True if the local database is open */
  char *zLocalRoot;       /* The directory holding the  local database */
  int minPrefix;          /* Number of digits needed for a distinct UUID */
  int fSqlTrace;          /* True if --sqltrace flag is present */
  int fSqlStats;          /* True if --sqltrace or --sqlstats are present */
  int fSqlPrint;          /* True if -sqlprint flag is present */
  int fQuiet;             /* True if -quiet flag is present */
Changes to src/setup.c.
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
  @ run by this page.  You can do serious and irrepairable damage to the
  @ repository.  Proceed with extreme caution.</p>
  @
  @ <p>Only a the first statement in the entry box will be run.
  @ Any subsequent statements will be silently ignored.</p>
  @
  @ <p>Database names:<ul><li>repository &rarr; %s(db_name("repository"))
  if( g.configOpen ){
    @ <li>config &rarr; %s(db_name("configdb"))
  }
  if( g.localOpen ){
    @ <li>local-checkout &rarr; %s(db_name("localdb"))
  }
  @ </ul></p>
  @







|







1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
  @ run by this page.  You can do serious and irrepairable damage to the
  @ repository.  Proceed with extreme caution.</p>
  @
  @ <p>Only a the first statement in the entry box will be run.
  @ Any subsequent statements will be silently ignored.</p>
  @
  @ <p>Database names:<ul><li>repository &rarr; %s(db_name("repository"))
  if( g.configDbName ){
    @ <li>config &rarr; %s(db_name("configdb"))
  }
  if( g.localOpen ){
    @ <li>local-checkout &rarr; %s(db_name("localdb"))
  }
  @ </ul></p>
  @