Fossil SCM

Integrate andygoth-changes, try two

andygoth 2016-11-07 00:33 trunk merge
Commit e7764947d78a64659b9a934d94cdaadf2490f1ac
+6 -6
--- src/add.c
+++ src/add.c
@@ -226,11 +226,11 @@
226226
if( filenames_are_case_sensitive() ){
227227
xCmp = fossil_strcmp;
228228
}else{
229229
xCmp = fossil_stricmp;
230230
}
231
- db_prepare(&loop, "SELECT x FROM sfile ORDER BY x");
231
+ db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
232232
while( db_step(&loop)==SQLITE_ROW ){
233233
const char *zToAdd = db_column_text(&loop, 0);
234234
if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235235
for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236236
if( xCmp(zToAdd, zReserved)==0 ) break;
@@ -307,11 +307,11 @@
307307
zIgnoreFlag = db_get("ignore-glob", 0);
308308
}
309309
if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
310310
vid = db_lget_int("checkout",0);
311311
db_begin_transaction();
312
- db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
312
+ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
313313
filename_collation());
314314
pClean = glob_create(zCleanFlag);
315315
pIgnore = glob_create(zIgnoreFlag);
316316
nRoot = strlen(g.zLocalRoot);
317317
@@ -349,11 +349,11 @@
349349
blob_reset(&fullName);
350350
continue;
351351
}
352352
}
353353
db_multi_exec(
354
- "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
354
+ "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)",
355355
zTreeName
356356
);
357357
}
358358
blob_reset(&fullName);
359359
}
@@ -474,11 +474,11 @@
474474
removeFiles = db_get_boolean("mv-rm-files",0);
475475
#else
476476
removeFiles = FOSSIL_MV_RM_FILE;
477477
#endif
478478
}
479
- db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
479
+ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
480480
filename_collation());
481481
for(i=2; i<g.argc; i++){
482482
Blob treeName;
483483
char *zTreeName;
484484
@@ -494,11 +494,11 @@
494494
filename_collation(), zTreeName, filename_collation()
495495
);
496496
blob_reset(&treeName);
497497
}
498498
499
- db_prepare(&loop, "SELECT x FROM sfile");
499
+ db_prepare(&loop, "SELECT pathname FROM sfile");
500500
while( db_step(&loop)==SQLITE_ROW ){
501501
fossil_print("DELETED %s\n", db_column_text(&loop, 0));
502502
if( removeFiles ) add_file_to_remove(db_column_text(&loop, 0));
503503
}
504504
db_finalize(&loop);
@@ -670,11 +670,11 @@
670670
** Populate the temp table "sfile" with the names of all unmanaged
671671
** files currently in the check-out, except for files that match the
672672
** --ignore or ignore-glob patterns and dot-files. Then add all of
673673
** the files in the sfile temp table to the set of managed files.
674674
*/
675
- db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
675
+ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
676676
filename_collation());
677677
n = strlen(g.zLocalRoot);
678678
blob_init(&path, g.zLocalRoot, n-1);
679679
/* now we read the complete file structure into a temp table */
680680
pClean = glob_create(zCleanFlag);
681681
--- src/add.c
+++ src/add.c
@@ -226,11 +226,11 @@
226 if( filenames_are_case_sensitive() ){
227 xCmp = fossil_strcmp;
228 }else{
229 xCmp = fossil_stricmp;
230 }
231 db_prepare(&loop, "SELECT x FROM sfile ORDER BY x");
232 while( db_step(&loop)==SQLITE_ROW ){
233 const char *zToAdd = db_column_text(&loop, 0);
234 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236 if( xCmp(zToAdd, zReserved)==0 ) break;
@@ -307,11 +307,11 @@
307 zIgnoreFlag = db_get("ignore-glob", 0);
308 }
309 if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
310 vid = db_lget_int("checkout",0);
311 db_begin_transaction();
312 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
313 filename_collation());
314 pClean = glob_create(zCleanFlag);
315 pIgnore = glob_create(zIgnoreFlag);
316 nRoot = strlen(g.zLocalRoot);
317
@@ -349,11 +349,11 @@
349 blob_reset(&fullName);
350 continue;
351 }
352 }
353 db_multi_exec(
354 "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
355 zTreeName
356 );
357 }
358 blob_reset(&fullName);
359 }
@@ -474,11 +474,11 @@
474 removeFiles = db_get_boolean("mv-rm-files",0);
475 #else
476 removeFiles = FOSSIL_MV_RM_FILE;
477 #endif
478 }
479 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
480 filename_collation());
481 for(i=2; i<g.argc; i++){
482 Blob treeName;
483 char *zTreeName;
484
@@ -494,11 +494,11 @@
494 filename_collation(), zTreeName, filename_collation()
495 );
496 blob_reset(&treeName);
497 }
498
499 db_prepare(&loop, "SELECT x FROM sfile");
500 while( db_step(&loop)==SQLITE_ROW ){
501 fossil_print("DELETED %s\n", db_column_text(&loop, 0));
502 if( removeFiles ) add_file_to_remove(db_column_text(&loop, 0));
503 }
504 db_finalize(&loop);
@@ -670,11 +670,11 @@
670 ** Populate the temp table "sfile" with the names of all unmanaged
671 ** files currently in the check-out, except for files that match the
672 ** --ignore or ignore-glob patterns and dot-files. Then add all of
673 ** the files in the sfile temp table to the set of managed files.
674 */
675 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
676 filename_collation());
677 n = strlen(g.zLocalRoot);
678 blob_init(&path, g.zLocalRoot, n-1);
679 /* now we read the complete file structure into a temp table */
680 pClean = glob_create(zCleanFlag);
681
--- src/add.c
+++ src/add.c
@@ -226,11 +226,11 @@
226 if( filenames_are_case_sensitive() ){
227 xCmp = fossil_strcmp;
228 }else{
229 xCmp = fossil_stricmp;
230 }
231 db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
232 while( db_step(&loop)==SQLITE_ROW ){
233 const char *zToAdd = db_column_text(&loop, 0);
234 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236 if( xCmp(zToAdd, zReserved)==0 ) break;
@@ -307,11 +307,11 @@
307 zIgnoreFlag = db_get("ignore-glob", 0);
308 }
309 if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
310 vid = db_lget_int("checkout",0);
311 db_begin_transaction();
312 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
313 filename_collation());
314 pClean = glob_create(zCleanFlag);
315 pIgnore = glob_create(zIgnoreFlag);
316 nRoot = strlen(g.zLocalRoot);
317
@@ -349,11 +349,11 @@
349 blob_reset(&fullName);
350 continue;
351 }
352 }
353 db_multi_exec(
354 "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)",
355 zTreeName
356 );
357 }
358 blob_reset(&fullName);
359 }
@@ -474,11 +474,11 @@
474 removeFiles = db_get_boolean("mv-rm-files",0);
475 #else
476 removeFiles = FOSSIL_MV_RM_FILE;
477 #endif
478 }
479 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
480 filename_collation());
481 for(i=2; i<g.argc; i++){
482 Blob treeName;
483 char *zTreeName;
484
@@ -494,11 +494,11 @@
494 filename_collation(), zTreeName, filename_collation()
495 );
496 blob_reset(&treeName);
497 }
498
499 db_prepare(&loop, "SELECT pathname FROM sfile");
500 while( db_step(&loop)==SQLITE_ROW ){
501 fossil_print("DELETED %s\n", db_column_text(&loop, 0));
502 if( removeFiles ) add_file_to_remove(db_column_text(&loop, 0));
503 }
504 db_finalize(&loop);
@@ -670,11 +670,11 @@
670 ** Populate the temp table "sfile" with the names of all unmanaged
671 ** files currently in the check-out, except for files that match the
672 ** --ignore or ignore-glob patterns and dot-files. Then add all of
673 ** the files in the sfile temp table to the set of managed files.
674 */
675 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
676 filename_collation());
677 n = strlen(g.zLocalRoot);
678 blob_init(&path, g.zLocalRoot, n-1);
679 /* now we read the complete file structure into a temp table */
680 pClean = glob_create(zCleanFlag);
681
+503 -283
--- src/checkin.c
+++ src/checkin.c
@@ -21,32 +21,115 @@
2121
#include "config.h"
2222
#include "checkin.h"
2323
#include <assert.h>
2424
2525
/*
26
-** Generate text describing all changes. Prepend zPrefix to each line
27
-** of output.
26
+** Change filter options.
27
+*/
28
+enum {
29
+ /* Zero-based bit indexes. */
30
+ CB_EDITED , CB_UPDATED , CB_CHANGED, CB_MISSING , CB_ADDED, CB_DELETED,
31
+ CB_RENAMED, CB_CONFLICT, CB_META , CB_UNCHANGED, CB_EXTRA, CB_MERGE ,
32
+ CB_RELPATH, CB_CLASSIFY, CB_MTIME , CB_SIZE , CB_FATAL, CB_COMMENT,
33
+
34
+ /* Bitmask values. */
35
+ C_EDITED = 1 << CB_EDITED, /* Edited, merged, and conflicted files. */
36
+ C_UPDATED = 1 << CB_UPDATED, /* Files updated by merge/integrate. */
37
+ C_CHANGED = 1 << CB_CHANGED, /* Treated the same as the above two. */
38
+ C_MISSING = 1 << CB_MISSING, /* Missing and non- files. */
39
+ C_ADDED = 1 << CB_ADDED, /* Added files. */
40
+ C_DELETED = 1 << CB_DELETED, /* Deleted files. */
41
+ C_RENAMED = 1 << CB_RENAMED, /* Renamed files. */
42
+ C_CONFLICT = 1 << CB_CONFLICT, /* Files having merge conflicts. */
43
+ C_META = 1 << CB_META, /* Files with metadata changes. */
44
+ C_UNCHANGED = 1 << CB_UNCHANGED, /* Unchanged files. */
45
+ C_EXTRA = 1 << CB_EXTRA, /* Unmanaged files. */
46
+ C_MERGE = 1 << CB_MERGE, /* Merge contributors. */
47
+ C_FILTER = C_EDITED | C_UPDATED | C_CHANGED | C_MISSING | C_ADDED
48
+ | C_DELETED | C_RENAMED | C_CONFLICT | C_META | C_UNCHANGED
49
+ | C_EXTRA | C_MERGE, /* All filter bits. */
50
+ C_ALL = C_FILTER & ~(C_EXTRA | C_MERGE),/* All managed files. */
51
+ C_DIFFER = C_FILTER & ~(C_UNCHANGED | C_MERGE),/* All differences. */
52
+ C_RELPATH = 1 << CB_RELPATH, /* Show relative paths. */
53
+ C_CLASSIFY = 1 << CB_CLASSIFY, /* Show file change types. */
54
+ C_DEFAULT = (C_ALL & ~C_UNCHANGED) | C_MERGE | C_CLASSIFY,
55
+ C_MTIME = 1 << CB_MTIME, /* Show file modification time. */
56
+ C_SIZE = 1 << CB_SIZE, /* Show file size in bytes. */
57
+ C_FATAL = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
58
+ C_COMMENT = 1 << CB_COMMENT, /* Precede each line with "# ". */
59
+};
60
+
61
+/*
62
+** Create a TEMP table named SFILE and add all unmanaged files named on
63
+** the command-line to that table. If directories are named, then add
64
+** all unmanaged files contained underneath those directories. If there
65
+** are no files or directories named on the command-line, then add all
66
+** unmanaged files anywhere in the checkout.
67
+*/
68
+static void locate_unmanaged_files(
69
+ int argc, /* Number of command-line arguments to examine */
70
+ char **argv, /* values of command-line arguments */
71
+ unsigned scanFlags, /* Zero or more SCAN_xxx flags */
72
+ Glob *pIgnore /* Do not add files that match this GLOB */
73
+){
74
+ Blob name; /* Name of a candidate file or directory */
75
+ char *zName; /* Name of a candidate file or directory */
76
+ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
77
+ int i; /* Loop counter */
78
+ int nRoot; /* length of g.zLocalRoot */
79
+
80
+ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s,"
81
+ " mtime INTEGER, size INTEGER)", filename_collation());
82
+ nRoot = (int)strlen(g.zLocalRoot);
83
+ if( argc==0 ){
84
+ blob_init(&name, g.zLocalRoot, nRoot - 1);
85
+ vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0);
86
+ blob_reset(&name);
87
+ }else{
88
+ for(i=0; i<argc; i++){
89
+ file_canonical_name(argv[i], &name, 0);
90
+ zName = blob_str(&name);
91
+ isDir = file_wd_isdir(zName);
92
+ if( isDir==1 ){
93
+ vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0);
94
+ }else if( isDir==0 ){
95
+ fossil_warning("not found: %s", &zName[nRoot]);
96
+ }else if( file_access(zName, R_OK) ){
97
+ fossil_fatal("cannot open %s", &zName[nRoot]);
98
+ }else{
99
+ db_multi_exec(
100
+ "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)",
101
+ &zName[nRoot]
102
+ );
103
+ }
104
+ blob_reset(&name);
105
+ }
106
+ }
107
+}
108
+
109
+/*
110
+** Generate text describing all changes.
28111
**
29112
** We assume that vfile_check_signature has been run.
30
-**
31
-** If missingIsFatal is true, then any files that are missing or which
32
-** are not true files results in a fatal error.
33113
*/
34114
static void status_report(
35115
Blob *report, /* Append the status report here */
36
- const char *zPrefix, /* Prefix on each line of the report */
37
- int missingIsFatal, /* MISSING and NOT_A_FILE are fatal errors */
38
- int cwdRelative /* Report relative to the current working dir */
116
+ unsigned flags /* Filter and other configuration flags */
39117
){
40118
Stmt q;
41
- int nPrefix = strlen(zPrefix);
42119
int nErr = 0;
43120
Blob rewrittenPathname;
44
- Blob where;
121
+ Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER;
45122
const char *zName;
46123
int i;
47124
125
+ /* Skip the file report if no files are requested at all. */
126
+ if( !(flags & (C_ALL | C_EXTRA)) ){
127
+ goto skipFiles;
128
+ }
129
+
130
+ /* Assemble the path-limiting WHERE clause, if any. */
48131
blob_zero(&where);
49132
for(i=2; i<g.argc; i++){
50133
Blob fname;
51134
file_tree_name(g.argv[i], &fname, 0, 1);
52135
zName = blob_str(&fname);
@@ -61,99 +144,187 @@
61144
filename_collation(), zName, filename_collation(),
62145
zName, filename_collation()
63146
);
64147
}
65148
66
- db_prepare(&q,
67
- "SELECT pathname, deleted, chnged,"
68
- " rid, coalesce(origname!=pathname,0), islink"
69
- " FROM vfile "
70
- " WHERE is_selected(id) %s"
71
- " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
72
- " ORDER BY 1 /*scan*/",
73
- blob_sql_text(&where)
74
- );
75
- blob_zero(&rewrittenPathname);
76
- while( db_step(&q)==SQLITE_ROW ){
77
- const char *zPathname = db_column_text(&q,0);
78
- const char *zDisplayName = zPathname;
79
- int isDeleted = db_column_int(&q, 1);
80
- int isChnged = db_column_int(&q,2);
81
- int isNew = db_column_int(&q,3)==0;
82
- int isRenamed = db_column_int(&q,4);
83
- int isLink = db_column_int(&q,5);
84
- char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
85
- if( cwdRelative ){
86
- file_relative_name(zFullName, &rewrittenPathname, 0);
87
- zDisplayName = blob_str(&rewrittenPathname);
88
- if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
89
- zDisplayName += 2; /* no unnecessary ./ prefix */
90
- }
91
- }
92
- blob_append(report, zPrefix, nPrefix);
93
- if( isDeleted ){
94
- blob_appendf(report, "DELETED %s\n", zDisplayName);
95
- }else if( !file_wd_isfile_or_link(zFullName) ){
96
- if( file_access(zFullName, F_OK)==0 ){
97
- blob_appendf(report, "NOT_A_FILE %s\n", zDisplayName);
98
- if( missingIsFatal ){
99
- fossil_warning("not a file: %s", zDisplayName);
100
- nErr++;
101
- }
102
- }else{
103
- blob_appendf(report, "MISSING %s\n", zDisplayName);
104
- if( missingIsFatal ){
105
- fossil_warning("missing file: %s", zDisplayName);
106
- nErr++;
107
- }
108
- }
109
- }else if( isNew ){
110
- blob_appendf(report, "ADDED %s\n", zDisplayName);
111
- }else if( isChnged ){
112
- if( isChnged==2 ){
113
- blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
114
- }else if( isChnged==3 ){
115
- blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
116
- }else if( isChnged==4 ){
117
- blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
118
- }else if( isChnged==5 ){
119
- blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
120
- }else if( isChnged==6 ){
121
- blob_appendf(report, "EXECUTABLE %s\n", zDisplayName);
122
- }else if( isChnged==7 ){
123
- blob_appendf(report, "SYMLINK %s\n", zDisplayName);
124
- }else if( isChnged==8 ){
125
- blob_appendf(report, "UNEXEC %s\n", zDisplayName);
126
- }else if( isChnged==9 ){
127
- blob_appendf(report, "UNLINK %s\n", zDisplayName);
128
- }else if( !isLink && file_contains_merge_marker(zFullName) ){
129
- blob_appendf(report, "CONFLICT %s\n", zDisplayName);
130
- }else{
131
- blob_appendf(report, "EDITED %s\n", zDisplayName);
132
- }
133
- }else if( isRenamed ){
134
- blob_appendf(report, "RENAMED %s\n", zDisplayName);
135
- }else{
136
- report->nUsed -= nPrefix;
149
+ /* Obtain the list of managed files if appropriate. */
150
+ blob_zero(&sql);
151
+ if( flags & C_ALL ){
152
+ /* Start with a list of all managed files. */
153
+ blob_append_sql(&sql,
154
+ "SELECT pathname, %s as mtime, %s as size, deleted, chnged, rid,"
155
+ " coalesce(origname!=pathname,0) AS renamed, islink, 1 AS managed"
156
+ " FROM vfile LEFT JOIN blob USING (rid)"
157
+ " WHERE is_selected(id)%s",
158
+ flags & C_MTIME ? "datetime(checkin_mtime(:vid, rid), "
159
+ "'unixepoch', toLocal())" : "''" /*safe-for-%s*/,
160
+ flags & C_SIZE ? "coalesce(blob.size, 0)" : "0" /*safe-for-%s*/,
161
+ blob_sql_text(&where));
162
+
163
+ /* Exclude unchanged files unless requested. */
164
+ if( !(flags & C_UNCHANGED) ){
165
+ blob_append_sql(&sql,
166
+ " AND (chnged OR deleted OR rid=0 OR pathname!=origname)");
167
+ }
168
+ }
169
+
170
+ /* If C_EXTRA, add unmanaged files to the query result too. */
171
+ if( flags & C_EXTRA ){
172
+ if( blob_size(&sql) ){
173
+ blob_append_sql(&sql, " UNION ALL");
174
+ }
175
+ blob_append_sql(&sql,
176
+ " SELECT pathname, %s, %s, 0, 0, 0, 0, 0, 0"
177
+ " FROM sfile WHERE pathname NOT IN (%s)%s",
178
+ flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''",
179
+ flags & C_SIZE ? "size" : "0",
180
+ fossil_all_reserved_names(0), blob_sql_text(&where));
181
+ }
182
+ blob_reset(&where);
183
+
184
+ /* Pre-create the "ok" temporary table so the checkin_mtime() SQL function
185
+ * does not lead to SQLITE_ABORT_ROLLBACK during execution of the OP_OpenRead
186
+ * SQLite opcode. checkin_mtime() calls mtime_of_manifest_file() which
187
+ * creates a temporary table if it doesn't already exist, thus invalidating
188
+ * the prepared statement in the middle of its execution. */
189
+ db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)");
190
+
191
+ /* Append an ORDER BY clause then compile the query. */
192
+ blob_append_sql(&sql, " ORDER BY pathname");
193
+ db_prepare(&q, "%s", blob_sql_text(&sql));
194
+ blob_reset(&sql);
195
+
196
+ /* Bind the checkout version ID to the query if needed. */
197
+ if( (flags & C_ALL) && (flags & C_MTIME) ){
198
+ db_bind_int(&q, ":vid", db_lget_int("checkout", 0));
199
+ }
200
+
201
+ /* Execute the query and assemble the report. */
202
+ blob_zero(&rewrittenPathname);
203
+ while( db_step(&q)==SQLITE_ROW ){
204
+ const char *zPathname = db_column_text(&q, 0);
205
+ const char *zClass = 0;
206
+ int isManaged = db_column_int(&q, 8);
207
+ const char *zMtime = db_column_text(&q, 1);
208
+ int size = db_column_int(&q, 2);
209
+ int isDeleted = db_column_int(&q, 3);
210
+ int isChnged = db_column_int(&q, 4);
211
+ int isNew = isManaged && !db_column_int(&q, 5);
212
+ int isRenamed = db_column_int(&q, 6);
213
+ int isLink = db_column_int(&q, 7);
214
+ char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
215
+ int isMissing = !file_wd_isfile_or_link(zFullName);
216
+
217
+ /* Determine the file change classification, if any. */
218
+ if( (flags & C_DELETED) && isDeleted ){
219
+ zClass = "DELETED";
220
+ }else if( (flags & C_MISSING) && isMissing ){
221
+ if( file_access(zFullName, F_OK)==0 ){
222
+ zClass = "NOT_A_FILE";
223
+ if( flags & C_FATAL ){
224
+ fossil_warning("not a file: %s", zFullName);
225
+ nErr++;
226
+ }
227
+ }else{
228
+ zClass = "MISSING";
229
+ if( flags & C_FATAL ){
230
+ fossil_warning("missing file: %s", zFullName);
231
+ nErr++;
232
+ }
233
+ }
234
+ }else if( (flags & C_ADDED) && isNew ){
235
+ zClass = "ADDED";
236
+ }else if( (flags & (C_UPDATED | C_CHANGED)) && isChnged==2 ){
237
+ zClass = "UPDATED_BY_MERGE";
238
+ }else if( (flags & C_ADDED) && isChnged==3 ){
239
+ zClass = "ADDED_BY_MERGE";
240
+ }else if( (flags & (C_UPDATED | C_CHANGED)) && isChnged==4 ){
241
+ zClass = "UPDATED_BY_INTEGRATE";
242
+ }else if( (flags & C_ADDED) && isChnged==5 ){
243
+ zClass = "ADDED_BY_INTEGRATE";
244
+ }else if( (flags & C_META) && isChnged==6 ){
245
+ zClass = "EXECUTABLE";
246
+ }else if( (flags & C_META) && isChnged==7 ){
247
+ zClass = "SYMLINK";
248
+ }else if( (flags & C_META) && isChnged==8 ){
249
+ zClass = "UNEXEC";
250
+ }else if( (flags & C_META) && isChnged==9 ){
251
+ zClass = "UNLINK";
252
+ }else if( (flags & C_CONFLICT) && isChnged && !isLink
253
+ && file_contains_merge_marker(zFullName) ){
254
+ zClass = "CONFLICT";
255
+ }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
256
+ && (isChnged<2 || isChnged>9) ){
257
+ zClass = "EDITED";
258
+ }else if( (flags & C_RENAMED) && isRenamed ){
259
+ zClass = "RENAMED";
260
+ }else if( (flags & C_UNCHANGED) && isManaged && !isDeleted && !isMissing
261
+ && !isNew && !isChnged && !isRenamed ){
262
+ zClass = "UNCHANGED";
263
+ }else if( (flags & C_EXTRA) && !isManaged ){
264
+ zClass = "EXTRA";
265
+ }
266
+
267
+ /* Only report files for which a change classification was determined. */
268
+ if( zClass ){
269
+ if( flags & C_COMMENT ){
270
+ blob_append(report, "# ", 2);
271
+ }
272
+ if( flags & C_CLASSIFY ){
273
+ blob_appendf(report, "%-10s ", zClass);
274
+ }
275
+ if( flags & C_MTIME ){
276
+ blob_append(report, zMtime, -1);
277
+ blob_append(report, " ", 2);
278
+ }
279
+ if( flags & C_SIZE ){
280
+ blob_appendf(report, "%7d ", size);
281
+ }
282
+ if( flags & C_RELPATH ){
283
+ /* If C_RELPATH, display paths relative to current directory. */
284
+ const char *zDisplayName;
285
+ file_relative_name(zFullName, &rewrittenPathname, 0);
286
+ zDisplayName = blob_str(&rewrittenPathname);
287
+ if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
288
+ zDisplayName += 2; /* no unnecessary ./ prefix */
289
+ }
290
+ blob_append(report, zDisplayName, -1);
291
+ }else{
292
+ /* If not C_RELPATH, display paths relative to project root. */
293
+ blob_append(report, zPathname, -1);
294
+ }
295
+ blob_append(report, "\n", 1);
137296
}
138297
free(zFullName);
139298
}
140299
blob_reset(&rewrittenPathname);
141300
db_finalize(&q);
142
- db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
143
- " WHERE id<=0");
144
- while( db_step(&q)==SQLITE_ROW ){
145
- const char *zLabel = "MERGED_WITH ";
146
- switch( db_column_int(&q, 1) ){
147
- case -1: zLabel = "CHERRYPICK "; break;
148
- case -2: zLabel = "BACKOUT "; break;
149
- case -4: zLabel = "INTEGRATE "; break;
150
- }
151
- blob_append(report, zPrefix, nPrefix);
152
- blob_appendf(report, "%s%s\n", zLabel, db_column_text(&q, 0));
153
- }
154
- db_finalize(&q);
301
+
302
+ /* If C_MERGE, put merge contributors at the end of the report. */
303
+skipFiles:
304
+ if( flags & C_MERGE ){
305
+ db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
306
+ " WHERE id<=0");
307
+ while( db_step(&q)==SQLITE_ROW ){
308
+ if( flags & C_COMMENT ){
309
+ blob_append(report, "# ", 2);
310
+ }
311
+ if( flags & C_CLASSIFY ){
312
+ const char *zClass;
313
+ switch( db_column_int(&q, 1) ){
314
+ case -1: zClass = "CHERRYPICK" ; break;
315
+ case -2: zClass = "BACKOUT" ; break;
316
+ case -4: zClass = "INTEGRATE" ; break;
317
+ default: zClass = "MERGED_WITH"; break;
318
+ }
319
+ blob_appendf(report, "%-10s ", zClass);
320
+ }
321
+ blob_append(report, db_column_text(&q, 0), -1);
322
+ blob_append(report, "\n", 1);
323
+ }
324
+ db_finalize(&q);
325
+ }
155326
if( nErr ){
156327
fossil_fatal("aborting due to prior errors");
157328
}
158329
}
159330
@@ -171,115 +342,228 @@
171342
if( absPathOption ){ relativePaths = 0; }
172343
if( relPathOption ){ relativePaths = 1; }
173344
return relativePaths;
174345
}
175346
176
-void print_changes(
177
- int useSha1sum, /* Verify file status using SHA1 hashing rather
178
- than relying on file mtimes. */
179
- int showHdr, /* Identify the repository if there are changes */
180
- int verboseFlag, /* Say "(none)" if there are no changes */
181
- int cwdRelative /* Report relative to the current working dir */
182
-){
183
- Blob report;
184
- int vid;
185
- blob_zero(&report);
186
-
187
- vid = db_lget_int("checkout", 0);
188
- vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
189
- status_report(&report, "", 0, cwdRelative);
190
- if( verboseFlag && blob_size(&report)==0 ){
191
- blob_append(&report, " (none)\n", -1);
192
- }
193
- if( showHdr && blob_size(&report)>0 ){
194
- fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
195
- g.zLocalRoot);
196
- }
197
- blob_write_to_file(&report, "-");
198
- blob_reset(&report);
199
-}
200
-
201
-/*
202
-** COMMAND: changes
203
-**
204
-** Usage: %fossil changes ?OPTIONS?
205
-**
206
-** Report on the edit status of all files in the current checkout.
207
-**
208
-** Pathnames are displayed according to the "relative-paths" setting,
209
-** unless overridden by the --abs-paths or --rel-paths options.
210
-**
211
-** Options:
212
-** --abs-paths Display absolute pathnames.
213
-** --rel-paths Display pathnames relative to the current working
214
-** directory.
215
-** --sha1sum Verify file status using SHA1 hashing rather
216
-** than relying on file mtimes.
217
-** --header Identify the repository if there are changes
218
-** -v|--verbose Say "(none)" if there are no changes
219
-**
220
-** See also: extras, ls, status
221
-*/
222
-void changes_cmd(void){
223
- int useSha1sum = find_option("sha1sum", 0, 0)!=0;
224
- int showHdr = find_option("header",0,0)!=0;
225
- int verboseFlag = find_option("verbose","v",0)!=0;
226
- int cwdRelative = 0;
227
- db_must_be_within_tree();
228
- cwdRelative = determine_cwd_relative_option();
229
-
230
- /* We should be done with options.. */
231
- verify_all_options();
232
-
233
- print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
234
-}
235
-
236
-/*
237
-** COMMAND: status
238
-**
239
-** Usage: %fossil status ?OPTIONS?
240
-**
241
-** Report on the status of the current checkout.
242
-**
243
-** Pathnames are displayed according to the "relative-paths" setting,
244
-** unless overridden by the --abs-paths or --rel-paths options.
245
-**
246
-** Options:
247
-**
248
-** --abs-paths Display absolute pathnames.
249
-** --rel-paths Display pathnames relative to the current working
250
-** directory.
251
-** --sha1sum Verify file status using SHA1 hashing rather
252
-** than relying on file mtimes.
253
-**
254
-** See also: changes, extras, ls
255
-*/
256
-void status_cmd(void){
257
- int vid;
258
- int useSha1sum = find_option("sha1sum", 0, 0)!=0;
259
- int showHdr = find_option("header",0,0)!=0;
260
- int verboseFlag = find_option("verbose","v",0)!=0;
261
- int cwdRelative = 0;
262
- db_must_be_within_tree();
263
- /* 012345678901234 */
264
- cwdRelative = determine_cwd_relative_option();
265
-
266
- /* We should be done with options.. */
267
- verify_all_options();
268
-
269
- fossil_print("repository: %s\n", db_repository_filename());
270
- fossil_print("local-root: %s\n", g.zLocalRoot);
271
- if( g.zConfigDbName ){
272
- fossil_print("config-db: %s\n", g.zConfigDbName);
273
- }
274
- vid = db_lget_int("checkout", 0);
275
- if( vid ){
276
- show_common_info(vid, "checkout:", 1, 1);
277
- }
278
- db_record_repository_filename(0);
279
- print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
280
- leaf_ambiguity_warning(vid, vid);
347
+/*
348
+** COMMAND: changes
349
+** COMMAND: status
350
+**
351
+** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
352
+**
353
+** Report the change status of files in the current checkout. If one or
354
+** more PATHS are specified, only changes among the named files and
355
+** directories are reported. Directories are searched recursively.
356
+**
357
+** The status command is similar to the changes command, except it lacks
358
+** several of the options supported by changes and it has its own header
359
+** and footer information. The header information is a subset of that
360
+** shown by the info command, and the footer shows if there are any forks.
361
+** Change type classification is always enabled for the status command.
362
+**
363
+** Each line of output is the name of a changed file, with paths shown
364
+** according to the "relative-paths" setting, unless overridden by the
365
+** --abs-paths or --rel-paths options.
366
+**
367
+** By default, all changed files are selected for display. This behavior
368
+** can be overridden by using one or more filter options (listed below),
369
+** in which case only files with the specified change type(s) are shown.
370
+** As a special case, the --no-merge option does not inhibit this default.
371
+** This default shows exactly the set of changes that would be checked
372
+** in by the commit command.
373
+**
374
+** If no filter options are used, or if the --merge option is used, the
375
+** SHA1 hash of each merge contributor check-in version is displayed at
376
+** the end of the report. The --no-merge option is useful to display the
377
+** default set of changed files without the merge contributors.
378
+**
379
+** If change type classification is enabled, each output line starts with
380
+** a code describing the file's change type, e.g. EDITED or RENAMED. It
381
+** is enabled by default unless exactly one change type is selected. For
382
+** the purposes of determining the default, --changed counts as selecting
383
+** one change type. The default can be overridden by the --classify or
384
+** --no-classify options.
385
+**
386
+** If both --merge and --no-merge are used, --no-merge has priority. The
387
+** same is true of --classify and --no-classify.
388
+**
389
+** The "fossil changes --extra" command is equivalent to "fossil extras".
390
+**
391
+** --edited and --updated produce disjoint sets. --updated shows a file
392
+** only when it is identical to that of its merge contributor, and the
393
+** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE.
394
+** If the file had to be merged with any other changes, it is considered
395
+** to be merged or conflicted and therefore will be shown by --edited, not
396
+** --updated, with types EDITED or CONFLICT. The --changed option can be
397
+** used to display the union of --edited and --updated.
398
+**
399
+** --differ is so named because it lists all the differences between the
400
+** checked-out version and the checkout directory. In addition to the
401
+** default changes (besides --merge), it lists extra files which (assuming
402
+** ignore-glob is set correctly) may be worth adding. Prior to doing a
403
+** commit, it is good practice to check --differ to see not only which
404
+** changes would be committed but also if any files need to be added.
405
+**
406
+** General options:
407
+** --abs-paths Display absolute pathnames.
408
+** --rel-paths Display pathnames relative to the current working
409
+** directory.
410
+** --sha1sum Verify file status using SHA1 hashing rather than
411
+** relying on file mtimes.
412
+** --case-sensitive <BOOL> Override case-sensitive setting.
413
+** --dotfiles Include unmanaged files beginning with a dot.
414
+** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
415
+**
416
+** Options specific to the changes command:
417
+** --header Identify the repository if report is non-empty.
418
+** -v|--verbose Say "(none)" if the change report is empty.
419
+** --classify Start each line with the file's change type.
420
+** --no-classify Do not print file change types.
421
+**
422
+** Filter options:
423
+** --edited Display edited, merged, and conflicted files.
424
+** --updated Display files updated by merge/integrate.
425
+** --changed Combination of the above two options.
426
+** --missing Display missing files.
427
+** --added Display added files.
428
+** --deleted Display deleted files.
429
+** --renamed Display renamed files.
430
+** --conflict Display files having merge conflicts.
431
+** --meta Display files with metadata changes.
432
+** --unchanged Display unchanged files.
433
+** --all Display all managed files, i.e. all of the above.
434
+** --extra Display unmanaged files.
435
+** --differ Display modified and extra files.
436
+** --merge Display merge contributors.
437
+** --no-merge Do not display merge contributors.
438
+**
439
+** See also: extras, ls
440
+*/
441
+void status_cmd(void){
442
+ /* Affirmative and negative flag option tables. */
443
+ static const struct {
444
+ const char *option; /* Flag name. */
445
+ unsigned mask; /* Flag bits. */
446
+ } flagDefs[] = {
447
+ {"edited" , C_EDITED }, {"updated" , C_UPDATED },
448
+ {"changed" , C_CHANGED }, {"missing" , C_MISSING },
449
+ {"added" , C_ADDED }, {"deleted" , C_DELETED },
450
+ {"renamed" , C_RENAMED }, {"conflict" , C_CONFLICT },
451
+ {"meta" , C_META }, {"unchanged" , C_UNCHANGED},
452
+ {"all" , C_ALL }, {"extra" , C_EXTRA },
453
+ {"differ" , C_DIFFER }, {"merge" , C_MERGE },
454
+ {"classify", C_CLASSIFY},
455
+ }, noFlagDefs[] = {
456
+ {"no-merge", C_MERGE }, {"no-classify", C_CLASSIFY },
457
+ };
458
+
459
+ Blob report = BLOB_INITIALIZER;
460
+ enum {CHANGES, STATUS} command = *g.argv[1]=='s' ? STATUS : CHANGES;
461
+ int useSha1sum = find_option("sha1sum", 0, 0)!=0;
462
+ int showHdr = command==CHANGES && find_option("header", 0, 0);
463
+ int verboseFlag = command==CHANGES && find_option("verbose", "v", 0);
464
+ const char *zIgnoreFlag = find_option("ignore", 0, 1);
465
+ unsigned scanFlags = 0;
466
+ unsigned flags = 0;
467
+ int vid, i;
468
+
469
+ /* Load affirmative flag options. */
470
+ for( i=0; i<count(flagDefs); ++i ){
471
+ if( (command==CHANGES || !(flagDefs[i].mask & C_CLASSIFY))
472
+ && find_option(flagDefs[i].option, 0, 0) ){
473
+ flags |= flagDefs[i].mask;
474
+ }
475
+ }
476
+
477
+ /* If no filter options are specified, enable defaults. */
478
+ if( !(flags & C_FILTER) ){
479
+ flags |= C_DEFAULT;
480
+ }
481
+
482
+ /* If more than one filter is enabled, enable classification. This is tricky.
483
+ * Having one filter means flags masked by C_FILTER is a power of two. If a
484
+ * number masked by one less than itself is zero, it's either zero or a power
485
+ * of two. It's already known to not be zero because of the above defaults.
486
+ * Unlike --all, --changed is a single filter, i.e. it sets only one bit.
487
+ * Also force classification for the status command. */
488
+ if( command==STATUS || (flags & (flags-1) & C_FILTER) ){
489
+ flags |= C_CLASSIFY;
490
+ }
491
+
492
+ /* Negative flag options override defaults applied above. */
493
+ for( i=0; i<count(noFlagDefs); ++i ){
494
+ if( (command==CHANGES || !(noFlagDefs[i].mask & C_CLASSIFY))
495
+ && find_option(noFlagDefs[i].option, 0, 0) ){
496
+ flags &= ~noFlagDefs[i].mask;
497
+ }
498
+ }
499
+
500
+ /* Confirm current working directory is within checkout. */
501
+ db_must_be_within_tree();
502
+
503
+ /* Get checkout version. l*/
504
+ vid = db_lget_int("checkout", 0);
505
+
506
+ /* Relative path flag determination is done by a shared function. */
507
+ if( determine_cwd_relative_option() ){
508
+ flags |= C_RELPATH;
509
+ }
510
+
511
+ /* If --ignore is not specified, use the ignore-glob setting. */
512
+ if( !zIgnoreFlag ){
513
+ zIgnoreFlag = db_get("ignore-glob", 0);
514
+ }
515
+
516
+ /* Get the --dotfiles argument, or read it from the dotfiles setting. */
517
+ if( find_option("dotfiles", 0, 0) || db_get_boolean("dotfiles", 0) ){
518
+ scanFlags = SCAN_ALL;
519
+ }
520
+
521
+ /* We should be done with options. */
522
+ verify_all_options();
523
+
524
+ /* Check for changed files. */
525
+ vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
526
+
527
+ /* Search for unmanaged files if requested. */
528
+ if( flags & C_EXTRA ){
529
+ Glob *pIgnore = glob_create(zIgnoreFlag);
530
+ locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
531
+ glob_free(pIgnore);
532
+ }
533
+
534
+ /* The status command prints general information before the change list. */
535
+ if( command==STATUS ){
536
+ fossil_print("repository: %s\n", db_repository_filename());
537
+ fossil_print("local-root: %s\n", g.zLocalRoot);
538
+ if( g.zConfigDbName ){
539
+ fossil_print("config-db: %s\n", g.zConfigDbName);
540
+ }
541
+ if( vid ){
542
+ show_common_info(vid, "checkout:", 1, 1);
543
+ }
544
+ db_record_repository_filename(0);
545
+ }
546
+
547
+ /* Find and print all requested changes. */
548
+ blob_zero(&report);
549
+ status_report(&report, flags);
550
+ if( blob_size(&report) ){
551
+ if( showHdr ){
552
+ fossil_print("Changes for %s at %s:\n", db_get("project-name", "???"),
553
+ g.zLocalRoot);
554
+ }
555
+ blob_write_to_file(&report, "-");
556
+ }else if( verboseFlag ){
557
+ fossil_print(" (none)\n");
558
+ }
559
+ blob_reset(&report);
560
+
561
+ /* The status command ends with warnings about ambiguous leaves (forks). */
562
+ if( command==STATUS ){
563
+ leaf_ambiguity_warning(vid, vid);
564
+ }
281565
}
282566
283567
/*
284568
** Take care of -r version of ls command
285569
*/
@@ -508,59 +792,10 @@
508792
free(zFullName);
509793
}
510794
db_finalize(&q);
511795
}
512796
513
-/*
514
-** Create a TEMP table named SFILE and add all unmanaged files named on
515
-** the command-line to that table. If directories are named, then add
516
-** all unmanaged files contained underneath those directories. If there
517
-** are no files or directories named on the command-line, then add all
518
-** unmanaged files anywhere in the checkout.
519
-*/
520
-static void locate_unmanaged_files(
521
- int argc, /* Number of command-line arguments to examine */
522
- char **argv, /* values of command-line arguments */
523
- unsigned scanFlags, /* Zero or more SCAN_xxx flags */
524
- Glob *pIgnore1, /* Do not add files that match this GLOB */
525
- Glob *pIgnore2 /* Omit files matching this GLOB too */
526
-){
527
- Blob name; /* Name of a candidate file or directory */
528
- char *zName; /* Name of a candidate file or directory */
529
- int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
530
- int i; /* Loop counter */
531
- int nRoot; /* length of g.zLocalRoot */
532
-
533
- db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
534
- filename_collation());
535
- nRoot = (int)strlen(g.zLocalRoot);
536
- if( argc==0 ){
537
- blob_init(&name, g.zLocalRoot, nRoot - 1);
538
- vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
539
- blob_reset(&name);
540
- }else{
541
- for(i=0; i<argc; i++){
542
- file_canonical_name(argv[i], &name, 0);
543
- zName = blob_str(&name);
544
- isDir = file_wd_isdir(zName);
545
- if( isDir==1 ){
546
- vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
547
- }else if( isDir==0 ){
548
- fossil_warning("not found: %s", &zName[nRoot]);
549
- }else if( file_access(zName, R_OK) ){
550
- fossil_fatal("cannot open %s", &zName[nRoot]);
551
- }else{
552
- db_multi_exec(
553
- "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
554
- &zName[nRoot]
555
- );
556
- }
557
- blob_reset(&name);
558
- }
559
- }
560
-}
561
-
562797
/*
563798
** COMMAND: extras
564799
**
565800
** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
566801
**
@@ -588,22 +823,23 @@
588823
** directory.
589824
**
590825
** See also: changes, clean, status
591826
*/
592827
void extras_cmd(void){
593
- Stmt q;
828
+ Blob report = BLOB_INITIALIZER;
594829
const char *zIgnoreFlag = find_option("ignore",0,1);
595830
unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
831
+ unsigned flags = C_EXTRA;
596832
int showHdr = find_option("header",0,0)!=0;
597
- int cwdRelative = 0;
598833
Glob *pIgnore;
599
- Blob rewrittenPathname;
600
- const char *zPathname, *zDisplayName;
601834
602835
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
603836
db_must_be_within_tree();
604
- cwdRelative = determine_cwd_relative_option();
837
+
838
+ if( determine_cwd_relative_option() ){
839
+ flags |= C_RELPATH;
840
+ }
605841
606842
if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
607843
608844
/* We should be done with options.. */
609845
verify_all_options();
@@ -610,41 +846,24 @@
610846
611847
if( zIgnoreFlag==0 ){
612848
zIgnoreFlag = db_get("ignore-glob", 0);
613849
}
614850
pIgnore = glob_create(zIgnoreFlag);
615
- locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
851
+ locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
616852
glob_free(pIgnore);
617
- db_prepare(&q,
618
- "SELECT x FROM sfile"
619
- " WHERE x NOT IN (%s)"
620
- " ORDER BY 1",
621
- fossil_all_reserved_names(0)
622
- );
623
- db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
624
- blob_zero(&rewrittenPathname);
625853
g.allowSymlinks = 1; /* Report on symbolic links */
626
- while( db_step(&q)==SQLITE_ROW ){
627
- zDisplayName = zPathname = db_column_text(&q, 0);
628
- if( cwdRelative ){
629
- char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
630
- file_relative_name(zFullName, &rewrittenPathname, 0);
631
- free(zFullName);
632
- zDisplayName = blob_str(&rewrittenPathname);
633
- if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
634
- zDisplayName += 2; /* no unnecessary ./ prefix */
635
- }
636
- }
854
+
855
+ blob_zero(&report);
856
+ status_report(&report, flags);
857
+ if( blob_size(&report) ){
637858
if( showHdr ){
638
- showHdr = 0;
639859
fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
640860
g.zLocalRoot);
641861
}
642
- fossil_print("%s\n", zDisplayName);
862
+ blob_write_to_file(&report, "-");
643863
}
644
- blob_reset(&rewrittenPathname);
645
- db_finalize(&q);
864
+ blob_reset(&report);
646865
}
647866
648867
/*
649868
** COMMAND: clean
650869
**
@@ -790,21 +1009,22 @@
7901009
g.allowSymlinks = 1; /* Find symlinks too */
7911010
if( !dirsOnlyFlag ){
7921011
Stmt q;
7931012
Blob repo;
7941013
if( !dryRunFlag && !disableUndo ) undo_begin();
795
- locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
1014
+ locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
7961015
db_prepare(&q,
797
- "SELECT %Q || x FROM sfile"
798
- " WHERE x NOT IN (%s)"
1016
+ "SELECT %Q || pathname FROM sfile"
1017
+ " WHERE pathname NOT IN (%s)"
7991018
" ORDER BY 1",
8001019
g.zLocalRoot, fossil_all_reserved_names(0)
8011020
);
8021021
if( file_tree_name(g.zRepositoryName, &repo, 0, 0) ){
803
- db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
1022
+ db_multi_exec("DELETE FROM sfile WHERE pathname=%B", &repo);
8041023
}
805
- db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
1024
+ db_multi_exec("DELETE FROM sfile WHERE pathname IN"
1025
+ " (SELECT pathname FROM vfile)");
8061026
while( db_step(&q)==SQLITE_ROW ){
8071027
const char *zName = db_column_text(&q, 0);
8081028
if( glob_match(pKeep, zName+nRoot) ){
8091029
if( verboseFlag ){
8101030
fossil_print("KEPT file \"%s\" not removed (due to --keep"
@@ -1081,11 +1301,11 @@
10811301
}
10821302
}
10831303
blob_appendf(&prompt, "\n#\n");
10841304
}
10851305
}
1086
- status_report(&prompt, "# ", 1, 0);
1306
+ status_report(&prompt, C_DEFAULT | C_FATAL | C_COMMENT);
10871307
if( g.markPrivate ){
10881308
blob_append(&prompt,
10891309
"# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
10901310
"# repositories.\n"
10911311
"#\n", -1
10921312
--- src/checkin.c
+++ src/checkin.c
@@ -21,32 +21,115 @@
21 #include "config.h"
22 #include "checkin.h"
23 #include <assert.h>
24
25 /*
26 ** Generate text describing all changes. Prepend zPrefix to each line
27 ** of output.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28 **
29 ** We assume that vfile_check_signature has been run.
30 **
31 ** If missingIsFatal is true, then any files that are missing or which
32 ** are not true files results in a fatal error.
33 */
34 static void status_report(
35 Blob *report, /* Append the status report here */
36 const char *zPrefix, /* Prefix on each line of the report */
37 int missingIsFatal, /* MISSING and NOT_A_FILE are fatal errors */
38 int cwdRelative /* Report relative to the current working dir */
39 ){
40 Stmt q;
41 int nPrefix = strlen(zPrefix);
42 int nErr = 0;
43 Blob rewrittenPathname;
44 Blob where;
45 const char *zName;
46 int i;
47
 
 
 
 
 
 
48 blob_zero(&where);
49 for(i=2; i<g.argc; i++){
50 Blob fname;
51 file_tree_name(g.argv[i], &fname, 0, 1);
52 zName = blob_str(&fname);
@@ -61,99 +144,187 @@
61 filename_collation(), zName, filename_collation(),
62 zName, filename_collation()
63 );
64 }
65
66 db_prepare(&q,
67 "SELECT pathname, deleted, chnged,"
68 " rid, coalesce(origname!=pathname,0), islink"
69 " FROM vfile "
70 " WHERE is_selected(id) %s"
71 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
72 " ORDER BY 1 /*scan*/",
73 blob_sql_text(&where)
74 );
75 blob_zero(&rewrittenPathname);
76 while( db_step(&q)==SQLITE_ROW ){
77 const char *zPathname = db_column_text(&q,0);
78 const char *zDisplayName = zPathname;
79 int isDeleted = db_column_int(&q, 1);
80 int isChnged = db_column_int(&q,2);
81 int isNew = db_column_int(&q,3)==0;
82 int isRenamed = db_column_int(&q,4);
83 int isLink = db_column_int(&q,5);
84 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
85 if( cwdRelative ){
86 file_relative_name(zFullName, &rewrittenPathname, 0);
87 zDisplayName = blob_str(&rewrittenPathname);
88 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
89 zDisplayName += 2; /* no unnecessary ./ prefix */
90 }
91 }
92 blob_append(report, zPrefix, nPrefix);
93 if( isDeleted ){
94 blob_appendf(report, "DELETED %s\n", zDisplayName);
95 }else if( !file_wd_isfile_or_link(zFullName) ){
96 if( file_access(zFullName, F_OK)==0 ){
97 blob_appendf(report, "NOT_A_FILE %s\n", zDisplayName);
98 if( missingIsFatal ){
99 fossil_warning("not a file: %s", zDisplayName);
100 nErr++;
101 }
102 }else{
103 blob_appendf(report, "MISSING %s\n", zDisplayName);
104 if( missingIsFatal ){
105 fossil_warning("missing file: %s", zDisplayName);
106 nErr++;
107 }
108 }
109 }else if( isNew ){
110 blob_appendf(report, "ADDED %s\n", zDisplayName);
111 }else if( isChnged ){
112 if( isChnged==2 ){
113 blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
114 }else if( isChnged==3 ){
115 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
116 }else if( isChnged==4 ){
117 blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
118 }else if( isChnged==5 ){
119 blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
120 }else if( isChnged==6 ){
121 blob_appendf(report, "EXECUTABLE %s\n", zDisplayName);
122 }else if( isChnged==7 ){
123 blob_appendf(report, "SYMLINK %s\n", zDisplayName);
124 }else if( isChnged==8 ){
125 blob_appendf(report, "UNEXEC %s\n", zDisplayName);
126 }else if( isChnged==9 ){
127 blob_appendf(report, "UNLINK %s\n", zDisplayName);
128 }else if( !isLink && file_contains_merge_marker(zFullName) ){
129 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
130 }else{
131 blob_appendf(report, "EDITED %s\n", zDisplayName);
132 }
133 }else if( isRenamed ){
134 blob_appendf(report, "RENAMED %s\n", zDisplayName);
135 }else{
136 report->nUsed -= nPrefix;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137 }
138 free(zFullName);
139 }
140 blob_reset(&rewrittenPathname);
141 db_finalize(&q);
142 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
143 " WHERE id<=0");
144 while( db_step(&q)==SQLITE_ROW ){
145 const char *zLabel = "MERGED_WITH ";
146 switch( db_column_int(&q, 1) ){
147 case -1: zLabel = "CHERRYPICK "; break;
148 case -2: zLabel = "BACKOUT "; break;
149 case -4: zLabel = "INTEGRATE "; break;
150 }
151 blob_append(report, zPrefix, nPrefix);
152 blob_appendf(report, "%s%s\n", zLabel, db_column_text(&q, 0));
153 }
154 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
155 if( nErr ){
156 fossil_fatal("aborting due to prior errors");
157 }
158 }
159
@@ -171,115 +342,228 @@
171 if( absPathOption ){ relativePaths = 0; }
172 if( relPathOption ){ relativePaths = 1; }
173 return relativePaths;
174 }
175
176 void print_changes(
177 int useSha1sum, /* Verify file status using SHA1 hashing rather
178 than relying on file mtimes. */
179 int showHdr, /* Identify the repository if there are changes */
180 int verboseFlag, /* Say "(none)" if there are no changes */
181 int cwdRelative /* Report relative to the current working dir */
182 ){
183 Blob report;
184 int vid;
185 blob_zero(&report);
186
187 vid = db_lget_int("checkout", 0);
188 vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
189 status_report(&report, "", 0, cwdRelative);
190 if( verboseFlag && blob_size(&report)==0 ){
191 blob_append(&report, " (none)\n", -1);
192 }
193 if( showHdr && blob_size(&report)>0 ){
194 fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
195 g.zLocalRoot);
196 }
197 blob_write_to_file(&report, "-");
198 blob_reset(&report);
199 }
200
201 /*
202 ** COMMAND: changes
203 **
204 ** Usage: %fossil changes ?OPTIONS?
205 **
206 ** Report on the edit status of all files in the current checkout.
207 **
208 ** Pathnames are displayed according to the "relative-paths" setting,
209 ** unless overridden by the --abs-paths or --rel-paths options.
210 **
211 ** Options:
212 ** --abs-paths Display absolute pathnames.
213 ** --rel-paths Display pathnames relative to the current working
214 ** directory.
215 ** --sha1sum Verify file status using SHA1 hashing rather
216 ** than relying on file mtimes.
217 ** --header Identify the repository if there are changes
218 ** -v|--verbose Say "(none)" if there are no changes
219 **
220 ** See also: extras, ls, status
221 */
222 void changes_cmd(void){
223 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
224 int showHdr = find_option("header",0,0)!=0;
225 int verboseFlag = find_option("verbose","v",0)!=0;
226 int cwdRelative = 0;
227 db_must_be_within_tree();
228 cwdRelative = determine_cwd_relative_option();
229
230 /* We should be done with options.. */
231 verify_all_options();
232
233 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
234 }
235
236 /*
237 ** COMMAND: status
238 **
239 ** Usage: %fossil status ?OPTIONS?
240 **
241 ** Report on the status of the current checkout.
242 **
243 ** Pathnames are displayed according to the "relative-paths" setting,
244 ** unless overridden by the --abs-paths or --rel-paths options.
245 **
246 ** Options:
247 **
248 ** --abs-paths Display absolute pathnames.
249 ** --rel-paths Display pathnames relative to the current working
250 ** directory.
251 ** --sha1sum Verify file status using SHA1 hashing rather
252 ** than relying on file mtimes.
253 **
254 ** See also: changes, extras, ls
255 */
256 void status_cmd(void){
257 int vid;
258 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
259 int showHdr = find_option("header",0,0)!=0;
260 int verboseFlag = find_option("verbose","v",0)!=0;
261 int cwdRelative = 0;
262 db_must_be_within_tree();
263 /* 012345678901234 */
264 cwdRelative = determine_cwd_relative_option();
265
266 /* We should be done with options.. */
267 verify_all_options();
268
269 fossil_print("repository: %s\n", db_repository_filename());
270 fossil_print("local-root: %s\n", g.zLocalRoot);
271 if( g.zConfigDbName ){
272 fossil_print("config-db: %s\n", g.zConfigDbName);
273 }
274 vid = db_lget_int("checkout", 0);
275 if( vid ){
276 show_common_info(vid, "checkout:", 1, 1);
277 }
278 db_record_repository_filename(0);
279 print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
280 leaf_ambiguity_warning(vid, vid);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281 }
282
283 /*
284 ** Take care of -r version of ls command
285 */
@@ -508,59 +792,10 @@
508 free(zFullName);
509 }
510 db_finalize(&q);
511 }
512
513 /*
514 ** Create a TEMP table named SFILE and add all unmanaged files named on
515 ** the command-line to that table. If directories are named, then add
516 ** all unmanaged files contained underneath those directories. If there
517 ** are no files or directories named on the command-line, then add all
518 ** unmanaged files anywhere in the checkout.
519 */
520 static void locate_unmanaged_files(
521 int argc, /* Number of command-line arguments to examine */
522 char **argv, /* values of command-line arguments */
523 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
524 Glob *pIgnore1, /* Do not add files that match this GLOB */
525 Glob *pIgnore2 /* Omit files matching this GLOB too */
526 ){
527 Blob name; /* Name of a candidate file or directory */
528 char *zName; /* Name of a candidate file or directory */
529 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
530 int i; /* Loop counter */
531 int nRoot; /* length of g.zLocalRoot */
532
533 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
534 filename_collation());
535 nRoot = (int)strlen(g.zLocalRoot);
536 if( argc==0 ){
537 blob_init(&name, g.zLocalRoot, nRoot - 1);
538 vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
539 blob_reset(&name);
540 }else{
541 for(i=0; i<argc; i++){
542 file_canonical_name(argv[i], &name, 0);
543 zName = blob_str(&name);
544 isDir = file_wd_isdir(zName);
545 if( isDir==1 ){
546 vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
547 }else if( isDir==0 ){
548 fossil_warning("not found: %s", &zName[nRoot]);
549 }else if( file_access(zName, R_OK) ){
550 fossil_fatal("cannot open %s", &zName[nRoot]);
551 }else{
552 db_multi_exec(
553 "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
554 &zName[nRoot]
555 );
556 }
557 blob_reset(&name);
558 }
559 }
560 }
561
562 /*
563 ** COMMAND: extras
564 **
565 ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
566 **
@@ -588,22 +823,23 @@
588 ** directory.
589 **
590 ** See also: changes, clean, status
591 */
592 void extras_cmd(void){
593 Stmt q;
594 const char *zIgnoreFlag = find_option("ignore",0,1);
595 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
 
596 int showHdr = find_option("header",0,0)!=0;
597 int cwdRelative = 0;
598 Glob *pIgnore;
599 Blob rewrittenPathname;
600 const char *zPathname, *zDisplayName;
601
602 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
603 db_must_be_within_tree();
604 cwdRelative = determine_cwd_relative_option();
 
 
 
605
606 if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
607
608 /* We should be done with options.. */
609 verify_all_options();
@@ -610,41 +846,24 @@
610
611 if( zIgnoreFlag==0 ){
612 zIgnoreFlag = db_get("ignore-glob", 0);
613 }
614 pIgnore = glob_create(zIgnoreFlag);
615 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
616 glob_free(pIgnore);
617 db_prepare(&q,
618 "SELECT x FROM sfile"
619 " WHERE x NOT IN (%s)"
620 " ORDER BY 1",
621 fossil_all_reserved_names(0)
622 );
623 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
624 blob_zero(&rewrittenPathname);
625 g.allowSymlinks = 1; /* Report on symbolic links */
626 while( db_step(&q)==SQLITE_ROW ){
627 zDisplayName = zPathname = db_column_text(&q, 0);
628 if( cwdRelative ){
629 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
630 file_relative_name(zFullName, &rewrittenPathname, 0);
631 free(zFullName);
632 zDisplayName = blob_str(&rewrittenPathname);
633 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
634 zDisplayName += 2; /* no unnecessary ./ prefix */
635 }
636 }
637 if( showHdr ){
638 showHdr = 0;
639 fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
640 g.zLocalRoot);
641 }
642 fossil_print("%s\n", zDisplayName);
643 }
644 blob_reset(&rewrittenPathname);
645 db_finalize(&q);
646 }
647
648 /*
649 ** COMMAND: clean
650 **
@@ -790,21 +1009,22 @@
790 g.allowSymlinks = 1; /* Find symlinks too */
791 if( !dirsOnlyFlag ){
792 Stmt q;
793 Blob repo;
794 if( !dryRunFlag && !disableUndo ) undo_begin();
795 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
796 db_prepare(&q,
797 "SELECT %Q || x FROM sfile"
798 " WHERE x NOT IN (%s)"
799 " ORDER BY 1",
800 g.zLocalRoot, fossil_all_reserved_names(0)
801 );
802 if( file_tree_name(g.zRepositoryName, &repo, 0, 0) ){
803 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
804 }
805 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
 
806 while( db_step(&q)==SQLITE_ROW ){
807 const char *zName = db_column_text(&q, 0);
808 if( glob_match(pKeep, zName+nRoot) ){
809 if( verboseFlag ){
810 fossil_print("KEPT file \"%s\" not removed (due to --keep"
@@ -1081,11 +1301,11 @@
1081 }
1082 }
1083 blob_appendf(&prompt, "\n#\n");
1084 }
1085 }
1086 status_report(&prompt, "# ", 1, 0);
1087 if( g.markPrivate ){
1088 blob_append(&prompt,
1089 "# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
1090 "# repositories.\n"
1091 "#\n", -1
1092
--- src/checkin.c
+++ src/checkin.c
@@ -21,32 +21,115 @@
21 #include "config.h"
22 #include "checkin.h"
23 #include <assert.h>
24
25 /*
26 ** Change filter options.
27 */
28 enum {
29 /* Zero-based bit indexes. */
30 CB_EDITED , CB_UPDATED , CB_CHANGED, CB_MISSING , CB_ADDED, CB_DELETED,
31 CB_RENAMED, CB_CONFLICT, CB_META , CB_UNCHANGED, CB_EXTRA, CB_MERGE ,
32 CB_RELPATH, CB_CLASSIFY, CB_MTIME , CB_SIZE , CB_FATAL, CB_COMMENT,
33
34 /* Bitmask values. */
35 C_EDITED = 1 << CB_EDITED, /* Edited, merged, and conflicted files. */
36 C_UPDATED = 1 << CB_UPDATED, /* Files updated by merge/integrate. */
37 C_CHANGED = 1 << CB_CHANGED, /* Treated the same as the above two. */
38 C_MISSING = 1 << CB_MISSING, /* Missing and non- files. */
39 C_ADDED = 1 << CB_ADDED, /* Added files. */
40 C_DELETED = 1 << CB_DELETED, /* Deleted files. */
41 C_RENAMED = 1 << CB_RENAMED, /* Renamed files. */
42 C_CONFLICT = 1 << CB_CONFLICT, /* Files having merge conflicts. */
43 C_META = 1 << CB_META, /* Files with metadata changes. */
44 C_UNCHANGED = 1 << CB_UNCHANGED, /* Unchanged files. */
45 C_EXTRA = 1 << CB_EXTRA, /* Unmanaged files. */
46 C_MERGE = 1 << CB_MERGE, /* Merge contributors. */
47 C_FILTER = C_EDITED | C_UPDATED | C_CHANGED | C_MISSING | C_ADDED
48 | C_DELETED | C_RENAMED | C_CONFLICT | C_META | C_UNCHANGED
49 | C_EXTRA | C_MERGE, /* All filter bits. */
50 C_ALL = C_FILTER & ~(C_EXTRA | C_MERGE),/* All managed files. */
51 C_DIFFER = C_FILTER & ~(C_UNCHANGED | C_MERGE),/* All differences. */
52 C_RELPATH = 1 << CB_RELPATH, /* Show relative paths. */
53 C_CLASSIFY = 1 << CB_CLASSIFY, /* Show file change types. */
54 C_DEFAULT = (C_ALL & ~C_UNCHANGED) | C_MERGE | C_CLASSIFY,
55 C_MTIME = 1 << CB_MTIME, /* Show file modification time. */
56 C_SIZE = 1 << CB_SIZE, /* Show file size in bytes. */
57 C_FATAL = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
58 C_COMMENT = 1 << CB_COMMENT, /* Precede each line with "# ". */
59 };
60
61 /*
62 ** Create a TEMP table named SFILE and add all unmanaged files named on
63 ** the command-line to that table. If directories are named, then add
64 ** all unmanaged files contained underneath those directories. If there
65 ** are no files or directories named on the command-line, then add all
66 ** unmanaged files anywhere in the checkout.
67 */
68 static void locate_unmanaged_files(
69 int argc, /* Number of command-line arguments to examine */
70 char **argv, /* values of command-line arguments */
71 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
72 Glob *pIgnore /* Do not add files that match this GLOB */
73 ){
74 Blob name; /* Name of a candidate file or directory */
75 char *zName; /* Name of a candidate file or directory */
76 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
77 int i; /* Loop counter */
78 int nRoot; /* length of g.zLocalRoot */
79
80 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s,"
81 " mtime INTEGER, size INTEGER)", filename_collation());
82 nRoot = (int)strlen(g.zLocalRoot);
83 if( argc==0 ){
84 blob_init(&name, g.zLocalRoot, nRoot - 1);
85 vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0);
86 blob_reset(&name);
87 }else{
88 for(i=0; i<argc; i++){
89 file_canonical_name(argv[i], &name, 0);
90 zName = blob_str(&name);
91 isDir = file_wd_isdir(zName);
92 if( isDir==1 ){
93 vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0);
94 }else if( isDir==0 ){
95 fossil_warning("not found: %s", &zName[nRoot]);
96 }else if( file_access(zName, R_OK) ){
97 fossil_fatal("cannot open %s", &zName[nRoot]);
98 }else{
99 db_multi_exec(
100 "INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)",
101 &zName[nRoot]
102 );
103 }
104 blob_reset(&name);
105 }
106 }
107 }
108
109 /*
110 ** Generate text describing all changes.
111 **
112 ** We assume that vfile_check_signature has been run.
 
 
 
113 */
114 static void status_report(
115 Blob *report, /* Append the status report here */
116 unsigned flags /* Filter and other configuration flags */
 
 
117 ){
118 Stmt q;
 
119 int nErr = 0;
120 Blob rewrittenPathname;
121 Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER;
122 const char *zName;
123 int i;
124
125 /* Skip the file report if no files are requested at all. */
126 if( !(flags & (C_ALL | C_EXTRA)) ){
127 goto skipFiles;
128 }
129
130 /* Assemble the path-limiting WHERE clause, if any. */
131 blob_zero(&where);
132 for(i=2; i<g.argc; i++){
133 Blob fname;
134 file_tree_name(g.argv[i], &fname, 0, 1);
135 zName = blob_str(&fname);
@@ -61,99 +144,187 @@
144 filename_collation(), zName, filename_collation(),
145 zName, filename_collation()
146 );
147 }
148
149 /* Obtain the list of managed files if appropriate. */
150 blob_zero(&sql);
151 if( flags & C_ALL ){
152 /* Start with a list of all managed files. */
153 blob_append_sql(&sql,
154 "SELECT pathname, %s as mtime, %s as size, deleted, chnged, rid,"
155 " coalesce(origname!=pathname,0) AS renamed, islink, 1 AS managed"
156 " FROM vfile LEFT JOIN blob USING (rid)"
157 " WHERE is_selected(id)%s",
158 flags & C_MTIME ? "datetime(checkin_mtime(:vid, rid), "
159 "'unixepoch', toLocal())" : "''" /*safe-for-%s*/,
160 flags & C_SIZE ? "coalesce(blob.size, 0)" : "0" /*safe-for-%s*/,
161 blob_sql_text(&where));
162
163 /* Exclude unchanged files unless requested. */
164 if( !(flags & C_UNCHANGED) ){
165 blob_append_sql(&sql,
166 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)");
167 }
168 }
169
170 /* If C_EXTRA, add unmanaged files to the query result too. */
171 if( flags & C_EXTRA ){
172 if( blob_size(&sql) ){
173 blob_append_sql(&sql, " UNION ALL");
174 }
175 blob_append_sql(&sql,
176 " SELECT pathname, %s, %s, 0, 0, 0, 0, 0, 0"
177 " FROM sfile WHERE pathname NOT IN (%s)%s",
178 flags & C_MTIME ? "datetime(mtime, 'unixepoch', toLocal())" : "''",
179 flags & C_SIZE ? "size" : "0",
180 fossil_all_reserved_names(0), blob_sql_text(&where));
181 }
182 blob_reset(&where);
183
184 /* Pre-create the "ok" temporary table so the checkin_mtime() SQL function
185 * does not lead to SQLITE_ABORT_ROLLBACK during execution of the OP_OpenRead
186 * SQLite opcode. checkin_mtime() calls mtime_of_manifest_file() which
187 * creates a temporary table if it doesn't already exist, thus invalidating
188 * the prepared statement in the middle of its execution. */
189 db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)");
190
191 /* Append an ORDER BY clause then compile the query. */
192 blob_append_sql(&sql, " ORDER BY pathname");
193 db_prepare(&q, "%s", blob_sql_text(&sql));
194 blob_reset(&sql);
195
196 /* Bind the checkout version ID to the query if needed. */
197 if( (flags & C_ALL) && (flags & C_MTIME) ){
198 db_bind_int(&q, ":vid", db_lget_int("checkout", 0));
199 }
200
201 /* Execute the query and assemble the report. */
202 blob_zero(&rewrittenPathname);
203 while( db_step(&q)==SQLITE_ROW ){
204 const char *zPathname = db_column_text(&q, 0);
205 const char *zClass = 0;
206 int isManaged = db_column_int(&q, 8);
207 const char *zMtime = db_column_text(&q, 1);
208 int size = db_column_int(&q, 2);
209 int isDeleted = db_column_int(&q, 3);
210 int isChnged = db_column_int(&q, 4);
211 int isNew = isManaged && !db_column_int(&q, 5);
212 int isRenamed = db_column_int(&q, 6);
213 int isLink = db_column_int(&q, 7);
214 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
215 int isMissing = !file_wd_isfile_or_link(zFullName);
216
217 /* Determine the file change classification, if any. */
218 if( (flags & C_DELETED) && isDeleted ){
219 zClass = "DELETED";
220 }else if( (flags & C_MISSING) && isMissing ){
221 if( file_access(zFullName, F_OK)==0 ){
222 zClass = "NOT_A_FILE";
223 if( flags & C_FATAL ){
224 fossil_warning("not a file: %s", zFullName);
225 nErr++;
226 }
227 }else{
228 zClass = "MISSING";
229 if( flags & C_FATAL ){
230 fossil_warning("missing file: %s", zFullName);
231 nErr++;
232 }
233 }
234 }else if( (flags & C_ADDED) && isNew ){
235 zClass = "ADDED";
236 }else if( (flags & (C_UPDATED | C_CHANGED)) && isChnged==2 ){
237 zClass = "UPDATED_BY_MERGE";
238 }else if( (flags & C_ADDED) && isChnged==3 ){
239 zClass = "ADDED_BY_MERGE";
240 }else if( (flags & (C_UPDATED | C_CHANGED)) && isChnged==4 ){
241 zClass = "UPDATED_BY_INTEGRATE";
242 }else if( (flags & C_ADDED) && isChnged==5 ){
243 zClass = "ADDED_BY_INTEGRATE";
244 }else if( (flags & C_META) && isChnged==6 ){
245 zClass = "EXECUTABLE";
246 }else if( (flags & C_META) && isChnged==7 ){
247 zClass = "SYMLINK";
248 }else if( (flags & C_META) && isChnged==8 ){
249 zClass = "UNEXEC";
250 }else if( (flags & C_META) && isChnged==9 ){
251 zClass = "UNLINK";
252 }else if( (flags & C_CONFLICT) && isChnged && !isLink
253 && file_contains_merge_marker(zFullName) ){
254 zClass = "CONFLICT";
255 }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
256 && (isChnged<2 || isChnged>9) ){
257 zClass = "EDITED";
258 }else if( (flags & C_RENAMED) && isRenamed ){
259 zClass = "RENAMED";
260 }else if( (flags & C_UNCHANGED) && isManaged && !isDeleted && !isMissing
261 && !isNew && !isChnged && !isRenamed ){
262 zClass = "UNCHANGED";
263 }else if( (flags & C_EXTRA) && !isManaged ){
264 zClass = "EXTRA";
265 }
266
267 /* Only report files for which a change classification was determined. */
268 if( zClass ){
269 if( flags & C_COMMENT ){
270 blob_append(report, "# ", 2);
271 }
272 if( flags & C_CLASSIFY ){
273 blob_appendf(report, "%-10s ", zClass);
274 }
275 if( flags & C_MTIME ){
276 blob_append(report, zMtime, -1);
277 blob_append(report, " ", 2);
278 }
279 if( flags & C_SIZE ){
280 blob_appendf(report, "%7d ", size);
281 }
282 if( flags & C_RELPATH ){
283 /* If C_RELPATH, display paths relative to current directory. */
284 const char *zDisplayName;
285 file_relative_name(zFullName, &rewrittenPathname, 0);
286 zDisplayName = blob_str(&rewrittenPathname);
287 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
288 zDisplayName += 2; /* no unnecessary ./ prefix */
289 }
290 blob_append(report, zDisplayName, -1);
291 }else{
292 /* If not C_RELPATH, display paths relative to project root. */
293 blob_append(report, zPathname, -1);
294 }
295 blob_append(report, "\n", 1);
296 }
297 free(zFullName);
298 }
299 blob_reset(&rewrittenPathname);
300 db_finalize(&q);
301
302 /* If C_MERGE, put merge contributors at the end of the report. */
303 skipFiles:
304 if( flags & C_MERGE ){
305 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
306 " WHERE id<=0");
307 while( db_step(&q)==SQLITE_ROW ){
308 if( flags & C_COMMENT ){
309 blob_append(report, "# ", 2);
310 }
311 if( flags & C_CLASSIFY ){
312 const char *zClass;
313 switch( db_column_int(&q, 1) ){
314 case -1: zClass = "CHERRYPICK" ; break;
315 case -2: zClass = "BACKOUT" ; break;
316 case -4: zClass = "INTEGRATE" ; break;
317 default: zClass = "MERGED_WITH"; break;
318 }
319 blob_appendf(report, "%-10s ", zClass);
320 }
321 blob_append(report, db_column_text(&q, 0), -1);
322 blob_append(report, "\n", 1);
323 }
324 db_finalize(&q);
325 }
326 if( nErr ){
327 fossil_fatal("aborting due to prior errors");
328 }
329 }
330
@@ -171,115 +342,228 @@
342 if( absPathOption ){ relativePaths = 0; }
343 if( relPathOption ){ relativePaths = 1; }
344 return relativePaths;
345 }
346
347 /*
348 ** COMMAND: changes
349 ** COMMAND: status
350 **
351 ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
352 **
353 ** Report the change status of files in the current checkout. If one or
354 ** more PATHS are specified, only changes among the named files and
355 ** directories are reported. Directories are searched recursively.
356 **
357 ** The status command is similar to the changes command, except it lacks
358 ** several of the options supported by changes and it has its own header
359 ** and footer information. The header information is a subset of that
360 ** shown by the info command, and the footer shows if there are any forks.
361 ** Change type classification is always enabled for the status command.
362 **
363 ** Each line of output is the name of a changed file, with paths shown
364 ** according to the "relative-paths" setting, unless overridden by the
365 ** --abs-paths or --rel-paths options.
366 **
367 ** By default, all changed files are selected for display. This behavior
368 ** can be overridden by using one or more filter options (listed below),
369 ** in which case only files with the specified change type(s) are shown.
370 ** As a special case, the --no-merge option does not inhibit this default.
371 ** This default shows exactly the set of changes that would be checked
372 ** in by the commit command.
373 **
374 ** If no filter options are used, or if the --merge option is used, the
375 ** SHA1 hash of each merge contributor check-in version is displayed at
376 ** the end of the report. The --no-merge option is useful to display the
377 ** default set of changed files without the merge contributors.
378 **
379 ** If change type classification is enabled, each output line starts with
380 ** a code describing the file's change type, e.g. EDITED or RENAMED. It
381 ** is enabled by default unless exactly one change type is selected. For
382 ** the purposes of determining the default, --changed counts as selecting
383 ** one change type. The default can be overridden by the --classify or
384 ** --no-classify options.
385 **
386 ** If both --merge and --no-merge are used, --no-merge has priority. The
387 ** same is true of --classify and --no-classify.
388 **
389 ** The "fossil changes --extra" command is equivalent to "fossil extras".
390 **
391 ** --edited and --updated produce disjoint sets. --updated shows a file
392 ** only when it is identical to that of its merge contributor, and the
393 ** change type classification is UPDATED_BY_MERGE or UPDATED_BY_INTEGRATE.
394 ** If the file had to be merged with any other changes, it is considered
395 ** to be merged or conflicted and therefore will be shown by --edited, not
396 ** --updated, with types EDITED or CONFLICT. The --changed option can be
397 ** used to display the union of --edited and --updated.
398 **
399 ** --differ is so named because it lists all the differences between the
400 ** checked-out version and the checkout directory. In addition to the
401 ** default changes (besides --merge), it lists extra files which (assuming
402 ** ignore-glob is set correctly) may be worth adding. Prior to doing a
403 ** commit, it is good practice to check --differ to see not only which
404 ** changes would be committed but also if any files need to be added.
405 **
406 ** General options:
407 ** --abs-paths Display absolute pathnames.
408 ** --rel-paths Display pathnames relative to the current working
409 ** directory.
410 ** --sha1sum Verify file status using SHA1 hashing rather than
411 ** relying on file mtimes.
412 ** --case-sensitive <BOOL> Override case-sensitive setting.
413 ** --dotfiles Include unmanaged files beginning with a dot.
414 ** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
415 **
416 ** Options specific to the changes command:
417 ** --header Identify the repository if report is non-empty.
418 ** -v|--verbose Say "(none)" if the change report is empty.
419 ** --classify Start each line with the file's change type.
420 ** --no-classify Do not print file change types.
421 **
422 ** Filter options:
423 ** --edited Display edited, merged, and conflicted files.
424 ** --updated Display files updated by merge/integrate.
425 ** --changed Combination of the above two options.
426 ** --missing Display missing files.
427 ** --added Display added files.
428 ** --deleted Display deleted files.
429 ** --renamed Display renamed files.
430 ** --conflict Display files having merge conflicts.
431 ** --meta Display files with metadata changes.
432 ** --unchanged Display unchanged files.
433 ** --all Display all managed files, i.e. all of the above.
434 ** --extra Display unmanaged files.
435 ** --differ Display modified and extra files.
436 ** --merge Display merge contributors.
437 ** --no-merge Do not display merge contributors.
438 **
439 ** See also: extras, ls
440 */
441 void status_cmd(void){
442 /* Affirmative and negative flag option tables. */
443 static const struct {
444 const char *option; /* Flag name. */
445 unsigned mask; /* Flag bits. */
446 } flagDefs[] = {
447 {"edited" , C_EDITED }, {"updated" , C_UPDATED },
448 {"changed" , C_CHANGED }, {"missing" , C_MISSING },
449 {"added" , C_ADDED }, {"deleted" , C_DELETED },
450 {"renamed" , C_RENAMED }, {"conflict" , C_CONFLICT },
451 {"meta" , C_META }, {"unchanged" , C_UNCHANGED},
452 {"all" , C_ALL }, {"extra" , C_EXTRA },
453 {"differ" , C_DIFFER }, {"merge" , C_MERGE },
454 {"classify", C_CLASSIFY},
455 }, noFlagDefs[] = {
456 {"no-merge", C_MERGE }, {"no-classify", C_CLASSIFY },
457 };
458
459 Blob report = BLOB_INITIALIZER;
460 enum {CHANGES, STATUS} command = *g.argv[1]=='s' ? STATUS : CHANGES;
461 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
462 int showHdr = command==CHANGES && find_option("header", 0, 0);
463 int verboseFlag = command==CHANGES && find_option("verbose", "v", 0);
464 const char *zIgnoreFlag = find_option("ignore", 0, 1);
465 unsigned scanFlags = 0;
466 unsigned flags = 0;
467 int vid, i;
468
469 /* Load affirmative flag options. */
470 for( i=0; i<count(flagDefs); ++i ){
471 if( (command==CHANGES || !(flagDefs[i].mask & C_CLASSIFY))
472 && find_option(flagDefs[i].option, 0, 0) ){
473 flags |= flagDefs[i].mask;
474 }
475 }
476
477 /* If no filter options are specified, enable defaults. */
478 if( !(flags & C_FILTER) ){
479 flags |= C_DEFAULT;
480 }
481
482 /* If more than one filter is enabled, enable classification. This is tricky.
483 * Having one filter means flags masked by C_FILTER is a power of two. If a
484 * number masked by one less than itself is zero, it's either zero or a power
485 * of two. It's already known to not be zero because of the above defaults.
486 * Unlike --all, --changed is a single filter, i.e. it sets only one bit.
487 * Also force classification for the status command. */
488 if( command==STATUS || (flags & (flags-1) & C_FILTER) ){
489 flags |= C_CLASSIFY;
490 }
491
492 /* Negative flag options override defaults applied above. */
493 for( i=0; i<count(noFlagDefs); ++i ){
494 if( (command==CHANGES || !(noFlagDefs[i].mask & C_CLASSIFY))
495 && find_option(noFlagDefs[i].option, 0, 0) ){
496 flags &= ~noFlagDefs[i].mask;
497 }
498 }
499
500 /* Confirm current working directory is within checkout. */
501 db_must_be_within_tree();
502
503 /* Get checkout version. l*/
504 vid = db_lget_int("checkout", 0);
505
506 /* Relative path flag determination is done by a shared function. */
507 if( determine_cwd_relative_option() ){
508 flags |= C_RELPATH;
509 }
510
511 /* If --ignore is not specified, use the ignore-glob setting. */
512 if( !zIgnoreFlag ){
513 zIgnoreFlag = db_get("ignore-glob", 0);
514 }
515
516 /* Get the --dotfiles argument, or read it from the dotfiles setting. */
517 if( find_option("dotfiles", 0, 0) || db_get_boolean("dotfiles", 0) ){
518 scanFlags = SCAN_ALL;
519 }
520
521 /* We should be done with options. */
522 verify_all_options();
523
524 /* Check for changed files. */
525 vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
526
527 /* Search for unmanaged files if requested. */
528 if( flags & C_EXTRA ){
529 Glob *pIgnore = glob_create(zIgnoreFlag);
530 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
531 glob_free(pIgnore);
532 }
533
534 /* The status command prints general information before the change list. */
535 if( command==STATUS ){
536 fossil_print("repository: %s\n", db_repository_filename());
537 fossil_print("local-root: %s\n", g.zLocalRoot);
538 if( g.zConfigDbName ){
539 fossil_print("config-db: %s\n", g.zConfigDbName);
540 }
541 if( vid ){
542 show_common_info(vid, "checkout:", 1, 1);
543 }
544 db_record_repository_filename(0);
545 }
546
547 /* Find and print all requested changes. */
548 blob_zero(&report);
549 status_report(&report, flags);
550 if( blob_size(&report) ){
551 if( showHdr ){
552 fossil_print("Changes for %s at %s:\n", db_get("project-name", "???"),
553 g.zLocalRoot);
554 }
555 blob_write_to_file(&report, "-");
556 }else if( verboseFlag ){
557 fossil_print(" (none)\n");
558 }
559 blob_reset(&report);
560
561 /* The status command ends with warnings about ambiguous leaves (forks). */
562 if( command==STATUS ){
563 leaf_ambiguity_warning(vid, vid);
564 }
565 }
566
567 /*
568 ** Take care of -r version of ls command
569 */
@@ -508,59 +792,10 @@
792 free(zFullName);
793 }
794 db_finalize(&q);
795 }
796
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797 /*
798 ** COMMAND: extras
799 **
800 ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
801 **
@@ -588,22 +823,23 @@
823 ** directory.
824 **
825 ** See also: changes, clean, status
826 */
827 void extras_cmd(void){
828 Blob report = BLOB_INITIALIZER;
829 const char *zIgnoreFlag = find_option("ignore",0,1);
830 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
831 unsigned flags = C_EXTRA;
832 int showHdr = find_option("header",0,0)!=0;
 
833 Glob *pIgnore;
 
 
834
835 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
836 db_must_be_within_tree();
837
838 if( determine_cwd_relative_option() ){
839 flags |= C_RELPATH;
840 }
841
842 if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL;
843
844 /* We should be done with options.. */
845 verify_all_options();
@@ -610,41 +846,24 @@
846
847 if( zIgnoreFlag==0 ){
848 zIgnoreFlag = db_get("ignore-glob", 0);
849 }
850 pIgnore = glob_create(zIgnoreFlag);
851 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
852 glob_free(pIgnore);
 
 
 
 
 
 
 
 
853 g.allowSymlinks = 1; /* Report on symbolic links */
854
855 blob_zero(&report);
856 status_report(&report, flags);
857 if( blob_size(&report) ){
 
 
 
 
 
 
 
858 if( showHdr ){
 
859 fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
860 g.zLocalRoot);
861 }
862 blob_write_to_file(&report, "-");
863 }
864 blob_reset(&report);
 
865 }
866
867 /*
868 ** COMMAND: clean
869 **
@@ -790,21 +1009,22 @@
1009 g.allowSymlinks = 1; /* Find symlinks too */
1010 if( !dirsOnlyFlag ){
1011 Stmt q;
1012 Blob repo;
1013 if( !dryRunFlag && !disableUndo ) undo_begin();
1014 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
1015 db_prepare(&q,
1016 "SELECT %Q || pathname FROM sfile"
1017 " WHERE pathname NOT IN (%s)"
1018 " ORDER BY 1",
1019 g.zLocalRoot, fossil_all_reserved_names(0)
1020 );
1021 if( file_tree_name(g.zRepositoryName, &repo, 0, 0) ){
1022 db_multi_exec("DELETE FROM sfile WHERE pathname=%B", &repo);
1023 }
1024 db_multi_exec("DELETE FROM sfile WHERE pathname IN"
1025 " (SELECT pathname FROM vfile)");
1026 while( db_step(&q)==SQLITE_ROW ){
1027 const char *zName = db_column_text(&q, 0);
1028 if( glob_match(pKeep, zName+nRoot) ){
1029 if( verboseFlag ){
1030 fossil_print("KEPT file \"%s\" not removed (due to --keep"
@@ -1081,11 +1301,11 @@
1301 }
1302 }
1303 blob_appendf(&prompt, "\n#\n");
1304 }
1305 }
1306 status_report(&prompt, C_DEFAULT | C_FATAL | C_COMMENT);
1307 if( g.markPrivate ){
1308 blob_append(&prompt,
1309 "# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
1310 "# repositories.\n"
1311 "#\n", -1
1312
--- src/descendants.c
+++ src/descendants.c
@@ -216,12 +216,12 @@
216216
static int prevVid = -1;
217217
static Stmt q;
218218
219219
if( prevVid!=vid ){
220220
prevVid = vid;
221
- db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
222
- "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
221
+ db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
222
+ "DELETE FROM ok;");
223223
compute_ancestors(vid, 100000000, 1);
224224
}
225225
db_static_prepare(&q,
226226
"SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
227227
" WHERE mlink.mid=event.objid"
228228
--- src/descendants.c
+++ src/descendants.c
@@ -216,12 +216,12 @@
216 static int prevVid = -1;
217 static Stmt q;
218
219 if( prevVid!=vid ){
220 prevVid = vid;
221 db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
222 "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
223 compute_ancestors(vid, 100000000, 1);
224 }
225 db_static_prepare(&q,
226 "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
227 " WHERE mlink.mid=event.objid"
228
--- src/descendants.c
+++ src/descendants.c
@@ -216,12 +216,12 @@
216 static int prevVid = -1;
217 static Stmt q;
218
219 if( prevVid!=vid ){
220 prevVid = vid;
221 db_multi_exec("CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
222 "DELETE FROM ok;");
223 compute_ancestors(vid, 100000000, 1);
224 }
225 db_static_prepare(&q,
226 "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
227 " WHERE mlink.mid=event.objid"
228
+4 -4
--- src/main.c
+++ src/main.c
@@ -1192,14 +1192,14 @@
11921192
int n = 0;
11931193
11941194
assert( g.db==0 );
11951195
blob_init(&base, g.zRepositoryName, -1);
11961196
sqlite3_open(":memory:", &g.db);
1197
- db_multi_exec("CREATE TABLE sfile(x TEXT);");
1197
+ db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
11981198
db_multi_exec("CREATE TABLE vfile(pathname);");
11991199
vfile_scan(&base, blob_size(&base), 0, 0, 0);
1200
- db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*[^/].fossil'");
1200
+ db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
12011201
n = db_int(0, "SELECT count(*) FROM sfile");
12021202
if( n>0 ){
12031203
Stmt q;
12041204
@ <html>
12051205
@ <head>
@@ -1207,12 +1207,12 @@
12071207
@ <title>Repository List</title>
12081208
@ </head>
12091209
@ <body>
12101210
@ <h1>Available Repositories:</h1>
12111211
@ <ol>
1212
- db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'"
1213
- " FROM sfile ORDER BY x COLLATE nocase;");
1212
+ db_prepare(&q, "SELECT pathname, substr(pathname,-7,-100000)||'/home'"
1213
+ " FROM sfile ORDER BY pathname COLLATE nocase;");
12141214
while( db_step(&q)==SQLITE_ROW ){
12151215
const char *zName = db_column_text(&q, 0);
12161216
const char *zUrl = db_column_text(&q, 1);
12171217
@ <li><a href="%R/%h(zUrl)" target="_blank">%h(zName)</a></li>
12181218
}
12191219
--- src/main.c
+++ src/main.c
@@ -1192,14 +1192,14 @@
1192 int n = 0;
1193
1194 assert( g.db==0 );
1195 blob_init(&base, g.zRepositoryName, -1);
1196 sqlite3_open(":memory:", &g.db);
1197 db_multi_exec("CREATE TABLE sfile(x TEXT);");
1198 db_multi_exec("CREATE TABLE vfile(pathname);");
1199 vfile_scan(&base, blob_size(&base), 0, 0, 0);
1200 db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*[^/].fossil'");
1201 n = db_int(0, "SELECT count(*) FROM sfile");
1202 if( n>0 ){
1203 Stmt q;
1204 @ <html>
1205 @ <head>
@@ -1207,12 +1207,12 @@
1207 @ <title>Repository List</title>
1208 @ </head>
1209 @ <body>
1210 @ <h1>Available Repositories:</h1>
1211 @ <ol>
1212 db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'"
1213 " FROM sfile ORDER BY x COLLATE nocase;");
1214 while( db_step(&q)==SQLITE_ROW ){
1215 const char *zName = db_column_text(&q, 0);
1216 const char *zUrl = db_column_text(&q, 1);
1217 @ <li><a href="%R/%h(zUrl)" target="_blank">%h(zName)</a></li>
1218 }
1219
--- src/main.c
+++ src/main.c
@@ -1192,14 +1192,14 @@
1192 int n = 0;
1193
1194 assert( g.db==0 );
1195 blob_init(&base, g.zRepositoryName, -1);
1196 sqlite3_open(":memory:", &g.db);
1197 db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
1198 db_multi_exec("CREATE TABLE vfile(pathname);");
1199 vfile_scan(&base, blob_size(&base), 0, 0, 0);
1200 db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
1201 n = db_int(0, "SELECT count(*) FROM sfile");
1202 if( n>0 ){
1203 Stmt q;
1204 @ <html>
1205 @ <head>
@@ -1207,12 +1207,12 @@
1207 @ <title>Repository List</title>
1208 @ </head>
1209 @ <body>
1210 @ <h1>Available Repositories:</h1>
1211 @ <ol>
1212 db_prepare(&q, "SELECT pathname, substr(pathname,-7,-100000)||'/home'"
1213 " FROM sfile ORDER BY pathname COLLATE nocase;");
1214 while( db_step(&q)==SQLITE_ROW ){
1215 const char *zName = db_column_text(&q, 0);
1216 const char *zUrl = db_column_text(&q, 1);
1217 @ <li><a href="%R/%h(zUrl)" target="_blank">%h(zName)</a></li>
1218 }
1219
+2 -2
--- src/stash.c
+++ src/stash.c
@@ -207,11 +207,11 @@
207207
"SELECT rid, isRemoved, isExec, isLink, origname, newname, delta"
208208
" FROM stashfile WHERE stashid=%d",
209209
stashid
210210
);
211211
vid = db_lget_int("checkout",0);
212
- db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
212
+ db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
213213
filename_collation());
214214
while( db_step(&q)==SQLITE_ROW ){
215215
int rid = db_column_int(&q, 0);
216216
int isRemoved = db_column_int(&q, 1);
217217
int isExec = db_column_int(&q, 2);
@@ -222,11 +222,11 @@
222222
char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew);
223223
Blob delta;
224224
undo_save(zNew);
225225
blob_zero(&delta);
226226
if( rid==0 ){
227
- db_multi_exec("INSERT OR IGNORE INTO sfile(x) VALUES(%Q)", zNew);
227
+ db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew);
228228
db_ephemeral_blob(&q, 6, &delta);
229229
blob_write_to_file(&delta, zNPath);
230230
file_wd_setexe(zNPath, isExec);
231231
}else if( isRemoved ){
232232
fossil_print("DELETE %s\n", zOrig);
233233
--- src/stash.c
+++ src/stash.c
@@ -207,11 +207,11 @@
207 "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta"
208 " FROM stashfile WHERE stashid=%d",
209 stashid
210 );
211 vid = db_lget_int("checkout",0);
212 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
213 filename_collation());
214 while( db_step(&q)==SQLITE_ROW ){
215 int rid = db_column_int(&q, 0);
216 int isRemoved = db_column_int(&q, 1);
217 int isExec = db_column_int(&q, 2);
@@ -222,11 +222,11 @@
222 char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew);
223 Blob delta;
224 undo_save(zNew);
225 blob_zero(&delta);
226 if( rid==0 ){
227 db_multi_exec("INSERT OR IGNORE INTO sfile(x) VALUES(%Q)", zNew);
228 db_ephemeral_blob(&q, 6, &delta);
229 blob_write_to_file(&delta, zNPath);
230 file_wd_setexe(zNPath, isExec);
231 }else if( isRemoved ){
232 fossil_print("DELETE %s\n", zOrig);
233
--- src/stash.c
+++ src/stash.c
@@ -207,11 +207,11 @@
207 "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta"
208 " FROM stashfile WHERE stashid=%d",
209 stashid
210 );
211 vid = db_lget_int("checkout",0);
212 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
213 filename_collation());
214 while( db_step(&q)==SQLITE_ROW ){
215 int rid = db_column_int(&q, 0);
216 int isRemoved = db_column_int(&q, 1);
217 int isExec = db_column_int(&q, 2);
@@ -222,11 +222,11 @@
222 char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew);
223 Blob delta;
224 undo_save(zNew);
225 blob_zero(&delta);
226 if( rid==0 ){
227 db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew);
228 db_ephemeral_blob(&q, 6, &delta);
229 blob_write_to_file(&delta, zNPath);
230 file_wd_setexe(zNPath, isExec);
231 }else if( isRemoved ){
232 fossil_print("DELETE %s\n", zOrig);
233
+16 -3
--- src/vfile.c
+++ src/vfile.c
@@ -455,10 +455,12 @@
455455
** Values for the scanFlags parameter to vfile_scan().
456456
*/
457457
#define SCAN_ALL 0x001 /* Includes files that begin with "." */
458458
#define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
459459
#define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
460
+#define SCAN_MTIME 0x008 /* Populate mtime column */
461
+#define SCAN_SIZE 0x010 /* Populate size column */
460462
#endif /* INTERFACE */
461463
462464
/*
463465
** Load into table SFILE the name of every ordinary file in
464466
** the directory pPath. Omit the first nPrefix characters of
@@ -498,13 +500,18 @@
498500
}
499501
if( skipAll ) return;
500502
501503
if( depth==0 ){
502504
db_prepare(&ins,
503
- "INSERT OR IGNORE INTO sfile(x) SELECT :file"
504
- " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
505
- " pathname=:file %s)", filename_collation()
505
+ "INSERT OR IGNORE INTO sfile(pathname%s%s) SELECT :file%s%s"
506
+ " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
507
+ " pathname=:file %s)",
508
+ scanFlags & SCAN_MTIME ? ", mtime" : "",
509
+ scanFlags & SCAN_SIZE ? ", size" : "",
510
+ scanFlags & SCAN_MTIME ? ", :mtime" : "",
511
+ scanFlags & SCAN_SIZE ? ", :size" : "",
512
+ filename_collation()
506513
);
507514
}
508515
depth++;
509516
510517
zNative = fossil_utf8_to_path(blob_str(pPath), 1);
@@ -539,10 +546,16 @@
539546
#else
540547
}else if( file_wd_isfile_or_link(zPath) ){
541548
#endif
542549
if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
543550
db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
551
+ if( scanFlags & SCAN_MTIME ){
552
+ db_bind_int(&ins, ":mtime", file_mtime(zPath));
553
+ }
554
+ if( scanFlags & SCAN_SIZE ){
555
+ db_bind_int(&ins, ":size", file_size(zPath));
556
+ }
544557
db_step(&ins);
545558
db_reset(&ins);
546559
}
547560
}
548561
fossil_path_free(zUtf8);
549562
--- src/vfile.c
+++ src/vfile.c
@@ -455,10 +455,12 @@
455 ** Values for the scanFlags parameter to vfile_scan().
456 */
457 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
458 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
459 #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
 
 
460 #endif /* INTERFACE */
461
462 /*
463 ** Load into table SFILE the name of every ordinary file in
464 ** the directory pPath. Omit the first nPrefix characters of
@@ -498,13 +500,18 @@
498 }
499 if( skipAll ) return;
500
501 if( depth==0 ){
502 db_prepare(&ins,
503 "INSERT OR IGNORE INTO sfile(x) SELECT :file"
504 " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
505 " pathname=:file %s)", filename_collation()
 
 
 
 
 
506 );
507 }
508 depth++;
509
510 zNative = fossil_utf8_to_path(blob_str(pPath), 1);
@@ -539,10 +546,16 @@
539 #else
540 }else if( file_wd_isfile_or_link(zPath) ){
541 #endif
542 if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
543 db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
 
 
 
 
 
 
544 db_step(&ins);
545 db_reset(&ins);
546 }
547 }
548 fossil_path_free(zUtf8);
549
--- src/vfile.c
+++ src/vfile.c
@@ -455,10 +455,12 @@
455 ** Values for the scanFlags parameter to vfile_scan().
456 */
457 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
458 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
459 #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
460 #define SCAN_MTIME 0x008 /* Populate mtime column */
461 #define SCAN_SIZE 0x010 /* Populate size column */
462 #endif /* INTERFACE */
463
464 /*
465 ** Load into table SFILE the name of every ordinary file in
466 ** the directory pPath. Omit the first nPrefix characters of
@@ -498,13 +500,18 @@
500 }
501 if( skipAll ) return;
502
503 if( depth==0 ){
504 db_prepare(&ins,
505 "INSERT OR IGNORE INTO sfile(pathname%s%s) SELECT :file%s%s"
506 " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
507 " pathname=:file %s)",
508 scanFlags & SCAN_MTIME ? ", mtime" : "",
509 scanFlags & SCAN_SIZE ? ", size" : "",
510 scanFlags & SCAN_MTIME ? ", :mtime" : "",
511 scanFlags & SCAN_SIZE ? ", :size" : "",
512 filename_collation()
513 );
514 }
515 depth++;
516
517 zNative = fossil_utf8_to_path(blob_str(pPath), 1);
@@ -539,10 +546,16 @@
546 #else
547 }else if( file_wd_isfile_or_link(zPath) ){
548 #endif
549 if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
550 db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
551 if( scanFlags & SCAN_MTIME ){
552 db_bind_int(&ins, ":mtime", file_mtime(zPath));
553 }
554 if( scanFlags & SCAN_SIZE ){
555 db_bind_int(&ins, ":size", file_size(zPath));
556 }
557 db_step(&ins);
558 db_reset(&ins);
559 }
560 }
561 fossil_path_free(zUtf8);
562
--- www/fileformat.wiki
+++ www/fileformat.wiki
--- www/fileformat.wiki
+++ www/fileformat.wiki
0
--- www/fileformat.wiki
+++ www/fileformat.wiki
0
--- www/fileformat.wiki
+++ www/fileformat.wiki
--- www/fileformat.wiki
+++ www/fileformat.wiki
0
--- www/fileformat.wiki
+++ www/fileformat.wiki
0
--- www/makefile.wiki
+++ www/makefile.wiki
--- www/makefile.wiki
+++ www/makefile.wiki
0
--- www/makefile.wiki
+++ www/makefile.wiki
0
--- www/makefile.wiki
+++ www/makefile.wiki
--- www/makefile.wiki
+++ www/makefile.wiki
0
--- www/makefile.wiki
+++ www/makefile.wiki
0
--- www/pop.wiki
+++ www/pop.wiki
--- www/pop.wiki
+++ www/pop.wiki
0
--- www/pop.wiki
+++ www/pop.wiki
0
--- www/pop.wiki
+++ www/pop.wiki
--- www/pop.wiki
+++ www/pop.wiki
0
--- www/pop.wiki
+++ www/pop.wiki
0
--- www/qandc.wiki
+++ www/qandc.wiki
--- www/qandc.wiki
+++ www/qandc.wiki
0
--- www/qandc.wiki
+++ www/qandc.wiki
0
--- www/qandc.wiki
+++ www/qandc.wiki
--- www/qandc.wiki
+++ www/qandc.wiki
0
--- www/qandc.wiki
+++ www/qandc.wiki
0

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button