Index: src/add.c ================================================================== --- src/add.c +++ src/add.c @@ -226,11 +226,11 @@ if( filenames_are_case_sensitive() ){ xCmp = fossil_strcmp; }else{ xCmp = fossil_stricmp; } - db_prepare(&loop, "SELECT x FROM sfile ORDER BY x"); + db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname"); while( db_step(&loop)==SQLITE_ROW ){ const char *zToAdd = db_column_text(&loop, 0); if( fossil_strcmp(zToAdd, zRepo)==0 ) continue; for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){ if( xCmp(zToAdd, zReserved)==0 ) break; @@ -307,11 +307,11 @@ zIgnoreFlag = db_get("ignore-glob", 0); } if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; vid = db_lget_int("checkout",0); db_begin_transaction(); - db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", + db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); pClean = glob_create(zCleanFlag); pIgnore = glob_create(zIgnoreFlag); nRoot = strlen(g.zLocalRoot); @@ -349,11 +349,11 @@ blob_reset(&fullName); continue; } } db_multi_exec( - "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)", + "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zTreeName ); } blob_reset(&fullName); } @@ -474,11 +474,11 @@ removeFiles = db_get_boolean("mv-rm-files",0); #else removeFiles = FOSSIL_MV_RM_FILE; #endif } - db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", + db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); for(i=2; i /* -** Generate text describing all changes. Prepend zPrefix to each line -** of output. +** Change filter options. +*/ +enum { + /* Zero-based bit indexes. */ + CB_EDITED , CB_UPDATED , CB_CHANGED, CB_MISSING , CB_ADDED, CB_DELETED, + CB_RENAMED, CB_CONFLICT, CB_META , CB_UNCHANGED, CB_EXTRA, CB_MERGE , + CB_RELPATH, CB_CLASSIFY, CB_MTIME , CB_SIZE , CB_FATAL, CB_COMMENT, + + /* Bitmask values. */ + C_EDITED = 1 << CB_EDITED, /* Edited, merged, and conflicted files. */ + C_UPDATED = 1 << CB_UPDATED, /* Files updated by merge/integrate. */ + C_CHANGED = 1 << CB_CHANGED, /* Treated the same as the above two. */ + C_MISSING = 1 << CB_MISSING, /* Missing and non- files. */ + C_ADDED = 1 << CB_ADDED, /* Added files. */ + C_DELETED = 1 << CB_DELETED, /* Deleted files. */ + C_RENAMED = 1 << CB_RENAMED, /* Renamed files. */ + C_CONFLICT = 1 << CB_CONFLICT, /* Files having merge conflicts. */ + C_META = 1 << CB_META, /* Files with metadata changes. */ + C_UNCHANGED = 1 << CB_UNCHANGED, /* Unchanged files. */ + C_EXTRA = 1 << CB_EXTRA, /* Unmanaged files. */ + C_MERGE = 1 << CB_MERGE, /* Merge contributors. */ + C_FILTER = C_EDITED | C_UPDATED | C_CHANGED | C_MISSING | C_ADDED + | C_DELETED | C_RENAMED | C_CONFLICT | C_META | C_UNCHANGED + | C_EXTRA | C_MERGE, /* All filter bits. */ + C_ALL = C_FILTER & ~(C_EXTRA | C_MERGE),/* All managed files. */ + C_DIFFER = C_FILTER & ~(C_UNCHANGED | C_MERGE),/* All differences. */ + C_RELPATH = 1 << CB_RELPATH, /* Show relative paths. */ + C_CLASSIFY = 1 << CB_CLASSIFY, /* Show file change types. */ + C_DEFAULT = (C_ALL & ~C_UNCHANGED) | C_MERGE | C_CLASSIFY, + C_MTIME = 1 << CB_MTIME, /* Show file modification time. */ + C_SIZE = 1 << CB_SIZE, /* Show file size in bytes. */ + C_FATAL = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */ + C_COMMENT = 1 << CB_COMMENT, /* Precede each line with "# ". */ +}; + +/* +** Create a TEMP table named SFILE and add all unmanaged files named on +** the command-line to that table. If directories are named, then add +** all unmanaged files contained underneath those directories. If there +** are no files or directories named on the command-line, then add all +** unmanaged files anywhere in the checkout. +*/ +static void locate_unmanaged_files( + int argc, /* Number of command-line arguments to examine */ + char **argv, /* values of command-line arguments */ + unsigned scanFlags, /* Zero or more SCAN_xxx flags */ + Glob *pIgnore /* Do not add files that match this GLOB */ +){ + Blob name; /* Name of a candidate file or directory */ + char *zName; /* Name of a candidate file or directory */ + int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */ + int i; /* Loop counter */ + int nRoot; /* length of g.zLocalRoot */ + + db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s," + " mtime INTEGER, size INTEGER)", filename_collation()); + nRoot = (int)strlen(g.zLocalRoot); + if( argc==0 ){ + blob_init(&name, g.zLocalRoot, nRoot - 1); + vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0); + blob_reset(&name); + }else{ + for(i=0; inUsed -= nPrefix; + /* Obtain the list of managed files if appropriate. */ + blob_zero(&sql); + if( flags & C_ALL ){ + /* Start with a list of all managed files. */ + blob_append_sql(&sql, + "SELECT pathname, %s as mtime, %s as size, deleted, chnged, rid," + " coalesce(origname!=pathname,0) AS renamed, islink, 1 AS managed" + " FROM vfile LEFT JOIN blob USING (rid)" + " WHERE is_selected(id)%s", + flags & C_MTIME ? "datetime(checkin_mtime(:vid, rid), " + "'unixepoch', toLocal())" : "''" /*safe-for-%s*/, + flags & C_SIZE ? "coalesce(blob.size, 0)" : "0" /*safe-for-%s*/, + blob_sql_text(&where)); + + /* Exclude unchanged files unless requested. */ + if( !(flags & C_UNCHANGED) ){ + blob_append_sql(&sql, + " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"); + } + } + + /* If C_EXTRA, add unmanaged files to the query result too. */ + if( flags & C_EXTRA ){ + if( blob_size(&sql) ){ + blob_append_sql(&sql, " UNION ALL"); + } + blob_append_sql(&sql, + " SELECT pathname, %s, %s, 0, 0, 0, 0, 0, 0" + " FROM sfile WHERE pathname NOT IN (%s)%s", + flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''", + flags & C_SIZE ? "size" : "0", + fossil_all_reserved_names(0), blob_sql_text(&where)); + } + blob_reset(&where); + + /* Pre-create the "ok" temporary table so the checkin_mtime() SQL function + * does not lead to SQLITE_ABORT_ROLLBACK during execution of the OP_OpenRead + * SQLite opcode. checkin_mtime() calls mtime_of_manifest_file() which + * creates a temporary table if it doesn't already exist, thus invalidating + * the prepared statement in the middle of its execution. */ + db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"); + + /* Append an ORDER BY clause then compile the query. */ + blob_append_sql(&sql, " ORDER BY pathname"); + db_prepare(&q, "%s", blob_sql_text(&sql)); + blob_reset(&sql); + + /* Bind the checkout version ID to the query if needed. */ + if( (flags & C_ALL) && (flags & C_MTIME) ){ + db_bind_int(&q, ":vid", db_lget_int("checkout", 0)); + } + + /* Execute the query and assemble the report. */ + blob_zero(&rewrittenPathname); + while( db_step(&q)==SQLITE_ROW ){ + const char *zPathname = db_column_text(&q, 0); + const char *zClass = 0; + int isManaged = db_column_int(&q, 8); + const char *zMtime = db_column_text(&q, 1); + int size = db_column_int(&q, 2); + int isDeleted = db_column_int(&q, 3); + int isChnged = db_column_int(&q, 4); + int isNew = isManaged && !db_column_int(&q, 5); + int isRenamed = db_column_int(&q, 6); + int isLink = db_column_int(&q, 7); + char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); + int isMissing = !file_wd_isfile_or_link(zFullName); + + /* Determine the file change classification, if any. */ + if( (flags & C_DELETED) && isDeleted ){ + zClass = "DELETED"; + }else if( (flags & C_MISSING) && isMissing ){ + if( file_access(zFullName, F_OK)==0 ){ + zClass = "NOT_A_FILE"; + if( flags & C_FATAL ){ + fossil_warning("not a file: %s", zFullName); + nErr++; + } + }else{ + zClass = "MISSING"; + if( flags & C_FATAL ){ + fossil_warning("missing file: %s", zFullName); + nErr++; + } + } + }else if( (flags & C_ADDED) && isNew ){ + zClass = "ADDED"; + }else if( (flags & (C_UPDATED | C_CHANGED)) && isChnged==2 ){ + zClass = "UPDATED_BY_MERGE"; + }else if( (flags & C_ADDED) && isChnged==3 ){ + zClass = "ADDED_BY_MERGE"; + }else if( (flags & (C_UPDATED | C_CHANGED)) && isChnged==4 ){ + zClass = "UPDATED_BY_INTEGRATE"; + }else if( (flags & C_ADDED) && isChnged==5 ){ + zClass = "ADDED_BY_INTEGRATE"; + }else if( (flags & C_META) && isChnged==6 ){ + zClass = "EXECUTABLE"; + }else if( (flags & C_META) && isChnged==7 ){ + zClass = "SYMLINK"; + }else if( (flags & C_META) && isChnged==8 ){ + zClass = "UNEXEC"; + }else if( (flags & C_META) && isChnged==9 ){ + zClass = "UNLINK"; + }else if( (flags & C_CONFLICT) && isChnged && !isLink + && file_contains_merge_marker(zFullName) ){ + zClass = "CONFLICT"; + }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged + && (isChnged<2 || isChnged>9) ){ + zClass = "EDITED"; + }else if( (flags & C_RENAMED) && isRenamed ){ + zClass = "RENAMED"; + }else if( (flags & C_UNCHANGED) && isManaged && !isDeleted && !isMissing + && !isNew && !isChnged && !isRenamed ){ + zClass = "UNCHANGED"; + }else if( (flags & C_EXTRA) && !isManaged ){ + zClass = "EXTRA"; + } + + /* Only report files for which a change classification was determined. */ + if( zClass ){ + if( flags & C_COMMENT ){ + blob_append(report, "# ", 2); + } + if( flags & C_CLASSIFY ){ + blob_appendf(report, "%-10s ", zClass); + } + if( flags & C_MTIME ){ + blob_append(report, zMtime, -1); + blob_append(report, " ", 2); + } + if( flags & C_SIZE ){ + blob_appendf(report, "%7d ", size); + } + if( flags & C_RELPATH ){ + /* If C_RELPATH, display paths relative to current directory. */ + const char *zDisplayName; + file_relative_name(zFullName, &rewrittenPathname, 0); + zDisplayName = blob_str(&rewrittenPathname); + if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){ + zDisplayName += 2; /* no unnecessary ./ prefix */ + } + blob_append(report, zDisplayName, -1); + }else{ + /* If not C_RELPATH, display paths relative to project root. */ + blob_append(report, zPathname, -1); + } + blob_append(report, "\n", 1); } free(zFullName); } blob_reset(&rewrittenPathname); db_finalize(&q); - db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid" - " WHERE id<=0"); - while( db_step(&q)==SQLITE_ROW ){ - const char *zLabel = "MERGED_WITH "; - switch( db_column_int(&q, 1) ){ - case -1: zLabel = "CHERRYPICK "; break; - case -2: zLabel = "BACKOUT "; break; - case -4: zLabel = "INTEGRATE "; break; - } - blob_append(report, zPrefix, nPrefix); - blob_appendf(report, "%s%s\n", zLabel, db_column_text(&q, 0)); - } - db_finalize(&q); + + /* If C_MERGE, put merge contributors at the end of the report. */ +skipFiles: + if( flags & C_MERGE ){ + db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid" + " WHERE id<=0"); + while( db_step(&q)==SQLITE_ROW ){ + if( flags & C_COMMENT ){ + blob_append(report, "# ", 2); + } + if( flags & C_CLASSIFY ){ + const char *zClass; + switch( db_column_int(&q, 1) ){ + case -1: zClass = "CHERRYPICK" ; break; + case -2: zClass = "BACKOUT" ; break; + case -4: zClass = "INTEGRATE" ; break; + default: zClass = "MERGED_WITH"; break; + } + blob_appendf(report, "%-10s ", zClass); + } + blob_append(report, db_column_text(&q, 0), -1); + blob_append(report, "\n", 1); + } + db_finalize(&q); + } if( nErr ){ fossil_fatal("aborting due to prior errors"); } } @@ -171,115 +342,228 @@ if( absPathOption ){ relativePaths = 0; } if( relPathOption ){ relativePaths = 1; } return relativePaths; } -void print_changes( - int useSha1sum, /* Verify file status using SHA1 hashing rather - than relying on file mtimes. */ - int showHdr, /* Identify the repository if there are changes */ - int verboseFlag, /* Say "(none)" if there are no changes */ - int cwdRelative /* Report relative to the current working dir */ -){ - Blob report; - int vid; - blob_zero(&report); - - vid = db_lget_int("checkout", 0); - vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); - status_report(&report, "", 0, cwdRelative); - if( verboseFlag && blob_size(&report)==0 ){ - blob_append(&report, " (none)\n", -1); - } - if( showHdr && blob_size(&report)>0 ){ - fossil_print("Changes for %s at %s:\n", db_get("project-name","???"), - g.zLocalRoot); - } - blob_write_to_file(&report, "-"); - blob_reset(&report); -} - -/* -** COMMAND: changes -** -** Usage: %fossil changes ?OPTIONS? -** -** Report on the edit status of all files in the current checkout. -** -** Pathnames are displayed according to the "relative-paths" setting, -** unless overridden by the --abs-paths or --rel-paths options. -** -** Options: -** --abs-paths Display absolute pathnames. -** --rel-paths Display pathnames relative to the current working -** directory. -** --sha1sum Verify file status using SHA1 hashing rather -** than relying on file mtimes. -** --header Identify the repository if there are changes -** -v|--verbose Say "(none)" if there are no changes -** -** See also: extras, ls, status -*/ -void changes_cmd(void){ - int useSha1sum = find_option("sha1sum", 0, 0)!=0; - int showHdr = find_option("header",0,0)!=0; - int verboseFlag = find_option("verbose","v",0)!=0; - int cwdRelative = 0; - db_must_be_within_tree(); - cwdRelative = determine_cwd_relative_option(); - - /* We should be done with options.. */ - verify_all_options(); - - print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative); -} - -/* -** COMMAND: status -** -** Usage: %fossil status ?OPTIONS? -** -** Report on the status of the current checkout. -** -** Pathnames are displayed according to the "relative-paths" setting, -** unless overridden by the --abs-paths or --rel-paths options. -** -** Options: -** -** --abs-paths Display absolute pathnames. -** --rel-paths Display pathnames relative to the current working -** directory. -** --sha1sum Verify file status using SHA1 hashing rather -** than relying on file mtimes. -** -** See also: changes, extras, ls -*/ -void status_cmd(void){ - int vid; - int useSha1sum = find_option("sha1sum", 0, 0)!=0; - int showHdr = find_option("header",0,0)!=0; - int verboseFlag = find_option("verbose","v",0)!=0; - int cwdRelative = 0; - db_must_be_within_tree(); - /* 012345678901234 */ - cwdRelative = determine_cwd_relative_option(); - - /* We should be done with options.. */ - verify_all_options(); - - fossil_print("repository: %s\n", db_repository_filename()); - fossil_print("local-root: %s\n", g.zLocalRoot); - if( g.zConfigDbName ){ - fossil_print("config-db: %s\n", g.zConfigDbName); - } - vid = db_lget_int("checkout", 0); - if( vid ){ - show_common_info(vid, "checkout:", 1, 1); - } - db_record_repository_filename(0); - print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative); - leaf_ambiguity_warning(vid, vid); +/* +** COMMAND: changes +** COMMAND: status +** +** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...? +** +** Report the change status of files in the current checkout. If one or +** more PATHS are specified, only changes among the named files and +** directories are reported. Directories are searched recursively. +** +** The status command is similar to the changes command, except it lacks +** several of the options supported by changes and it has its own header +** and footer information. The header information is a subset of that +** shown by the info command, and the footer shows if there are any forks. +** Change type classification is always enabled for the status command. +** +** Each line of output is the name of a changed file, with paths shown +** according to the "relative-paths" setting, unless overridden by the +** --abs-paths or --rel-paths options. +** +** By default, all changed files are selected for display. This behavior +** can be overridden by using one or more filter options (listed below), +** in which case only files with the specified change type(s) are shown. +** As a special case, the --no-merge option does not inhibit this default. +** This default shows exactly the set of changes that would be checked +** in by the commit command. +** +** If no filter options are used, or if the --merge option is used, the +** SHA1 hash of each merge contributor check-in version is displayed at +** the end of the report. The --no-merge option is useful to display the +** default set of changed files without the merge contributors. +** +** If change type classification is enabled, each output line starts with +** a code describing the file's change type, e.g. EDITED or RENAMED. It +** is enabled by default unless exactly one change type is selected. For +** the purposes of determining the default, --changed counts as selecting +** one change type. The default can be overridden by the --classify or +** --no-classify options. +** +** If both --merge and --no-merge are used, --no-merge has priority. The +** same is true of --classify and --no-classify. +** +** The "fossil changes --extra" command is equivalent to "fossil extras". +** +** --edited and --updated produce disjoint sets. --updated shows a file +** only when it is identical to that of its merge contributor, and the +** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE. +** If the file had to be merged with any other changes, it is considered +** to be merged or conflicted and therefore will be shown by --edited, not +** --updated, with types EDITED or CONFLICT. The --changed option can be +** used to display the union of --edited and --updated. +** +** --differ is so named because it lists all the differences between the +** checked-out version and the checkout directory. In addition to the +** default changes (besides --merge), it lists extra files which (assuming +** ignore-glob is set correctly) may be worth adding. Prior to doing a +** commit, it is good practice to check --differ to see not only which +** changes would be committed but also if any files need to be added. +** +** General options: +** --abs-paths Display absolute pathnames. +** --rel-paths Display pathnames relative to the current working +** directory. +** --sha1sum Verify file status using SHA1 hashing rather than +** relying on file mtimes. +** --case-sensitive Override case-sensitive setting. +** --dotfiles Include unmanaged files beginning with a dot. +** --ignore Ignore unmanaged files matching CSG glob patterns. +** +** Options specific to the changes command: +** --header Identify the repository if report is non-empty. +** -v|--verbose Say "(none)" if the change report is empty. +** --classify Start each line with the file's change type. +** --no-classify Do not print file change types. +** +** Filter options: +** --edited Display edited, merged, and conflicted files. +** --updated Display files updated by merge/integrate. +** --changed Combination of the above two options. +** --missing Display missing files. +** --added Display added files. +** --deleted Display deleted files. +** --renamed Display renamed files. +** --conflict Display files having merge conflicts. +** --meta Display files with metadata changes. +** --unchanged Display unchanged files. +** --all Display all managed files, i.e. all of the above. +** --extra Display unmanaged files. +** --differ Display modified and extra files. +** --merge Display merge contributors. +** --no-merge Do not display merge contributors. +** +** See also: extras, ls +*/ +void status_cmd(void){ + /* Affirmative and negative flag option tables. */ + static const struct { + const char *option; /* Flag name. */ + unsigned mask; /* Flag bits. */ + } flagDefs[] = { + {"edited" , C_EDITED }, {"updated" , C_UPDATED }, + {"changed" , C_CHANGED }, {"missing" , C_MISSING }, + {"added" , C_ADDED }, {"deleted" , C_DELETED }, + {"renamed" , C_RENAMED }, {"conflict" , C_CONFLICT }, + {"meta" , C_META }, {"unchanged" , C_UNCHANGED}, + {"all" , C_ALL }, {"extra" , C_EXTRA }, + {"differ" , C_DIFFER }, {"merge" , C_MERGE }, + {"classify", C_CLASSIFY}, + }, noFlagDefs[] = { + {"no-merge", C_MERGE }, {"no-classify", C_CLASSIFY }, + }; + + Blob report = BLOB_INITIALIZER; + enum {CHANGES, STATUS} command = *g.argv[1]=='s' ? STATUS : CHANGES; + int useSha1sum = find_option("sha1sum", 0, 0)!=0; + int showHdr = command==CHANGES && find_option("header", 0, 0); + int verboseFlag = command==CHANGES && find_option("verbose", "v", 0); + const char *zIgnoreFlag = find_option("ignore", 0, 1); + unsigned scanFlags = 0; + unsigned flags = 0; + int vid, i; + + /* Load affirmative flag options. */ + for( i=0; i0 ){ Stmt q; @ @ @@ -1207,12 +1207,12 @@ @ Repository List @ @ @

Available Repositories:

@
    - db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'" - " FROM sfile ORDER BY x COLLATE nocase;"); + db_prepare(&q, "SELECT pathname, substr(pathname,-7,-100000)||'/home'" + " FROM sfile ORDER BY pathname COLLATE nocase;"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zUrl = db_column_text(&q, 1); @
  1. %h(zName)
  2. } Index: src/stash.c ================================================================== --- src/stash.c +++ src/stash.c @@ -207,11 +207,11 @@ "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile WHERE stashid=%d", stashid ); vid = db_lget_int("checkout",0); - db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", + db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)", filename_collation()); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); int isRemoved = db_column_int(&q, 1); int isExec = db_column_int(&q, 2); @@ -222,11 +222,11 @@ char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew); Blob delta; undo_save(zNew); blob_zero(&delta); if( rid==0 ){ - db_multi_exec("INSERT OR IGNORE INTO sfile(x) VALUES(%Q)", zNew); + db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew); db_ephemeral_blob(&q, 6, &delta); blob_write_to_file(&delta, zNPath); file_wd_setexe(zNPath, isExec); }else if( isRemoved ){ fossil_print("DELETE %s\n", zOrig); Index: src/vfile.c ================================================================== --- src/vfile.c +++ src/vfile.c @@ -455,10 +455,12 @@ ** Values for the scanFlags parameter to vfile_scan(). */ #define SCAN_ALL 0x001 /* Includes files that begin with "." */ #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */ #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */ +#define SCAN_MTIME 0x008 /* Populate mtime column */ +#define SCAN_SIZE 0x010 /* Populate size column */ #endif /* INTERFACE */ /* ** Load into table SFILE the name of every ordinary file in ** the directory pPath. Omit the first nPrefix characters of @@ -498,13 +500,18 @@ } if( skipAll ) return; if( depth==0 ){ db_prepare(&ins, - "INSERT OR IGNORE INTO sfile(x) SELECT :file" - " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE" - " pathname=:file %s)", filename_collation() + "INSERT OR IGNORE INTO sfile(pathname%s%s) SELECT :file%s%s" + " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE" + " pathname=:file %s)", + scanFlags & SCAN_MTIME ? ", mtime" : "", + scanFlags & SCAN_SIZE ? ", size" : "", + scanFlags & SCAN_MTIME ? ", :mtime" : "", + scanFlags & SCAN_SIZE ? ", :size" : "", + filename_collation() ); } depth++; zNative = fossil_utf8_to_path(blob_str(pPath), 1); @@ -539,10 +546,16 @@ #else }else if( file_wd_isfile_or_link(zPath) ){ #endif if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){ db_bind_text(&ins, ":file", &zPath[nPrefix+1]); + if( scanFlags & SCAN_MTIME ){ + db_bind_int(&ins, ":mtime", file_mtime(zPath)); + } + if( scanFlags & SCAN_SIZE ){ + db_bind_int(&ins, ":size", file_size(zPath)); + } db_step(&ins); db_reset(&ins); } } fossil_path_free(zUtf8);