@@ -1399,24 +1399,93 @@ sqlite3 *dbTemp = g.db; g.db = g.dbConfig; g.dbConfig = dbTemp; } } + +/* +** Logic for reading potentially versioned settings from +** .fossil-settings/ , and emits warnings if necessary. +** Returns the non-versioned value without modification if there is no +** versioned value. +*/ +static char *db_get_do_versionable(const char *zName, char *zNonVersionedSetting){ + /* Attempt to load the versioned setting from a checked out file */ + char *zVersionedSetting = 0; + int noWarn = 0; + + if( db_open_local() ){ + Blob versionedPathname; + char *zVersionedPathname; + blob_zero(&versionedPathname); + blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", + g.zLocalRoot, zName); + zVersionedPathname = blob_str(&versionedPathname); + if( file_size(zVersionedPathname)>=0 ){ + /* File exists, and contains the value for this setting. Load from + ** the file. */ + Blob setting; + blob_zero(&setting); + if( blob_read_from_file(&setting, zVersionedPathname) >= 0 ){ + blob_trim(&setting); /* Avoid non-obvious problems with line endings + ** on boolean properties */ + zVersionedSetting = strdup(blob_str(&setting)); + } + blob_reset(&setting); + /* See if there's a no-warn flag */ + blob_append(&versionedPathname, ".no-warn", -1); + if( file_size(blob_str(&versionedPathname))>=0 ){ + noWarn = 1; + } + } + blob_reset(&versionedPathname); + } + /* Display a warning? */ + if( zVersionedSetting!=0 && zNonVersionedSetting!=0 + && zNonVersionedSetting[0]!='\0' && !noWarn + ){ + /* There's a versioned setting, and a non-versioned setting. Tell + ** the user about the conflict */ + fossil_warning( + "setting %s has both versioned and non-versioned values: using " + "versioned value from file .fossil-settings/%s (to silence this " + "warning, either create an empty file named " + ".fossil-settings/%s.no-warn or delete the non-versioned setting " + " with \"fossil unset %s\")", zName, zName, zName, zName + ); + } + /* Prefer the versioned setting */ + return ( zVersionedSetting!=0 ) ? zVersionedSetting : zNonVersionedSetting; +} + /* ** Get and set values from the CONFIG, GLOBAL_CONFIG and VVAR table in the ** repository and local databases. */ char *db_get(const char *zName, char *zDefault){ char *z = 0; + int i; + const struct stControlSettings *ctrlSetting = 0; + /* Is this a setting? */ + for(i=0; ctrlSettings[i].name; i++){ + if( strcmp(ctrlSettings[i].name, zName)==0 ){ + 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 ){ + /* This is a versionable setting, try and get the info from a checked out file */ + z = db_get_do_versionable(zName, z); } if( z==0 ){ z = zDefault; } return z; @@ -1603,30 +1672,39 @@ } /* ** Print the value of a setting named zName */ -static void print_setting(const char *zName){ +static void print_setting(const struct stControlSettings *ctrlSetting, int localOpen){ Stmt q; if( g.repositoryOpen ){ db_prepare(&q, "SELECT '(local)', value FROM config WHERE name=%Q" " UNION ALL " "SELECT '(global)', value FROM global_config WHERE name=%Q", - zName, zName + ctrlSetting->name, ctrlSetting->name ); }else{ db_prepare(&q, "SELECT '(global)', value FROM global_config WHERE name=%Q", - zName + ctrlSetting->name ); } if( db_step(&q)==SQLITE_ROW ){ - fossil_print("%-20s %-8s %s\n", zName, db_column_text(&q, 0), + fossil_print("%-20s %-8s %s\n", ctrlSetting->name, db_column_text(&q, 0), db_column_text(&q, 1)); }else{ - fossil_print("%-20s\n", zName); + fossil_print("%-20s\n", ctrlSetting->name); + } + if( ctrlSetting->versionable && localOpen ){ + /* Check to see if this is overridden by a versionable settings file */ + Blob versionedPathname; + blob_zero(&versionedPathname); + blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, ctrlSetting->name); + if( file_size(blob_str(&versionedPathname))>=0 ){ + fossil_print(" (overridden by contents of file .fossil-settings/%s)\n", ctrlSetting->name); + } } db_finalize(&q); } @@ -1642,44 +1720,49 @@ #if INTERFACE struct stControlSettings { char const *name; /* Name of the setting */ char const *var; /* Internal variable name used by db_set() */ int width; /* Width of display. 0 for boolean values */ + int versionable; /* Is this setting versionable? */ char const *def; /* Default value */ }; #endif /* INTERFACE */ struct stControlSettings const ctrlSettings[] = { - { "access-log", 0, 0, "off" }, - { "auto-captcha", "autocaptcha", 0, "on" }, - { "auto-shun", 0, 0, "on" }, - { "autosync", 0, 0, "on" }, - { "binary-glob", 0, 32, "" }, - { "case-sensitive",0, 0, "on" }, - { "clearsign", 0, 0, "off" }, - { "crnl-glob", 0, 16, "" }, - { "default-perms", 0, 16, "u" }, - { "diff-command", 0, 16, "" }, - { "dont-push", 0, 0, "off" }, - { "editor", 0, 16, "" }, - { "gdiff-command", 0, 16, "gdiff" }, - { "gmerge-command",0, 40, "" }, - { "https-login", 0, 0, "off" }, - { "ignore-glob", 0, 40, "" }, - { "http-port", 0, 16, "8080" }, - { "localauth", 0, 0, "off" }, - { "main-branch", 0, 40, "trunk" }, - { "manifest", 0, 0, "off" }, - { "max-upload", 0, 25, "250000" }, - { "mtime-changes", 0, 0, "on" }, - { "pgp-command", 0, 32, "gpg --clearsign -o " }, - { "proxy", 0, 32, "off" }, - { "repo-cksum", 0, 0, "on" }, - { "self-register", 0, 0, "off" }, - { "ssh-command", 0, 32, "" }, - { "web-browser", 0, 32, "" }, - { "white-foreground", 0, 0, "off" }, - { 0,0,0,0 } + { "access-log", 0, 0, 0, "off" }, + { "auto-captcha", "autocaptcha", 0, 0, "on" }, + { "auto-shun", 0, 0, 0, "on" }, + { "autosync", 0, 0, 0, "on" }, + { "binary-glob", 0, 32, 1, "" }, + { "clearsign", 0, 0, 0, "off" }, + { "case-sensitive",0, 0, 0, "on" }, + { "crnl-glob", 0, 16, 1, "" }, + { "default-perms", 0, 16, 0, "u" }, + { "diff-command", 0, 16, 0, "" }, + { "dont-push", 0, 0, 0, "off" }, + { "editor", 0, 16, 0, "" }, + { "gdiff-command", 0, 16, 0, "gdiff" }, + { "gmerge-command",0, 40, 0, "" }, + { "https-login", 0, 0, 0, "off" }, + { "ignore-glob", 0, 40, 1, "" }, + { "empty-dirs", 0, 40, 1, "" }, + { "http-port", 0, 16, 0, "8080" }, + { "localauth", 0, 0, 0, "off" }, + { "main-branch", 0, 40, 0, "trunk" }, + { "manifest", 0, 0, 1, "off" }, + { "max-upload", 0, 25, 0, "250000" }, + { "mtime-changes", 0, 0, 0, "on" }, + { "pgp-command", 0, 32, 0, "gpg --clearsign -o " }, + { "proxy", 0, 32, 0, "off" }, + { "relative-paths",0, 0, 0, "on" }, + { "repo-cksum", 0, 0, 0, "on" }, + { "self-register", 0, 0, 0, "off" }, + { "ssl-ca-location",0, 40, 0, "" }, + { "ssl-identity", 0, 40, 0, "" }, + { "ssh-command", 0, 32, 0, "" }, + { "web-browser", 0, 32, 0, "" }, + { "white-foreground", 0, 0, 0, "off" }, + { 0,0,0,0,0 } }; /* ** COMMAND: settings ** COMMAND: unset @@ -1688,10 +1771,14 @@ ** %fossil unset PROPERTY ?-global? ** ** The "settings" command with no arguments lists all properties and their ** values. With just a property name it shows the value of that property. ** With a value argument it changes the property for the current repository. +** +** Settings marked as versionable are overridden by the contents of the +** file named .fossil-settings/PROPERTY in the checked out files, if that +** file exists. ** ** The "unset" command clears a property setting. ** ** ** auto-captcha If enabled, the Login page provides a button to @@ -1705,13 +1792,13 @@ ** or update and automatically push after commit or ** tag or branch creation. If the value is "pullonly" ** then only pull operations occur automatically. ** Default: on ** -** binary-glob The VALUE is a comma-separated list of GLOB patterns -** that should be treated as binary files for merging -** purposes. Example: *.xml +** binary-glob The VALUE is a comma or newline-separated list of +** (versionable) GLOB patterns that should be treated as binary files +** for merging purposes. Example: *.xml ** ** case-sensitive If TRUE, the files whose names differ only in case ** care considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to ** TRUE for unix and FALSE for windows and mac. @@ -1718,12 +1805,12 @@ ** ** clearsign When enabled, fossil will attempt to sign all commits ** with gpg. When disabled (the default), commits will ** be unsigned. Default: off ** -** crnl-glob A comma-separated list of GLOB patterns for text files -** in which it is ok to have CR+NL line endings. +** crnl-glob A comma or newline-separated list of GLOB patterns for +** (versionable) text files in which it is ok to have CR+NL line endings. ** Set to "*" to disable CR+NL checking. ** ** default-perms Permissions given automatically to new users. For more ** information on permissions see Users page in Server ** Administration of the HTTP UI. Default: u. @@ -1731,10 +1818,15 @@ ** diff-command External command to run when performing a diff. ** If undefined, the internal text diff will be used. ** ** dont-push Prevent this repository from pushing from client to ** server. Useful when setting up a private branch. +** +** empty-dirs A comma or newline-separated list of pathnames. On +** (versionable) update and checkout commands, if no file or directory +** exists with that name, an empty directory will be +** created. ** ** editor Text editor command used for check-in comments. ** ** gdiff-command External command to run when performing a graphical ** diff. If undefined, text diff will be used. @@ -1749,23 +1841,23 @@ ** and "ui" commands. Default: 8080 ** ** https-login Send login creditials using HTTPS instead of HTTP ** even if the login page request came via HTTP. ** -** ignore-glob The VALUE is a comma-separated list of GLOB patterns -** specifying files that the "extra" command will ignore. -** Example: *.o,*.obj,*.exe +** ignore-glob The VALUE is a comma or newline-separated list of GLOB +** (versionable) patterns specifying files that the "extra" command will +** ignore. Example: *.o,*.obj,*.exe ** ** localauth If enabled, require that HTTP connections from ** 127.0.0.1 be authenticated by password. If ** false, all HTTP requests from localhost have ** unrestricted access to the repository. ** ** main-branch The primary branch for the project. Default: trunk ** ** manifest If enabled, automatically create files "manifest" and -** "manifest.uuid" in every checkout. The SQLite and +** (versionable) "manifest.uuid" in every checkout. The SQLite and ** Fossil repositories both require this. Default: off. ** ** max-upload A limit on the size of uplink HTTP requests. The ** default is 250000 bytes. ** @@ -1777,10 +1869,13 @@ ** ** proxy URL of the HTTP proxy. If undefined or "off" then ** the "http_proxy" environment variable is consulted. ** If the http_proxy environment variable is undefined ** then a direct HTTP connection is used. +** +** relative-paths When showing changes and extras, report paths relative +** to the current working directory. Default: "on" ** ** repo-cksum Compute checksums over all files in each checkout ** as a double-check of correctness. Defaults to "on". ** Disable on large repositories for a performance ** improvement. @@ -1787,10 +1882,28 @@ ** ** self-register Allow users to register themselves through the HTTP UI. ** This is useful if you want to see other names than ** "Anonymous" in e.g. ticketing system. On the other hand ** users can not be deleted. Default: off. +** +** ssl-ca-location The full pathname to a file containing PEM encoded +** CA root certificates, or a directory of certificates +** with filenames formed from the certificate hashes as +** required by OpenSSL. +** If set, this will override the OS default list of +** OpenSSL CAs. If unset, the default list will be used. +** Some platforms may add additional certificates. +** Check your platform behaviour is as required if the +** exact contents of the CA root is critical for your +** application. +** +** ssl-identity The full pathname to a file containing a certificate +** and private key in PEM format. Create by concatenating +** the certificate and private key files. +** This identity will be presented to SSL servers to +** authenticate this client, in addition to the normal +** password authentication. ** ** ssh-command Command used to talk to a remote machine with ** the "ssh://" protocol. ** ** web-browser A shell command used to launch your preferred @@ -1811,12 +1924,13 @@ } if( unsetFlag && g.argc!=3 ){ usage("PROPERTY ?-global?"); } if( g.argc==2 ){ + int openLocal = db_open_local(); for(i=0; ctrlSettings[i].name; i++){ - print_setting(ctrlSettings[i].name); + print_setting(&ctrlSettings[i], openLocal); } }else if( g.argc==3 || g.argc==4 ){ const char *zName = g.argv[2]; int isManifest; int n = strlen(zName); @@ -1834,11 +1948,11 @@ db_unset(ctrlSettings[i].name, globalFlag); }else if( g.argc==4 ){ db_set(ctrlSettings[i].name, g.argv[3], globalFlag); }else{ isManifest = 0; - print_setting(ctrlSettings[i].name); + print_setting(&ctrlSettings[i], db_open_local()); } if( isManifest && g.localOpen ){ manifest_to_disk(db_lget_int("checkout", 0)); } }else{