Fossil SCM

Added ability for "/local" to display files present in the checkout but not managed by Fossil (cf. "fossil extras").

graham 2020-06-01 22:12 ui-local-diff
Commit 07829f371b1c0c9ee287c018b2755fa78f65c0d2c5946caeaea2a933cd3b9257
2 files changed +1 -1 +373 -26
+1 -1
--- src/checkin.c
+++ src/checkin.c
@@ -63,11 +63,11 @@
6363
** the command-line to that table. If directories are named, then add
6464
** all unmanaged files contained underneath those directories. If there
6565
** are no files or directories named on the command-line, then add all
6666
** unmanaged files anywhere in the checkout.
6767
*/
68
-static void locate_unmanaged_files(
68
+void locate_unmanaged_files(
6969
int argc, /* Number of command-line arguments to examine */
7070
char **argv, /* values of command-line arguments */
7171
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
7272
Glob *pIgnore /* Do not add files that match this GLOB */
7373
){
7474
--- src/checkin.c
+++ src/checkin.c
@@ -63,11 +63,11 @@
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
--- src/checkin.c
+++ src/checkin.c
@@ -63,11 +63,11 @@
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 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
+373 -26
--- src/info.c
+++ src/info.c
@@ -1,15 +1,20 @@
1
-/*TODO
2
-** o Have seen some "MERGE" entries and updated messages: still not 100% happy.
1
+/*TODO Graham's Notes
32
** o Should /file behave differently for non-existent local files?
4
-** o Look at adding an "extras" option (non-added, non-ignored files).
53
** o Find a place to add links to /local.
64
** o Remove //TODO TESTING HACK TODO
75
** ?? In hexdump_page(), should content (and downloadName?) be reset/freed?
8
-** ?? In the test fossil (\x\$Test\Fossil) there are (at time of writing) two
9
-** commits under the same artifact... is this normal?
10
-** ?? A settings entry to control one- or two-pass mode?
6
+** ?? In clean_cmd() in checkin.c, should "Blob repo" be blob_reset()?
7
+** ?? Do I need to worry about deleting/emptying TEMP SFILE?
8
+** ?? Is it normal for one artifact to have several check-ins associated with
9
+** it? In the test fossil (\x\$Test\Fossil) there are several commits under
10
+** the same artifact...
11
+** ?? A setting to control one- or two-pass mode?
12
+** ?? Add two-pass to the normal loop?
13
+** ?? A setting to control whether Extras are intially shown or not?
14
+** ?? A setting to control max. entries to show initially?
15
+**------------------------------------------------------------------------------
1116
*/
1217
/*
1318
** Copyright (c) 2007 D. Richard Hipp
1419
**
1520
** This program is free software; you can redistribute it and/or
@@ -568,11 +573,11 @@
568573
}else{
569574
@ Missing %h(zName) (was added to checkout).
570575
}
571576
}else switch( isChnged ){
572577
/*TODO
573
- ** These "special cases" have not been properly tested (by creating
578
+ ** These "special cases" have not all been properly tested (by creating
574579
** entries in a in a repository to trigger them), but they do display
575580
** as expected when "forced" to appear.
576581
*/
577582
case 3:
578583
@ Added %h(zName) due to a merge.
@@ -825,10 +830,305 @@
825830
www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
826831
0, 0, 0, rid, 0, 0);
827832
db_finalize(&q);
828833
style_footer();
829834
}
835
+
836
+/*
837
+** Options for the "extras" report. The bit-mask versions are used for "&ef=.."
838
+** to select which category(ies) to show.
839
+*/
840
+enum {
841
+ EXB_PLAIN, EXB_IGNORE, EXB_CLEAN, EXB_KEEP,
842
+
843
+ EX_PLAIN = 1 << EXB_PLAIN, /* Matches none of the others */
844
+ EX_IGNORE = 1 << EXB_IGNORE, /* Matches "ignore-glob" */
845
+ EX_CLEAN = 1 << EXB_CLEAN, /* Matches "clean-glob" */
846
+ EX_KEEP = 1 << EXB_KEEP, /* Matches "keep-glob" */
847
+ EX_ALL = EX_PLAIN /* All entries */
848
+ | EX_IGNORE
849
+ | EX_CLEAN
850
+ | EX_KEEP
851
+};
852
+
853
+/*
854
+** Called while generating "/local": appends a report of any "extra" files that
855
+** might be present in the current checkout.
856
+**
857
+** The format is controlled by "zExtra" (the value from the "ex=" URL option).
858
+** This is converted to an int ("extrasFlags") and treated as a collection of
859
+** the EX_xxx flags defined above. Thus "1" will list all "plain" files:
860
+** unmanaged files that match none of the ignore/clean/keep blob-lists, and "2"
861
+** would list all files matching the ignore-blob setting. "3" would list both
862
+** those sets of files.
863
+**
864
+** An empty "zExtra" is a special case: it converts to zero which would normally
865
+** select none of the EX_xxx flags above. Instead, it is converted to EX_PLAIN
866
+** (=1) but with a (smallish) upper-limit on the number of files that will be
867
+** listed. This is the "default" mode as it offers a combination of usefulness
868
+** and non-intrusiveness:
869
+** o If the glob-lists are configured well, the only files that will show are
870
+** likely to be new source files that have not been "fossil add"ed.
871
+** o If the glob-lists HAVEN'T been configured, only a relatively small number
872
+** of temporary files (e.g. ".o" or ".obj") will be shown.
873
+**
874
+*/
875
+static void append_extras_report(
876
+ const char *zExtra, /* Value of "ef=" from URL */
877
+ const int diffType, /* Used to preserve current */
878
+ const char *zW /* settings in URLs */
879
+){
880
+ const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
881
+ Glob *pIgnore, *pKeep, *pClean;
882
+ int nRoot;
883
+ zIgnoreFlag = db_get("ignore-glob", 0); /* Patterns to ignore */
884
+ zCleanFlag = db_get("clean-glob", 0); /* ...that "clean" clobbers */
885
+ zKeepFlag = db_get("keep-glob", 0); /* ...that "clean" won't touch */
886
+ pIgnore = glob_create(zIgnoreFlag); /* Object versions of above */
887
+ pKeep = glob_create(zKeepFlag);
888
+ pClean = glob_create(zCleanFlag);
889
+ nRoot = (int)strlen(g.zLocalRoot); /* Length of root component */
890
+ Stmt q;
891
+ Blob repo; /* TODO May not be needed */
892
+ int maxExtrasToShow = 5; /* TODO Take from a setting? */
893
+ int extrasFlags = atoi(zExtra); /* Which entries to show */
894
+ int nExtras;
895
+ int nMatch;
896
+ int nShown;
897
+ int nPlain;
898
+ int nIgnore;
899
+ int nClean;
900
+ int nKeep;
901
+
902
+ /*TODO?
903
+ ** It feels sensible to limit the number of "extra" entries shown by default
904
+ ** for cases where "ignore-glob" or "clean-glob" haven't been fully setup.
905
+ ** A minor irritation is that this can lead to "... plus 1 more file", on a
906
+ ** line that COULD have been used to display the omitted file. If we knew in
907
+ ** advance how many entries were going to match, we could temporarily "bump"
908
+ ** the limit by one show all entries would be shown. However, to know the
909
+ ** number of matches in advance we'd have to:
910
+ ** a) Pre-scan SFILE, testing and counting matches against each glob-list,
911
+ ** possibly bump the limit, then re-scan the table repeating the tests
912
+ ** against each glob-list to decide which to show.
913
+ ** b) SFILE could have an extra FLAGS field: during the pre-scan, this could
914
+ ** be updated to indicate which groups each file belong to. This would
915
+ ** save re-testing every file against each glob-list (the main pass could
916
+ ** select "WHERE flags & selector" to get only the matching entries, but
917
+ ** the updates (selecting by "pathname" each time) could be a bit much.
918
+ ** c) vfile_scan() -- where SFILE is populated -- COULD have an option to
919
+ ** do the testing at the time entries are added. This would be the "best"
920
+ ** way, but feels too much disruption to other code for what is only a
921
+ ** minor benefit.
922
+ ** For now, I'll stick with the minor annoyance of "plus 1 more file" :-)
923
+ **
924
+ ** Being able to determine the counts up-front would also allow us to hide
925
+ ** the "extras report" if there were no unmanaged files.
926
+ **
927
+ **TODO?
928
+ ** Does it make sense (and/or is it practiable) to offer an "ADD" button
929
+ ** against files that are unmanaged?
930
+ **
931
+ **TODO?
932
+ ** Does it make sense (and/or ...) to offer ediing of the various blob-lists
933
+ ** from the Extras report? Showing the existing configuration screen would
934
+ ** probably not be a problem (permissions permitting), but what happens if
935
+ ** those settings have been overriden by .fossil-settings/ignore-glob? As we
936
+ ** have access to the local checkout, is it feasible to edit it in the browser
937
+ ** (perhaps piggy-backing /fileedit)?
938
+ */
939
+
940
+ locate_unmanaged_files(0, NULL, 0, NULL); /* Get all unmanaged */
941
+ /*TODO
942
+ ** The first two of these exclusions come from clean_cmd() in checkin.c.
943
+ ** Not sure exactly what they are intended to do (seem to have no effect on
944
+ ** my test repos). Last exclusion is an alternative to the WHERE clause above
945
+ ** so that COUNT(*) returns the correct value. TODO Even though, as noted
946
+ ** above, getting the count ahead of time is of little use (it was used to
947
+ ** bump the display limit if only one entry would be omitted), I'll probably
948
+ ** retain omitting the WHERE, and using DELETE FROM to exclude reserved
949
+ ** names, just in case (c) above was implemented.
950
+ */
951
+ /*TODO deletions from clean_cmd() */
952
+ if( file_tree_name(g.zRepositoryName, &repo, 0, 0) ){
953
+ db_multi_exec("DELETE FROM sfile WHERE pathname=%B", &repo);
954
+ }
955
+ db_multi_exec("DELETE FROM sfile WHERE pathname IN"
956
+ " (SELECT pathname FROM vfile)");
957
+ /*TODO Delete reserved names, rather than WHERE them out. */
958
+ db_multi_exec("DELETE FROM sfile WHERE pathname IN (%s)",
959
+ fossil_all_reserved_names(0));
960
+
961
+ /*TODO
962
+ ** If we had a count of matching entries before scanning, this is where
963
+ ** we'd bump the maximum to show so as to avoid "plus 1 file".
964
+ ** ...
965
+ ** If there's only one more than the maximum, let it through...
966
+ ** a line used to say "plus 1 more" may as well display that item!
967
+ if( nExtras == maxExtrasToShow+1 ){ maxExtrasToShow++; }
968
+ ** ...
969
+ */
970
+
971
+ /* Handle the special case where zExtra was empty (and got converted to zero).
972
+ ** If so, show "plain" files (those not matching any glob-list) but with an
973
+ ** upper limit to the number shown (set above). If a value WAS given (i.e.
974
+ ** after following a link), display all of the selected entries.
975
+ */
976
+ if( extrasFlags==0 ){
977
+ extrasFlags = EX_PLAIN;
978
+ }else{
979
+ maxExtrasToShow = 0x7fffffff; /* Basically, all of them... */
980
+ }
981
+
982
+ /* Describe the files listed. Currently, the only "built-in" options are to
983
+ ** list "plain" files (those unmanaged files not matching any glob-list),
984
+ ** or to list those files matching ONE of the glob-lists. However, manual
985
+ ** editing would allow selecting combinations of matching files.
986
+ **
987
+ ** If only EX_PLAIN is present, then other types are explicitly excluded
988
+ ** by definition: PLAIN means "not matching any glob-list". For all other
989
+ ** cases, we cannot say things like "not ignored" because a file can match
990
+ ** more than one list.
991
+ */
992
+ @ <p><b>Extra Files
993
+ if( extrasFlags == EX_PLAIN ){
994
+ @ (unmanaged, not ignored, not for cleaning, not kept)
995
+ }else{
996
+ Blob desc;
997
+ blob_zero(&desc);
998
+ if( extrasFlags & EX_PLAIN ){ blob_appendf(&desc, " + unmanaged" ); }
999
+ if( extrasFlags & EX_IGNORE ){ blob_appendf(&desc, " + ignored" ); }
1000
+ if( extrasFlags & EX_CLEAN ){ blob_appendf(&desc, " + to be cleaned"); }
1001
+ if( extrasFlags & EX_KEEP ){ blob_appendf(&desc, " + to be kept" ); }
1002
+ if( blob_size(&desc) > 3 ){ /* Should never fail... */
1003
+ /* Add the string built above, skipping the leading " + " */
1004
+ @ (%h(blob_str(&desc)+3))
1005
+ }
1006
+ blob_reset(&desc);
1007
+ }
1008
+ @ </b></p>
1009
+
1010
+ db_prepare(&q,
1011
+ "SELECT %Q || pathname FROM sfile"
1012
+ " ORDER BY 1", //TODO Order by pathname?
1013
+ g.zLocalRoot
1014
+ );
1015
+ /*
1016
+ ** Put the file-list in one paragraph with line-breaks between.
1017
+ **TODO
1018
+ ** Might a table (with columns for name, ignore/clean/keep) work?
1019
+ */
1020
+ @ <p>
1021
+ nExtras = nMatch = nShown = nPlain = nKeep = nClean = nIgnore = 0;
1022
+ while( db_step(&q)==SQLITE_ROW ){
1023
+ const char *zName = db_column_text(&q, 0);
1024
+ int entryFlags = 0
1025
+ | ( glob_match(pIgnore, zName+nRoot) ? EX_IGNORE : 0 )
1026
+ | ( glob_match(pClean, zName+nRoot) ? EX_CLEAN : 0 )
1027
+ | ( glob_match(pKeep, zName+nRoot) ? EX_KEEP : 0 ) ;
1028
+ if( entryFlags == 0 ){
1029
+ entryFlags = EX_PLAIN;
1030
+ }
1031
+ if( entryFlags & EX_PLAIN ){ nPlain++; }
1032
+ if( entryFlags & EX_IGNORE ){ nIgnore++; }
1033
+ if( entryFlags & EX_CLEAN ){ nClean++; }
1034
+ if( entryFlags & EX_KEEP ){ nKeep++; }
1035
+
1036
+ nExtras++;
1037
+ if( entryFlags & extrasFlags ){
1038
+ nMatch++ ;
1039
+ if( nShown < maxExtrasToShow ){
1040
+ nShown++;
1041
+ if( g.perm.Hyperlink ){
1042
+ @ %z(href("%R/file/%T?ci=ckout&annot=not managed",zName+nRoot))
1043
+ @ %h(zName+nRoot)</a>
1044
+ }else{
1045
+ @ %h(zName+nRoot)
1046
+ }
1047
+ if( entryFlags & EX_IGNORE ){
1048
+ @ (marked ignore)
1049
+ }
1050
+ if( entryFlags & EX_CLEAN ){
1051
+ @ (marked clean)
1052
+ }
1053
+ if( entryFlags & EX_KEEP ){
1054
+ @ (marked keep)
1055
+ }
1056
+ @ <br/>
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ if( nShown < nMatch ){
1062
+ const int nHidden = nMatch - nShown;
1063
+ @ ... plus %d(nHidden) other matching file%h(nHidden==1?"":"s")
1064
+ @ (%z(href("/local?diff=%d%s&ef=%d",diffType,zW,extrasFlags))
1065
+ @ show all)</a>.
1066
+ }
1067
+ @ </p>
1068
+
1069
+ @ <p>
1070
+ if( nExtras==0 ){
1071
+ @ No unmanaged files in checkout\
1072
+ }else if( (nPlain==0) && (P("ef")==NULL) ){
1073
+ @ No extra files in checkout
1074
+ @ (%z(href("%R/local?diff=%d%s&ef=1",diffType,zW))show exclusions</a>)\
1075
+ }else{
1076
+ /* Report types and counts of extra files, with links to see all of the
1077
+ ** selected type. Note the extra space before "including": the output of
1078
+ ** append_count() ends with "\" to get the formatting correct.
1079
+ */
1080
+ append_count( EX_ALL, nExtras, "extra file", 1, 0, diffType,zW );
1081
+ @ including
1082
+ append_count( EX_PLAIN, nPlain, "unmanaged", 0, 1, diffType,zW );
1083
+ append_count( EX_IGNORE, nIgnore, "marked ignore", 0, 1, diffType,zW );
1084
+ append_count( EX_CLEAN, nClean, "to be cleaned", 0, 1, diffType,zW );
1085
+ append_count( EX_KEEP, nKeep, "to be kept", 0, 1, diffType,zW );
1086
+ }
1087
+ @ .</p><hr/>
1088
+ blob_reset(&repo);
1089
+ db_finalize(&q);
1090
+}
1091
+
1092
+/*
1093
+** Append "26 extra files" type message as a link (assuming count is non-zero),
1094
+** with pluralisation if requested and needed. If "commaBefore" is true, the
1095
+** link is preceded by ", " if there have been earler entries with commaBefore
1096
+** set. If false, it resets the count. This allows correct construction of
1097
+** variants like:
1098
+** 27 extra files including 27 ignored.
1099
+** 30 extra files including 3 unmanaged, 27 ignored.
1100
+** The dt (diffType) and zW parameters pass on formatting selections from the
1101
+** rest of the /local page.
1102
+*/
1103
+void append_count(
1104
+ int ef, /* Flags for link */
1105
+ int count, /* Number of files */
1106
+ const char *linkText, /* Link text after count */
1107
+ int pluralise, /* Add optional "s"? */
1108
+ int commaBefore, /* Precede with ", " if earlier non-zero counts */
1109
+ int dt, /* DiffType */
1110
+ const char *zW /* Whitespace setting ("" or "&w") */
1111
+){
1112
+ static int earlierCounts = 0;
1113
+ if( count == 0 ){
1114
+ return;
1115
+ }
1116
+ if( !commaBefore ){
1117
+ earlierCounts = 0 ;
1118
+ }else if( earlierCounts ){
1119
+ @ ,
1120
+ }
1121
+ @ %z(href("%R/local?diff=%d%s&ef=%d",dt,zW,ef))%d(count) %h(linkText)\
1122
+ if( pluralise ){
1123
+ @ %h(count==1?"":"s")\
1124
+ }
1125
+ @ </a>\
1126
+ if( commaBefore ){
1127
+ earlierCounts += count;
1128
+ }
1129
+}
8301130
8311131
/*
8321132
** WEBPAGE: vinfo
8331133
** WEBPAGE: ci
8341134
** WEBPAGE: local
@@ -842,11 +1142,12 @@
8421142
** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
8431143
** or a tag or branch name that identifies the check-in.
8441144
**
8451145
** Use of /local (or the use of "ckout" for ARTIFACTID) will show the
8461146
** same header details as /ci/tip, but then displays any (uncommitted)
847
-** edits made to files in the checkout directory.
1147
+** edits made to files in the checkout directory. It can also display
1148
+** any "extra" files (roughly equivalent to "fossil extras").
8481149
*/
8491150
void ci_page(void){
8501151
Stmt q1, q2, q3;
8511152
int rid;
8521153
int isLeaf;
@@ -861,20 +1162,48 @@
8611162
const char *zPage = "vinfo"; /* Page that shows diffs */
8621163
const char *zPageHide = "ci"; /* Page that hides diffs */
8631164
const char *zBrName; /* Branch name */
8641165
int bLocalMode; /* TRUE for /local; FALSE otherwise */
8651166
int vid; /* Virtual file system? */
1167
+ int showExtras; /* Whether to show the extras report */
1168
+ const char *zExtra; /* How to show the report */
8661169
8671170
login_check_credentials();
8681171
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
8691172
zName = P("name");
1173
+ /*
1174
+ ** "zExtra" controls if, and how, the "extras report" is displayed. It is a
1175
+ ** string, because when passed around in the URL (as "ef=") a value of "" has
1176
+ ** a different meaning to "0". A value of "" means "show a limited number of
1177
+ ** unmanaged files" (those that aren't ignored, marked to be cleaned, or
1178
+ ** marked kept)... this is what you'd most want to see if you've created a new
1179
+ ** source file and forgotten to "fossil add" it. A value of "0" will hide the
1180
+ ** extras report. Other (numeric) values control what the report shows (e.g.
1181
+ ** "1" would list ALL unmanaged files without limiting their number).
1182
+ **
1183
+ ** If the "ef=" isn't present (as when first navigating to "/local") then a
1184
+ ** default setting is used. Set to "0" to initially hide the report.
1185
+ */
1186
+ zExtra = P("ef");
1187
+ if( zExtra==NULL ) {
1188
+ zExtra = ""; /*TODO Take the default form a config. option? */
1189
+ }
1190
+ showExtras = strcmp(zExtra,"0")!=0;
1191
+
8701192
/* Local mode is selected by either "/local" or with a "name" of "ckout".
8711193
** First, check we have access to the checkout (and report to the user if we
8721194
** don't), then refresh the "vfile" table (recording which files in the
8731195
** checkout have changed etc.). We then change the "name" parameter to "tip"
8741196
** so that the "header" section displays info about the check-in that the
8751197
** checkout came from.
1198
+ **TODO
1199
+ ** It would probably make sense to limit "/local" (and other links that come
1200
+ ** from it) to only be permitted when Fossil is running locally in "ui" mode.
1201
+ ** It's probably not critical when all you can do is view files in the
1202
+ ** checkout (they can already see the checked-in versions), but if a COMMIT
1203
+ ** option WERE ever to be implemented, you wouldn't essentially random people
1204
+ ** on the internet firing off commits.
8761205
*/
8771206
bLocalMode = (g.zPath[0]=='l') || (fossil_strcmp(zName,"ckout")==0);
8781207
if( bLocalMode ){
8791208
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
8801209
if( vid==0 ){
@@ -911,11 +1240,11 @@
9111240
" WHERE blob.rid=%d"
9121241
" AND event.objid=%d",
9131242
rid, rid
9141243
);
9151244
zBrName = branch_of_rid(rid);
916
-
1245
+
9171246
cookie_link_parameter("diff","diff","2");
9181247
diffType = atoi(PD("diff","2"));
9191248
if( db_step(&q1)==SQLITE_ROW ){
9201249
const char *zUuid = db_column_text(&q1, 0);
9211250
int nUuid = db_column_bytes(&q1, 0);
@@ -1146,35 +1475,38 @@
11461475
@ <div class="section">Changes</div>
11471476
}
11481477
@ <div class="sectionmenu">
11491478
diffFlags = construct_diff_flags(diffType);
11501479
zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
1480
+
11511481
/* In local mode, having displayed the header info for "tip", switch zName
11521482
** to be "ckout" so the style-altering links (unified or side-by-side etc.)
11531483
** will correctly re-select local-mode.
11541484
*/
11551485
if( bLocalMode ){
11561486
zName = "ckout";
11571487
}
11581488
if( diffType!=0 ){
1159
- @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
1489
+ @ %z(chref("button","%R/%s/%T?diff=0&ef=%s",zPageHide,zName,zExtra))\
11601490
@ Hide&nbsp;Diffs</a>
11611491
}
11621492
if( diffType!=1 ){
1163
- @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
1493
+ @ %z(chref("button","%R/%s/%T?diff=1%s&ef=%s",zPage,zName,zW,zExtra))\
11641494
@ Unified&nbsp;Diffs</a>
11651495
}
11661496
if( diffType!=2 ){
1167
- @ %z(chref("button","%R/%s/%T?diff=2%s",zPage,zName,zW))\
1497
+ @ %z(chref("button","%R/%s/%T?diff=2%s&ef=%s",zPage,zName,zW,zExtra))\
11681498
@ Side-by-Side&nbsp;Diffs</a>
11691499
}
11701500
if( diffType!=0 ){
11711501
if( *zW ){
1172
- @ %z(chref("button","%R/%s/%T?diff=%d",zPage,zName,diffType))
1502
+ @ %z(chref("button","%R/%s/%T?diff=%d&ef=%s",zPage,zName,diffType,zExtra))
11731503
@ Show&nbsp;Whitespace&nbsp;Changes</a>
11741504
}else{
1175
- @ %z(chref("button","%R/%s/%T?diff=%d&w",zPage,zName,diffType))
1505
+ char *button = chref("button","%R/%s/%T?diff=%d&w&ef=%s",
1506
+ zPage,zName,diffType,zExtra);
1507
+ @ %z(button)
11761508
@ Ignore&nbsp;Whitespace</a>
11771509
}
11781510
}
11791511
if( bLocalMode ){
11801512
@ %z(chref("button","%R/localpatch")) Patch</a>
@@ -1184,36 +1516,46 @@
11841516
@ Patch</a>
11851517
}
11861518
}
11871519
if( g.perm.Admin ){
11881520
@ %z(chref("button","%R/mlink?ci=%!S",zUuid))MLink Table</a>
1521
+ }
1522
+ if( bLocalMode ){
1523
+ if( showExtras ){
1524
+ @ %z(chref("button","%R/local?diff=%d%s&ef=0",diffType,zW))Hide Extras</a>
1525
+ }else{
1526
+ @ %z(chref("button","%R/local?diff=%d%s&ef=",diffType,zW))Show Extras</a>
1527
+ }
1528
+ /*TODO
1529
+ ** There would be a fair chunk of stuff to get right (not least appropriate
1530
+ ** restrictions), but it MIGHT be nice to have a COMMIT button here...
1531
+ */
11891532
}
11901533
@</div>
11911534
if( pRe ){
11921535
@ <p><b>Only differences that match regular expression "%h(zRe)"
11931536
@ are shown.</b></p>
11941537
}
11951538
if( bLocalMode ){
1196
-//--------------------------------------------------- TODO TESTING HACK TODO
1197
- int bTwoPass = P("op")==NULL;
1198
-//--------------------------------------------------- TODO TESTING HACK TODO
1539
+ if( showExtras ){
1540
+ append_extras_report(zExtra, diffType, zW);
1541
+ }
11991542
/* Following SQL taken from diff_against_disk() in diffcmd.c */
1543
+ /*TODO
1544
+ ** That code wrapped the query/processing in a transaction (but, from
1545
+ ** memory, other similar uses did not). Is it neeeded?
1546
+ */
12001547
db_begin_transaction();
12011548
db_prepare(&q3,
12021549
"SELECT pathname, deleted, chnged , rid==0, rid, islink"
12031550
" FROM vfile"
12041551
" WHERE vid=%d"
12051552
" AND (deleted OR chnged OR rid==0)"
12061553
" ORDER BY pathname /*scan*/",
12071554
vid
12081555
);
1209
- /* TODO Have the option of showing "extras" (non-ignored files in the
1210
- ** checkout directory that have not been ADDed). If done, they should
1211
- ** be ahead of any potential "diff-blocks" so they don't get lost
1212
- ** (which is the inspiration for...)
1213
- ** TODO Possibly (at some stage) have an option to commit?
1214
- */
1556
+
12151557
/* To prevent single-line diff-entries (those without "diff-blocks") from
12161558
** getting "lost", there's an optional "two-pass" mode for processing
12171559
** differences. If enabled, the first pass will only show one-line entries
12181560
** and the second pass will only show those with diff-blocks. This has the
12191561
** side-effect of altering the order entries are shown in (but within each
@@ -1222,10 +1564,13 @@
12221564
** If disabled, (pass gets set to 3), only one pass is made on which all
12231565
** entries are shown in their "normal" order.
12241566
**TODO
12251567
** Add this to the original (non-local) loop?
12261568
*/
1569
+//--------------------------------------------------- TODO TESTING HACK TODO
1570
+ int bTwoPass = P("op")==NULL; //TODO Taken from a config option?
1571
+//--------------------------------------------------- TODO TESTING HACK TODO
12271572
int pass = bTwoPass?1:3;
12281573
do{
12291574
while( db_step(&q3)==SQLITE_ROW ){
12301575
const char *zPathname = db_column_text(&q3,0);
12311576
int isDeleted = db_column_int(&q3, 1);
@@ -1232,17 +1577,17 @@
12321577
int isChnged = db_column_int(&q3,2);
12331578
int isNew = db_column_int(&q3,3);
12341579
int srcid = db_column_int(&q3, 4);
12351580
int isLink = db_column_int(&q3, 5);
12361581
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcid);
1237
- append_local_file_change_line(zPathname, zUuid,
1238
- isDeleted, isChnged, isNew, isLink, diffFlags,pRe,pass);
1582
+ append_local_file_change_line( zPathname, zUuid,
1583
+ isDeleted, isChnged, isNew, isLink, diffFlags,pRe,pass );
12391584
free(zUuid);
12401585
}
12411586
db_reset(&q3);
12421587
}while( ++pass < 3 ); /* Either "1, 2, stop" or "3, stop". */
1243
- db_finalize(&q3); /*TODO: Is this needed if we're reseting? */
1588
+ db_finalize(&q3);
12441589
db_end_transaction(1); /* ROLLBACK */
12451590
}else{ /* Normal, non-local-mode: show diffs against parent */
12461591
/*TODO: Implement the optional two-pass code? */
12471592
db_prepare(&q3,
12481593
"SELECT name,"
@@ -1630,15 +1975,17 @@
16301975
"%R/vdiff?%s&diff=1%s%T%s",
16311976
zQuery,
16321977
zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
16331978
}
16341979
if( zBranch==0 ){
1980
+ //TODO Is there an extra "&" here?
16351981
style_submenu_element("Invert",
16361982
"%R/vdiff?from=%T&to=%T&%s%T%s", zTo, zFrom,
16371983
zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
16381984
}
16391985
if( zGlob ){
1986
+ //TODO Is there an extra "&" here?
16401987
style_submenu_element("Clear glob",
16411988
"%R/vdiff?%s&%s", zQuery, zW);
16421989
}else{
16431990
style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW);
16441991
}
16451992
--- src/info.c
+++ src/info.c
@@ -1,15 +1,20 @@
1 /*TODO
2 ** o Have seen some "MERGE" entries and updated messages: still not 100% happy.
3 ** o Should /file behave differently for non-existent local files?
4 ** o Look at adding an "extras" option (non-added, non-ignored files).
5 ** o Find a place to add links to /local.
6 ** o Remove //TODO TESTING HACK TODO
7 ** ?? In hexdump_page(), should content (and downloadName?) be reset/freed?
8 ** ?? In the test fossil (\x\$Test\Fossil) there are (at time of writing) two
9 ** commits under the same artifact... is this normal?
10 ** ?? A settings entry to control one- or two-pass mode?
 
 
 
 
 
 
 
11 */
12 /*
13 ** Copyright (c) 2007 D. Richard Hipp
14 **
15 ** This program is free software; you can redistribute it and/or
@@ -568,11 +573,11 @@
568 }else{
569 @ Missing %h(zName) (was added to checkout).
570 }
571 }else switch( isChnged ){
572 /*TODO
573 ** These "special cases" have not been properly tested (by creating
574 ** entries in a in a repository to trigger them), but they do display
575 ** as expected when "forced" to appear.
576 */
577 case 3:
578 @ Added %h(zName) due to a merge.
@@ -825,10 +830,305 @@
825 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
826 0, 0, 0, rid, 0, 0);
827 db_finalize(&q);
828 style_footer();
829 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830
831 /*
832 ** WEBPAGE: vinfo
833 ** WEBPAGE: ci
834 ** WEBPAGE: local
@@ -842,11 +1142,12 @@
842 ** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
843 ** or a tag or branch name that identifies the check-in.
844 **
845 ** Use of /local (or the use of "ckout" for ARTIFACTID) will show the
846 ** same header details as /ci/tip, but then displays any (uncommitted)
847 ** edits made to files in the checkout directory.
 
848 */
849 void ci_page(void){
850 Stmt q1, q2, q3;
851 int rid;
852 int isLeaf;
@@ -861,20 +1162,48 @@
861 const char *zPage = "vinfo"; /* Page that shows diffs */
862 const char *zPageHide = "ci"; /* Page that hides diffs */
863 const char *zBrName; /* Branch name */
864 int bLocalMode; /* TRUE for /local; FALSE otherwise */
865 int vid; /* Virtual file system? */
 
 
866
867 login_check_credentials();
868 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
869 zName = P("name");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
870 /* Local mode is selected by either "/local" or with a "name" of "ckout".
871 ** First, check we have access to the checkout (and report to the user if we
872 ** don't), then refresh the "vfile" table (recording which files in the
873 ** checkout have changed etc.). We then change the "name" parameter to "tip"
874 ** so that the "header" section displays info about the check-in that the
875 ** checkout came from.
 
 
 
 
 
 
 
876 */
877 bLocalMode = (g.zPath[0]=='l') || (fossil_strcmp(zName,"ckout")==0);
878 if( bLocalMode ){
879 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
880 if( vid==0 ){
@@ -911,11 +1240,11 @@
911 " WHERE blob.rid=%d"
912 " AND event.objid=%d",
913 rid, rid
914 );
915 zBrName = branch_of_rid(rid);
916
917 cookie_link_parameter("diff","diff","2");
918 diffType = atoi(PD("diff","2"));
919 if( db_step(&q1)==SQLITE_ROW ){
920 const char *zUuid = db_column_text(&q1, 0);
921 int nUuid = db_column_bytes(&q1, 0);
@@ -1146,35 +1475,38 @@
1146 @ <div class="section">Changes</div>
1147 }
1148 @ <div class="sectionmenu">
1149 diffFlags = construct_diff_flags(diffType);
1150 zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
 
1151 /* In local mode, having displayed the header info for "tip", switch zName
1152 ** to be "ckout" so the style-altering links (unified or side-by-side etc.)
1153 ** will correctly re-select local-mode.
1154 */
1155 if( bLocalMode ){
1156 zName = "ckout";
1157 }
1158 if( diffType!=0 ){
1159 @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
1160 @ Hide&nbsp;Diffs</a>
1161 }
1162 if( diffType!=1 ){
1163 @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
1164 @ Unified&nbsp;Diffs</a>
1165 }
1166 if( diffType!=2 ){
1167 @ %z(chref("button","%R/%s/%T?diff=2%s",zPage,zName,zW))\
1168 @ Side-by-Side&nbsp;Diffs</a>
1169 }
1170 if( diffType!=0 ){
1171 if( *zW ){
1172 @ %z(chref("button","%R/%s/%T?diff=%d",zPage,zName,diffType))
1173 @ Show&nbsp;Whitespace&nbsp;Changes</a>
1174 }else{
1175 @ %z(chref("button","%R/%s/%T?diff=%d&w",zPage,zName,diffType))
 
 
1176 @ Ignore&nbsp;Whitespace</a>
1177 }
1178 }
1179 if( bLocalMode ){
1180 @ %z(chref("button","%R/localpatch")) Patch</a>
@@ -1184,36 +1516,46 @@
1184 @ Patch</a>
1185 }
1186 }
1187 if( g.perm.Admin ){
1188 @ %z(chref("button","%R/mlink?ci=%!S",zUuid))MLink Table</a>
 
 
 
 
 
 
 
 
 
 
 
1189 }
1190 @</div>
1191 if( pRe ){
1192 @ <p><b>Only differences that match regular expression "%h(zRe)"
1193 @ are shown.</b></p>
1194 }
1195 if( bLocalMode ){
1196 //--------------------------------------------------- TODO TESTING HACK TODO
1197 int bTwoPass = P("op")==NULL;
1198 //--------------------------------------------------- TODO TESTING HACK TODO
1199 /* Following SQL taken from diff_against_disk() in diffcmd.c */
 
 
 
 
1200 db_begin_transaction();
1201 db_prepare(&q3,
1202 "SELECT pathname, deleted, chnged , rid==0, rid, islink"
1203 " FROM vfile"
1204 " WHERE vid=%d"
1205 " AND (deleted OR chnged OR rid==0)"
1206 " ORDER BY pathname /*scan*/",
1207 vid
1208 );
1209 /* TODO Have the option of showing "extras" (non-ignored files in the
1210 ** checkout directory that have not been ADDed). If done, they should
1211 ** be ahead of any potential "diff-blocks" so they don't get lost
1212 ** (which is the inspiration for...)
1213 ** TODO Possibly (at some stage) have an option to commit?
1214 */
1215 /* To prevent single-line diff-entries (those without "diff-blocks") from
1216 ** getting "lost", there's an optional "two-pass" mode for processing
1217 ** differences. If enabled, the first pass will only show one-line entries
1218 ** and the second pass will only show those with diff-blocks. This has the
1219 ** side-effect of altering the order entries are shown in (but within each
@@ -1222,10 +1564,13 @@
1222 ** If disabled, (pass gets set to 3), only one pass is made on which all
1223 ** entries are shown in their "normal" order.
1224 **TODO
1225 ** Add this to the original (non-local) loop?
1226 */
 
 
 
1227 int pass = bTwoPass?1:3;
1228 do{
1229 while( db_step(&q3)==SQLITE_ROW ){
1230 const char *zPathname = db_column_text(&q3,0);
1231 int isDeleted = db_column_int(&q3, 1);
@@ -1232,17 +1577,17 @@
1232 int isChnged = db_column_int(&q3,2);
1233 int isNew = db_column_int(&q3,3);
1234 int srcid = db_column_int(&q3, 4);
1235 int isLink = db_column_int(&q3, 5);
1236 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcid);
1237 append_local_file_change_line(zPathname, zUuid,
1238 isDeleted, isChnged, isNew, isLink, diffFlags,pRe,pass);
1239 free(zUuid);
1240 }
1241 db_reset(&q3);
1242 }while( ++pass < 3 ); /* Either "1, 2, stop" or "3, stop". */
1243 db_finalize(&q3); /*TODO: Is this needed if we're reseting? */
1244 db_end_transaction(1); /* ROLLBACK */
1245 }else{ /* Normal, non-local-mode: show diffs against parent */
1246 /*TODO: Implement the optional two-pass code? */
1247 db_prepare(&q3,
1248 "SELECT name,"
@@ -1630,15 +1975,17 @@
1630 "%R/vdiff?%s&diff=1%s%T%s",
1631 zQuery,
1632 zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
1633 }
1634 if( zBranch==0 ){
 
1635 style_submenu_element("Invert",
1636 "%R/vdiff?from=%T&to=%T&%s%T%s", zTo, zFrom,
1637 zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
1638 }
1639 if( zGlob ){
 
1640 style_submenu_element("Clear glob",
1641 "%R/vdiff?%s&%s", zQuery, zW);
1642 }else{
1643 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW);
1644 }
1645
--- src/info.c
+++ src/info.c
@@ -1,15 +1,20 @@
1 /*TODO Graham's Notes
 
2 ** o Should /file behave differently for non-existent local files?
 
3 ** o Find a place to add links to /local.
4 ** o Remove //TODO TESTING HACK TODO
5 ** ?? In hexdump_page(), should content (and downloadName?) be reset/freed?
6 ** ?? In clean_cmd() in checkin.c, should "Blob repo" be blob_reset()?
7 ** ?? Do I need to worry about deleting/emptying TEMP SFILE?
8 ** ?? Is it normal for one artifact to have several check-ins associated with
9 ** it? In the test fossil (\x\$Test\Fossil) there are several commits under
10 ** the same artifact...
11 ** ?? A setting to control one- or two-pass mode?
12 ** ?? Add two-pass to the normal loop?
13 ** ?? A setting to control whether Extras are intially shown or not?
14 ** ?? A setting to control max. entries to show initially?
15 **------------------------------------------------------------------------------
16 */
17 /*
18 ** Copyright (c) 2007 D. Richard Hipp
19 **
20 ** This program is free software; you can redistribute it and/or
@@ -568,11 +573,11 @@
573 }else{
574 @ Missing %h(zName) (was added to checkout).
575 }
576 }else switch( isChnged ){
577 /*TODO
578 ** These "special cases" have not all been properly tested (by creating
579 ** entries in a in a repository to trigger them), but they do display
580 ** as expected when "forced" to appear.
581 */
582 case 3:
583 @ Added %h(zName) due to a merge.
@@ -825,10 +830,305 @@
830 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
831 0, 0, 0, rid, 0, 0);
832 db_finalize(&q);
833 style_footer();
834 }
835
836 /*
837 ** Options for the "extras" report. The bit-mask versions are used for "&ef=.."
838 ** to select which category(ies) to show.
839 */
840 enum {
841 EXB_PLAIN, EXB_IGNORE, EXB_CLEAN, EXB_KEEP,
842
843 EX_PLAIN = 1 << EXB_PLAIN, /* Matches none of the others */
844 EX_IGNORE = 1 << EXB_IGNORE, /* Matches "ignore-glob" */
845 EX_CLEAN = 1 << EXB_CLEAN, /* Matches "clean-glob" */
846 EX_KEEP = 1 << EXB_KEEP, /* Matches "keep-glob" */
847 EX_ALL = EX_PLAIN /* All entries */
848 | EX_IGNORE
849 | EX_CLEAN
850 | EX_KEEP
851 };
852
853 /*
854 ** Called while generating "/local": appends a report of any "extra" files that
855 ** might be present in the current checkout.
856 **
857 ** The format is controlled by "zExtra" (the value from the "ex=" URL option).
858 ** This is converted to an int ("extrasFlags") and treated as a collection of
859 ** the EX_xxx flags defined above. Thus "1" will list all "plain" files:
860 ** unmanaged files that match none of the ignore/clean/keep blob-lists, and "2"
861 ** would list all files matching the ignore-blob setting. "3" would list both
862 ** those sets of files.
863 **
864 ** An empty "zExtra" is a special case: it converts to zero which would normally
865 ** select none of the EX_xxx flags above. Instead, it is converted to EX_PLAIN
866 ** (=1) but with a (smallish) upper-limit on the number of files that will be
867 ** listed. This is the "default" mode as it offers a combination of usefulness
868 ** and non-intrusiveness:
869 ** o If the glob-lists are configured well, the only files that will show are
870 ** likely to be new source files that have not been "fossil add"ed.
871 ** o If the glob-lists HAVEN'T been configured, only a relatively small number
872 ** of temporary files (e.g. ".o" or ".obj") will be shown.
873 **
874 */
875 static void append_extras_report(
876 const char *zExtra, /* Value of "ef=" from URL */
877 const int diffType, /* Used to preserve current */
878 const char *zW /* settings in URLs */
879 ){
880 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
881 Glob *pIgnore, *pKeep, *pClean;
882 int nRoot;
883 zIgnoreFlag = db_get("ignore-glob", 0); /* Patterns to ignore */
884 zCleanFlag = db_get("clean-glob", 0); /* ...that "clean" clobbers */
885 zKeepFlag = db_get("keep-glob", 0); /* ...that "clean" won't touch */
886 pIgnore = glob_create(zIgnoreFlag); /* Object versions of above */
887 pKeep = glob_create(zKeepFlag);
888 pClean = glob_create(zCleanFlag);
889 nRoot = (int)strlen(g.zLocalRoot); /* Length of root component */
890 Stmt q;
891 Blob repo; /* TODO May not be needed */
892 int maxExtrasToShow = 5; /* TODO Take from a setting? */
893 int extrasFlags = atoi(zExtra); /* Which entries to show */
894 int nExtras;
895 int nMatch;
896 int nShown;
897 int nPlain;
898 int nIgnore;
899 int nClean;
900 int nKeep;
901
902 /*TODO?
903 ** It feels sensible to limit the number of "extra" entries shown by default
904 ** for cases where "ignore-glob" or "clean-glob" haven't been fully setup.
905 ** A minor irritation is that this can lead to "... plus 1 more file", on a
906 ** line that COULD have been used to display the omitted file. If we knew in
907 ** advance how many entries were going to match, we could temporarily "bump"
908 ** the limit by one show all entries would be shown. However, to know the
909 ** number of matches in advance we'd have to:
910 ** a) Pre-scan SFILE, testing and counting matches against each glob-list,
911 ** possibly bump the limit, then re-scan the table repeating the tests
912 ** against each glob-list to decide which to show.
913 ** b) SFILE could have an extra FLAGS field: during the pre-scan, this could
914 ** be updated to indicate which groups each file belong to. This would
915 ** save re-testing every file against each glob-list (the main pass could
916 ** select "WHERE flags & selector" to get only the matching entries, but
917 ** the updates (selecting by "pathname" each time) could be a bit much.
918 ** c) vfile_scan() -- where SFILE is populated -- COULD have an option to
919 ** do the testing at the time entries are added. This would be the "best"
920 ** way, but feels too much disruption to other code for what is only a
921 ** minor benefit.
922 ** For now, I'll stick with the minor annoyance of "plus 1 more file" :-)
923 **
924 ** Being able to determine the counts up-front would also allow us to hide
925 ** the "extras report" if there were no unmanaged files.
926 **
927 **TODO?
928 ** Does it make sense (and/or is it practiable) to offer an "ADD" button
929 ** against files that are unmanaged?
930 **
931 **TODO?
932 ** Does it make sense (and/or ...) to offer ediing of the various blob-lists
933 ** from the Extras report? Showing the existing configuration screen would
934 ** probably not be a problem (permissions permitting), but what happens if
935 ** those settings have been overriden by .fossil-settings/ignore-glob? As we
936 ** have access to the local checkout, is it feasible to edit it in the browser
937 ** (perhaps piggy-backing /fileedit)?
938 */
939
940 locate_unmanaged_files(0, NULL, 0, NULL); /* Get all unmanaged */
941 /*TODO
942 ** The first two of these exclusions come from clean_cmd() in checkin.c.
943 ** Not sure exactly what they are intended to do (seem to have no effect on
944 ** my test repos). Last exclusion is an alternative to the WHERE clause above
945 ** so that COUNT(*) returns the correct value. TODO Even though, as noted
946 ** above, getting the count ahead of time is of little use (it was used to
947 ** bump the display limit if only one entry would be omitted), I'll probably
948 ** retain omitting the WHERE, and using DELETE FROM to exclude reserved
949 ** names, just in case (c) above was implemented.
950 */
951 /*TODO deletions from clean_cmd() */
952 if( file_tree_name(g.zRepositoryName, &repo, 0, 0) ){
953 db_multi_exec("DELETE FROM sfile WHERE pathname=%B", &repo);
954 }
955 db_multi_exec("DELETE FROM sfile WHERE pathname IN"
956 " (SELECT pathname FROM vfile)");
957 /*TODO Delete reserved names, rather than WHERE them out. */
958 db_multi_exec("DELETE FROM sfile WHERE pathname IN (%s)",
959 fossil_all_reserved_names(0));
960
961 /*TODO
962 ** If we had a count of matching entries before scanning, this is where
963 ** we'd bump the maximum to show so as to avoid "plus 1 file".
964 ** ...
965 ** If there's only one more than the maximum, let it through...
966 ** a line used to say "plus 1 more" may as well display that item!
967 if( nExtras == maxExtrasToShow+1 ){ maxExtrasToShow++; }
968 ** ...
969 */
970
971 /* Handle the special case where zExtra was empty (and got converted to zero).
972 ** If so, show "plain" files (those not matching any glob-list) but with an
973 ** upper limit to the number shown (set above). If a value WAS given (i.e.
974 ** after following a link), display all of the selected entries.
975 */
976 if( extrasFlags==0 ){
977 extrasFlags = EX_PLAIN;
978 }else{
979 maxExtrasToShow = 0x7fffffff; /* Basically, all of them... */
980 }
981
982 /* Describe the files listed. Currently, the only "built-in" options are to
983 ** list "plain" files (those unmanaged files not matching any glob-list),
984 ** or to list those files matching ONE of the glob-lists. However, manual
985 ** editing would allow selecting combinations of matching files.
986 **
987 ** If only EX_PLAIN is present, then other types are explicitly excluded
988 ** by definition: PLAIN means "not matching any glob-list". For all other
989 ** cases, we cannot say things like "not ignored" because a file can match
990 ** more than one list.
991 */
992 @ <p><b>Extra Files
993 if( extrasFlags == EX_PLAIN ){
994 @ (unmanaged, not ignored, not for cleaning, not kept)
995 }else{
996 Blob desc;
997 blob_zero(&desc);
998 if( extrasFlags & EX_PLAIN ){ blob_appendf(&desc, " + unmanaged" ); }
999 if( extrasFlags & EX_IGNORE ){ blob_appendf(&desc, " + ignored" ); }
1000 if( extrasFlags & EX_CLEAN ){ blob_appendf(&desc, " + to be cleaned"); }
1001 if( extrasFlags & EX_KEEP ){ blob_appendf(&desc, " + to be kept" ); }
1002 if( blob_size(&desc) > 3 ){ /* Should never fail... */
1003 /* Add the string built above, skipping the leading " + " */
1004 @ (%h(blob_str(&desc)+3))
1005 }
1006 blob_reset(&desc);
1007 }
1008 @ </b></p>
1009
1010 db_prepare(&q,
1011 "SELECT %Q || pathname FROM sfile"
1012 " ORDER BY 1", //TODO Order by pathname?
1013 g.zLocalRoot
1014 );
1015 /*
1016 ** Put the file-list in one paragraph with line-breaks between.
1017 **TODO
1018 ** Might a table (with columns for name, ignore/clean/keep) work?
1019 */
1020 @ <p>
1021 nExtras = nMatch = nShown = nPlain = nKeep = nClean = nIgnore = 0;
1022 while( db_step(&q)==SQLITE_ROW ){
1023 const char *zName = db_column_text(&q, 0);
1024 int entryFlags = 0
1025 | ( glob_match(pIgnore, zName+nRoot) ? EX_IGNORE : 0 )
1026 | ( glob_match(pClean, zName+nRoot) ? EX_CLEAN : 0 )
1027 | ( glob_match(pKeep, zName+nRoot) ? EX_KEEP : 0 ) ;
1028 if( entryFlags == 0 ){
1029 entryFlags = EX_PLAIN;
1030 }
1031 if( entryFlags & EX_PLAIN ){ nPlain++; }
1032 if( entryFlags & EX_IGNORE ){ nIgnore++; }
1033 if( entryFlags & EX_CLEAN ){ nClean++; }
1034 if( entryFlags & EX_KEEP ){ nKeep++; }
1035
1036 nExtras++;
1037 if( entryFlags & extrasFlags ){
1038 nMatch++ ;
1039 if( nShown < maxExtrasToShow ){
1040 nShown++;
1041 if( g.perm.Hyperlink ){
1042 @ %z(href("%R/file/%T?ci=ckout&annot=not managed",zName+nRoot))
1043 @ %h(zName+nRoot)</a>
1044 }else{
1045 @ %h(zName+nRoot)
1046 }
1047 if( entryFlags & EX_IGNORE ){
1048 @ (marked ignore)
1049 }
1050 if( entryFlags & EX_CLEAN ){
1051 @ (marked clean)
1052 }
1053 if( entryFlags & EX_KEEP ){
1054 @ (marked keep)
1055 }
1056 @ <br/>
1057 }
1058 }
1059 }
1060
1061 if( nShown < nMatch ){
1062 const int nHidden = nMatch - nShown;
1063 @ ... plus %d(nHidden) other matching file%h(nHidden==1?"":"s")
1064 @ (%z(href("/local?diff=%d%s&ef=%d",diffType,zW,extrasFlags))
1065 @ show all)</a>.
1066 }
1067 @ </p>
1068
1069 @ <p>
1070 if( nExtras==0 ){
1071 @ No unmanaged files in checkout\
1072 }else if( (nPlain==0) && (P("ef")==NULL) ){
1073 @ No extra files in checkout
1074 @ (%z(href("%R/local?diff=%d%s&ef=1",diffType,zW))show exclusions</a>)\
1075 }else{
1076 /* Report types and counts of extra files, with links to see all of the
1077 ** selected type. Note the extra space before "including": the output of
1078 ** append_count() ends with "\" to get the formatting correct.
1079 */
1080 append_count( EX_ALL, nExtras, "extra file", 1, 0, diffType,zW );
1081 @ including
1082 append_count( EX_PLAIN, nPlain, "unmanaged", 0, 1, diffType,zW );
1083 append_count( EX_IGNORE, nIgnore, "marked ignore", 0, 1, diffType,zW );
1084 append_count( EX_CLEAN, nClean, "to be cleaned", 0, 1, diffType,zW );
1085 append_count( EX_KEEP, nKeep, "to be kept", 0, 1, diffType,zW );
1086 }
1087 @ .</p><hr/>
1088 blob_reset(&repo);
1089 db_finalize(&q);
1090 }
1091
1092 /*
1093 ** Append "26 extra files" type message as a link (assuming count is non-zero),
1094 ** with pluralisation if requested and needed. If "commaBefore" is true, the
1095 ** link is preceded by ", " if there have been earler entries with commaBefore
1096 ** set. If false, it resets the count. This allows correct construction of
1097 ** variants like:
1098 ** 27 extra files including 27 ignored.
1099 ** 30 extra files including 3 unmanaged, 27 ignored.
1100 ** The dt (diffType) and zW parameters pass on formatting selections from the
1101 ** rest of the /local page.
1102 */
1103 void append_count(
1104 int ef, /* Flags for link */
1105 int count, /* Number of files */
1106 const char *linkText, /* Link text after count */
1107 int pluralise, /* Add optional "s"? */
1108 int commaBefore, /* Precede with ", " if earlier non-zero counts */
1109 int dt, /* DiffType */
1110 const char *zW /* Whitespace setting ("" or "&w") */
1111 ){
1112 static int earlierCounts = 0;
1113 if( count == 0 ){
1114 return;
1115 }
1116 if( !commaBefore ){
1117 earlierCounts = 0 ;
1118 }else if( earlierCounts ){
1119 @ ,
1120 }
1121 @ %z(href("%R/local?diff=%d%s&ef=%d",dt,zW,ef))%d(count) %h(linkText)\
1122 if( pluralise ){
1123 @ %h(count==1?"":"s")\
1124 }
1125 @ </a>\
1126 if( commaBefore ){
1127 earlierCounts += count;
1128 }
1129 }
1130
1131 /*
1132 ** WEBPAGE: vinfo
1133 ** WEBPAGE: ci
1134 ** WEBPAGE: local
@@ -842,11 +1142,12 @@
1142 ** The ARTIFACTID can be a unique prefix for the HASH of the check-in,
1143 ** or a tag or branch name that identifies the check-in.
1144 **
1145 ** Use of /local (or the use of "ckout" for ARTIFACTID) will show the
1146 ** same header details as /ci/tip, but then displays any (uncommitted)
1147 ** edits made to files in the checkout directory. It can also display
1148 ** any "extra" files (roughly equivalent to "fossil extras").
1149 */
1150 void ci_page(void){
1151 Stmt q1, q2, q3;
1152 int rid;
1153 int isLeaf;
@@ -861,20 +1162,48 @@
1162 const char *zPage = "vinfo"; /* Page that shows diffs */
1163 const char *zPageHide = "ci"; /* Page that hides diffs */
1164 const char *zBrName; /* Branch name */
1165 int bLocalMode; /* TRUE for /local; FALSE otherwise */
1166 int vid; /* Virtual file system? */
1167 int showExtras; /* Whether to show the extras report */
1168 const char *zExtra; /* How to show the report */
1169
1170 login_check_credentials();
1171 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1172 zName = P("name");
1173 /*
1174 ** "zExtra" controls if, and how, the "extras report" is displayed. It is a
1175 ** string, because when passed around in the URL (as "ef=") a value of "" has
1176 ** a different meaning to "0". A value of "" means "show a limited number of
1177 ** unmanaged files" (those that aren't ignored, marked to be cleaned, or
1178 ** marked kept)... this is what you'd most want to see if you've created a new
1179 ** source file and forgotten to "fossil add" it. A value of "0" will hide the
1180 ** extras report. Other (numeric) values control what the report shows (e.g.
1181 ** "1" would list ALL unmanaged files without limiting their number).
1182 **
1183 ** If the "ef=" isn't present (as when first navigating to "/local") then a
1184 ** default setting is used. Set to "0" to initially hide the report.
1185 */
1186 zExtra = P("ef");
1187 if( zExtra==NULL ) {
1188 zExtra = ""; /*TODO Take the default form a config. option? */
1189 }
1190 showExtras = strcmp(zExtra,"0")!=0;
1191
1192 /* Local mode is selected by either "/local" or with a "name" of "ckout".
1193 ** First, check we have access to the checkout (and report to the user if we
1194 ** don't), then refresh the "vfile" table (recording which files in the
1195 ** checkout have changed etc.). We then change the "name" parameter to "tip"
1196 ** so that the "header" section displays info about the check-in that the
1197 ** checkout came from.
1198 **TODO
1199 ** It would probably make sense to limit "/local" (and other links that come
1200 ** from it) to only be permitted when Fossil is running locally in "ui" mode.
1201 ** It's probably not critical when all you can do is view files in the
1202 ** checkout (they can already see the checked-in versions), but if a COMMIT
1203 ** option WERE ever to be implemented, you wouldn't essentially random people
1204 ** on the internet firing off commits.
1205 */
1206 bLocalMode = (g.zPath[0]=='l') || (fossil_strcmp(zName,"ckout")==0);
1207 if( bLocalMode ){
1208 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
1209 if( vid==0 ){
@@ -911,11 +1240,11 @@
1240 " WHERE blob.rid=%d"
1241 " AND event.objid=%d",
1242 rid, rid
1243 );
1244 zBrName = branch_of_rid(rid);
1245
1246 cookie_link_parameter("diff","diff","2");
1247 diffType = atoi(PD("diff","2"));
1248 if( db_step(&q1)==SQLITE_ROW ){
1249 const char *zUuid = db_column_text(&q1, 0);
1250 int nUuid = db_column_bytes(&q1, 0);
@@ -1146,35 +1475,38 @@
1475 @ <div class="section">Changes</div>
1476 }
1477 @ <div class="sectionmenu">
1478 diffFlags = construct_diff_flags(diffType);
1479 zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
1480
1481 /* In local mode, having displayed the header info for "tip", switch zName
1482 ** to be "ckout" so the style-altering links (unified or side-by-side etc.)
1483 ** will correctly re-select local-mode.
1484 */
1485 if( bLocalMode ){
1486 zName = "ckout";
1487 }
1488 if( diffType!=0 ){
1489 @ %z(chref("button","%R/%s/%T?diff=0&ef=%s",zPageHide,zName,zExtra))\
1490 @ Hide&nbsp;Diffs</a>
1491 }
1492 if( diffType!=1 ){
1493 @ %z(chref("button","%R/%s/%T?diff=1%s&ef=%s",zPage,zName,zW,zExtra))\
1494 @ Unified&nbsp;Diffs</a>
1495 }
1496 if( diffType!=2 ){
1497 @ %z(chref("button","%R/%s/%T?diff=2%s&ef=%s",zPage,zName,zW,zExtra))\
1498 @ Side-by-Side&nbsp;Diffs</a>
1499 }
1500 if( diffType!=0 ){
1501 if( *zW ){
1502 @ %z(chref("button","%R/%s/%T?diff=%d&ef=%s",zPage,zName,diffType,zExtra))
1503 @ Show&nbsp;Whitespace&nbsp;Changes</a>
1504 }else{
1505 char *button = chref("button","%R/%s/%T?diff=%d&w&ef=%s",
1506 zPage,zName,diffType,zExtra);
1507 @ %z(button)
1508 @ Ignore&nbsp;Whitespace</a>
1509 }
1510 }
1511 if( bLocalMode ){
1512 @ %z(chref("button","%R/localpatch")) Patch</a>
@@ -1184,36 +1516,46 @@
1516 @ Patch</a>
1517 }
1518 }
1519 if( g.perm.Admin ){
1520 @ %z(chref("button","%R/mlink?ci=%!S",zUuid))MLink Table</a>
1521 }
1522 if( bLocalMode ){
1523 if( showExtras ){
1524 @ %z(chref("button","%R/local?diff=%d%s&ef=0",diffType,zW))Hide Extras</a>
1525 }else{
1526 @ %z(chref("button","%R/local?diff=%d%s&ef=",diffType,zW))Show Extras</a>
1527 }
1528 /*TODO
1529 ** There would be a fair chunk of stuff to get right (not least appropriate
1530 ** restrictions), but it MIGHT be nice to have a COMMIT button here...
1531 */
1532 }
1533 @</div>
1534 if( pRe ){
1535 @ <p><b>Only differences that match regular expression "%h(zRe)"
1536 @ are shown.</b></p>
1537 }
1538 if( bLocalMode ){
1539 if( showExtras ){
1540 append_extras_report(zExtra, diffType, zW);
1541 }
1542 /* Following SQL taken from diff_against_disk() in diffcmd.c */
1543 /*TODO
1544 ** That code wrapped the query/processing in a transaction (but, from
1545 ** memory, other similar uses did not). Is it neeeded?
1546 */
1547 db_begin_transaction();
1548 db_prepare(&q3,
1549 "SELECT pathname, deleted, chnged , rid==0, rid, islink"
1550 " FROM vfile"
1551 " WHERE vid=%d"
1552 " AND (deleted OR chnged OR rid==0)"
1553 " ORDER BY pathname /*scan*/",
1554 vid
1555 );
1556
 
 
 
 
 
1557 /* To prevent single-line diff-entries (those without "diff-blocks") from
1558 ** getting "lost", there's an optional "two-pass" mode for processing
1559 ** differences. If enabled, the first pass will only show one-line entries
1560 ** and the second pass will only show those with diff-blocks. This has the
1561 ** side-effect of altering the order entries are shown in (but within each
@@ -1222,10 +1564,13 @@
1564 ** If disabled, (pass gets set to 3), only one pass is made on which all
1565 ** entries are shown in their "normal" order.
1566 **TODO
1567 ** Add this to the original (non-local) loop?
1568 */
1569 //--------------------------------------------------- TODO TESTING HACK TODO
1570 int bTwoPass = P("op")==NULL; //TODO Taken from a config option?
1571 //--------------------------------------------------- TODO TESTING HACK TODO
1572 int pass = bTwoPass?1:3;
1573 do{
1574 while( db_step(&q3)==SQLITE_ROW ){
1575 const char *zPathname = db_column_text(&q3,0);
1576 int isDeleted = db_column_int(&q3, 1);
@@ -1232,17 +1577,17 @@
1577 int isChnged = db_column_int(&q3,2);
1578 int isNew = db_column_int(&q3,3);
1579 int srcid = db_column_int(&q3, 4);
1580 int isLink = db_column_int(&q3, 5);
1581 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcid);
1582 append_local_file_change_line( zPathname, zUuid,
1583 isDeleted, isChnged, isNew, isLink, diffFlags,pRe,pass );
1584 free(zUuid);
1585 }
1586 db_reset(&q3);
1587 }while( ++pass < 3 ); /* Either "1, 2, stop" or "3, stop". */
1588 db_finalize(&q3);
1589 db_end_transaction(1); /* ROLLBACK */
1590 }else{ /* Normal, non-local-mode: show diffs against parent */
1591 /*TODO: Implement the optional two-pass code? */
1592 db_prepare(&q3,
1593 "SELECT name,"
@@ -1630,15 +1975,17 @@
1975 "%R/vdiff?%s&diff=1%s%T%s",
1976 zQuery,
1977 zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
1978 }
1979 if( zBranch==0 ){
1980 //TODO Is there an extra "&" here?
1981 style_submenu_element("Invert",
1982 "%R/vdiff?from=%T&to=%T&%s%T%s", zTo, zFrom,
1983 zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
1984 }
1985 if( zGlob ){
1986 //TODO Is there an extra "&" here?
1987 style_submenu_element("Clear glob",
1988 "%R/vdiff?%s&%s", zQuery, zW);
1989 }else{
1990 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW);
1991 }
1992

Keyboard Shortcuts

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