Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -59,16 +59,19 @@ # You should not need to change anything below this line ############################################################################### # # Automatic platform-specific options. HOST_OS!= uname -s +# Some makes use a different syntax +HOST_OS_ALT :sh = uname -s LIB.SunOS= -lsocket -lnsl LIB += $(LIB.$(HOST_OS)) +LIB += $(LIB.$(HOST_OS_ALT)) TCC.DragonFly += -DUSE_PREAD TCC.FreeBSD += -DUSE_PREAD TCC.NetBSD += -DUSE_PREAD TCC.OpenBSD += -DUSE_PREAD TCC += $(TCC.$(HOST_OS)) include $(SRCDIR)/main.mk Index: src/add.c ================================================================== --- src/add.c +++ src/add.c @@ -60,11 +60,11 @@ "manifest.uuid", }; if( N>=0 && N<count(azName) ) return azName[N]; if( N>=count(azName) && N<count(azName)+count(azManifest) - && db_get_boolean("manifest",0) ){ + && db_get_versionable_setting_boolean("manifest",0) ){ return azManifest[N-count(azName)]; } return 0; } @@ -185,11 +185,11 @@ zIgnoreFlag = find_option("ignore",0,1); includeDotFiles = find_option("dotfiles",0,0)!=0; db_must_be_within_tree(); if( zIgnoreFlag==0 ){ - zIgnoreFlag = db_get("ignore-glob", 0); + zIgnoreFlag = db_get_versionable_setting("ignore-glob", 0); } vid = db_lget_int("checkout",0); if( vid==0 ){ fossil_panic("no checkout to add to"); } @@ -337,11 +337,11 @@ int nDelete = 0; Glob *pIgnore; db_must_be_within_tree(); if( zIgnoreFlag==0 ){ - zIgnoreFlag = db_get("ignore-glob", 0); + zIgnoreFlag = db_get_versionable_setting("ignore-glob", 0); } vid = db_lget_int("checkout",0); if( vid==0 ){ fossil_panic("no checkout to add to"); } Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -224,16 +224,16 @@ int allFlag = find_option("dotfiles",0,0)!=0; int outputManifest; Glob *pIgnore; db_must_be_within_tree(); - outputManifest = db_get_boolean("manifest",0); + outputManifest = db_get_versionable_setting_boolean("manifest",0); db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); n = strlen(g.zLocalRoot); blob_init(&path, g.zLocalRoot, n-1); if( zIgnoreFlag==0 ){ - zIgnoreFlag = db_get("ignore-glob", 0); + zIgnoreFlag = db_get_versionable_setting("ignore-glob", 0); } pIgnore = glob_create(zIgnoreFlag); vfile_scan(&path, blob_size(&path), allFlag, pIgnore); glob_free(pIgnore); db_prepare(&q, @@ -283,11 +283,11 @@ allFlag = find_option("force","f",0)!=0; dotfilesFlag = find_option("dotfiles",0,0)!=0; zIgnoreFlag = find_option("ignore",0,1); db_must_be_within_tree(); if( zIgnoreFlag==0 ){ - zIgnoreFlag = db_get("ignore-glob", 0); + zIgnoreFlag = db_get_versionable_setting("ignore-glob", 0); } db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); n = strlen(g.zLocalRoot); blob_init(&path, g.zLocalRoot, n-1); pIgnore = glob_create(zIgnoreFlag); @@ -831,11 +831,11 @@ zUserOvrd = find_option("user-override",0,1); db_must_be_within_tree(); noSign = db_get_boolean("omitsign", 0)|noSign; if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; } useCksum = db_get_boolean("repo-cksum", 1); - outputManifest = db_get_boolean("manifest", 0); + outputManifest = db_get_versionable_setting_boolean("manifest", 0); verify_all_options(); /* So that older versions of Fossil (that do not understand delta- ** manifest) can continue to use this repository, do not create a new ** delta-manifest unless this repository already contains one or more @@ -972,11 +972,11 @@ ** the identified fils are inserted (if they have been modified). */ db_prepare(&q, "SELECT id, %Q || pathname, mrid, %s FROM vfile " "WHERE chnged==1 AND NOT deleted AND file_is_selected(id)", - g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")) + g.zLocalRoot, glob_expr("pathname", db_get_versionable_setting("crnl-glob","")) ); while( db_step(&q)==SQLITE_ROW ){ int id, rid; const char *zFullname; Blob content; Index: src/checkout.c ================================================================== --- src/checkout.c +++ src/checkout.c @@ -141,11 +141,11 @@ void manifest_to_disk(int vid){ char *zManFile; Blob manifest; Blob hash; - if( db_get_boolean("manifest",0) ){ + if( db_get_versionable_setting_boolean("manifest",0) ){ blob_zero(&manifest); content_get(vid, &manifest); zManFile = mprintf("%smanifest", g.zLocalRoot); blob_write_to_file(&manifest, zManFile); free(zManFile); @@ -242,10 +242,11 @@ if( !keepFlag ){ vfile_to_disk(vid, 0, 1, promptFlag); } checkout_set_all_exe(vid); manifest_to_disk(vid); + ensure_empty_dirs_created(); db_lset_int("checkout", vid); undo_reset(); db_multi_exec("DELETE FROM vmerge"); if( !keepFlag && db_get_boolean("repo-cksum",1) ){ vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); Index: src/configure.c ================================================================== --- src/configure.c +++ src/configure.c @@ -81,10 +81,11 @@ { "project-name", CONFIGSET_PROJ }, { "project-description", CONFIGSET_PROJ }, { "manifest", CONFIGSET_PROJ }, { "ignore-glob", CONFIGSET_PROJ }, { "crnl-glob", CONFIGSET_PROJ }, + { "empty-dirs", CONFIGSET_PROJ }, { "index-page", CONFIGSET_SKIN }, { "timeline-block-markup", CONFIGSET_SKIN }, { "timeline-max-comment", CONFIGSET_SKIN }, { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, Index: src/db.c ================================================================== --- src/db.c +++ src/db.c @@ -1390,10 +1390,46 @@ sqlite3 *dbTemp = g.db; g.db = g.dbConfig; g.dbConfig = dbTemp; } } + +/* +** Get a potentially versioned setting - either from .fossil-settings/<name> +*/ +char *db_get_versionable_setting(const char *zName, char *zDefault){ + char *s = 0; + if( db_open_local() ){ + /* See if there's a versioned setting */ + Blob versionedPathname; + blob_zero(&versionedPathname); + blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, zName); + char *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 ){ + s = strdup(blob_str(&setting)); + } + blob_reset(&setting); + } + blob_reset(&versionedPathname); + } + if( s != 0 ){ + return s; + } + /* Fall back to settings in the database */ + return db_get(zName, zDefault); +} +int db_get_versionable_setting_boolean(const char *zName, int dflt){ + char *zVal = db_get_versionable_setting(zName, dflt ? "on" : "off"); + if( is_truth(zVal) ) return 1; + if( is_false(zVal) ) return 0; + return dflt; +} + /* ** Get and set values from the CONFIG, GLOBAL_CONFIG and VVAR table in the ** repository and local databases. */ @@ -1652,10 +1688,11 @@ { "editor", 0, 16, "" }, { "gdiff-command", 0, 16, "gdiff" }, { "gmerge-command",0, 40, "" }, { "https-login", 0, 0, "off" }, { "ignore-glob", 0, 40, "" }, + { "empty-dirs", 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" }, Index: src/glob.c ================================================================== --- src/glob.c +++ src/glob.c @@ -110,24 +110,24 @@ p = fossil_malloc( sizeof(*p) + nList+1 ); memset(p, 0, sizeof(*p)); z = (char*)&p[1]; memcpy(z, zPatternList, nList+1); while( z[0] ){ - while( z[0]==',' || z[0]==' ' ) z++; /* Skip leading spaces */ + while( z[0]==',' || z[0]==' ' || z[0]=='\n' || z[0]=='\r' ) z++; /* Skip leading spaces and newlines */ if( z[0]=='\'' || z[0]=='"' ){ delimiter = z[0]; z++; }else{ delimiter = ','; } if( z[0]==0 ) break; p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) ); p->azPattern[p->nPattern++] = z; - for(i=0; z[i] && z[i]!=delimiter; i++){} + for(i=0; z[i] && z[i]!=delimiter && z[i]!='\n' && z[i]!='\r'; i++){} if( delimiter==',' ){ - /* Remove trailing spaces on a comma-delimited pattern */ - for(j=i; j>1 && z[j-1]==' '; j--){} + /* Remove trailing spaces / newlines on a comma-delimited pattern */ + for(j=i; j>1 && (z[j-1]==' ' || z[j-1]=='\n' || z[j-1]=='\r'); j--){} if( j<i ) z[j] = 0; } if( z[i]==0 ) break; z[i] = 0; z += i+1; Index: src/merge.c ================================================================== --- src/merge.c +++ src/merge.c @@ -91,11 +91,11 @@ zPivot = find_option("baseline",0,1); if( g.argc!=3 ){ usage("VERSION"); } db_must_be_within_tree(); - if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); + if( zBinGlob==0 ) zBinGlob = db_get_versionable_setting("binary-glob",0); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("nothing is checked out"); } mid = name_to_rid(g.argv[2]); Index: src/tar.c ================================================================== --- src/tar.c +++ src/tar.c @@ -215,11 +215,11 @@ nPrefix = blob_size(&filename); pManifest = manifest_get(rid, CFTYPE_MANIFEST); if( pManifest ){ mTime = (pManifest->rDate - 2440587.5)*86400.0; - if( db_get_boolean("manifest", 0) ){ + if( db_get_versionable_setting_boolean("manifest", 0) ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); tar_add_file(zName, &mfile, 0, mTime); sha1sum_blob(&mfile, &hash); blob_reset(&mfile); Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -115,10 +115,13 @@ } if( !nochangeFlag && db_exists("SELECT 1 FROM vmerge") ){ fossil_fatal("cannot update an uncommitted merge"); } if( !nochangeFlag && !internalUpdate ) autosync(AUTOSYNC_PULL); + + /* Create any empty directories now, as well as after the update, so changes in settings are reflected now */ + ensure_empty_dirs_created(); if( internalUpdate ){ tid = internalUpdate; }else if( g.argc>=3 ){ if( strcmp(g.argv[2], "current")==0 ){ @@ -435,10 +438,11 @@ ** Clean up the mid and pid VFILE entries. Then commit the changes. */ if( nochangeFlag ){ db_end_transaction(1); /* With --nochange, rollback changes */ }else{ + ensure_empty_dirs_created(); if( g.argc<=3 ){ /* All files updated. Shift the current checkout to the target. */ db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid); checkout_set_all_exe(vid); manifest_to_disk(tid); @@ -450,10 +454,35 @@ } if( !internalUpdate ) undo_finish(); db_end_transaction(0); } } + +/* +** Make sure empty directories are created +*/ +void ensure_empty_dirs_created() +{ + /* Make empty directories? */ + char *zEmptyDirs = db_get_versionable_setting("empty-dirs", 0); + if( zEmptyDirs!=0 ){ + Blob dirsList, line; + blob_zero(&dirsList); + blob_init(&dirsList, zEmptyDirs, strlen(zEmptyDirs)); + while( blob_line(&dirsList, &line) ){ + if( blob_buffer(&line)[0]=='#' ) continue; + Blob dirName; + int l = blob_token(&line, &dirName); + if(l > 0) { + /* Try and create the directory */ + if( file_mkdir(blob_str(&dirName), 0)!=0 ) { + fossil_warning("couldn't create empty-dir %s", blob_str(&dirName)); + } + } + } + } +} /* ** Get the contents of a file within the checking "revision". If ** revision==NULL then get the file content for the current checkout. Index: src/user.c ================================================================== --- src/user.c +++ src/user.c @@ -19,10 +19,14 @@ ** querying information about users. */ #include "config.h" #include "user.h" +#if defined(__sun__) || defined(sun) + /* On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257. */ + #define getpass getpassphrase +#endif /* ** Strip leading and trailing space from a string and add the string ** onto the end of a blob. */ Index: src/zip.c ================================================================== --- src/zip.c +++ src/zip.c @@ -337,11 +337,11 @@ pManifest = manifest_get(rid, CFTYPE_MANIFEST); if( pManifest ){ char *zName; zip_set_timedate(pManifest->rDate); - if( db_get_boolean("manifest", 0) ){ + if( db_get_versionable_setting_boolean("manifest", 0) ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); zip_add_folders(zName); zip_add_file(zName, &mfile, 0); sha1sum_blob(&mfile, &hash);