Fossil SCM

Fold print_changes() into status_cmd() (formerly changes_cmd()). Remove C_SHA1SUM, C_HEADER, and C_VERBOSE flags which are no longer needed for communicating options to print_changes(). Move locate_unmanaged_files() closer to the top of the file so status_cmd() can call it. Implement C_UNMODIFIED and C_EXTRA in status_report(). Document the fact that the changes and status commands take optional path arguments. Let changes and status commands accept --case-sensitive (was already done), --dotfiles, and --ignore for the benefit of --extras. Incorporate search for extra files into status_cmd().

andygoth 2016-11-06 02:35 UTC andygoth-changes
Commit f15d20e39b55c7ac3e007a5df84293885c4404a1
1 file changed +146 -107
+146 -107
--- src/checkin.c
+++ src/checkin.c
@@ -25,14 +25,13 @@
2525
/*
2626
** Change filter options.
2727
*/
2828
enum {
2929
/* 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_UNMODIFIED, CB_EXTRA , CB_MERGE ,
32
- CB_RELPATH, CB_SHA1SUM , CB_HEADER , CB_VERBOSE , CB_CLASSIFY, CB_FATAL ,
33
- CB_COMMENT,
30
+ CB_EDITED , CB_UPDATED , CB_CHANGED, CB_MISSING , CB_ADDED, CB_DELETED,
31
+ CB_RENAMED, CB_CONFLICT, CB_META , CB_UNMODIFIED, CB_EXTRA, CB_MERGE ,
32
+ CB_RELPATH, CB_CLASSIFY, CB_FATAL , CB_COMMENT ,
3433
3534
/* Bitmask values. */
3635
C_EDITED = 1 << CB_EDITED, /* Edited, merged, and conflicted files. */
3736
C_UPDATED = 1 << CB_UPDATED, /* Files updated by merge/integrate. */
3837
C_CHANGED = 1 << CB_CHANGED, /* Treated the same as the above two. */
@@ -48,18 +47,64 @@
4847
C_FILTER = C_EDITED | C_UPDATED | C_CHANGED | C_MISSING | C_ADDED
4948
| C_DELETED | C_RENAMED | C_CONFLICT | C_META | C_UNMODIFIED
5049
| C_EXTRA | C_MERGE,
5150
C_ALL = C_FILTER & ~(C_EXTRA | C_MERGE),
5251
C_RELPATH = 1 << CB_RELPATH, /* Show relative paths. */
53
- C_SHA1SUM = 1 << CB_SHA1SUM, /* Use SHA1 checksums not mtimes. */
54
- C_HEADER = 1 << CB_HEADER, /* Display repository name if non-empty. */
55
- C_VERBOSE = 1 << CB_VERBOSE, /* Display "(none)" if empty. */
5652
C_CLASSIFY = 1 << CB_CLASSIFY, /* Show file change types. */
5753
C_DEFAULT = (C_ALL & ~C_UNMODIFIED) | C_MERGE | C_CLASSIFY,
5854
C_FATAL = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
5955
C_COMMENT = 1 << CB_COMMENT, /* Precede each line with "# ". */
6056
};
57
+
58
+/*
59
+** Create a TEMP table named SFILE and add all unmanaged files named on
60
+** the command-line to that table. If directories are named, then add
61
+** all unmanaged files contained underneath those directories. If there
62
+** are no files or directories named on the command-line, then add all
63
+** unmanaged files anywhere in the checkout.
64
+*/
65
+static void locate_unmanaged_files(
66
+ int argc, /* Number of command-line arguments to examine */
67
+ char **argv, /* values of command-line arguments */
68
+ unsigned scanFlags, /* Zero or more SCAN_xxx flags */
69
+ Glob *pIgnore1, /* Do not add files that match this GLOB */
70
+ Glob *pIgnore2 /* Omit files matching this GLOB too */
71
+){
72
+ Blob name; /* Name of a candidate file or directory */
73
+ char *zName; /* Name of a candidate file or directory */
74
+ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
75
+ int i; /* Loop counter */
76
+ int nRoot; /* length of g.zLocalRoot */
77
+
78
+ db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
79
+ filename_collation());
80
+ nRoot = (int)strlen(g.zLocalRoot);
81
+ if( argc==0 ){
82
+ blob_init(&name, g.zLocalRoot, nRoot - 1);
83
+ vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
84
+ blob_reset(&name);
85
+ }else{
86
+ for(i=0; i<argc; i++){
87
+ file_canonical_name(argv[i], &name, 0);
88
+ zName = blob_str(&name);
89
+ isDir = file_wd_isdir(zName);
90
+ if( isDir==1 ){
91
+ vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
92
+ }else if( isDir==0 ){
93
+ fossil_warning("not found: %s", &zName[nRoot]);
94
+ }else if( file_access(zName, R_OK) ){
95
+ fossil_fatal("cannot open %s", &zName[nRoot]);
96
+ }else{
97
+ db_multi_exec(
98
+ "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
99
+ &zName[nRoot]
100
+ );
101
+ }
102
+ blob_reset(&name);
103
+ }
104
+ }
105
+}
61106
62107
/*
63108
** Generate text describing all changes.
64109
**
65110
** We assume that vfile_check_signature has been run.
@@ -69,14 +114,15 @@
69114
unsigned flags /* Filter and other configuration flags */
70115
){
71116
Stmt q;
72117
int nErr = 0;
73118
Blob rewrittenPathname;
74
- Blob where;
119
+ Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER;
75120
const char *zName;
76121
int i;
77122
123
+ /* Assemble the path-limiting WHERE clause, if any. */
78124
blob_zero(&where);
79125
for(i=2; i<g.argc; i++){
80126
Blob fname;
81127
file_tree_name(g.argv[i], &fname, 0, 1);
82128
zName = blob_str(&fname);
@@ -91,28 +137,47 @@
91137
filename_collation(), zName, filename_collation(),
92138
zName, filename_collation()
93139
);
94140
}
95141
96
- db_prepare(&q,
97
- "SELECT pathname, deleted, chnged,"
98
- " rid, coalesce(origname!=pathname,0), islink"
99
- " FROM vfile "
100
- " WHERE is_selected(id) %s"
101
- " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
102
- " ORDER BY 1 /*scan*/",
103
- blob_sql_text(&where)
104
- );
142
+ /* Start building the SELECT statement. */
143
+ blob_zero(&sql);
144
+ blob_append_sql(&sql,
145
+ "SELECT pathname, deleted, chnged, rid,"
146
+ " coalesce(origname!=pathname,0) AS renamed, islink, 1 AS managed"
147
+ " FROM vfile"
148
+ " WHERE is_selected(id)%s", blob_sql_text(&where));
149
+
150
+ /* Exclude unmodified files unless requested. */
151
+ if( !(flags & C_UNMODIFIED) ){
152
+ blob_append_sql(&sql,
153
+ " AND (chnged OR deleted OR rid=0 OR pathname!=origname)");
154
+ }
155
+
156
+ /* If C_EXTRA, add unmanaged files to the query result too. */
157
+ if( flags & C_EXTRA ){
158
+ blob_append_sql(&sql, " UNION ALL SELECT x AS pathname, 0, 0, 0, 0, 0, 0"
159
+ " FROM sfile WHERE 1%s", blob_sql_text(&where));
160
+ }
161
+
162
+ /* Append an ORDER BY clause then compile the query. */
163
+ blob_append_sql(&sql, " ORDER BY pathname");
164
+ db_prepare(&q, "%s", blob_sql_text(&sql));
165
+ blob_reset(&sql);
166
+ blob_reset(&where);
167
+
168
+ /* Execute the query and assemble the report. */
105169
blob_zero(&rewrittenPathname);
106170
while( db_step(&q)==SQLITE_ROW ){
107
- const char *zPathname = db_column_text(&q,0);
171
+ const char *zPathname = db_column_text(&q, 0);
108172
const char *zClass = 0;
173
+ int isManaged = db_column_int(&q, 6);
109174
int isDeleted = db_column_int(&q, 1);
110
- int isChnged = db_column_int(&q,2);
111
- int isNew = db_column_int(&q,3)==0;
112
- int isRenamed = db_column_int(&q,4);
113
- int isLink = db_column_int(&q,5);
175
+ int isChnged = db_column_int(&q, 2);
176
+ int isNew = isManaged && !db_column_int(&q, 3);
177
+ int isRenamed = db_column_int(&q, 4);
178
+ int isLink = db_column_int(&q, 5);
114179
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
115180
int isMissing = !file_wd_isfile_or_link(zFullName);
116181
117182
/* Determine the file change classification, if any. */
118183
if( (flags & C_DELETED) && isDeleted ){
@@ -150,20 +215,21 @@
150215
}else if( (flags & C_META) && isChnged==9 ){
151216
zClass = "UNLINK";
152217
}else if( (flags & C_CONFLICT) && isChnged && !isLink
153218
&& file_contains_merge_marker(zFullName) ){
154219
zClass = "CONFLICT";
155
- }else if( (flags & (C_EDITED | C_CHANGED)) && (isChnged<2 || isChnged>9) ){
220
+ }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
221
+ && (isChnged<2 || isChnged>9) ){
156222
zClass = "EDITED";
157223
}else if( (flags & C_RENAMED) && isRenamed ){
158224
zClass = "RENAMED";
159
- }else if( (flags & C_UNMODIFIED) && !isDeleted && !isMissing && !isNew
160
- && !isChnged && !isRenamed ){
161
- /* TODO: never gets executed because query only yields modified files. */
225
+ }else if( (flags & C_UNMODIFIED) && isManaged && !isDeleted && !isMissing
226
+ && !isNew && !isChnged && !isRenamed ){
162227
zClass = "UNMODIFIED";
228
+ }else if( (flags & C_EXTRA) && !isManaged ){
229
+ zClass = "EXTRA";
163230
}
164
- /* TODO: implement C_EXTRA. */
165231
/* TODO: reimplement ls and extras in terms of this function. */
166232
167233
/* Only report files for which a change classification was determined. */
168234
if( zClass ){
169235
/* If C_COMMENT, precede each line with "# ". */
@@ -243,38 +309,19 @@
243309
if( absPathOption ){ relativePaths = 0; }
244310
if( relPathOption ){ relativePaths = 1; }
245311
return relativePaths;
246312
}
247313
248
-void print_changes(
249
- unsigned flags /* Configuration flags */
250
-){
251
- Blob report;
252
- int vid;
253
- blob_zero(&report);
254
-
255
- vid = db_lget_int("checkout", 0);
256
- vfile_check_signature(vid, flags & C_SHA1SUM ? CKSIG_SHA1 : 0);
257
- status_report(&report, flags);
258
- if( (flags & C_VERBOSE) && blob_size(&report)==0 ){
259
- blob_append(&report, " (none)\n", -1);
260
- }
261
- if( (flags & C_HEADER) && blob_size(&report)>0 ){
262
- fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
263
- g.zLocalRoot);
264
- }
265
- blob_write_to_file(&report, "-");
266
- blob_reset(&report);
267
-}
268
-
269314
/*
270315
** COMMAND: changes
271316
** COMMAND: status
272317
**
273
-** Usage: %fossil changes|status ?OPTIONS?
318
+** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
274319
**
275
-** Report the change status of files in the current checkout.
320
+** Report the change status of files in the current checkout. If one or
321
+** more PATHS are specified, only changes among the named files and
322
+** directories are reported. Directories are searched recursively.
276323
**
277324
** The status command is similar to the changes command, except it lacks
278325
** several of the options supported by changes and it has its own header
279326
** and footer information. The header information is a subset of that
280327
** shown by the info command, and the footer shows if there are any forks.
@@ -318,10 +365,13 @@
318365
** --abs-paths Display absolute pathnames.
319366
** --rel-paths Display pathnames relative to the current working
320367
** directory.
321368
** --sha1sum Verify file status using SHA1 hashing rather than
322369
** relying on file mtimes.
370
+** --case-sensitive <BOOL> Override case-sensitive setting.
371
+** --dotfiles Include unmanaged files beginning with a dot.
372
+** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
323373
**
324374
** Options specific to the changes command:
325375
** --header Identify the repository if report is non-empty.
326376
** -v|--verbose Say "(none)" if the change report is empty.
327377
** --classify Start each line with the file's change type.
@@ -356,28 +406,41 @@
356406
{"changed" , C_CHANGED, 0}, {"missing" , C_MISSING , 0},
357407
{"added" , C_ADDED , 0}, {"deleted" , C_DELETED , 0},
358408
{"renamed" , C_RENAMED, 0}, {"conflict" , C_CONFLICT , 0},
359409
{"meta" , C_META , 0}, {"unmodified" , C_UNMODIFIED, 0},
360410
{"all" , C_ALL , 0}, {"extra" , C_EXTRA , 0},
361
- {"merge" , C_MERGE , 0}, {"sha1sum" , C_SHA1SUM , 0},
362
- {"header" , C_HEADER , 1}, {"v" , C_VERBOSE , 1},
363
- {"verbose" , C_VERBOSE, 1}, {"classify" , C_CLASSIFY , 1},
411
+ {"merge" , C_MERGE , 0}, {"classify" , C_CLASSIFY , 1},
364412
}, noFlagDefs[] = {
365413
{"no-merge", C_MERGE , 0}, {"no-classify", C_CLASSIFY , 1},
366414
};
367415
368416
#ifdef FOSSIL_DEBUG
369417
static const char *const bits[] = {
370418
"EDITED", "UPDATED", "CHANGED", "MISSING", "ADDED", "DELETED", "RENAMED",
371
- "CONFLICT", "META", "UNMODIFIED", "EXTRA", "MERGE", "RELPATH", "SHA1SUM",
372
- "HEADER", "VERBOSE", "CLASSIFY",
419
+ "CONFLICT", "META", "UNMODIFIED", "EXTRA", "MERGE", "RELPATH", "CLASSIFY",
373420
};
374421
#endif
375422
423
+ Blob report = BLOB_INITIALIZER;
424
+ int useSha1sum = find_option("sha1sum", 0, 0)!=0;
425
+ int showHdr = find_option("header",0,0)!=0;
426
+ int verboseFlag = find_option("verbose","v",0)!=0;
427
+ const char *zIgnoreFlag = find_option("ignore", 0, 1);
428
+ unsigned scanFlags = 0;
376429
int changes = g.argv[1][0]=='c';
377430
unsigned flags = 0;
378431
int vid, i;
432
+
433
+ /* If --ignore is not specified, use the ignore-glob setting. */
434
+ if( !zIgnoreFlag ){
435
+ zIgnoreFlag = db_get("ignore-glob", 0);
436
+ }
437
+
438
+ /* Get the --dotfiles argument, or read it from the dotfiles setting. */
439
+ if( find_option("dotfiles", 0, 0) || db_get_boolean("dotfiles", 0) ){
440
+ scanFlags = SCAN_ALL;
441
+ }
379442
380443
/* Load affirmative flag options. */
381444
for( i=0; i<count(flagDefs); ++i ){
382445
if( (!flagDefs[i].changesOnly || changes)
383446
&& find_option(flagDefs[i].option, 0, 0) ){
@@ -409,10 +472,13 @@
409472
}
410473
411474
/* Confirm current working directory is within checkout. */
412475
db_must_be_within_tree();
413476
477
+ /* Get checkout version. l*/
478
+ vid = db_lget_int("checkout", 0);
479
+
414480
/* Relative path flag determination is done by a shared function. */
415481
if( determine_cwd_relative_option() ){
416482
flags |= C_RELPATH;
417483
}
418484
@@ -425,14 +491,25 @@
425491
printf("\n");
426492
#endif
427493
428494
/* We should be done with options. */
429495
verify_all_options();
496
+
497
+ /* Check for changed files. */
498
+ vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
499
+
500
+ /* Search for unmanaged files if requested. Exclude reserved files. */
501
+ if( flags & C_EXTRA ){
502
+ Glob *pIgnore = glob_create(zIgnoreFlag);
503
+ locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
504
+ glob_free(pIgnore);
505
+ db_multi_exec("DELETE FROM sfile WHERE x IN (%s)",
506
+ fossil_all_reserved_names(0));
507
+ }
430508
431509
/* The status command prints general information before the change list. */
432510
if( !changes ){
433
- vid = db_lget_int("checkout", 0);
434511
fossil_print("repository: %s\n", db_repository_filename());
435512
fossil_print("local-root: %s\n", g.zLocalRoot);
436513
if( g.zConfigDbName ){
437514
fossil_print("config-db: %s\n", g.zConfigDbName);
438515
}
@@ -440,12 +517,23 @@
440517
show_common_info(vid, "checkout:", 1, 1);
441518
}
442519
db_record_repository_filename(0);
443520
}
444521
445
- /* Print all requested changes. */
446
- print_changes(flags);
522
+ /* Find and print all requested changes. */
523
+ blob_zero(&report);
524
+ status_report(&report, flags);
525
+ if( blob_size(&report) ){
526
+ if( showHdr ){
527
+ fossil_print("Changes for %s at %s:\n", db_get("project-name", "???"),
528
+ g.zLocalRoot);
529
+ }
530
+ blob_write_to_file(&report, "-");
531
+ }else if( verboseFlag ){
532
+ fossil_print(" (none)\n");
533
+ }
534
+ blob_reset(&report);
447535
448536
/* The status command ends with warnings about ambiguous leaves (forks). */
449537
if( !changes ){
450538
leaf_ambiguity_warning(vid, vid);
451539
}
@@ -666,59 +754,10 @@
666754
free(zFullName);
667755
}
668756
db_finalize(&q);
669757
}
670758
671
-/*
672
-** Create a TEMP table named SFILE and add all unmanaged files named on
673
-** the command-line to that table. If directories are named, then add
674
-** all unmanaged files contained underneath those directories. If there
675
-** are no files or directories named on the command-line, then add all
676
-** unmanaged files anywhere in the checkout.
677
-*/
678
-static void locate_unmanaged_files(
679
- int argc, /* Number of command-line arguments to examine */
680
- char **argv, /* values of command-line arguments */
681
- unsigned scanFlags, /* Zero or more SCAN_xxx flags */
682
- Glob *pIgnore1, /* Do not add files that match this GLOB */
683
- Glob *pIgnore2 /* Omit files matching this GLOB too */
684
-){
685
- Blob name; /* Name of a candidate file or directory */
686
- char *zName; /* Name of a candidate file or directory */
687
- int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
688
- int i; /* Loop counter */
689
- int nRoot; /* length of g.zLocalRoot */
690
-
691
- db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
692
- filename_collation());
693
- nRoot = (int)strlen(g.zLocalRoot);
694
- if( argc==0 ){
695
- blob_init(&name, g.zLocalRoot, nRoot - 1);
696
- vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
697
- blob_reset(&name);
698
- }else{
699
- for(i=0; i<argc; i++){
700
- file_canonical_name(argv[i], &name, 0);
701
- zName = blob_str(&name);
702
- isDir = file_wd_isdir(zName);
703
- if( isDir==1 ){
704
- vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
705
- }else if( isDir==0 ){
706
- fossil_warning("not found: %s", &zName[nRoot]);
707
- }else if( file_access(zName, R_OK) ){
708
- fossil_fatal("cannot open %s", &zName[nRoot]);
709
- }else{
710
- db_multi_exec(
711
- "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
712
- &zName[nRoot]
713
- );
714
- }
715
- blob_reset(&name);
716
- }
717
- }
718
-}
719
-
720759
/*
721760
** COMMAND: extras
722761
**
723762
** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
724763
**
725764
--- src/checkin.c
+++ src/checkin.c
@@ -25,14 +25,13 @@
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_UNMODIFIED, CB_EXTRA , CB_MERGE ,
32 CB_RELPATH, CB_SHA1SUM , CB_HEADER , CB_VERBOSE , CB_CLASSIFY, CB_FATAL ,
33 CB_COMMENT,
34
35 /* Bitmask values. */
36 C_EDITED = 1 << CB_EDITED, /* Edited, merged, and conflicted files. */
37 C_UPDATED = 1 << CB_UPDATED, /* Files updated by merge/integrate. */
38 C_CHANGED = 1 << CB_CHANGED, /* Treated the same as the above two. */
@@ -48,18 +47,64 @@
48 C_FILTER = C_EDITED | C_UPDATED | C_CHANGED | C_MISSING | C_ADDED
49 | C_DELETED | C_RENAMED | C_CONFLICT | C_META | C_UNMODIFIED
50 | C_EXTRA | C_MERGE,
51 C_ALL = C_FILTER & ~(C_EXTRA | C_MERGE),
52 C_RELPATH = 1 << CB_RELPATH, /* Show relative paths. */
53 C_SHA1SUM = 1 << CB_SHA1SUM, /* Use SHA1 checksums not mtimes. */
54 C_HEADER = 1 << CB_HEADER, /* Display repository name if non-empty. */
55 C_VERBOSE = 1 << CB_VERBOSE, /* Display "(none)" if empty. */
56 C_CLASSIFY = 1 << CB_CLASSIFY, /* Show file change types. */
57 C_DEFAULT = (C_ALL & ~C_UNMODIFIED) | C_MERGE | C_CLASSIFY,
58 C_FATAL = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
59 C_COMMENT = 1 << CB_COMMENT, /* Precede each line with "# ". */
60 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
62 /*
63 ** Generate text describing all changes.
64 **
65 ** We assume that vfile_check_signature has been run.
@@ -69,14 +114,15 @@
69 unsigned flags /* Filter and other configuration flags */
70 ){
71 Stmt q;
72 int nErr = 0;
73 Blob rewrittenPathname;
74 Blob where;
75 const char *zName;
76 int i;
77
 
78 blob_zero(&where);
79 for(i=2; i<g.argc; i++){
80 Blob fname;
81 file_tree_name(g.argv[i], &fname, 0, 1);
82 zName = blob_str(&fname);
@@ -91,28 +137,47 @@
91 filename_collation(), zName, filename_collation(),
92 zName, filename_collation()
93 );
94 }
95
96 db_prepare(&q,
97 "SELECT pathname, deleted, chnged,"
98 " rid, coalesce(origname!=pathname,0), islink"
99 " FROM vfile "
100 " WHERE is_selected(id) %s"
101 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
102 " ORDER BY 1 /*scan*/",
103 blob_sql_text(&where)
104 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105 blob_zero(&rewrittenPathname);
106 while( db_step(&q)==SQLITE_ROW ){
107 const char *zPathname = db_column_text(&q,0);
108 const char *zClass = 0;
 
109 int isDeleted = db_column_int(&q, 1);
110 int isChnged = db_column_int(&q,2);
111 int isNew = db_column_int(&q,3)==0;
112 int isRenamed = db_column_int(&q,4);
113 int isLink = db_column_int(&q,5);
114 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
115 int isMissing = !file_wd_isfile_or_link(zFullName);
116
117 /* Determine the file change classification, if any. */
118 if( (flags & C_DELETED) && isDeleted ){
@@ -150,20 +215,21 @@
150 }else if( (flags & C_META) && isChnged==9 ){
151 zClass = "UNLINK";
152 }else if( (flags & C_CONFLICT) && isChnged && !isLink
153 && file_contains_merge_marker(zFullName) ){
154 zClass = "CONFLICT";
155 }else if( (flags & (C_EDITED | C_CHANGED)) && (isChnged<2 || isChnged>9) ){
 
156 zClass = "EDITED";
157 }else if( (flags & C_RENAMED) && isRenamed ){
158 zClass = "RENAMED";
159 }else if( (flags & C_UNMODIFIED) && !isDeleted && !isMissing && !isNew
160 && !isChnged && !isRenamed ){
161 /* TODO: never gets executed because query only yields modified files. */
162 zClass = "UNMODIFIED";
 
 
163 }
164 /* TODO: implement C_EXTRA. */
165 /* TODO: reimplement ls and extras in terms of this function. */
166
167 /* Only report files for which a change classification was determined. */
168 if( zClass ){
169 /* If C_COMMENT, precede each line with "# ". */
@@ -243,38 +309,19 @@
243 if( absPathOption ){ relativePaths = 0; }
244 if( relPathOption ){ relativePaths = 1; }
245 return relativePaths;
246 }
247
248 void print_changes(
249 unsigned flags /* Configuration flags */
250 ){
251 Blob report;
252 int vid;
253 blob_zero(&report);
254
255 vid = db_lget_int("checkout", 0);
256 vfile_check_signature(vid, flags & C_SHA1SUM ? CKSIG_SHA1 : 0);
257 status_report(&report, flags);
258 if( (flags & C_VERBOSE) && blob_size(&report)==0 ){
259 blob_append(&report, " (none)\n", -1);
260 }
261 if( (flags & C_HEADER) && blob_size(&report)>0 ){
262 fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
263 g.zLocalRoot);
264 }
265 blob_write_to_file(&report, "-");
266 blob_reset(&report);
267 }
268
269 /*
270 ** COMMAND: changes
271 ** COMMAND: status
272 **
273 ** Usage: %fossil changes|status ?OPTIONS?
274 **
275 ** Report the change status of files in the current checkout.
 
 
276 **
277 ** The status command is similar to the changes command, except it lacks
278 ** several of the options supported by changes and it has its own header
279 ** and footer information. The header information is a subset of that
280 ** shown by the info command, and the footer shows if there are any forks.
@@ -318,10 +365,13 @@
318 ** --abs-paths Display absolute pathnames.
319 ** --rel-paths Display pathnames relative to the current working
320 ** directory.
321 ** --sha1sum Verify file status using SHA1 hashing rather than
322 ** relying on file mtimes.
 
 
 
323 **
324 ** Options specific to the changes command:
325 ** --header Identify the repository if report is non-empty.
326 ** -v|--verbose Say "(none)" if the change report is empty.
327 ** --classify Start each line with the file's change type.
@@ -356,28 +406,41 @@
356 {"changed" , C_CHANGED, 0}, {"missing" , C_MISSING , 0},
357 {"added" , C_ADDED , 0}, {"deleted" , C_DELETED , 0},
358 {"renamed" , C_RENAMED, 0}, {"conflict" , C_CONFLICT , 0},
359 {"meta" , C_META , 0}, {"unmodified" , C_UNMODIFIED, 0},
360 {"all" , C_ALL , 0}, {"extra" , C_EXTRA , 0},
361 {"merge" , C_MERGE , 0}, {"sha1sum" , C_SHA1SUM , 0},
362 {"header" , C_HEADER , 1}, {"v" , C_VERBOSE , 1},
363 {"verbose" , C_VERBOSE, 1}, {"classify" , C_CLASSIFY , 1},
364 }, noFlagDefs[] = {
365 {"no-merge", C_MERGE , 0}, {"no-classify", C_CLASSIFY , 1},
366 };
367
368 #ifdef FOSSIL_DEBUG
369 static const char *const bits[] = {
370 "EDITED", "UPDATED", "CHANGED", "MISSING", "ADDED", "DELETED", "RENAMED",
371 "CONFLICT", "META", "UNMODIFIED", "EXTRA", "MERGE", "RELPATH", "SHA1SUM",
372 "HEADER", "VERBOSE", "CLASSIFY",
373 };
374 #endif
375
 
 
 
 
 
 
376 int changes = g.argv[1][0]=='c';
377 unsigned flags = 0;
378 int vid, i;
 
 
 
 
 
 
 
 
 
 
379
380 /* Load affirmative flag options. */
381 for( i=0; i<count(flagDefs); ++i ){
382 if( (!flagDefs[i].changesOnly || changes)
383 && find_option(flagDefs[i].option, 0, 0) ){
@@ -409,10 +472,13 @@
409 }
410
411 /* Confirm current working directory is within checkout. */
412 db_must_be_within_tree();
413
 
 
 
414 /* Relative path flag determination is done by a shared function. */
415 if( determine_cwd_relative_option() ){
416 flags |= C_RELPATH;
417 }
418
@@ -425,14 +491,25 @@
425 printf("\n");
426 #endif
427
428 /* We should be done with options. */
429 verify_all_options();
 
 
 
 
 
 
 
 
 
 
 
 
430
431 /* The status command prints general information before the change list. */
432 if( !changes ){
433 vid = db_lget_int("checkout", 0);
434 fossil_print("repository: %s\n", db_repository_filename());
435 fossil_print("local-root: %s\n", g.zLocalRoot);
436 if( g.zConfigDbName ){
437 fossil_print("config-db: %s\n", g.zConfigDbName);
438 }
@@ -440,12 +517,23 @@
440 show_common_info(vid, "checkout:", 1, 1);
441 }
442 db_record_repository_filename(0);
443 }
444
445 /* Print all requested changes. */
446 print_changes(flags);
 
 
 
 
 
 
 
 
 
 
 
447
448 /* The status command ends with warnings about ambiguous leaves (forks). */
449 if( !changes ){
450 leaf_ambiguity_warning(vid, vid);
451 }
@@ -666,59 +754,10 @@
666 free(zFullName);
667 }
668 db_finalize(&q);
669 }
670
671 /*
672 ** Create a TEMP table named SFILE and add all unmanaged files named on
673 ** the command-line to that table. If directories are named, then add
674 ** all unmanaged files contained underneath those directories. If there
675 ** are no files or directories named on the command-line, then add all
676 ** unmanaged files anywhere in the checkout.
677 */
678 static void locate_unmanaged_files(
679 int argc, /* Number of command-line arguments to examine */
680 char **argv, /* values of command-line arguments */
681 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
682 Glob *pIgnore1, /* Do not add files that match this GLOB */
683 Glob *pIgnore2 /* Omit files matching this GLOB too */
684 ){
685 Blob name; /* Name of a candidate file or directory */
686 char *zName; /* Name of a candidate file or directory */
687 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
688 int i; /* Loop counter */
689 int nRoot; /* length of g.zLocalRoot */
690
691 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
692 filename_collation());
693 nRoot = (int)strlen(g.zLocalRoot);
694 if( argc==0 ){
695 blob_init(&name, g.zLocalRoot, nRoot - 1);
696 vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
697 blob_reset(&name);
698 }else{
699 for(i=0; i<argc; i++){
700 file_canonical_name(argv[i], &name, 0);
701 zName = blob_str(&name);
702 isDir = file_wd_isdir(zName);
703 if( isDir==1 ){
704 vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
705 }else if( isDir==0 ){
706 fossil_warning("not found: %s", &zName[nRoot]);
707 }else if( file_access(zName, R_OK) ){
708 fossil_fatal("cannot open %s", &zName[nRoot]);
709 }else{
710 db_multi_exec(
711 "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
712 &zName[nRoot]
713 );
714 }
715 blob_reset(&name);
716 }
717 }
718 }
719
720 /*
721 ** COMMAND: extras
722 **
723 ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
724 **
725
--- src/checkin.c
+++ src/checkin.c
@@ -25,14 +25,13 @@
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_UNMODIFIED, CB_EXTRA, CB_MERGE ,
32 CB_RELPATH, CB_CLASSIFY, 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. */
@@ -48,18 +47,64 @@
47 C_FILTER = C_EDITED | C_UPDATED | C_CHANGED | C_MISSING | C_ADDED
48 | C_DELETED | C_RENAMED | C_CONFLICT | C_META | C_UNMODIFIED
49 | C_EXTRA | C_MERGE,
50 C_ALL = C_FILTER & ~(C_EXTRA | C_MERGE),
51 C_RELPATH = 1 << CB_RELPATH, /* Show relative paths. */
 
 
 
52 C_CLASSIFY = 1 << CB_CLASSIFY, /* Show file change types. */
53 C_DEFAULT = (C_ALL & ~C_UNMODIFIED) | C_MERGE | C_CLASSIFY,
54 C_FATAL = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
55 C_COMMENT = 1 << CB_COMMENT, /* Precede each line with "# ". */
56 };
57
58 /*
59 ** Create a TEMP table named SFILE and add all unmanaged files named on
60 ** the command-line to that table. If directories are named, then add
61 ** all unmanaged files contained underneath those directories. If there
62 ** are no files or directories named on the command-line, then add all
63 ** unmanaged files anywhere in the checkout.
64 */
65 static void locate_unmanaged_files(
66 int argc, /* Number of command-line arguments to examine */
67 char **argv, /* values of command-line arguments */
68 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
69 Glob *pIgnore1, /* Do not add files that match this GLOB */
70 Glob *pIgnore2 /* Omit files matching this GLOB too */
71 ){
72 Blob name; /* Name of a candidate file or directory */
73 char *zName; /* Name of a candidate file or directory */
74 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
75 int i; /* Loop counter */
76 int nRoot; /* length of g.zLocalRoot */
77
78 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
79 filename_collation());
80 nRoot = (int)strlen(g.zLocalRoot);
81 if( argc==0 ){
82 blob_init(&name, g.zLocalRoot, nRoot - 1);
83 vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
84 blob_reset(&name);
85 }else{
86 for(i=0; i<argc; i++){
87 file_canonical_name(argv[i], &name, 0);
88 zName = blob_str(&name);
89 isDir = file_wd_isdir(zName);
90 if( isDir==1 ){
91 vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
92 }else if( isDir==0 ){
93 fossil_warning("not found: %s", &zName[nRoot]);
94 }else if( file_access(zName, R_OK) ){
95 fossil_fatal("cannot open %s", &zName[nRoot]);
96 }else{
97 db_multi_exec(
98 "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
99 &zName[nRoot]
100 );
101 }
102 blob_reset(&name);
103 }
104 }
105 }
106
107 /*
108 ** Generate text describing all changes.
109 **
110 ** We assume that vfile_check_signature has been run.
@@ -69,14 +114,15 @@
114 unsigned flags /* Filter and other configuration flags */
115 ){
116 Stmt q;
117 int nErr = 0;
118 Blob rewrittenPathname;
119 Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER;
120 const char *zName;
121 int i;
122
123 /* Assemble the path-limiting WHERE clause, if any. */
124 blob_zero(&where);
125 for(i=2; i<g.argc; i++){
126 Blob fname;
127 file_tree_name(g.argv[i], &fname, 0, 1);
128 zName = blob_str(&fname);
@@ -91,28 +137,47 @@
137 filename_collation(), zName, filename_collation(),
138 zName, filename_collation()
139 );
140 }
141
142 /* Start building the SELECT statement. */
143 blob_zero(&sql);
144 blob_append_sql(&sql,
145 "SELECT pathname, deleted, chnged, rid,"
146 " coalesce(origname!=pathname,0) AS renamed, islink, 1 AS managed"
147 " FROM vfile"
148 " WHERE is_selected(id)%s", blob_sql_text(&where));
149
150 /* Exclude unmodified files unless requested. */
151 if( !(flags & C_UNMODIFIED) ){
152 blob_append_sql(&sql,
153 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)");
154 }
155
156 /* If C_EXTRA, add unmanaged files to the query result too. */
157 if( flags & C_EXTRA ){
158 blob_append_sql(&sql, " UNION ALL SELECT x AS pathname, 0, 0, 0, 0, 0, 0"
159 " FROM sfile WHERE 1%s", blob_sql_text(&where));
160 }
161
162 /* Append an ORDER BY clause then compile the query. */
163 blob_append_sql(&sql, " ORDER BY pathname");
164 db_prepare(&q, "%s", blob_sql_text(&sql));
165 blob_reset(&sql);
166 blob_reset(&where);
167
168 /* Execute the query and assemble the report. */
169 blob_zero(&rewrittenPathname);
170 while( db_step(&q)==SQLITE_ROW ){
171 const char *zPathname = db_column_text(&q, 0);
172 const char *zClass = 0;
173 int isManaged = db_column_int(&q, 6);
174 int isDeleted = db_column_int(&q, 1);
175 int isChnged = db_column_int(&q, 2);
176 int isNew = isManaged && !db_column_int(&q, 3);
177 int isRenamed = db_column_int(&q, 4);
178 int isLink = db_column_int(&q, 5);
179 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
180 int isMissing = !file_wd_isfile_or_link(zFullName);
181
182 /* Determine the file change classification, if any. */
183 if( (flags & C_DELETED) && isDeleted ){
@@ -150,20 +215,21 @@
215 }else if( (flags & C_META) && isChnged==9 ){
216 zClass = "UNLINK";
217 }else if( (flags & C_CONFLICT) && isChnged && !isLink
218 && file_contains_merge_marker(zFullName) ){
219 zClass = "CONFLICT";
220 }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
221 && (isChnged<2 || isChnged>9) ){
222 zClass = "EDITED";
223 }else if( (flags & C_RENAMED) && isRenamed ){
224 zClass = "RENAMED";
225 }else if( (flags & C_UNMODIFIED) && isManaged && !isDeleted && !isMissing
226 && !isNew && !isChnged && !isRenamed ){
 
227 zClass = "UNMODIFIED";
228 }else if( (flags & C_EXTRA) && !isManaged ){
229 zClass = "EXTRA";
230 }
 
231 /* TODO: reimplement ls and extras in terms of this function. */
232
233 /* Only report files for which a change classification was determined. */
234 if( zClass ){
235 /* If C_COMMENT, precede each line with "# ". */
@@ -243,38 +309,19 @@
309 if( absPathOption ){ relativePaths = 0; }
310 if( relPathOption ){ relativePaths = 1; }
311 return relativePaths;
312 }
313
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314 /*
315 ** COMMAND: changes
316 ** COMMAND: status
317 **
318 ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
319 **
320 ** Report the change status of files in the current checkout. If one or
321 ** more PATHS are specified, only changes among the named files and
322 ** directories are reported. Directories are searched recursively.
323 **
324 ** The status command is similar to the changes command, except it lacks
325 ** several of the options supported by changes and it has its own header
326 ** and footer information. The header information is a subset of that
327 ** shown by the info command, and the footer shows if there are any forks.
@@ -318,10 +365,13 @@
365 ** --abs-paths Display absolute pathnames.
366 ** --rel-paths Display pathnames relative to the current working
367 ** directory.
368 ** --sha1sum Verify file status using SHA1 hashing rather than
369 ** relying on file mtimes.
370 ** --case-sensitive <BOOL> Override case-sensitive setting.
371 ** --dotfiles Include unmanaged files beginning with a dot.
372 ** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
373 **
374 ** Options specific to the changes command:
375 ** --header Identify the repository if report is non-empty.
376 ** -v|--verbose Say "(none)" if the change report is empty.
377 ** --classify Start each line with the file's change type.
@@ -356,28 +406,41 @@
406 {"changed" , C_CHANGED, 0}, {"missing" , C_MISSING , 0},
407 {"added" , C_ADDED , 0}, {"deleted" , C_DELETED , 0},
408 {"renamed" , C_RENAMED, 0}, {"conflict" , C_CONFLICT , 0},
409 {"meta" , C_META , 0}, {"unmodified" , C_UNMODIFIED, 0},
410 {"all" , C_ALL , 0}, {"extra" , C_EXTRA , 0},
411 {"merge" , C_MERGE , 0}, {"classify" , C_CLASSIFY , 1},
 
 
412 }, noFlagDefs[] = {
413 {"no-merge", C_MERGE , 0}, {"no-classify", C_CLASSIFY , 1},
414 };
415
416 #ifdef FOSSIL_DEBUG
417 static const char *const bits[] = {
418 "EDITED", "UPDATED", "CHANGED", "MISSING", "ADDED", "DELETED", "RENAMED",
419 "CONFLICT", "META", "UNMODIFIED", "EXTRA", "MERGE", "RELPATH", "CLASSIFY",
 
420 };
421 #endif
422
423 Blob report = BLOB_INITIALIZER;
424 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
425 int showHdr = find_option("header",0,0)!=0;
426 int verboseFlag = find_option("verbose","v",0)!=0;
427 const char *zIgnoreFlag = find_option("ignore", 0, 1);
428 unsigned scanFlags = 0;
429 int changes = g.argv[1][0]=='c';
430 unsigned flags = 0;
431 int vid, i;
432
433 /* If --ignore is not specified, use the ignore-glob setting. */
434 if( !zIgnoreFlag ){
435 zIgnoreFlag = db_get("ignore-glob", 0);
436 }
437
438 /* Get the --dotfiles argument, or read it from the dotfiles setting. */
439 if( find_option("dotfiles", 0, 0) || db_get_boolean("dotfiles", 0) ){
440 scanFlags = SCAN_ALL;
441 }
442
443 /* Load affirmative flag options. */
444 for( i=0; i<count(flagDefs); ++i ){
445 if( (!flagDefs[i].changesOnly || changes)
446 && find_option(flagDefs[i].option, 0, 0) ){
@@ -409,10 +472,13 @@
472 }
473
474 /* Confirm current working directory is within checkout. */
475 db_must_be_within_tree();
476
477 /* Get checkout version. l*/
478 vid = db_lget_int("checkout", 0);
479
480 /* Relative path flag determination is done by a shared function. */
481 if( determine_cwd_relative_option() ){
482 flags |= C_RELPATH;
483 }
484
@@ -425,14 +491,25 @@
491 printf("\n");
492 #endif
493
494 /* We should be done with options. */
495 verify_all_options();
496
497 /* Check for changed files. */
498 vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
499
500 /* Search for unmanaged files if requested. Exclude reserved files. */
501 if( flags & C_EXTRA ){
502 Glob *pIgnore = glob_create(zIgnoreFlag);
503 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
504 glob_free(pIgnore);
505 db_multi_exec("DELETE FROM sfile WHERE x IN (%s)",
506 fossil_all_reserved_names(0));
507 }
508
509 /* The status command prints general information before the change list. */
510 if( !changes ){
 
511 fossil_print("repository: %s\n", db_repository_filename());
512 fossil_print("local-root: %s\n", g.zLocalRoot);
513 if( g.zConfigDbName ){
514 fossil_print("config-db: %s\n", g.zConfigDbName);
515 }
@@ -440,12 +517,23 @@
517 show_common_info(vid, "checkout:", 1, 1);
518 }
519 db_record_repository_filename(0);
520 }
521
522 /* Find and print all requested changes. */
523 blob_zero(&report);
524 status_report(&report, flags);
525 if( blob_size(&report) ){
526 if( showHdr ){
527 fossil_print("Changes for %s at %s:\n", db_get("project-name", "???"),
528 g.zLocalRoot);
529 }
530 blob_write_to_file(&report, "-");
531 }else if( verboseFlag ){
532 fossil_print(" (none)\n");
533 }
534 blob_reset(&report);
535
536 /* The status command ends with warnings about ambiguous leaves (forks). */
537 if( !changes ){
538 leaf_ambiguity_warning(vid, vid);
539 }
@@ -666,59 +754,10 @@
754 free(zFullName);
755 }
756 db_finalize(&q);
757 }
758
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
759 /*
760 ** COMMAND: extras
761 **
762 ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
763 **
764

Keyboard Shortcuts

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