Fossil SCM

Merge-in styling improvements from trunk

george 2020-11-17 18:38 wiki-history merge
Commit bb159b9e96b035cc523fc279c0e0c4ad3e4bf63b2a2f68af441346969cde34e0
79 files changed +1 -1 +219 -191 +1 -1 +14 -14 +5 -5 +2 -2 +3 -3 +4 -4 +1 -1 +2 -2 +2 -2 +67 -24 +1 -1 +5 -4 +2 -6 +1 -1 +1 -1 +2 -2 +9 -9 +4 -4 +1 -1 +2 -2 +3 -3 +6 -6 +1 -1 +16 -16 +2 -2 +1 -1 +4 -4 +2 -2 +1 -1 +6 -6 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +7 -7 +5 -5 +6 -6 +15 -15 +7 -7 +7 -4 +3 -3 +1 -1 +6 -6 +2 -2 +57 -15 +1 -1 +7 -7 +1 -1 +26 -17 +2 -2 +2 -2 +1 -1 +4 -4 +11 -11 +3 -3 +2 -2 +49 +24 -2 +5 -5 +15 -15 +15 -15 +18 -15 +2 -2 +2 -2 +48 -40 +10 +1 -1 +33 +88 -35 +705 -202 +4 -4 +10 -1 +2 -1 +5 -4 +21 -1 +17
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.13
1
+2.14
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.13
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.14
2
+219 -191
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -1,236 +1,264 @@
1
+/* Overall page style */
2
+
13
body {
2
- margin: 0 auto;
3
- background-color: white;
4
- font-family: sans-serif;
5
- font-size:14pt;
6
- -moz-text-size-adjust: none;
7
- -webkit-text-size-adjust: none;
8
- -mx-text-size-adjust: none;
4
+ margin: 0 auto;
5
+ background-color: white;
6
+ font-family: sans-serif;
7
+ font-size: 14pt;
8
+ -moz-text-size-adjust: none;
9
+ -mx-text-size-adjust: none;
10
+ -webkit-text-size-adjust: none;
911
}
1012
1113
a {
12
- color: #4183C4;
13
- text-decoration: none;
14
+ color: #4183C4;
15
+ text-decoration: none;
1416
}
1517
a:hover {
16
- color: #4183C4;
17
- text-decoration: underline;
18
-}
19
-div.forumPosts a:visited {
20
- color: #6A7F94;
18
+ color: #4183C4;
19
+ text-decoration: underline;
2120
}
2221
23
-hr {
24
- color: #eee;
25
-}
22
+
23
+/* Page title, above menu bars */
2624
2725
.title {
28
- color: #4183C4;
29
- float:left;
26
+ color: #4183C4;
27
+ float: left;
3028
}
3129
.title h1 {
32
- display:inline;
30
+ display: inline;
3331
}
3432
.title h1:after {
35
- content: " / ";
36
- color: #777;
37
- font-weight: normal;
38
-}
39
-
40
-.content h1 {
41
- font-size: 1.25em;
42
-}
43
-.content h2 {
44
- font-size: 1.15em;
45
-}
46
-.content h3 {
47
- font-size: 1.05em;
48
- font-weight: bold;
49
-}
50
-
51
-.section {
52
- font-size: 1em;
53
- font-weight: bold;
54
- background-color: #f5f5f5;
55
- border: 1px solid #d8d8d8;
56
- border-radius: 3px 3px 0 0;
57
- padding: 9px 10px 10px;
58
- margin: 10px 0;
59
-}
60
-
61
-.sectionmenu {
62
- border: 1px solid #d8d8d8;
63
- border-radius: 0 0 3px 3px;
64
- border-top: 0;
65
- margin-top: -10px;
66
- margin-bottom: 10px;
67
- padding: 10px;
68
-}
69
-.sectionmenu a {
70
- display: inline-block;
71
- margin-right: 1em;
72
-}
73
-
33
+ content: " / ";
34
+ color: #777;
35
+ font-weight: normal;
36
+}
7437
.status {
75
- float:right;
76
- font-size:.7em;
38
+ float: right;
39
+ font-size: 0.7em;
7740
}
7841
42
+
43
+/* Main menu and optional sub-menu */
44
+
7945
.mainmenu {
80
- font-size:.8em;
81
- clear:both;
82
- background:#eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x;
83
- border:1px solid #eaeaea;
84
- border-radius:5px;
85
- overflow-x: auto;
86
- overflow-y: hidden;
87
- white-space: nowrap;
88
- z-index: 21; /* just above hbdrop */
89
-}
90
-
46
+ font-size: 0.8em;
47
+ clear: both;
48
+ background: #eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x;
49
+ border: 1px solid #eaeaea;
50
+ border-radius: 5px;
51
+ overflow-x: auto;
52
+ overflow-y: hidden;
53
+ white-space: nowrap;
54
+ z-index: 21; /* just above hbdrop */
55
+}
9156
.mainmenu a {
92
- text-decoration:none;
93
- color: #777;
94
- border-right:1px solid #eaeaea;
57
+ text-decoration: none;
58
+ color: #777;
59
+ border-right: 1px solid #eaeaea;
9560
}
9661
.mainmenu a.active,
9762
.mainmenu a:hover {
98
- color: #000;
99
- border-bottom:2px solid #D26911;
100
-}
101
-
102
-div#hbdrop {
103
- background-color: white;
104
- border: 1px solid black;
105
- border-top: white;
106
- border-radius: 0 0 0.5em 0.5em;
107
- display: none;
108
- font-size: 80%;
109
- left: 2em;
110
- width: 90%;
111
- padding-right: 1em;
112
- position: absolute;
113
- z-index: 20; /* just below mainmenu, but above timeline bubbles */
63
+ color: #000;
64
+ border-bottom: 2px solid #D26911;
65
+}
66
+.mainmenu div#hbdrop {
67
+ background-color: white;
68
+ border: 1px solid black;
69
+ border-top: white;
70
+ border-radius: 0 0 0.5em 0.5em;
71
+ display: none;
72
+ font-size: 80%;
73
+ left: 2em;
74
+ width: 90%;
75
+ padding-right: 1em;
76
+ position: absolute;
77
+ z-index: 20; /* just below mainmenu, but above timeline bubbles */
11478
}
11579
11680
.submenu {
117
- font-size: .7em;
118
- padding: 10px;
119
- border-bottom: 1px solid #ccc;
81
+ font-size: .7em;
82
+ padding: 10px;
83
+ border-bottom: 1px solid #ccc;
12084
}
121
-
12285
.submenu a, .submenu label {
123
- padding: 10px 11px;
124
- text-decoration:none;
125
- color: #777;
86
+ padding: 10px 11px;
87
+ text-decoration: none;
88
+ color: #777;
12689
}
127
-
90
+.submenu label {
91
+ white-space: nowrap;
92
+}
12893
.submenu a:hover, .submenu label:hover {
129
- padding: 6px 10px;
130
- border: 1px solid #ccc;
131
- border-radius: 5px;
132
- color: #000;
133
-}
134
-
135
-.content {
136
- padding-top: 10px;
137
- font-size:.8em;
138
- color: #444;
139
-}
140
-
141
-.udiff, .sbsdiff {
142
- font-size: .85em !important;
143
- overflow: auto;
144
- border: 1px solid #ccc;
145
- border-radius: 5px;
146
-}
147
-.content blockquote {
148
- padding: 0 15px;
149
-}
150
-div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote, div.forumTime blockquote, div.forumTimeline blockquote {
151
- background-color: rgba(65, 131, 196, 0.1);
152
- border-left: 3px solid #254769;
153
- padding: .1em 1em;
154
-}
155
-
156
-table.report {
157
- cursor: auto;
158
- border-radius: 5px;
159
- border: 1px solid #ccc;
160
- margin: 1em 0;
161
-}
162
-.report td, .report th {
163
- border: 0;
164
- font-size: .8em;
165
- padding: 10px;
166
-}
167
-.report td:first-child {
168
- border-top-left-radius: 5px;
169
-}
170
-.report tbody tr:last-child td:first-child {
171
- border-bottom-left-radius: 5px;
172
-}
173
-.report td:last-child {
174
- border-top-right-radius: 5px;
175
-}
176
-.report tbody tr:last-child {
177
- border-bottom-left-radius: 5px;
178
- border-bottom-right-radius: 5px;
179
-}
180
-.report tbody tr:last-child td:last-child {
181
- border-bottom-right-radius: 5px;
182
-}
183
-.report th {
184
- cursor: pointer;
185
-}
186
-.report thead+tbody tr:hover {
187
- background-color: #f5f9fc !important;
188
-}
189
-
190
-td.tktDspLabel {
191
- width: 70px;
192
- text-align: right;
193
- overflow: hidden;
194
-}
195
-td.tktDspValue {
196
- text-align: left;
197
- vertical-align: top;
198
- background-color: #f8f8f8;
199
- border: 1px solid #ccc;
200
-}
201
-td.tktDspValue pre {
202
- white-space: pre-wrap;
203
-}
204
-
205
-span.timelineDetail {
206
- font-size: 90%;
207
-}
208
-
209
-.footer {
210
- border-top: 1px solid #ccc;
211
- padding: 10px;
212
- font-size:.7em;
213
- margin-top: 10px;
214
- color: #ccc;
215
-}
216
-div.timelineDate {
217
- font-weight: bold;
218
- white-space: nowrap;
94
+ padding: 6px 10px;
95
+ border: 1px solid #ccc;
96
+ border-radius: 5px;
97
+ color: #000;
21998
}
22099
span.submenuctrl, span.submenuctrl input, select.submenuctrl {
221100
color: #777;
222101
}
223102
span.submenuctrl {
224103
white-space: nowrap;
225104
}
226
-div.submenu label {
227
- white-space: nowrap;
105
+
106
+
107
+/* Main document area; elements common to most pages. */
108
+
109
+.content {
110
+ padding-top: 10px;
111
+ font-size: 0.8em;
112
+ color: #444;
113
+}
114
+.content blockquote {
115
+ padding: 0 15px;
116
+}
117
+.content h1 {
118
+ font-size: 1.25em;
119
+}
120
+.content h2 {
121
+ font-size: 1.15em;
122
+}
123
+.content h3 {
124
+ font-size: 1.05em;
125
+}
126
+
127
+.section {
128
+ font-size: 1em;
129
+ font-weight: bold;
130
+ background-color: #f5f5f5;
131
+ border: 1px solid #d8d8d8;
132
+ border-radius: 3px 3px 0 0;
133
+ padding: 9px 10px 10px;
134
+ margin: 10px 0;
135
+}
136
+.sectionmenu {
137
+ border: 1px solid #d8d8d8;
138
+ border-radius: 0 0 3px 3px;
139
+ border-top: 0;
140
+ margin-top: -10px;
141
+ margin-bottom: 10px;
142
+ padding: 10px;
143
+}
144
+.sectionmenu a {
145
+ display: inline-block;
146
+ margin-right: 1em;
147
+}
148
+
149
+hr {
150
+ color: #eee;
151
+}
152
+
153
+
154
+/* Page footer */
155
+
156
+.footer {
157
+ border-top: 1px solid #ccc;
158
+ padding: 10px;
159
+ font-size: 0.7em;
160
+ margin-top: 10px;
161
+ color: #ccc;
162
+}
163
+
164
+
165
+/* Exceptions for /info diff views */
166
+
167
+.udiff, .sbsdiff {
168
+ font-size: .85em !important;
169
+ overflow: auto;
170
+ border: 1px solid #ccc;
171
+ border-radius: 5px;
172
+}
173
+
174
+
175
+/* Forum */
176
+
177
+.forum a:visited {
178
+ color: #6A7F94;
179
+}
180
+
181
+.forum blockquote {
182
+ background-color: rgba(65, 131, 196, 0.1);
183
+ border-left: 3px solid #254769;
184
+ padding: .1em 1em;
185
+}
186
+
187
+
188
+/* Tickets */
189
+
190
+table.report {
191
+ cursor: auto;
192
+ border-radius: 5px;
193
+ border: 1px solid #ccc;
194
+ margin: 1em 0;
195
+}
196
+.report td, .report th {
197
+ border: 0;
198
+ font-size: .8em;
199
+ padding: 10px;
200
+}
201
+.report td:first-child {
202
+ border-top-left-radius: 5px;
203
+}
204
+.report tbody tr:last-child td:first-child {
205
+ border-bottom-left-radius: 5px;
206
+}
207
+.report td:last-child {
208
+ border-top-right-radius: 5px;
209
+}
210
+.report tbody tr:last-child {
211
+ border-bottom-left-radius: 5px;
212
+ border-bottom-right-radius: 5px;
213
+}
214
+.report tbody tr:last-child td:last-child {
215
+ border-bottom-right-radius: 5px;
216
+}
217
+.report th {
218
+ cursor: pointer;
219
+}
220
+.report thead+tbody tr:hover {
221
+ background-color: #f5f9fc !important;
222
+}
223
+
224
+td.tktDspLabel {
225
+ width: 70px;
226
+ text-align: right;
227
+ overflow: hidden;
228
+}
229
+td.tktDspValue {
230
+ text-align: left;
231
+ vertical-align: top;
232
+ background-color: #f8f8f8;
233
+ border: 1px solid #ccc;
234
+}
235
+td.tktDspValue pre {
236
+ white-space: pre-wrap;
237
+}
238
+
239
+
240
+/* Timeline */
241
+
242
+span.timelineDetail {
243
+ font-size: 90%;
244
+}
245
+div.timelineDate {
246
+ font-weight: bold;
247
+ white-space: nowrap;
228248
}
249
+
250
+
251
+/* Miscellaneous UI elements */
252
+
229253
.fossil-tooltip.help-buttonlet-content {
230254
background-color: lightyellow;
231255
}
256
+
257
+
258
+/* Exceptions for specific screen sizes */
259
+
232260
@media screen and (max-width: 600px) {
233261
/* Spacing for mobile */
234262
body {
235263
padding-left: 4px;
236264
padding-right: 4px;
237265
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -1,236 +1,264 @@
 
 
1 body {
2 margin: 0 auto;
3 background-color: white;
4 font-family: sans-serif;
5 font-size:14pt;
6 -moz-text-size-adjust: none;
7 -webkit-text-size-adjust: none;
8 -mx-text-size-adjust: none;
9 }
10
11 a {
12 color: #4183C4;
13 text-decoration: none;
14 }
15 a:hover {
16 color: #4183C4;
17 text-decoration: underline;
18 }
19 div.forumPosts a:visited {
20 color: #6A7F94;
21 }
22
23 hr {
24 color: #eee;
25 }
26
27 .title {
28 color: #4183C4;
29 float:left;
30 }
31 .title h1 {
32 display:inline;
33 }
34 .title h1:after {
35 content: " / ";
36 color: #777;
37 font-weight: normal;
38 }
39
40 .content h1 {
41 font-size: 1.25em;
42 }
43 .content h2 {
44 font-size: 1.15em;
45 }
46 .content h3 {
47 font-size: 1.05em;
48 font-weight: bold;
49 }
50
51 .section {
52 font-size: 1em;
53 font-weight: bold;
54 background-color: #f5f5f5;
55 border: 1px solid #d8d8d8;
56 border-radius: 3px 3px 0 0;
57 padding: 9px 10px 10px;
58 margin: 10px 0;
59 }
60
61 .sectionmenu {
62 border: 1px solid #d8d8d8;
63 border-radius: 0 0 3px 3px;
64 border-top: 0;
65 margin-top: -10px;
66 margin-bottom: 10px;
67 padding: 10px;
68 }
69 .sectionmenu a {
70 display: inline-block;
71 margin-right: 1em;
72 }
73
74 .status {
75 float:right;
76 font-size:.7em;
77 }
78
 
 
 
79 .mainmenu {
80 font-size:.8em;
81 clear:both;
82 background:#eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x;
83 border:1px solid #eaeaea;
84 border-radius:5px;
85 overflow-x: auto;
86 overflow-y: hidden;
87 white-space: nowrap;
88 z-index: 21; /* just above hbdrop */
89 }
90
91 .mainmenu a {
92 text-decoration:none;
93 color: #777;
94 border-right:1px solid #eaeaea;
95 }
96 .mainmenu a.active,
97 .mainmenu a:hover {
98 color: #000;
99 border-bottom:2px solid #D26911;
100 }
101
102 div#hbdrop {
103 background-color: white;
104 border: 1px solid black;
105 border-top: white;
106 border-radius: 0 0 0.5em 0.5em;
107 display: none;
108 font-size: 80%;
109 left: 2em;
110 width: 90%;
111 padding-right: 1em;
112 position: absolute;
113 z-index: 20; /* just below mainmenu, but above timeline bubbles */
114 }
115
116 .submenu {
117 font-size: .7em;
118 padding: 10px;
119 border-bottom: 1px solid #ccc;
120 }
121
122 .submenu a, .submenu label {
123 padding: 10px 11px;
124 text-decoration:none;
125 color: #777;
126 }
127
 
 
128 .submenu a:hover, .submenu label:hover {
129 padding: 6px 10px;
130 border: 1px solid #ccc;
131 border-radius: 5px;
132 color: #000;
133 }
134
135 .content {
136 padding-top: 10px;
137 font-size:.8em;
138 color: #444;
139 }
140
141 .udiff, .sbsdiff {
142 font-size: .85em !important;
143 overflow: auto;
144 border: 1px solid #ccc;
145 border-radius: 5px;
146 }
147 .content blockquote {
148 padding: 0 15px;
149 }
150 div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote, div.forumTime blockquote, div.forumTimeline blockquote {
151 background-color: rgba(65, 131, 196, 0.1);
152 border-left: 3px solid #254769;
153 padding: .1em 1em;
154 }
155
156 table.report {
157 cursor: auto;
158 border-radius: 5px;
159 border: 1px solid #ccc;
160 margin: 1em 0;
161 }
162 .report td, .report th {
163 border: 0;
164 font-size: .8em;
165 padding: 10px;
166 }
167 .report td:first-child {
168 border-top-left-radius: 5px;
169 }
170 .report tbody tr:last-child td:first-child {
171 border-bottom-left-radius: 5px;
172 }
173 .report td:last-child {
174 border-top-right-radius: 5px;
175 }
176 .report tbody tr:last-child {
177 border-bottom-left-radius: 5px;
178 border-bottom-right-radius: 5px;
179 }
180 .report tbody tr:last-child td:last-child {
181 border-bottom-right-radius: 5px;
182 }
183 .report th {
184 cursor: pointer;
185 }
186 .report thead+tbody tr:hover {
187 background-color: #f5f9fc !important;
188 }
189
190 td.tktDspLabel {
191 width: 70px;
192 text-align: right;
193 overflow: hidden;
194 }
195 td.tktDspValue {
196 text-align: left;
197 vertical-align: top;
198 background-color: #f8f8f8;
199 border: 1px solid #ccc;
200 }
201 td.tktDspValue pre {
202 white-space: pre-wrap;
203 }
204
205 span.timelineDetail {
206 font-size: 90%;
207 }
208
209 .footer {
210 border-top: 1px solid #ccc;
211 padding: 10px;
212 font-size:.7em;
213 margin-top: 10px;
214 color: #ccc;
215 }
216 div.timelineDate {
217 font-weight: bold;
218 white-space: nowrap;
219 }
220 span.submenuctrl, span.submenuctrl input, select.submenuctrl {
221 color: #777;
222 }
223 span.submenuctrl {
224 white-space: nowrap;
225 }
226 div.submenu label {
227 white-space: nowrap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228 }
 
 
 
 
229 .fossil-tooltip.help-buttonlet-content {
230 background-color: lightyellow;
231 }
 
 
 
 
232 @media screen and (max-width: 600px) {
233 /* Spacing for mobile */
234 body {
235 padding-left: 4px;
236 padding-right: 4px;
237
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -1,236 +1,264 @@
1 /* Overall page style */
2
3 body {
4 margin: 0 auto;
5 background-color: white;
6 font-family: sans-serif;
7 font-size: 14pt;
8 -moz-text-size-adjust: none;
9 -mx-text-size-adjust: none;
10 -webkit-text-size-adjust: none;
11 }
12
13 a {
14 color: #4183C4;
15 text-decoration: none;
16 }
17 a:hover {
18 color: #4183C4;
19 text-decoration: underline;
 
 
 
20 }
21
22
23 /* Page title, above menu bars */
 
24
25 .title {
26 color: #4183C4;
27 float: left;
28 }
29 .title h1 {
30 display: inline;
31 }
32 .title h1:after {
33 content: " / ";
34 color: #777;
35 font-weight: normal;
36 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37 .status {
38 float: right;
39 font-size: 0.7em;
40 }
41
42
43 /* Main menu and optional sub-menu */
44
45 .mainmenu {
46 font-size: 0.8em;
47 clear: both;
48 background: #eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x;
49 border: 1px solid #eaeaea;
50 border-radius: 5px;
51 overflow-x: auto;
52 overflow-y: hidden;
53 white-space: nowrap;
54 z-index: 21; /* just above hbdrop */
55 }
 
56 .mainmenu a {
57 text-decoration: none;
58 color: #777;
59 border-right: 1px solid #eaeaea;
60 }
61 .mainmenu a.active,
62 .mainmenu a:hover {
63 color: #000;
64 border-bottom: 2px solid #D26911;
65 }
66 .mainmenu div#hbdrop {
67 background-color: white;
68 border: 1px solid black;
69 border-top: white;
70 border-radius: 0 0 0.5em 0.5em;
71 display: none;
72 font-size: 80%;
73 left: 2em;
74 width: 90%;
75 padding-right: 1em;
76 position: absolute;
77 z-index: 20; /* just below mainmenu, but above timeline bubbles */
 
78 }
79
80 .submenu {
81 font-size: .7em;
82 padding: 10px;
83 border-bottom: 1px solid #ccc;
84 }
 
85 .submenu a, .submenu label {
86 padding: 10px 11px;
87 text-decoration: none;
88 color: #777;
89 }
90 .submenu label {
91 white-space: nowrap;
92 }
93 .submenu a:hover, .submenu label:hover {
94 padding: 6px 10px;
95 border: 1px solid #ccc;
96 border-radius: 5px;
97 color: #000;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98 }
99 span.submenuctrl, span.submenuctrl input, select.submenuctrl {
100 color: #777;
101 }
102 span.submenuctrl {
103 white-space: nowrap;
104 }
105
106
107 /* Main document area; elements common to most pages. */
108
109 .content {
110 padding-top: 10px;
111 font-size: 0.8em;
112 color: #444;
113 }
114 .content blockquote {
115 padding: 0 15px;
116 }
117 .content h1 {
118 font-size: 1.25em;
119 }
120 .content h2 {
121 font-size: 1.15em;
122 }
123 .content h3 {
124 font-size: 1.05em;
125 }
126
127 .section {
128 font-size: 1em;
129 font-weight: bold;
130 background-color: #f5f5f5;
131 border: 1px solid #d8d8d8;
132 border-radius: 3px 3px 0 0;
133 padding: 9px 10px 10px;
134 margin: 10px 0;
135 }
136 .sectionmenu {
137 border: 1px solid #d8d8d8;
138 border-radius: 0 0 3px 3px;
139 border-top: 0;
140 margin-top: -10px;
141 margin-bottom: 10px;
142 padding: 10px;
143 }
144 .sectionmenu a {
145 display: inline-block;
146 margin-right: 1em;
147 }
148
149 hr {
150 color: #eee;
151 }
152
153
154 /* Page footer */
155
156 .footer {
157 border-top: 1px solid #ccc;
158 padding: 10px;
159 font-size: 0.7em;
160 margin-top: 10px;
161 color: #ccc;
162 }
163
164
165 /* Exceptions for /info diff views */
166
167 .udiff, .sbsdiff {
168 font-size: .85em !important;
169 overflow: auto;
170 border: 1px solid #ccc;
171 border-radius: 5px;
172 }
173
174
175 /* Forum */
176
177 .forum a:visited {
178 color: #6A7F94;
179 }
180
181 .forum blockquote {
182 background-color: rgba(65, 131, 196, 0.1);
183 border-left: 3px solid #254769;
184 padding: .1em 1em;
185 }
186
187
188 /* Tickets */
189
190 table.report {
191 cursor: auto;
192 border-radius: 5px;
193 border: 1px solid #ccc;
194 margin: 1em 0;
195 }
196 .report td, .report th {
197 border: 0;
198 font-size: .8em;
199 padding: 10px;
200 }
201 .report td:first-child {
202 border-top-left-radius: 5px;
203 }
204 .report tbody tr:last-child td:first-child {
205 border-bottom-left-radius: 5px;
206 }
207 .report td:last-child {
208 border-top-right-radius: 5px;
209 }
210 .report tbody tr:last-child {
211 border-bottom-left-radius: 5px;
212 border-bottom-right-radius: 5px;
213 }
214 .report tbody tr:last-child td:last-child {
215 border-bottom-right-radius: 5px;
216 }
217 .report th {
218 cursor: pointer;
219 }
220 .report thead+tbody tr:hover {
221 background-color: #f5f9fc !important;
222 }
223
224 td.tktDspLabel {
225 width: 70px;
226 text-align: right;
227 overflow: hidden;
228 }
229 td.tktDspValue {
230 text-align: left;
231 vertical-align: top;
232 background-color: #f8f8f8;
233 border: 1px solid #ccc;
234 }
235 td.tktDspValue pre {
236 white-space: pre-wrap;
237 }
238
239
240 /* Timeline */
241
242 span.timelineDetail {
243 font-size: 90%;
244 }
245 div.timelineDate {
246 font-weight: bold;
247 white-space: nowrap;
248 }
249
250
251 /* Miscellaneous UI elements */
252
253 .fossil-tooltip.help-buttonlet-content {
254 background-color: lightyellow;
255 }
256
257
258 /* Exceptions for specific screen sizes */
259
260 @media screen and (max-width: 600px) {
261 /* Spacing for mobile */
262 body {
263 padding-left: 4px;
264 padding-right: 4px;
265
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -381,11 +381,11 @@
381381
border: 1px solid white;
382382
}
383383
div.forumTimeline {
384384
border: 1px solid white;
385385
}
386
-div.forumHier, div.forumTime {
386
+div.forumTime {
387387
border: 1px solid white;
388388
}
389389
div.forumSel {
390390
background-color: #808080;
391391
}
392392
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -381,11 +381,11 @@
381 border: 1px solid white;
382 }
383 div.forumTimeline {
384 border: 1px solid white;
385 }
386 div.forumHier, div.forumTime {
387 border: 1px solid white;
388 }
389 div.forumSel {
390 background-color: #808080;
391 }
392
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -381,11 +381,11 @@
381 border: 1px solid white;
382 }
383 div.forumTimeline {
384 border: 1px solid white;
385 }
386 div.forumTime {
387 border: 1px solid white;
388 }
389 div.forumSel {
390 background-color: #808080;
391 }
392
+14 -14
--- src/alerts.c
+++ src/alerts.c
@@ -173,11 +173,11 @@
173173
*/
174174
static int alert_webpages_disabled(void){
175175
if( alert_tables_exist() ) return 0;
176176
style_header("Email Alerts Are Disabled");
177177
@ <p>Email alerts are disabled on this server</p>
178
- style_footer();
178
+ style_finish_page("alerts");
179179
return 1;
180180
}
181181
182182
/*
183183
** Insert a "Subscriber List" submenu link if the current user
@@ -308,11 +308,11 @@
308308
@ <hr>
309309
310310
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
311311
@ </div></form>
312312
db_end_transaction(0);
313
- style_footer();
313
+ style_finish_page("alerts");
314314
}
315315
316316
#if 0
317317
/*
318318
** Encode pMsg as MIME base64 and append it to pOut
@@ -1435,11 +1435,11 @@
14351435
@ <p>An email has been sent to "%h(zEAddr)". That email contains a
14361436
@ hyperlink that you must click to activate your
14371437
@ subscription.</p>
14381438
}
14391439
alert_sender_free(pSender);
1440
- style_footer();
1440
+ style_finish_page("alerts");
14411441
}
14421442
return;
14431443
}
14441444
style_header("Signup For Email Alerts");
14451445
if( P("submit")==0 ){
@@ -1552,11 +1552,11 @@
15521552
@ Enter the 8 characters above in the "Security Code" box<br/>
15531553
@ </td></tr></table></div>
15541554
}
15551555
@ </form>
15561556
fossil_free(zErr);
1557
- style_footer();
1557
+ style_finish_page("alerts");
15581558
}
15591559
15601560
/*
15611561
** Either shutdown or completely delete a subscription entry given
15621562
** by the hex value zName. Then paint a webpage that explains that
@@ -1590,11 +1590,11 @@
15901590
@ <a href="%R/setup_uedit?id=%d(uid)">edit or delete
15911591
@ the corresponding user "%h(zLogin)"</a></p>
15921592
}
15931593
}
15941594
db_finalize(&q);
1595
- style_footer();
1595
+ style_finish_page("alerts");
15961596
return;
15971597
}
15981598
15991599
/*
16001600
** WEBPAGE: alerts
@@ -1914,11 +1914,11 @@
19141914
@ </tr>
19151915
@ </table>
19161916
@ </form>
19171917
fossil_free(zErr);
19181918
db_finalize(&q);
1919
- style_footer();
1919
+ style_finish_page("alerts");
19201920
db_commit_transaction();
19211921
return;
19221922
}
19231923
19241924
/* This is the message that gets sent to describe how to change
@@ -2021,11 +2021,11 @@
20212021
}else{
20222022
@ <p>An email has been sent to "%h(zEAddr)" that explains how to
20232023
@ unsubscribe and/or modify your subscription settings</p>
20242024
}
20252025
alert_sender_free(pSender);
2026
- style_footer();
2026
+ style_finish_page("alerts");
20272027
return;
20282028
}
20292029
20302030
/* Non-logged-in users have to enter an email address to which is
20312031
** sent a message containing the unsubscribe link.
@@ -2071,11 +2071,11 @@
20712071
@ </pre>
20722072
@ Enter the 8 characters above in the "Security Code" box<br/>
20732073
@ </td></tr></table></div>
20742074
@ </form>
20752075
fossil_free(zErr);
2076
- style_footer();
2076
+ style_finish_page("alerts");
20772077
}
20782078
20792079
/*
20802080
** WEBPAGE: subscribers
20812081
**
@@ -2182,11 +2182,11 @@
21822182
@ </tr>
21832183
}
21842184
@ </tbody></table>
21852185
db_finalize(&q);
21862186
style_table_sorter();
2187
- style_footer();
2187
+ style_finish_page("alerts");
21882188
}
21892189
21902190
#if LOCAL_INTERFACE
21912191
/*
21922192
** A single event that might appear in an alert is recorded as an
@@ -2802,11 +2802,11 @@
28022802
28032803
login_check_credentials();
28042804
if( zAdminEmail==0 || zAdminEmail[0]==0 ){
28052805
style_header("Outbound Email Disabled");
28062806
@ <p>Outbound email is disabled on this repository
2807
- style_footer();
2807
+ style_finish_page("alerts");
28082808
return;
28092809
}
28102810
if( P("submit")!=0
28112811
&& P("subject")!=0
28122812
&& P("msg")!=0
@@ -2834,11 +2834,11 @@
28342834
}else{
28352835
@ <p>Your message has been sent to the repository administrator.
28362836
@ Thank you for your input.</p>
28372837
}
28382838
alert_sender_free(pSender);
2839
- style_footer();
2839
+ style_finish_page("alerts");
28402840
return;
28412841
}
28422842
if( captcha_needed() ){
28432843
uSeed = captcha_seed();
28442844
zDecoded = captcha_decode(uSeed);
@@ -2881,11 +2881,11 @@
28812881
@ </pre>
28822882
@ Enter the 8 characters above in the "Security Code" box<br/>
28832883
@ </td></tr></table></div>
28842884
}
28852885
@ </form>
2886
- style_footer();
2886
+ style_finish_page("alerts");
28872887
}
28882888
28892889
/*
28902890
** Send an annoucement message described by query parameter.
28912891
** Permission to do this has already been verified.
@@ -2989,11 +2989,11 @@
29892989
@ </pre></blockquote>
29902990
}else{
29912991
@ <p>The announcement has been sent.
29922992
@ <a href="%h(PD("REQUEST_URI","/"))">Send another</a></p>
29932993
}
2994
- style_footer();
2994
+ style_finish_page("alerts");
29952995
return;
29962996
} else if( !alert_enabled() ){
29972997
style_header("Cannot Send Announcement");
29982998
@ <p>Either you have no subscribers yet, or email alerts are not yet
29992999
@ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
@@ -3043,7 +3043,7 @@
30433043
@ <td><input type="submit" name="submit" value="Send Message">
30443044
}
30453045
@ </tr>
30463046
@ </table>
30473047
@ </form>
3048
- style_footer();
3048
+ style_finish_page("alerts");
30493049
}
30503050
--- src/alerts.c
+++ src/alerts.c
@@ -173,11 +173,11 @@
173 */
174 static int alert_webpages_disabled(void){
175 if( alert_tables_exist() ) return 0;
176 style_header("Email Alerts Are Disabled");
177 @ <p>Email alerts are disabled on this server</p>
178 style_footer();
179 return 1;
180 }
181
182 /*
183 ** Insert a "Subscriber List" submenu link if the current user
@@ -308,11 +308,11 @@
308 @ <hr>
309
310 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
311 @ </div></form>
312 db_end_transaction(0);
313 style_footer();
314 }
315
316 #if 0
317 /*
318 ** Encode pMsg as MIME base64 and append it to pOut
@@ -1435,11 +1435,11 @@
1435 @ <p>An email has been sent to "%h(zEAddr)". That email contains a
1436 @ hyperlink that you must click to activate your
1437 @ subscription.</p>
1438 }
1439 alert_sender_free(pSender);
1440 style_footer();
1441 }
1442 return;
1443 }
1444 style_header("Signup For Email Alerts");
1445 if( P("submit")==0 ){
@@ -1552,11 +1552,11 @@
1552 @ Enter the 8 characters above in the "Security Code" box<br/>
1553 @ </td></tr></table></div>
1554 }
1555 @ </form>
1556 fossil_free(zErr);
1557 style_footer();
1558 }
1559
1560 /*
1561 ** Either shutdown or completely delete a subscription entry given
1562 ** by the hex value zName. Then paint a webpage that explains that
@@ -1590,11 +1590,11 @@
1590 @ <a href="%R/setup_uedit?id=%d(uid)">edit or delete
1591 @ the corresponding user "%h(zLogin)"</a></p>
1592 }
1593 }
1594 db_finalize(&q);
1595 style_footer();
1596 return;
1597 }
1598
1599 /*
1600 ** WEBPAGE: alerts
@@ -1914,11 +1914,11 @@
1914 @ </tr>
1915 @ </table>
1916 @ </form>
1917 fossil_free(zErr);
1918 db_finalize(&q);
1919 style_footer();
1920 db_commit_transaction();
1921 return;
1922 }
1923
1924 /* This is the message that gets sent to describe how to change
@@ -2021,11 +2021,11 @@
2021 }else{
2022 @ <p>An email has been sent to "%h(zEAddr)" that explains how to
2023 @ unsubscribe and/or modify your subscription settings</p>
2024 }
2025 alert_sender_free(pSender);
2026 style_footer();
2027 return;
2028 }
2029
2030 /* Non-logged-in users have to enter an email address to which is
2031 ** sent a message containing the unsubscribe link.
@@ -2071,11 +2071,11 @@
2071 @ </pre>
2072 @ Enter the 8 characters above in the "Security Code" box<br/>
2073 @ </td></tr></table></div>
2074 @ </form>
2075 fossil_free(zErr);
2076 style_footer();
2077 }
2078
2079 /*
2080 ** WEBPAGE: subscribers
2081 **
@@ -2182,11 +2182,11 @@
2182 @ </tr>
2183 }
2184 @ </tbody></table>
2185 db_finalize(&q);
2186 style_table_sorter();
2187 style_footer();
2188 }
2189
2190 #if LOCAL_INTERFACE
2191 /*
2192 ** A single event that might appear in an alert is recorded as an
@@ -2802,11 +2802,11 @@
2802
2803 login_check_credentials();
2804 if( zAdminEmail==0 || zAdminEmail[0]==0 ){
2805 style_header("Outbound Email Disabled");
2806 @ <p>Outbound email is disabled on this repository
2807 style_footer();
2808 return;
2809 }
2810 if( P("submit")!=0
2811 && P("subject")!=0
2812 && P("msg")!=0
@@ -2834,11 +2834,11 @@
2834 }else{
2835 @ <p>Your message has been sent to the repository administrator.
2836 @ Thank you for your input.</p>
2837 }
2838 alert_sender_free(pSender);
2839 style_footer();
2840 return;
2841 }
2842 if( captcha_needed() ){
2843 uSeed = captcha_seed();
2844 zDecoded = captcha_decode(uSeed);
@@ -2881,11 +2881,11 @@
2881 @ </pre>
2882 @ Enter the 8 characters above in the "Security Code" box<br/>
2883 @ </td></tr></table></div>
2884 }
2885 @ </form>
2886 style_footer();
2887 }
2888
2889 /*
2890 ** Send an annoucement message described by query parameter.
2891 ** Permission to do this has already been verified.
@@ -2989,11 +2989,11 @@
2989 @ </pre></blockquote>
2990 }else{
2991 @ <p>The announcement has been sent.
2992 @ <a href="%h(PD("REQUEST_URI","/"))">Send another</a></p>
2993 }
2994 style_footer();
2995 return;
2996 } else if( !alert_enabled() ){
2997 style_header("Cannot Send Announcement");
2998 @ <p>Either you have no subscribers yet, or email alerts are not yet
2999 @ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
@@ -3043,7 +3043,7 @@
3043 @ <td><input type="submit" name="submit" value="Send Message">
3044 }
3045 @ </tr>
3046 @ </table>
3047 @ </form>
3048 style_footer();
3049 }
3050
--- src/alerts.c
+++ src/alerts.c
@@ -173,11 +173,11 @@
173 */
174 static int alert_webpages_disabled(void){
175 if( alert_tables_exist() ) return 0;
176 style_header("Email Alerts Are Disabled");
177 @ <p>Email alerts are disabled on this server</p>
178 style_finish_page("alerts");
179 return 1;
180 }
181
182 /*
183 ** Insert a "Subscriber List" submenu link if the current user
@@ -308,11 +308,11 @@
308 @ <hr>
309
310 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
311 @ </div></form>
312 db_end_transaction(0);
313 style_finish_page("alerts");
314 }
315
316 #if 0
317 /*
318 ** Encode pMsg as MIME base64 and append it to pOut
@@ -1435,11 +1435,11 @@
1435 @ <p>An email has been sent to "%h(zEAddr)". That email contains a
1436 @ hyperlink that you must click to activate your
1437 @ subscription.</p>
1438 }
1439 alert_sender_free(pSender);
1440 style_finish_page("alerts");
1441 }
1442 return;
1443 }
1444 style_header("Signup For Email Alerts");
1445 if( P("submit")==0 ){
@@ -1552,11 +1552,11 @@
1552 @ Enter the 8 characters above in the "Security Code" box<br/>
1553 @ </td></tr></table></div>
1554 }
1555 @ </form>
1556 fossil_free(zErr);
1557 style_finish_page("alerts");
1558 }
1559
1560 /*
1561 ** Either shutdown or completely delete a subscription entry given
1562 ** by the hex value zName. Then paint a webpage that explains that
@@ -1590,11 +1590,11 @@
1590 @ <a href="%R/setup_uedit?id=%d(uid)">edit or delete
1591 @ the corresponding user "%h(zLogin)"</a></p>
1592 }
1593 }
1594 db_finalize(&q);
1595 style_finish_page("alerts");
1596 return;
1597 }
1598
1599 /*
1600 ** WEBPAGE: alerts
@@ -1914,11 +1914,11 @@
1914 @ </tr>
1915 @ </table>
1916 @ </form>
1917 fossil_free(zErr);
1918 db_finalize(&q);
1919 style_finish_page("alerts");
1920 db_commit_transaction();
1921 return;
1922 }
1923
1924 /* This is the message that gets sent to describe how to change
@@ -2021,11 +2021,11 @@
2021 }else{
2022 @ <p>An email has been sent to "%h(zEAddr)" that explains how to
2023 @ unsubscribe and/or modify your subscription settings</p>
2024 }
2025 alert_sender_free(pSender);
2026 style_finish_page("alerts");
2027 return;
2028 }
2029
2030 /* Non-logged-in users have to enter an email address to which is
2031 ** sent a message containing the unsubscribe link.
@@ -2071,11 +2071,11 @@
2071 @ </pre>
2072 @ Enter the 8 characters above in the "Security Code" box<br/>
2073 @ </td></tr></table></div>
2074 @ </form>
2075 fossil_free(zErr);
2076 style_finish_page("alerts");
2077 }
2078
2079 /*
2080 ** WEBPAGE: subscribers
2081 **
@@ -2182,11 +2182,11 @@
2182 @ </tr>
2183 }
2184 @ </tbody></table>
2185 db_finalize(&q);
2186 style_table_sorter();
2187 style_finish_page("alerts");
2188 }
2189
2190 #if LOCAL_INTERFACE
2191 /*
2192 ** A single event that might appear in an alert is recorded as an
@@ -2802,11 +2802,11 @@
2802
2803 login_check_credentials();
2804 if( zAdminEmail==0 || zAdminEmail[0]==0 ){
2805 style_header("Outbound Email Disabled");
2806 @ <p>Outbound email is disabled on this repository
2807 style_finish_page("alerts");
2808 return;
2809 }
2810 if( P("submit")!=0
2811 && P("subject")!=0
2812 && P("msg")!=0
@@ -2834,11 +2834,11 @@
2834 }else{
2835 @ <p>Your message has been sent to the repository administrator.
2836 @ Thank you for your input.</p>
2837 }
2838 alert_sender_free(pSender);
2839 style_finish_page("alerts");
2840 return;
2841 }
2842 if( captcha_needed() ){
2843 uSeed = captcha_seed();
2844 zDecoded = captcha_decode(uSeed);
@@ -2881,11 +2881,11 @@
2881 @ </pre>
2882 @ Enter the 8 characters above in the "Security Code" box<br/>
2883 @ </td></tr></table></div>
2884 }
2885 @ </form>
2886 style_finish_page("alerts");
2887 }
2888
2889 /*
2890 ** Send an annoucement message described by query parameter.
2891 ** Permission to do this has already been verified.
@@ -2989,11 +2989,11 @@
2989 @ </pre></blockquote>
2990 }else{
2991 @ <p>The announcement has been sent.
2992 @ <a href="%h(PD("REQUEST_URI","/"))">Send another</a></p>
2993 }
2994 style_finish_page("alerts");
2995 return;
2996 } else if( !alert_enabled() ){
2997 style_header("Cannot Send Announcement");
2998 @ <p>Either you have no subscribers yet, or email alerts are not yet
2999 @ <a href="https://fossil-scm.org/fossil/doc/trunk/www/alerts.md">set up</a>
@@ -3043,7 +3043,7 @@
3043 @ <td><input type="submit" name="submit" value="Send Message">
3044 }
3045 @ </tr>
3046 @ </table>
3047 @ </form>
3048 style_finish_page("alerts");
3049 }
3050
+5 -5
--- src/attach.c
+++ src/attach.c
@@ -145,11 +145,11 @@
145145
hyperlink_to_date(zDate, ".");
146146
free(zUrlTail);
147147
}
148148
db_finalize(&q);
149149
@ </ol>
150
- style_footer();
150
+ style_finish_page("attach");
151151
return;
152152
}
153153
154154
/*
155155
** WEBPAGE: attachdownload
@@ -205,16 +205,16 @@
205205
);
206206
}
207207
if( zUUID==0 || zUUID[0]==0 ){
208208
style_header("No Such Attachment");
209209
@ No such attachment....
210
- style_footer();
210
+ style_finish_page("attach");
211211
return;
212212
}else if( zUUID[0]=='x' ){
213213
style_header("Missing");
214214
@ Attachment has been deleted
215
- style_footer();
215
+ style_finish_page("attach");
216216
return;
217217
}else{
218218
g.perm.Read = 1;
219219
cgi_replace_parameter("name",zUUID);
220220
if( fossil_strcmp(g.zPath,"attachview")==0 ){
@@ -410,11 +410,11 @@
410410
@ <input type="submit" name="ok" value="Add Attachment" />
411411
@ <input type="submit" name="cancel" value="Cancel" />
412412
@ </div>
413413
captcha_generate(0);
414414
@ </form>
415
- style_footer();
415
+ style_finish_page("attach");
416416
fossil_free(zTargetType);
417417
}
418418
419419
/*
420420
** WEBPAGE: ainfo
@@ -622,11 +622,11 @@
622622
@ <i>(file is %d(sz) bytes of binary data)</i>
623623
}
624624
@ </blockquote>
625625
manifest_destroy(pAttach);
626626
blob_reset(&attach);
627
- style_footer();
627
+ style_finish_page("attach");
628628
}
629629
630630
/*
631631
** Output HTML to show a list of attachments.
632632
*/
633633
--- src/attach.c
+++ src/attach.c
@@ -145,11 +145,11 @@
145 hyperlink_to_date(zDate, ".");
146 free(zUrlTail);
147 }
148 db_finalize(&q);
149 @ </ol>
150 style_footer();
151 return;
152 }
153
154 /*
155 ** WEBPAGE: attachdownload
@@ -205,16 +205,16 @@
205 );
206 }
207 if( zUUID==0 || zUUID[0]==0 ){
208 style_header("No Such Attachment");
209 @ No such attachment....
210 style_footer();
211 return;
212 }else if( zUUID[0]=='x' ){
213 style_header("Missing");
214 @ Attachment has been deleted
215 style_footer();
216 return;
217 }else{
218 g.perm.Read = 1;
219 cgi_replace_parameter("name",zUUID);
220 if( fossil_strcmp(g.zPath,"attachview")==0 ){
@@ -410,11 +410,11 @@
410 @ <input type="submit" name="ok" value="Add Attachment" />
411 @ <input type="submit" name="cancel" value="Cancel" />
412 @ </div>
413 captcha_generate(0);
414 @ </form>
415 style_footer();
416 fossil_free(zTargetType);
417 }
418
419 /*
420 ** WEBPAGE: ainfo
@@ -622,11 +622,11 @@
622 @ <i>(file is %d(sz) bytes of binary data)</i>
623 }
624 @ </blockquote>
625 manifest_destroy(pAttach);
626 blob_reset(&attach);
627 style_footer();
628 }
629
630 /*
631 ** Output HTML to show a list of attachments.
632 */
633
--- src/attach.c
+++ src/attach.c
@@ -145,11 +145,11 @@
145 hyperlink_to_date(zDate, ".");
146 free(zUrlTail);
147 }
148 db_finalize(&q);
149 @ </ol>
150 style_finish_page("attach");
151 return;
152 }
153
154 /*
155 ** WEBPAGE: attachdownload
@@ -205,16 +205,16 @@
205 );
206 }
207 if( zUUID==0 || zUUID[0]==0 ){
208 style_header("No Such Attachment");
209 @ No such attachment....
210 style_finish_page("attach");
211 return;
212 }else if( zUUID[0]=='x' ){
213 style_header("Missing");
214 @ Attachment has been deleted
215 style_finish_page("attach");
216 return;
217 }else{
218 g.perm.Read = 1;
219 cgi_replace_parameter("name",zUUID);
220 if( fossil_strcmp(g.zPath,"attachview")==0 ){
@@ -410,11 +410,11 @@
410 @ <input type="submit" name="ok" value="Add Attachment" />
411 @ <input type="submit" name="cancel" value="Cancel" />
412 @ </div>
413 captcha_generate(0);
414 @ </form>
415 style_finish_page("attach");
416 fossil_free(zTargetType);
417 }
418
419 /*
420 ** WEBPAGE: ainfo
@@ -622,11 +622,11 @@
622 @ <i>(file is %d(sz) bytes of binary data)</i>
623 }
624 @ </blockquote>
625 manifest_destroy(pAttach);
626 blob_reset(&attach);
627 style_finish_page("attach");
628 }
629
630 /*
631 ** Output HTML to show a list of attachments.
632 */
633
+2 -2
--- src/backlink.c
+++ src/backlink.c
@@ -91,11 +91,11 @@
9191
blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
9292
db_prepare(&q, "%s", blob_sql_text(&sql));
9393
www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
9494
0, 0, 0, 0, 0, 0);
9595
db_finalize(&q);
96
- style_footer();
96
+ style_finish_page("test");
9797
}
9898
9999
/*
100100
** WEBPAGE: test-backlinks
101101
**
@@ -152,11 +152,11 @@
152152
@ <td>%h(zMtime)</tr>
153153
}
154154
@ </tbody>
155155
@ </table>
156156
db_finalize(&q);
157
- style_footer();
157
+ style_finish_page("test");
158158
}
159159
160160
/*
161161
** Remove all prior backlinks for the wiki page given. Then
162162
** add new backlinks for the latest version of the wiki page.
163163
--- src/backlink.c
+++ src/backlink.c
@@ -91,11 +91,11 @@
91 blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
92 db_prepare(&q, "%s", blob_sql_text(&sql));
93 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
94 0, 0, 0, 0, 0, 0);
95 db_finalize(&q);
96 style_footer();
97 }
98
99 /*
100 ** WEBPAGE: test-backlinks
101 **
@@ -152,11 +152,11 @@
152 @ <td>%h(zMtime)</tr>
153 }
154 @ </tbody>
155 @ </table>
156 db_finalize(&q);
157 style_footer();
158 }
159
160 /*
161 ** Remove all prior backlinks for the wiki page given. Then
162 ** add new backlinks for the latest version of the wiki page.
163
--- src/backlink.c
+++ src/backlink.c
@@ -91,11 +91,11 @@
91 blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
92 db_prepare(&q, "%s", blob_sql_text(&sql));
93 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
94 0, 0, 0, 0, 0, 0);
95 db_finalize(&q);
96 style_finish_page("test");
97 }
98
99 /*
100 ** WEBPAGE: test-backlinks
101 **
@@ -152,11 +152,11 @@
152 @ <td>%h(zMtime)</tr>
153 }
154 @ </tbody>
155 @ </table>
156 db_finalize(&q);
157 style_finish_page("test");
158 }
159
160 /*
161 ** Remove all prior backlinks for the wiki page given. Then
162 ** add new backlinks for the latest version of the wiki page.
163
+3 -3
--- src/branch.c
+++ src/branch.c
@@ -514,11 +514,11 @@
514514
@ </tr>
515515
}
516516
@ </tbody></table></div>
517517
db_finalize(&q);
518518
style_table_sorter();
519
- style_footer();
519
+ style_finish_page("branch");
520520
}
521521
522522
/*
523523
** WEBPAGE: brlist
524524
** Show a list of branches. With no query parameters, a sortable table
@@ -622,11 +622,11 @@
622622
}
623623
if( cnt ){
624624
@ </ul>
625625
}
626626
db_finalize(&q);
627
- style_footer();
627
+ style_finish_page("branch");
628628
}
629629
630630
/*
631631
** This routine is called while for each check-in that is rendered by
632632
** the timeline of a "brlist" page. Add some additional hyperlinks
@@ -698,7 +698,7 @@
698698
if( PB("ng")==0 ) tmFlags |= TIMELINE_GRAPH;
699699
if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
700700
if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
701701
www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, brtimeline_extra);
702702
db_finalize(&q);
703
- style_footer();
703
+ style_finish_page("branch");
704704
}
705705
--- src/branch.c
+++ src/branch.c
@@ -514,11 +514,11 @@
514 @ </tr>
515 }
516 @ </tbody></table></div>
517 db_finalize(&q);
518 style_table_sorter();
519 style_footer();
520 }
521
522 /*
523 ** WEBPAGE: brlist
524 ** Show a list of branches. With no query parameters, a sortable table
@@ -622,11 +622,11 @@
622 }
623 if( cnt ){
624 @ </ul>
625 }
626 db_finalize(&q);
627 style_footer();
628 }
629
630 /*
631 ** This routine is called while for each check-in that is rendered by
632 ** the timeline of a "brlist" page. Add some additional hyperlinks
@@ -698,7 +698,7 @@
698 if( PB("ng")==0 ) tmFlags |= TIMELINE_GRAPH;
699 if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
700 if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
701 www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, brtimeline_extra);
702 db_finalize(&q);
703 style_footer();
704 }
705
--- src/branch.c
+++ src/branch.c
@@ -514,11 +514,11 @@
514 @ </tr>
515 }
516 @ </tbody></table></div>
517 db_finalize(&q);
518 style_table_sorter();
519 style_finish_page("branch");
520 }
521
522 /*
523 ** WEBPAGE: brlist
524 ** Show a list of branches. With no query parameters, a sortable table
@@ -622,11 +622,11 @@
622 }
623 if( cnt ){
624 @ </ul>
625 }
626 db_finalize(&q);
627 style_finish_page("branch");
628 }
629
630 /*
631 ** This routine is called while for each check-in that is rendered by
632 ** the timeline of a "brlist" page. Add some additional hyperlinks
@@ -698,7 +698,7 @@
698 if( PB("ng")==0 ) tmFlags |= TIMELINE_GRAPH;
699 if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
700 if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
701 www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, brtimeline_extra);
702 db_finalize(&q);
703 style_finish_page("branch");
704 }
705
+4 -4
--- src/browse.c
+++ src/browse.c
@@ -336,11 +336,11 @@
336336
337337
/* If the "noreadme" query parameter is present, do not try to
338338
** show the content of the README file.
339339
*/
340340
if( P("noreadme")!=0 ){
341
- style_footer();
341
+ style_finish_page("dir");
342342
return;
343343
}
344344
345345
/* If the directory contains a readme file, then display its content below
346346
** the list of files
@@ -397,11 +397,11 @@
397397
document_emit_js();
398398
}
399399
}
400400
}
401401
db_finalize(&q);
402
- style_footer();
402
+ style_finish_page("dir");
403403
}
404404
405405
/*
406406
** Objects used by the "tree" webpage.
407407
*/
@@ -913,11 +913,11 @@
913913
}
914914
}
915915
@ </ul>
916916
@ </ul></div>
917917
builtin_request_js("tree.js");
918
- style_footer();
918
+ style_finish_page("tree");
919919
920920
/* We could free memory used by sTree here if we needed to. But
921921
** the process is about to exit, so doing so would not really accomplish
922922
** anything useful. */
923923
}
@@ -1167,7 +1167,7 @@
11671167
fossil_free(zAge);
11681168
}
11691169
@ </table></div>
11701170
db_finalize(&q1);
11711171
db_finalize(&q2);
1172
- style_footer();
1172
+ style_finish_page("fileage");
11731173
}
11741174
--- src/browse.c
+++ src/browse.c
@@ -336,11 +336,11 @@
336
337 /* If the "noreadme" query parameter is present, do not try to
338 ** show the content of the README file.
339 */
340 if( P("noreadme")!=0 ){
341 style_footer();
342 return;
343 }
344
345 /* If the directory contains a readme file, then display its content below
346 ** the list of files
@@ -397,11 +397,11 @@
397 document_emit_js();
398 }
399 }
400 }
401 db_finalize(&q);
402 style_footer();
403 }
404
405 /*
406 ** Objects used by the "tree" webpage.
407 */
@@ -913,11 +913,11 @@
913 }
914 }
915 @ </ul>
916 @ </ul></div>
917 builtin_request_js("tree.js");
918 style_footer();
919
920 /* We could free memory used by sTree here if we needed to. But
921 ** the process is about to exit, so doing so would not really accomplish
922 ** anything useful. */
923 }
@@ -1167,7 +1167,7 @@
1167 fossil_free(zAge);
1168 }
1169 @ </table></div>
1170 db_finalize(&q1);
1171 db_finalize(&q2);
1172 style_footer();
1173 }
1174
--- src/browse.c
+++ src/browse.c
@@ -336,11 +336,11 @@
336
337 /* If the "noreadme" query parameter is present, do not try to
338 ** show the content of the README file.
339 */
340 if( P("noreadme")!=0 ){
341 style_finish_page("dir");
342 return;
343 }
344
345 /* If the directory contains a readme file, then display its content below
346 ** the list of files
@@ -397,11 +397,11 @@
397 document_emit_js();
398 }
399 }
400 }
401 db_finalize(&q);
402 style_finish_page("dir");
403 }
404
405 /*
406 ** Objects used by the "tree" webpage.
407 */
@@ -913,11 +913,11 @@
913 }
914 }
915 @ </ul>
916 @ </ul></div>
917 builtin_request_js("tree.js");
918 style_finish_page("tree");
919
920 /* We could free memory used by sTree here if we needed to. But
921 ** the process is about to exit, so doing so would not really accomplish
922 ** anything useful. */
923 }
@@ -1167,7 +1167,7 @@
1167 fossil_free(zAge);
1168 }
1169 @ </table></div>
1170 db_finalize(&q1);
1171 db_finalize(&q2);
1172 style_finish_page("fileage");
1173 }
1174
+1 -1
--- src/builtin.c
+++ src/builtin.c
@@ -103,11 +103,11 @@
103103
char *zUrl = href("%R/builtin?name=%T&id=%.8s&mimetype=text/plain",
104104
z,fossil_exe_id());
105105
@ <li>%z(zUrl)%h(z)</a>
106106
}
107107
@ </ol>
108
- style_footer();
108
+ style_finish_page("test");
109109
}
110110
111111
/*
112112
** COMMAND: test-builtin-get
113113
**
114114
--- src/builtin.c
+++ src/builtin.c
@@ -103,11 +103,11 @@
103 char *zUrl = href("%R/builtin?name=%T&id=%.8s&mimetype=text/plain",
104 z,fossil_exe_id());
105 @ <li>%z(zUrl)%h(z)</a>
106 }
107 @ </ol>
108 style_footer();
109 }
110
111 /*
112 ** COMMAND: test-builtin-get
113 **
114
--- src/builtin.c
+++ src/builtin.c
@@ -103,11 +103,11 @@
103 char *zUrl = href("%R/builtin?name=%T&id=%.8s&mimetype=text/plain",
104 z,fossil_exe_id());
105 @ <li>%z(zUrl)%h(z)</a>
106 }
107 @ </ol>
108 style_finish_page("test");
109 }
110
111 /*
112 ** COMMAND: test-builtin-get
113 **
114
+2 -2
--- src/cache.c
+++ src/cache.c
@@ -384,11 +384,11 @@
384384
@ <p>cache-file name: %h(zDbName)</p>
385385
@ <p>cache-file size: %s(zBuf)</p>
386386
fossil_free(zDbName);
387387
sqlite3_close(db);
388388
}
389
- style_footer();
389
+ style_finish_page("cache");
390390
}
391391
392392
/*
393393
** WEBPAGE: cacheget
394394
**
@@ -407,11 +407,11 @@
407407
zKey = PD("key","");
408408
blob_zero(&content);
409409
if( cache_read(&content, zKey)==0 ){
410410
style_header("Cache Download Error");
411411
@ The cache does not contain any entry with this key: "%h(zKey)"
412
- style_footer();
412
+ style_finish_page("cache");
413413
return;
414414
}
415415
cgi_set_content(&content);
416416
cgi_set_content_type("application/x-compressed");
417417
}
418418
--- src/cache.c
+++ src/cache.c
@@ -384,11 +384,11 @@
384 @ <p>cache-file name: %h(zDbName)</p>
385 @ <p>cache-file size: %s(zBuf)</p>
386 fossil_free(zDbName);
387 sqlite3_close(db);
388 }
389 style_footer();
390 }
391
392 /*
393 ** WEBPAGE: cacheget
394 **
@@ -407,11 +407,11 @@
407 zKey = PD("key","");
408 blob_zero(&content);
409 if( cache_read(&content, zKey)==0 ){
410 style_header("Cache Download Error");
411 @ The cache does not contain any entry with this key: "%h(zKey)"
412 style_footer();
413 return;
414 }
415 cgi_set_content(&content);
416 cgi_set_content_type("application/x-compressed");
417 }
418
--- src/cache.c
+++ src/cache.c
@@ -384,11 +384,11 @@
384 @ <p>cache-file name: %h(zDbName)</p>
385 @ <p>cache-file size: %s(zBuf)</p>
386 fossil_free(zDbName);
387 sqlite3_close(db);
388 }
389 style_finish_page("cache");
390 }
391
392 /*
393 ** WEBPAGE: cacheget
394 **
@@ -407,11 +407,11 @@
407 zKey = PD("key","");
408 blob_zero(&content);
409 if( cache_read(&content, zKey)==0 ){
410 style_header("Cache Download Error");
411 @ The cache does not contain any entry with this key: "%h(zKey)"
412 style_finish_page("cache");
413 return;
414 }
415 cgi_set_content(&content);
416 cgi_set_content_type("application/x-compressed");
417 }
418
+2 -2
--- src/captcha.c
+++ src/captcha.c
@@ -590,11 +590,11 @@
590590
}
591591
style_header("Captcha Test");
592592
@ <pre>
593593
@ %s(captcha_render(zPw))
594594
@ </pre>
595
- style_footer();
595
+ style_finish_page("test");
596596
}
597597
598598
/*
599599
** Check to see if the current request is coming from an agent that might
600600
** be a spider. If the agent is not a spider, then return 0 without doing
@@ -627,11 +627,11 @@
627627
@ <form method='POST' action='%s(g.zPath)'>
628628
cgi_query_parameters_to_hidden();
629629
@ <p>Please demonstrate that you are human, not a spider or robot</p>
630630
captcha_generate(1);
631631
@ </form>
632
- style_footer();
632
+ style_finish_page("captcha");
633633
return 1;
634634
}
635635
636636
/*
637637
** Generate a WAV file that reads aloud the hex digits given by
638638
--- src/captcha.c
+++ src/captcha.c
@@ -590,11 +590,11 @@
590 }
591 style_header("Captcha Test");
592 @ <pre>
593 @ %s(captcha_render(zPw))
594 @ </pre>
595 style_footer();
596 }
597
598 /*
599 ** Check to see if the current request is coming from an agent that might
600 ** be a spider. If the agent is not a spider, then return 0 without doing
@@ -627,11 +627,11 @@
627 @ <form method='POST' action='%s(g.zPath)'>
628 cgi_query_parameters_to_hidden();
629 @ <p>Please demonstrate that you are human, not a spider or robot</p>
630 captcha_generate(1);
631 @ </form>
632 style_footer();
633 return 1;
634 }
635
636 /*
637 ** Generate a WAV file that reads aloud the hex digits given by
638
--- src/captcha.c
+++ src/captcha.c
@@ -590,11 +590,11 @@
590 }
591 style_header("Captcha Test");
592 @ <pre>
593 @ %s(captcha_render(zPw))
594 @ </pre>
595 style_finish_page("test");
596 }
597
598 /*
599 ** Check to see if the current request is coming from an agent that might
600 ** be a spider. If the agent is not a spider, then return 0 without doing
@@ -627,11 +627,11 @@
627 @ <form method='POST' action='%s(g.zPath)'>
628 cgi_query_parameters_to_hidden();
629 @ <p>Please demonstrate that you are human, not a spider or robot</p>
630 captcha_generate(1);
631 @ </form>
632 style_finish_page("captcha");
633 return 1;
634 }
635
636 /*
637 ** Generate a WAV file that reads aloud the hex digits given by
638
+67 -24
--- src/clone.c
+++ src/clone.c
@@ -80,15 +80,17 @@
8080
8181
8282
/*
8383
** COMMAND: clone
8484
**
85
-** Usage: %fossil clone ?OPTIONS? URI FILENAME
85
+** Usage: %fossil clone ?OPTIONS? URI ?FILENAME?
8686
**
8787
** Make a clone of a repository specified by URI in the local
88
-** file named FILENAME. URI may be one of the following forms:
89
-** ([...] denotes optional elements):
88
+** file named FILENAME. If FILENAME is omitted, then an appropriate
89
+** filename is deduced from last element of the path in the URL.
90
+**
91
+** URI may be one of the following forms ([...] denotes optional elements):
9092
**
9193
** * HTTP/HTTPS protocol:
9294
**
9395
** http[s]://[userid[:password]@]host[:port][/path]
9496
**
@@ -98,36 +100,43 @@
98100
**
99101
** * Filesystem:
100102
**
101103
** [file://]path/to/repo.fossil
102104
**
103
-** Note that in Fossil (in contrast to some other DVCSes) a repository
104
-** is distinct from a checkout. This command create a clone of a repository.
105
-** Use the separate [[open]] command to open a checkout from that repository.
106
-**
107105
** For ssh and filesystem, path must have an extra leading
108106
** '/' to use an absolute path.
109107
**
110108
** Use %HH escapes for special characters in the userid and
111109
** password. For example "%40" in place of "@", "%2f" in place
112110
** of "/", and "%3a" in place of ":".
111
+**
112
+** Note that in Fossil (in contrast to some other DVCSes) a repository
113
+** is distinct from a checkout. Cloning a repository is not the same thing
114
+** as opening a repository. This command always clones the repository. This
115
+** command might also open the repository, but only if the --no-open option
116
+** is omitted and either the --workdir option is included or the FILENAME
117
+** argument is omitted. Use the separate [[open]] command to open a
118
+** repository that was previously cloned and already exists on the
119
+** local machine.
113120
**
114121
** By default, the current login name is used to create the default
115
-** admin user. This can be overridden using the -A|--admin-user
116
-** parameter.
122
+** admin user for the new clone. This can be overridden using
123
+** the -A|--admin-user parameter.
117124
**
118125
** Options:
119126
** --admin-user|-A USERNAME Make USERNAME the administrator
120127
** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
121128
** --nocompress Omit extra delta compression
129
+** --no-open Clone only. Do not open a check-out.
122130
** --once Don't remember the URI.
123131
** --private Also clone private branches
124132
** --save-http-password Remember the HTTP password without asking
125133
** --ssh-command|-c SSH Use SSH as the "ssh" command
126134
** --ssl-identity FILENAME Use the SSL identity if requested by the server
127135
** -u|--unversioned Also sync unversioned content
128136
** -v|--verbose Show more statistics in output
137
+** --workdir DIR Also open a checkout in DIR
129138
**
130139
** See also: [[init]], [[open]]
131140
*/
132141
void clone_cmd(void){
133142
char *zPassword;
@@ -135,10 +144,14 @@
135144
const char *zHttpAuth; /* HTTP Authorization user:pass information */
136145
int nErr = 0;
137146
int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
138147
int syncFlags = SYNC_CLONE;
139148
int noCompress = find_option("nocompress",0,0)!=0;
149
+ int noOpen = find_option("no-open",0,0)!=0;
150
+ const char *zRepo = 0; /* Name of the new local repository file */
151
+ const char *zWorkDir = 0; /* Open in this director, if not zero */
152
+
140153
141154
/* Also clone private branches */
142155
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
143156
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
144157
if( find_option("save-http-password",0,0)!=0 ){
@@ -147,49 +160,65 @@
147160
}
148161
if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
149162
if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED;
150163
zHttpAuth = find_option("httpauth","B",1);
151164
zDefaultUser = find_option("admin-user","A",1);
165
+ zWorkDir = find_option("workdir", 0, 1);
152166
clone_ssh_find_options();
153167
url_proxy_options();
154168
155169
/* We should be done with options.. */
156170
verify_all_options();
157171
158
- if( g.argc < 4 ){
159
- usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
172
+ if( g.argc < 3 ){
173
+ usage("?OPTIONS? FILE-OR-URL ?NEW-REPOSITORY?");
160174
}
161175
db_open_config(0, 0);
162
- if( -1 != file_size(g.argv[3], ExtFILE) ){
163
- fossil_fatal("file already exists: %s", g.argv[3]);
176
+ if( g.argc==4 ){
177
+ zRepo = g.argv[3];
178
+ }else{
179
+ char *zBase = url_to_repo_basename(g.argv[2]);
180
+ if( zBase==0 ){
181
+ fossil_fatal(
182
+ "unable to guess a repository name from the url \"%s\".\n"
183
+ "give the repository filename as an additional argument.",
184
+ g.argv[2]);
185
+ }
186
+ zRepo = mprintf("./%s.fossil", zBase);
187
+ if( zWorkDir==0 ){
188
+ zWorkDir = mprintf("./%s", zBase);
189
+ }
190
+ fossil_free(zBase);
191
+ }
192
+ if( -1 != file_size(zRepo, ExtFILE) ){
193
+ fossil_fatal("file already exists: %s", zRepo);
164194
}
165
-
166195
url_parse(g.argv[2], urlFlags);
167196
if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
168197
if( g.url.isFile ){
169
- file_copy(g.url.name, g.argv[3]);
198
+ file_copy(g.url.name, zRepo);
170199
db_close(1);
171
- db_open_repository(g.argv[3]);
200
+ db_open_repository(zRepo);
172201
db_open_config(1,0);
173
- db_record_repository_filename(g.argv[3]);
202
+ db_record_repository_filename(zRepo);
174203
url_remember();
175204
if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
176205
shun_artifacts();
177206
db_create_default_users(1, zDefaultUser);
178207
if( zDefaultUser ){
179208
g.zLogin = zDefaultUser;
180209
}else{
181210
g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
182211
}
183
- fossil_print("Repository cloned into %s\n", g.argv[3]);
212
+ fossil_print("Repository cloned into %s\n", zRepo);
184213
}else{
185214
db_close_config();
186
- db_create_repository(g.argv[3]);
187
- db_open_repository(g.argv[3]);
215
+ db_create_repository(zRepo);
216
+ db_open_repository(zRepo);
188217
db_open_config(0,0);
189218
db_begin_transaction();
190
- db_record_repository_filename(g.argv[3]);
219
+ db_record_repository_filename(zRepo);
191220
db_initial_setup(0, 0, zDefaultUser);
192221
user_select();
193222
db_set("content-schema", CONTENT_SCHEMA, 0);
194223
db_set("aux-schema", AUX_SCHEMA_MAX, 0);
195224
db_set("rebuilt", get_version(), 0);
@@ -221,14 +250,14 @@
221250
g.xlinkClusterOnly = 0;
222251
verify_cancel();
223252
db_end_transaction(0);
224253
db_close(1);
225254
if( nErr ){
226
- file_delete(g.argv[3]);
255
+ file_delete(zRepo);
227256
fossil_fatal("server returned an error - clone aborted");
228257
}
229
- db_open_repository(g.argv[3]);
258
+ db_open_repository(zRepo);
230259
}
231260
db_begin_transaction();
232261
fossil_print("Rebuilding repository meta-data...\n");
233262
rebuild_db(0, 1, 0);
234263
if( !noCompress ){
@@ -247,10 +276,24 @@
247276
db_protect_pop();
248277
fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
249278
fossil_print("server-id: %s\n", db_get("server-code", 0));
250279
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
251280
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
281
+ if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
282
+ char *azNew[6];
283
+ fossil_print("opening the new %s repository in directory %s...\n",
284
+ zRepo, zWorkDir);
285
+ azNew[0] = g.argv[0];
286
+ azNew[1] = "open";
287
+ azNew[2] = (char*)zRepo;
288
+ azNew[3] = "--workdir";
289
+ azNew[4] = (char*)zWorkDir;
290
+ azNew[5] = 0;
291
+ g.argv = azNew;
292
+ g.argc = 5;
293
+ cmd_open();
294
+ }
252295
}
253296
254297
/*
255298
** If user chooses to use HTTP Authentication over unencrypted HTTP,
256299
** remember decision. Otherwise, if the URL is being changed and no
@@ -363,7 +406,7 @@
363406
@ <p>Clone the repository using this command:
364407
@ <blockquote><pre>
365408
@ fossil clone %s(g.zBaseURL) %h(zNm).fossil
366409
@ </pre></blockquote>
367410
}
368
- style_footer();
411
+ style_finish_page("download");
369412
}
370413
--- src/clone.c
+++ src/clone.c
@@ -80,15 +80,17 @@
80
81
82 /*
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URI FILENAME
86 **
87 ** Make a clone of a repository specified by URI in the local
88 ** file named FILENAME. URI may be one of the following forms:
89 ** ([...] denotes optional elements):
 
 
90 **
91 ** * HTTP/HTTPS protocol:
92 **
93 ** http[s]://[userid[:password]@]host[:port][/path]
94 **
@@ -98,36 +100,43 @@
98 **
99 ** * Filesystem:
100 **
101 ** [file://]path/to/repo.fossil
102 **
103 ** Note that in Fossil (in contrast to some other DVCSes) a repository
104 ** is distinct from a checkout. This command create a clone of a repository.
105 ** Use the separate [[open]] command to open a checkout from that repository.
106 **
107 ** For ssh and filesystem, path must have an extra leading
108 ** '/' to use an absolute path.
109 **
110 ** Use %HH escapes for special characters in the userid and
111 ** password. For example "%40" in place of "@", "%2f" in place
112 ** of "/", and "%3a" in place of ":".
 
 
 
 
 
 
 
 
 
113 **
114 ** By default, the current login name is used to create the default
115 ** admin user. This can be overridden using the -A|--admin-user
116 ** parameter.
117 **
118 ** Options:
119 ** --admin-user|-A USERNAME Make USERNAME the administrator
120 ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
121 ** --nocompress Omit extra delta compression
 
122 ** --once Don't remember the URI.
123 ** --private Also clone private branches
124 ** --save-http-password Remember the HTTP password without asking
125 ** --ssh-command|-c SSH Use SSH as the "ssh" command
126 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
127 ** -u|--unversioned Also sync unversioned content
128 ** -v|--verbose Show more statistics in output
 
129 **
130 ** See also: [[init]], [[open]]
131 */
132 void clone_cmd(void){
133 char *zPassword;
@@ -135,10 +144,14 @@
135 const char *zHttpAuth; /* HTTP Authorization user:pass information */
136 int nErr = 0;
137 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
138 int syncFlags = SYNC_CLONE;
139 int noCompress = find_option("nocompress",0,0)!=0;
 
 
 
 
140
141 /* Also clone private branches */
142 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
143 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
144 if( find_option("save-http-password",0,0)!=0 ){
@@ -147,49 +160,65 @@
147 }
148 if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
149 if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED;
150 zHttpAuth = find_option("httpauth","B",1);
151 zDefaultUser = find_option("admin-user","A",1);
 
152 clone_ssh_find_options();
153 url_proxy_options();
154
155 /* We should be done with options.. */
156 verify_all_options();
157
158 if( g.argc < 4 ){
159 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
160 }
161 db_open_config(0, 0);
162 if( -1 != file_size(g.argv[3], ExtFILE) ){
163 fossil_fatal("file already exists: %s", g.argv[3]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164 }
165
166 url_parse(g.argv[2], urlFlags);
167 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
168 if( g.url.isFile ){
169 file_copy(g.url.name, g.argv[3]);
170 db_close(1);
171 db_open_repository(g.argv[3]);
172 db_open_config(1,0);
173 db_record_repository_filename(g.argv[3]);
174 url_remember();
175 if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
176 shun_artifacts();
177 db_create_default_users(1, zDefaultUser);
178 if( zDefaultUser ){
179 g.zLogin = zDefaultUser;
180 }else{
181 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
182 }
183 fossil_print("Repository cloned into %s\n", g.argv[3]);
184 }else{
185 db_close_config();
186 db_create_repository(g.argv[3]);
187 db_open_repository(g.argv[3]);
188 db_open_config(0,0);
189 db_begin_transaction();
190 db_record_repository_filename(g.argv[3]);
191 db_initial_setup(0, 0, zDefaultUser);
192 user_select();
193 db_set("content-schema", CONTENT_SCHEMA, 0);
194 db_set("aux-schema", AUX_SCHEMA_MAX, 0);
195 db_set("rebuilt", get_version(), 0);
@@ -221,14 +250,14 @@
221 g.xlinkClusterOnly = 0;
222 verify_cancel();
223 db_end_transaction(0);
224 db_close(1);
225 if( nErr ){
226 file_delete(g.argv[3]);
227 fossil_fatal("server returned an error - clone aborted");
228 }
229 db_open_repository(g.argv[3]);
230 }
231 db_begin_transaction();
232 fossil_print("Rebuilding repository meta-data...\n");
233 rebuild_db(0, 1, 0);
234 if( !noCompress ){
@@ -247,10 +276,24 @@
247 db_protect_pop();
248 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
249 fossil_print("server-id: %s\n", db_get("server-code", 0));
250 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
251 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252 }
253
254 /*
255 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
256 ** remember decision. Otherwise, if the URL is being changed and no
@@ -363,7 +406,7 @@
363 @ <p>Clone the repository using this command:
364 @ <blockquote><pre>
365 @ fossil clone %s(g.zBaseURL) %h(zNm).fossil
366 @ </pre></blockquote>
367 }
368 style_footer();
369 }
370
--- src/clone.c
+++ src/clone.c
@@ -80,15 +80,17 @@
80
81
82 /*
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URI ?FILENAME?
86 **
87 ** Make a clone of a repository specified by URI in the local
88 ** file named FILENAME. If FILENAME is omitted, then an appropriate
89 ** filename is deduced from last element of the path in the URL.
90 **
91 ** URI may be one of the following forms ([...] denotes optional elements):
92 **
93 ** * HTTP/HTTPS protocol:
94 **
95 ** http[s]://[userid[:password]@]host[:port][/path]
96 **
@@ -98,36 +100,43 @@
100 **
101 ** * Filesystem:
102 **
103 ** [file://]path/to/repo.fossil
104 **
 
 
 
 
105 ** For ssh and filesystem, path must have an extra leading
106 ** '/' to use an absolute path.
107 **
108 ** Use %HH escapes for special characters in the userid and
109 ** password. For example "%40" in place of "@", "%2f" in place
110 ** of "/", and "%3a" in place of ":".
111 **
112 ** Note that in Fossil (in contrast to some other DVCSes) a repository
113 ** is distinct from a checkout. Cloning a repository is not the same thing
114 ** as opening a repository. This command always clones the repository. This
115 ** command might also open the repository, but only if the --no-open option
116 ** is omitted and either the --workdir option is included or the FILENAME
117 ** argument is omitted. Use the separate [[open]] command to open a
118 ** repository that was previously cloned and already exists on the
119 ** local machine.
120 **
121 ** By default, the current login name is used to create the default
122 ** admin user for the new clone. This can be overridden using
123 ** the -A|--admin-user parameter.
124 **
125 ** Options:
126 ** --admin-user|-A USERNAME Make USERNAME the administrator
127 ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
128 ** --nocompress Omit extra delta compression
129 ** --no-open Clone only. Do not open a check-out.
130 ** --once Don't remember the URI.
131 ** --private Also clone private branches
132 ** --save-http-password Remember the HTTP password without asking
133 ** --ssh-command|-c SSH Use SSH as the "ssh" command
134 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
135 ** -u|--unversioned Also sync unversioned content
136 ** -v|--verbose Show more statistics in output
137 ** --workdir DIR Also open a checkout in DIR
138 **
139 ** See also: [[init]], [[open]]
140 */
141 void clone_cmd(void){
142 char *zPassword;
@@ -135,10 +144,14 @@
144 const char *zHttpAuth; /* HTTP Authorization user:pass information */
145 int nErr = 0;
146 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
147 int syncFlags = SYNC_CLONE;
148 int noCompress = find_option("nocompress",0,0)!=0;
149 int noOpen = find_option("no-open",0,0)!=0;
150 const char *zRepo = 0; /* Name of the new local repository file */
151 const char *zWorkDir = 0; /* Open in this director, if not zero */
152
153
154 /* Also clone private branches */
155 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
156 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
157 if( find_option("save-http-password",0,0)!=0 ){
@@ -147,49 +160,65 @@
160 }
161 if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
162 if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED;
163 zHttpAuth = find_option("httpauth","B",1);
164 zDefaultUser = find_option("admin-user","A",1);
165 zWorkDir = find_option("workdir", 0, 1);
166 clone_ssh_find_options();
167 url_proxy_options();
168
169 /* We should be done with options.. */
170 verify_all_options();
171
172 if( g.argc < 3 ){
173 usage("?OPTIONS? FILE-OR-URL ?NEW-REPOSITORY?");
174 }
175 db_open_config(0, 0);
176 if( g.argc==4 ){
177 zRepo = g.argv[3];
178 }else{
179 char *zBase = url_to_repo_basename(g.argv[2]);
180 if( zBase==0 ){
181 fossil_fatal(
182 "unable to guess a repository name from the url \"%s\".\n"
183 "give the repository filename as an additional argument.",
184 g.argv[2]);
185 }
186 zRepo = mprintf("./%s.fossil", zBase);
187 if( zWorkDir==0 ){
188 zWorkDir = mprintf("./%s", zBase);
189 }
190 fossil_free(zBase);
191 }
192 if( -1 != file_size(zRepo, ExtFILE) ){
193 fossil_fatal("file already exists: %s", zRepo);
194 }
 
195 url_parse(g.argv[2], urlFlags);
196 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
197 if( g.url.isFile ){
198 file_copy(g.url.name, zRepo);
199 db_close(1);
200 db_open_repository(zRepo);
201 db_open_config(1,0);
202 db_record_repository_filename(zRepo);
203 url_remember();
204 if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
205 shun_artifacts();
206 db_create_default_users(1, zDefaultUser);
207 if( zDefaultUser ){
208 g.zLogin = zDefaultUser;
209 }else{
210 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
211 }
212 fossil_print("Repository cloned into %s\n", zRepo);
213 }else{
214 db_close_config();
215 db_create_repository(zRepo);
216 db_open_repository(zRepo);
217 db_open_config(0,0);
218 db_begin_transaction();
219 db_record_repository_filename(zRepo);
220 db_initial_setup(0, 0, zDefaultUser);
221 user_select();
222 db_set("content-schema", CONTENT_SCHEMA, 0);
223 db_set("aux-schema", AUX_SCHEMA_MAX, 0);
224 db_set("rebuilt", get_version(), 0);
@@ -221,14 +250,14 @@
250 g.xlinkClusterOnly = 0;
251 verify_cancel();
252 db_end_transaction(0);
253 db_close(1);
254 if( nErr ){
255 file_delete(zRepo);
256 fossil_fatal("server returned an error - clone aborted");
257 }
258 db_open_repository(zRepo);
259 }
260 db_begin_transaction();
261 fossil_print("Rebuilding repository meta-data...\n");
262 rebuild_db(0, 1, 0);
263 if( !noCompress ){
@@ -247,10 +276,24 @@
276 db_protect_pop();
277 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
278 fossil_print("server-id: %s\n", db_get("server-code", 0));
279 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
280 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
281 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
282 char *azNew[6];
283 fossil_print("opening the new %s repository in directory %s...\n",
284 zRepo, zWorkDir);
285 azNew[0] = g.argv[0];
286 azNew[1] = "open";
287 azNew[2] = (char*)zRepo;
288 azNew[3] = "--workdir";
289 azNew[4] = (char*)zWorkDir;
290 azNew[5] = 0;
291 g.argv = azNew;
292 g.argc = 5;
293 cmd_open();
294 }
295 }
296
297 /*
298 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
299 ** remember decision. Otherwise, if the URL is being changed and no
@@ -363,7 +406,7 @@
406 @ <p>Clone the repository using this command:
407 @ <blockquote><pre>
408 @ fossil clone %s(g.zBaseURL) %h(zNm).fossil
409 @ </pre></blockquote>
410 }
411 style_finish_page("download");
412 }
413
+1 -1
--- src/cookies.c
+++ src/cookies.c
@@ -225,7 +225,7 @@
225225
@ <li>Raw cookie value: "%h(PD("fossil_display_settings",""))"
226226
for(i=0; i<cookies.nParam; i++){
227227
@ <li>%h(cookies.aParam[i].zPName): "%h(cookies.aParam[i].zPValue)"
228228
}
229229
@ </ul>
230
- style_footer();
230
+ style_finish_page("cookies");
231231
}
232232
--- src/cookies.c
+++ src/cookies.c
@@ -225,7 +225,7 @@
225 @ <li>Raw cookie value: "%h(PD("fossil_display_settings",""))"
226 for(i=0; i<cookies.nParam; i++){
227 @ <li>%h(cookies.aParam[i].zPName): "%h(cookies.aParam[i].zPValue)"
228 }
229 @ </ul>
230 style_footer();
231 }
232
--- src/cookies.c
+++ src/cookies.c
@@ -225,7 +225,7 @@
225 @ <li>Raw cookie value: "%h(PD("fossil_display_settings",""))"
226 for(i=0; i<cookies.nParam; i++){
227 @ <li>%h(cookies.aParam[i].zPName): "%h(cookies.aParam[i].zPValue)"
228 }
229 @ </ul>
230 style_finish_page("cookies");
231 }
232
+5 -4
--- src/db.c
+++ src/db.c
@@ -3499,19 +3499,20 @@
34993499
35003500
/* If REPOSITORY looks like a URI, then try to clone it first */
35013501
if( isUri ){
35023502
char *zNewBase; /* Base name of the cloned repository file */
35033503
const char *zUri; /* URI to clone */
3504
- int i; /* Loop counter */
35053504
int rc; /* Result code from fossil_system() */
35063505
Blob cmd; /* Clone command to be run */
35073506
char *zCmd; /* String version of the clone command */
35083507
35093508
zUri = zRepo;
3510
- zNewBase = fossil_strdup(file_tail(zUri));
3511
- for(i=(int)strlen(zNewBase)-1; i>1 && zNewBase[i]!='.'; i--){}
3512
- if( zNewBase[i]=='.' ) zNewBase[i] = 0;
3509
+ zNewBase = url_to_repo_basename(zUri);
3510
+ if( zNewBase==0 ){
3511
+ fossil_fatal("unable to deduce a repository name from the url \"%s\"",
3512
+ zUri);
3513
+ }
35133514
if( zRepoDir==0 ) zRepoDir = zPwd;
35143515
zRepo = mprintf("%s/%s.fossil", zRepoDir, zNewBase);
35153516
fossil_free(zNewBase);
35163517
blob_init(&cmd, 0, 0);
35173518
blob_append_escaped_arg(&cmd, g.nameOfExe);
35183519
--- src/db.c
+++ src/db.c
@@ -3499,19 +3499,20 @@
3499
3500 /* If REPOSITORY looks like a URI, then try to clone it first */
3501 if( isUri ){
3502 char *zNewBase; /* Base name of the cloned repository file */
3503 const char *zUri; /* URI to clone */
3504 int i; /* Loop counter */
3505 int rc; /* Result code from fossil_system() */
3506 Blob cmd; /* Clone command to be run */
3507 char *zCmd; /* String version of the clone command */
3508
3509 zUri = zRepo;
3510 zNewBase = fossil_strdup(file_tail(zUri));
3511 for(i=(int)strlen(zNewBase)-1; i>1 && zNewBase[i]!='.'; i--){}
3512 if( zNewBase[i]=='.' ) zNewBase[i] = 0;
 
 
3513 if( zRepoDir==0 ) zRepoDir = zPwd;
3514 zRepo = mprintf("%s/%s.fossil", zRepoDir, zNewBase);
3515 fossil_free(zNewBase);
3516 blob_init(&cmd, 0, 0);
3517 blob_append_escaped_arg(&cmd, g.nameOfExe);
3518
--- src/db.c
+++ src/db.c
@@ -3499,19 +3499,20 @@
3499
3500 /* If REPOSITORY looks like a URI, then try to clone it first */
3501 if( isUri ){
3502 char *zNewBase; /* Base name of the cloned repository file */
3503 const char *zUri; /* URI to clone */
 
3504 int rc; /* Result code from fossil_system() */
3505 Blob cmd; /* Clone command to be run */
3506 char *zCmd; /* String version of the clone command */
3507
3508 zUri = zRepo;
3509 zNewBase = url_to_repo_basename(zUri);
3510 if( zNewBase==0 ){
3511 fossil_fatal("unable to deduce a repository name from the url \"%s\"",
3512 zUri);
3513 }
3514 if( zRepoDir==0 ) zRepoDir = zPwd;
3515 zRepo = mprintf("%s/%s.fossil", zRepoDir, zNewBase);
3516 fossil_free(zNewBase);
3517 blob_init(&cmd, 0, 0);
3518 blob_append_escaped_arg(&cmd, g.nameOfExe);
3519
+2 -6
--- src/default.css
+++ src/default.css
@@ -752,23 +752,19 @@
752752
white-space: pre-wrap;
753753
}
754754
div.markdown code {
755755
white-space: pre-wrap;
756756
}
757
-div.forumHier, div.forumTime {
757
+div.forumTime {
758758
border: 1px solid black;
759759
padding-left: 1ex;
760760
padding-right: 1ex;
761761
margin-top: 1ex;
762
-}
763
-div.forumHier, div.forumTime, div.forumHierRoot {
764762
display: flex;
765763
flex-direction: column;
766764
}
767
-div.forumHier > div > form,
768
-div.forumTime > div > form,
769
-div.forumHierRoot > div > form {
765
+.forum div > form {
770766
margin: 0.5em 0;
771767
}
772768
.forum-post-collapser {
773769
/* Common style for the bottom-of-post and right-of-post
774770
expand/collapse widgets. */
775771
--- src/default.css
+++ src/default.css
@@ -752,23 +752,19 @@
752 white-space: pre-wrap;
753 }
754 div.markdown code {
755 white-space: pre-wrap;
756 }
757 div.forumHier, div.forumTime {
758 border: 1px solid black;
759 padding-left: 1ex;
760 padding-right: 1ex;
761 margin-top: 1ex;
762 }
763 div.forumHier, div.forumTime, div.forumHierRoot {
764 display: flex;
765 flex-direction: column;
766 }
767 div.forumHier > div > form,
768 div.forumTime > div > form,
769 div.forumHierRoot > div > form {
770 margin: 0.5em 0;
771 }
772 .forum-post-collapser {
773 /* Common style for the bottom-of-post and right-of-post
774 expand/collapse widgets. */
775
--- src/default.css
+++ src/default.css
@@ -752,23 +752,19 @@
752 white-space: pre-wrap;
753 }
754 div.markdown code {
755 white-space: pre-wrap;
756 }
757 div.forumTime {
758 border: 1px solid black;
759 padding-left: 1ex;
760 padding-right: 1ex;
761 margin-top: 1ex;
 
 
762 display: flex;
763 flex-direction: column;
764 }
765 .forum div > form {
 
 
766 margin: 0.5em 0;
767 }
768 .forum-post-collapser {
769 /* Common style for the bottom-of-post and right-of-post
770 expand/collapse widgets. */
771
--- src/descendants.c
+++ src/descendants.c
@@ -613,11 +613,11 @@
613613
if( fBrBg ) tmFlags |= TIMELINE_BRCOLOR;
614614
if( fUBg ) tmFlags |= TIMELINE_UCOLOR;
615615
www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
616616
db_finalize(&q);
617617
@ <br />
618
- style_footer();
618
+ style_finish_page("leaves");
619619
}
620620
621621
#if INTERFACE
622622
/* Flag parameters to compute_uses_file() */
623623
#define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */
624624
--- src/descendants.c
+++ src/descendants.c
@@ -613,11 +613,11 @@
613 if( fBrBg ) tmFlags |= TIMELINE_BRCOLOR;
614 if( fUBg ) tmFlags |= TIMELINE_UCOLOR;
615 www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
616 db_finalize(&q);
617 @ <br />
618 style_footer();
619 }
620
621 #if INTERFACE
622 /* Flag parameters to compute_uses_file() */
623 #define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */
624
--- src/descendants.c
+++ src/descendants.c
@@ -613,11 +613,11 @@
613 if( fBrBg ) tmFlags |= TIMELINE_BRCOLOR;
614 if( fUBg ) tmFlags |= TIMELINE_UCOLOR;
615 www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
616 db_finalize(&q);
617 @ <br />
618 style_finish_page("leaves");
619 }
620
621 #if INTERFACE
622 /* Flag parameters to compute_uses_file() */
623 #define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */
624
+1 -1
--- src/diff.c
+++ src/diff.c
@@ -2556,11 +2556,11 @@
25562556
}
25572557
@ %s(zPrefix) %h(z)
25582558
25592559
}
25602560
@ </pre>
2561
- style_footer();
2561
+ style_finish_page("annotate");
25622562
}
25632563
25642564
/*
25652565
** COMMAND: annotate
25662566
** COMMAND: blame
25672567
--- src/diff.c
+++ src/diff.c
@@ -2556,11 +2556,11 @@
2556 }
2557 @ %s(zPrefix) %h(z)
2558
2559 }
2560 @ </pre>
2561 style_footer();
2562 }
2563
2564 /*
2565 ** COMMAND: annotate
2566 ** COMMAND: blame
2567
--- src/diff.c
+++ src/diff.c
@@ -2556,11 +2556,11 @@
2556 }
2557 @ %s(zPrefix) %h(z)
2558
2559 }
2560 @ </pre>
2561 style_finish_page("annotate");
2562 }
2563
2564 /*
2565 ** COMMAND: annotate
2566 ** COMMAND: blame
2567
+2 -2
--- src/dispatch.c
+++ src/dispatch.c
@@ -850,11 +850,11 @@
850850
}
851851
}
852852
@ </ul></div>
853853
854854
}
855
- style_footer();
855
+ style_finish_page("help");
856856
}
857857
858858
/*
859859
** WEBPAGE: test-all-help
860860
**
@@ -901,11 +901,11 @@
901901
help_to_html(aCommand[i].zHelp, cgi_output_blob());
902902
@ </dd>
903903
}
904904
@ </dl>
905905
blob_reset(&buf);
906
- style_footer();
906
+ style_finish_page("help");
907907
}
908908
909909
static void multi_column_list(const char **azWord, int nWord){
910910
int i, j, len;
911911
int mxLen = 0;
912912
--- src/dispatch.c
+++ src/dispatch.c
@@ -850,11 +850,11 @@
850 }
851 }
852 @ </ul></div>
853
854 }
855 style_footer();
856 }
857
858 /*
859 ** WEBPAGE: test-all-help
860 **
@@ -901,11 +901,11 @@
901 help_to_html(aCommand[i].zHelp, cgi_output_blob());
902 @ </dd>
903 }
904 @ </dl>
905 blob_reset(&buf);
906 style_footer();
907 }
908
909 static void multi_column_list(const char **azWord, int nWord){
910 int i, j, len;
911 int mxLen = 0;
912
--- src/dispatch.c
+++ src/dispatch.c
@@ -850,11 +850,11 @@
850 }
851 }
852 @ </ul></div>
853
854 }
855 style_finish_page("help");
856 }
857
858 /*
859 ** WEBPAGE: test-all-help
860 **
@@ -901,11 +901,11 @@
901 help_to_html(aCommand[i].zHelp, cgi_output_blob());
902 @ </dd>
903 }
904 @ </dl>
905 blob_reset(&buf);
906 style_finish_page("help");
907 }
908
909 static void multi_column_list(const char **azWord, int nWord){
910 int i, j, len;
911 int mxLen = 0;
912
+9 -9
--- src/doc.c
+++ src/doc.c
@@ -555,11 +555,11 @@
555555
}
556556
@ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
557557
}
558558
@ </tbody></table>
559559
style_table_sorter();
560
- style_footer();
560
+ style_finish_page("mimetypes");
561561
}
562562
563563
/*
564564
** Check to see if the file in the pContent blob is "embedded HTML". Return
565565
** true if it is, and fill pTitle with the document title.
@@ -770,11 +770,11 @@
770770
}else{
771771
style_header("%s", zDefaultTitle);
772772
wiki_convert(pBody, 0, WIKI_BUTTONS);
773773
}
774774
document_emit_js();
775
- style_footer();
775
+ style_finish_page("doc");
776776
}else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
777777
Blob tail = BLOB_INITIALIZER;
778778
markdown_to_html(pBody, &title, &tail);
779779
if( blob_size(&title)>0 ){
780780
style_header("%s", blob_str(&title));
@@ -781,30 +781,30 @@
781781
}else{
782782
style_header("%s", zDefaultTitle);
783783
}
784784
convert_href_and_output(&tail);
785785
document_emit_js();
786
- style_footer();
786
+ style_finish_page("doc");
787787
}else if( fossil_strcmp(zMime, "text/plain")==0 ){
788788
style_header("%s", zDefaultTitle);
789789
@ <blockquote><pre>
790790
@ %h(blob_str(pBody))
791791
@ </pre></blockquote>
792792
document_emit_js();
793
- style_footer();
793
+ style_finish_page("doc");
794794
}else if( fossil_strcmp(zMime, "text/html")==0
795795
&& doc_is_embedded_html(pBody, &title) ){
796796
if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1);
797797
style_header("%s", blob_str(&title));
798798
convert_href_and_output(pBody);
799799
document_emit_js();
800
- style_footer();
800
+ style_finish_page("doc");
801801
}else if( fossil_strcmp(zMime, "text/x-pikchr")==0 ){
802802
style_adunit_config(ADUNIT_RIGHT_OK);
803803
style_header("%s", zDefaultTitle);
804804
wiki_render_by_mimetype(pBody, zMime);
805
- style_footer();
805
+ style_finish_page("doc");
806806
#ifdef FOSSIL_ENABLE_TH1_DOCS
807807
}else if( Th_AreDocsEnabled() &&
808808
fossil_strcmp(zMime, "application/x-th1")==0 ){
809809
int raw = P("raw")!=0;
810810
if( !raw ){
@@ -821,11 +821,11 @@
821821
}else{
822822
Th_Render(blob_str(pBody));
823823
}
824824
if( !raw ){
825825
document_emit_js();
826
- style_footer();
826
+ style_finish_page("doc");
827827
}
828828
#endif
829829
}else{
830830
fossil_free(style_csp(1));
831831
cgi_set_content_type(zMime);
@@ -1029,11 +1029,11 @@
10291029
style_header("Not Found");
10301030
@ <p>Document %h(zOrigName) not found
10311031
if( fossil_strcmp(zCheckin,"ckout")!=0 ){
10321032
@ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a>
10331033
}
1034
- style_footer();
1034
+ style_finish_page("doc");
10351035
return;
10361036
}
10371037
10381038
/*
10391039
** The default logo.
@@ -1202,7 +1202,7 @@
12021202
*/
12031203
void doc_search_page(void){
12041204
login_check_credentials();
12051205
style_header("Document Search");
12061206
search_screen(SRCH_DOC, 0);
1207
- style_footer();
1207
+ style_finish_page("docsrch");
12081208
}
12091209
--- src/doc.c
+++ src/doc.c
@@ -555,11 +555,11 @@
555 }
556 @ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
557 }
558 @ </tbody></table>
559 style_table_sorter();
560 style_footer();
561 }
562
563 /*
564 ** Check to see if the file in the pContent blob is "embedded HTML". Return
565 ** true if it is, and fill pTitle with the document title.
@@ -770,11 +770,11 @@
770 }else{
771 style_header("%s", zDefaultTitle);
772 wiki_convert(pBody, 0, WIKI_BUTTONS);
773 }
774 document_emit_js();
775 style_footer();
776 }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
777 Blob tail = BLOB_INITIALIZER;
778 markdown_to_html(pBody, &title, &tail);
779 if( blob_size(&title)>0 ){
780 style_header("%s", blob_str(&title));
@@ -781,30 +781,30 @@
781 }else{
782 style_header("%s", zDefaultTitle);
783 }
784 convert_href_and_output(&tail);
785 document_emit_js();
786 style_footer();
787 }else if( fossil_strcmp(zMime, "text/plain")==0 ){
788 style_header("%s", zDefaultTitle);
789 @ <blockquote><pre>
790 @ %h(blob_str(pBody))
791 @ </pre></blockquote>
792 document_emit_js();
793 style_footer();
794 }else if( fossil_strcmp(zMime, "text/html")==0
795 && doc_is_embedded_html(pBody, &title) ){
796 if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1);
797 style_header("%s", blob_str(&title));
798 convert_href_and_output(pBody);
799 document_emit_js();
800 style_footer();
801 }else if( fossil_strcmp(zMime, "text/x-pikchr")==0 ){
802 style_adunit_config(ADUNIT_RIGHT_OK);
803 style_header("%s", zDefaultTitle);
804 wiki_render_by_mimetype(pBody, zMime);
805 style_footer();
806 #ifdef FOSSIL_ENABLE_TH1_DOCS
807 }else if( Th_AreDocsEnabled() &&
808 fossil_strcmp(zMime, "application/x-th1")==0 ){
809 int raw = P("raw")!=0;
810 if( !raw ){
@@ -821,11 +821,11 @@
821 }else{
822 Th_Render(blob_str(pBody));
823 }
824 if( !raw ){
825 document_emit_js();
826 style_footer();
827 }
828 #endif
829 }else{
830 fossil_free(style_csp(1));
831 cgi_set_content_type(zMime);
@@ -1029,11 +1029,11 @@
1029 style_header("Not Found");
1030 @ <p>Document %h(zOrigName) not found
1031 if( fossil_strcmp(zCheckin,"ckout")!=0 ){
1032 @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a>
1033 }
1034 style_footer();
1035 return;
1036 }
1037
1038 /*
1039 ** The default logo.
@@ -1202,7 +1202,7 @@
1202 */
1203 void doc_search_page(void){
1204 login_check_credentials();
1205 style_header("Document Search");
1206 search_screen(SRCH_DOC, 0);
1207 style_footer();
1208 }
1209
--- src/doc.c
+++ src/doc.c
@@ -555,11 +555,11 @@
555 }
556 @ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
557 }
558 @ </tbody></table>
559 style_table_sorter();
560 style_finish_page("mimetypes");
561 }
562
563 /*
564 ** Check to see if the file in the pContent blob is "embedded HTML". Return
565 ** true if it is, and fill pTitle with the document title.
@@ -770,11 +770,11 @@
770 }else{
771 style_header("%s", zDefaultTitle);
772 wiki_convert(pBody, 0, WIKI_BUTTONS);
773 }
774 document_emit_js();
775 style_finish_page("doc");
776 }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
777 Blob tail = BLOB_INITIALIZER;
778 markdown_to_html(pBody, &title, &tail);
779 if( blob_size(&title)>0 ){
780 style_header("%s", blob_str(&title));
@@ -781,30 +781,30 @@
781 }else{
782 style_header("%s", zDefaultTitle);
783 }
784 convert_href_and_output(&tail);
785 document_emit_js();
786 style_finish_page("doc");
787 }else if( fossil_strcmp(zMime, "text/plain")==0 ){
788 style_header("%s", zDefaultTitle);
789 @ <blockquote><pre>
790 @ %h(blob_str(pBody))
791 @ </pre></blockquote>
792 document_emit_js();
793 style_finish_page("doc");
794 }else if( fossil_strcmp(zMime, "text/html")==0
795 && doc_is_embedded_html(pBody, &title) ){
796 if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1);
797 style_header("%s", blob_str(&title));
798 convert_href_and_output(pBody);
799 document_emit_js();
800 style_finish_page("doc");
801 }else if( fossil_strcmp(zMime, "text/x-pikchr")==0 ){
802 style_adunit_config(ADUNIT_RIGHT_OK);
803 style_header("%s", zDefaultTitle);
804 wiki_render_by_mimetype(pBody, zMime);
805 style_finish_page("doc");
806 #ifdef FOSSIL_ENABLE_TH1_DOCS
807 }else if( Th_AreDocsEnabled() &&
808 fossil_strcmp(zMime, "application/x-th1")==0 ){
809 int raw = P("raw")!=0;
810 if( !raw ){
@@ -821,11 +821,11 @@
821 }else{
822 Th_Render(blob_str(pBody));
823 }
824 if( !raw ){
825 document_emit_js();
826 style_finish_page("doc");
827 }
828 #endif
829 }else{
830 fossil_free(style_csp(1));
831 cgi_set_content_type(zMime);
@@ -1029,11 +1029,11 @@
1029 style_header("Not Found");
1030 @ <p>Document %h(zOrigName) not found
1031 if( fossil_strcmp(zCheckin,"ckout")!=0 ){
1032 @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a>
1033 }
1034 style_finish_page("doc");
1035 return;
1036 }
1037
1038 /*
1039 ** The default logo.
@@ -1202,7 +1202,7 @@
1202 */
1203 void doc_search_page(void){
1204 login_check_credentials();
1205 style_header("Document Search");
1206 search_screen(SRCH_DOC, 0);
1207 style_finish_page("docsrch");
1208 }
1209
+4 -4
--- src/event.c
+++ src/event.c
@@ -113,11 +113,11 @@
113113
}
114114
db_finalize(&q1);
115115
if( rid==0 || (specRid!=0 && specRid!=rid) ){
116116
style_header("No Such Tech-Note");
117117
@ Cannot locate a technical note called <b>%h(zId)</b>.
118
- style_footer();
118
+ style_finish_page("event");
119119
return;
120120
}
121121
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
122122
zVerbose = P("v");
123123
if( !zVerbose ){
@@ -229,11 +229,11 @@
229229
" FROM tag"
230230
" WHERE tagname GLOB 'event-%q*'",
231231
zId);
232232
attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>");
233233
document_emit_js();
234
- style_footer();
234
+ style_finish_page("event");
235235
manifest_destroy(pTNote);
236236
}
237237
238238
/*
239239
** Add or update a new tech note to the repository. rid is id of
@@ -473,11 +473,11 @@
473473
zMimetype, zComment, zTags,
474474
zClrFlag[0] ? zClr : 0) ){
475475
style_header("Error");
476476
@ Internal error: Fossil tried to make an invalid artifact for
477477
@ the edited technote.
478
- style_footer();
478
+ style_finish_page("event");
479479
return;
480480
}
481481
cgi_redirectf("%R/technote?name=%T", zId);
482482
}
483483
if( P("cancel")!=0 ){
@@ -567,11 +567,11 @@
567567
if( P("preview") ){
568568
@ <input type="submit" name="submit" value="Submit" />
569569
}
570570
@ </td></tr></table>
571571
@ </div></form>
572
- style_footer();
572
+ style_finish_page("event");
573573
}
574574
575575
/*
576576
** Add a new tech note to the repository. The timestamp is
577577
** given by the zETime parameter. rid must be zero to create
578578
--- src/event.c
+++ src/event.c
@@ -113,11 +113,11 @@
113 }
114 db_finalize(&q1);
115 if( rid==0 || (specRid!=0 && specRid!=rid) ){
116 style_header("No Such Tech-Note");
117 @ Cannot locate a technical note called <b>%h(zId)</b>.
118 style_footer();
119 return;
120 }
121 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
122 zVerbose = P("v");
123 if( !zVerbose ){
@@ -229,11 +229,11 @@
229 " FROM tag"
230 " WHERE tagname GLOB 'event-%q*'",
231 zId);
232 attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>");
233 document_emit_js();
234 style_footer();
235 manifest_destroy(pTNote);
236 }
237
238 /*
239 ** Add or update a new tech note to the repository. rid is id of
@@ -473,11 +473,11 @@
473 zMimetype, zComment, zTags,
474 zClrFlag[0] ? zClr : 0) ){
475 style_header("Error");
476 @ Internal error: Fossil tried to make an invalid artifact for
477 @ the edited technote.
478 style_footer();
479 return;
480 }
481 cgi_redirectf("%R/technote?name=%T", zId);
482 }
483 if( P("cancel")!=0 ){
@@ -567,11 +567,11 @@
567 if( P("preview") ){
568 @ <input type="submit" name="submit" value="Submit" />
569 }
570 @ </td></tr></table>
571 @ </div></form>
572 style_footer();
573 }
574
575 /*
576 ** Add a new tech note to the repository. The timestamp is
577 ** given by the zETime parameter. rid must be zero to create
578
--- src/event.c
+++ src/event.c
@@ -113,11 +113,11 @@
113 }
114 db_finalize(&q1);
115 if( rid==0 || (specRid!=0 && specRid!=rid) ){
116 style_header("No Such Tech-Note");
117 @ Cannot locate a technical note called <b>%h(zId)</b>.
118 style_finish_page("event");
119 return;
120 }
121 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
122 zVerbose = P("v");
123 if( !zVerbose ){
@@ -229,11 +229,11 @@
229 " FROM tag"
230 " WHERE tagname GLOB 'event-%q*'",
231 zId);
232 attachment_list(zFullId, "<hr /><h2>Attachments:</h2><ul>");
233 document_emit_js();
234 style_finish_page("event");
235 manifest_destroy(pTNote);
236 }
237
238 /*
239 ** Add or update a new tech note to the repository. rid is id of
@@ -473,11 +473,11 @@
473 zMimetype, zComment, zTags,
474 zClrFlag[0] ? zClr : 0) ){
475 style_header("Error");
476 @ Internal error: Fossil tried to make an invalid artifact for
477 @ the edited technote.
478 style_finish_page("event");
479 return;
480 }
481 cgi_redirectf("%R/technote?name=%T", zId);
482 }
483 if( P("cancel")!=0 ){
@@ -567,11 +567,11 @@
567 if( P("preview") ){
568 @ <input type="submit" name="submit" value="Submit" />
569 }
570 @ </td></tr></table>
571 @ </div></form>
572 style_finish_page("event");
573 }
574
575 /*
576 ** Add a new tech note to the repository. The timestamp is
577 ** given by the zETime parameter. rid must be zero to create
578
+1 -1
--- src/extcgi.c
+++ src/extcgi.c
@@ -416,7 +416,7 @@
416416
@ </tr>
417417
}
418418
db_finalize(&q);
419419
@ </tbody>
420420
@ </table>
421
- style_footer();
421
+ style_finish_page("extcgi");
422422
}
423423
--- src/extcgi.c
+++ src/extcgi.c
@@ -416,7 +416,7 @@
416 @ </tr>
417 }
418 db_finalize(&q);
419 @ </tbody>
420 @ </table>
421 style_footer();
422 }
423
--- src/extcgi.c
+++ src/extcgi.c
@@ -416,7 +416,7 @@
416 @ </tr>
417 }
418 db_finalize(&q);
419 @ </tbody>
420 @ </table>
421 style_finish_page("extcgi");
422 }
423
+2 -2
--- src/fileedit.c
+++ src/fileedit.c
@@ -1606,11 +1606,11 @@
16061606
"values matching files which may be edited online."
16071607
"</p>\n");
16081608
}else{
16091609
CX("<p>Online editing is disabled for this repository.</p>\n");
16101610
}
1611
- style_footer();
1611
+ style_finish_page("fileedit");
16121612
return;
16131613
}
16141614
16151615
/* Dispatch AJAX methods based tail of the request URI.
16161616
** The AJAX parts do their own permissions/CSRF check and
@@ -2061,7 +2061,7 @@
20612061
style_script_end();
20622062
}
20632063
blob_reset(&err);
20642064
CheckinMiniInfo_cleanup(&cimi);
20652065
db_end_transaction(0);
2066
- style_footer();
2066
+ style_finish_page("fileedit");
20672067
}
20682068
--- src/fileedit.c
+++ src/fileedit.c
@@ -1606,11 +1606,11 @@
1606 "values matching files which may be edited online."
1607 "</p>\n");
1608 }else{
1609 CX("<p>Online editing is disabled for this repository.</p>\n");
1610 }
1611 style_footer();
1612 return;
1613 }
1614
1615 /* Dispatch AJAX methods based tail of the request URI.
1616 ** The AJAX parts do their own permissions/CSRF check and
@@ -2061,7 +2061,7 @@
2061 style_script_end();
2062 }
2063 blob_reset(&err);
2064 CheckinMiniInfo_cleanup(&cimi);
2065 db_end_transaction(0);
2066 style_footer();
2067 }
2068
--- src/fileedit.c
+++ src/fileedit.c
@@ -1606,11 +1606,11 @@
1606 "values matching files which may be edited online."
1607 "</p>\n");
1608 }else{
1609 CX("<p>Online editing is disabled for this repository.</p>\n");
1610 }
1611 style_finish_page("fileedit");
1612 return;
1613 }
1614
1615 /* Dispatch AJAX methods based tail of the request URI.
1616 ** The AJAX parts do their own permissions/CSRF check and
@@ -2061,7 +2061,7 @@
2061 style_script_end();
2062 }
2063 blob_reset(&err);
2064 CheckinMiniInfo_cleanup(&cimi);
2065 db_end_transaction(0);
2066 style_finish_page("fileedit");
2067 }
2068
+3 -3
--- src/finfo.c
+++ src/finfo.c
@@ -367,11 +367,11 @@
367367
ridFrom = name_to_rid_www("from");
368368
zPrevDate[0] = 0;
369369
cookie_render();
370370
if( fnid==0 ){
371371
@ No such file: %h(zFilename)
372
- style_footer();
372
+ style_finish_page("finfo");
373373
return;
374374
}
375375
if( g.perm.Admin ){
376376
style_submenu_element("MLink Table", "%R/mlink?name=%t", zFilename);
377377
}
@@ -754,11 +754,11 @@
754754
@ <td></td><td></td><td></td></tr>
755755
}
756756
}
757757
@ </table>
758758
timeline_output_graph_javascript(pGraph, TIMELINE_FILEDIFF, iTableId);
759
- style_footer();
759
+ style_finish_page("finfo");
760760
}
761761
762762
/*
763763
** WEBPAGE: mlink
764764
** URL: /mlink?name=FILENAME
@@ -934,7 +934,7 @@
934934
db_finalize(&q);
935935
@ </tbody>
936936
@ </table>
937937
@ </div>
938938
}
939
- style_footer();
939
+ style_finish_page("finfo");
940940
}
941941
--- src/finfo.c
+++ src/finfo.c
@@ -367,11 +367,11 @@
367 ridFrom = name_to_rid_www("from");
368 zPrevDate[0] = 0;
369 cookie_render();
370 if( fnid==0 ){
371 @ No such file: %h(zFilename)
372 style_footer();
373 return;
374 }
375 if( g.perm.Admin ){
376 style_submenu_element("MLink Table", "%R/mlink?name=%t", zFilename);
377 }
@@ -754,11 +754,11 @@
754 @ <td></td><td></td><td></td></tr>
755 }
756 }
757 @ </table>
758 timeline_output_graph_javascript(pGraph, TIMELINE_FILEDIFF, iTableId);
759 style_footer();
760 }
761
762 /*
763 ** WEBPAGE: mlink
764 ** URL: /mlink?name=FILENAME
@@ -934,7 +934,7 @@
934 db_finalize(&q);
935 @ </tbody>
936 @ </table>
937 @ </div>
938 }
939 style_footer();
940 }
941
--- src/finfo.c
+++ src/finfo.c
@@ -367,11 +367,11 @@
367 ridFrom = name_to_rid_www("from");
368 zPrevDate[0] = 0;
369 cookie_render();
370 if( fnid==0 ){
371 @ No such file: %h(zFilename)
372 style_finish_page("finfo");
373 return;
374 }
375 if( g.perm.Admin ){
376 style_submenu_element("MLink Table", "%R/mlink?name=%t", zFilename);
377 }
@@ -754,11 +754,11 @@
754 @ <td></td><td></td><td></td></tr>
755 }
756 }
757 @ </table>
758 timeline_output_graph_javascript(pGraph, TIMELINE_FILEDIFF, iTableId);
759 style_finish_page("finfo");
760 }
761
762 /*
763 ** WEBPAGE: mlink
764 ** URL: /mlink?name=FILENAME
@@ -934,7 +934,7 @@
934 db_finalize(&q);
935 @ </tbody>
936 @ </table>
937 @ </div>
938 }
939 style_finish_page("finfo");
940 }
941
+6 -6
--- src/forum.c
+++ src/forum.c
@@ -878,11 +878,11 @@
878878
/* Emit Forum Javascript. */
879879
builtin_request_js("forum.js");
880880
forum_emit_js();
881881
882882
/* Emit the page style. */
883
- style_footer();
883
+ style_finish_page("forum");
884884
}
885885
886886
/*
887887
** Return true if a forum post should be moderated.
888888
*/
@@ -1074,11 +1074,11 @@
10741074
@ <input type="submit" value="Login">
10751075
@ </form>
10761076
@ <td>Log into an existing account
10771077
@ </table>
10781078
forum_emit_js();
1079
- style_footer();
1079
+ style_finish_page("forum");
10801080
fossil_free(zGoto);
10811081
}
10821082
10831083
/*
10841084
** Write the "From: USER" line on the webpage.
@@ -1135,11 +1135,11 @@
11351135
@ Show query parameters</label>
11361136
@ </div>
11371137
}
11381138
@ </form>
11391139
forum_emit_js();
1140
- style_footer();
1140
+ style_finish_page("forum");
11411141
}
11421142
11431143
/*
11441144
** WEBPAGE: forume2
11451145
**
@@ -1315,11 +1315,11 @@
13151315
@ Show query parameters</label>
13161316
@ </div>
13171317
}
13181318
@ </form>
13191319
forum_emit_js();
1320
- style_footer();
1320
+ style_finish_page("forum");
13211321
}
13221322
13231323
/*
13241324
** WEBPAGE: forummain
13251325
** WEBPAGE: forum
@@ -1357,11 +1357,11 @@
13571357
style_submenu_element("Moderation Requests", "%R/modreq");
13581358
}
13591359
if( (srchFlags & SRCH_FORUM)!=0 ){
13601360
if( search_screen(SRCH_FORUM, 0) ){
13611361
style_submenu_element("Recent Threads","%R/forum");
1362
- style_footer();
1362
+ style_finish_page("forum");
13631363
return;
13641364
}
13651365
}
13661366
iLimit = atoi(PD("n","25"));
13671367
iOfst = atoi(PD("x","0"));
@@ -1450,7 +1450,7 @@
14501450
if( iCnt>0 ){
14511451
@ </table></div>
14521452
}else{
14531453
@ <h1>No forum posts found</h1>
14541454
}
1455
- style_footer();
1455
+ style_finish_page("forum");
14561456
}
14571457
--- src/forum.c
+++ src/forum.c
@@ -878,11 +878,11 @@
878 /* Emit Forum Javascript. */
879 builtin_request_js("forum.js");
880 forum_emit_js();
881
882 /* Emit the page style. */
883 style_footer();
884 }
885
886 /*
887 ** Return true if a forum post should be moderated.
888 */
@@ -1074,11 +1074,11 @@
1074 @ <input type="submit" value="Login">
1075 @ </form>
1076 @ <td>Log into an existing account
1077 @ </table>
1078 forum_emit_js();
1079 style_footer();
1080 fossil_free(zGoto);
1081 }
1082
1083 /*
1084 ** Write the "From: USER" line on the webpage.
@@ -1135,11 +1135,11 @@
1135 @ Show query parameters</label>
1136 @ </div>
1137 }
1138 @ </form>
1139 forum_emit_js();
1140 style_footer();
1141 }
1142
1143 /*
1144 ** WEBPAGE: forume2
1145 **
@@ -1315,11 +1315,11 @@
1315 @ Show query parameters</label>
1316 @ </div>
1317 }
1318 @ </form>
1319 forum_emit_js();
1320 style_footer();
1321 }
1322
1323 /*
1324 ** WEBPAGE: forummain
1325 ** WEBPAGE: forum
@@ -1357,11 +1357,11 @@
1357 style_submenu_element("Moderation Requests", "%R/modreq");
1358 }
1359 if( (srchFlags & SRCH_FORUM)!=0 ){
1360 if( search_screen(SRCH_FORUM, 0) ){
1361 style_submenu_element("Recent Threads","%R/forum");
1362 style_footer();
1363 return;
1364 }
1365 }
1366 iLimit = atoi(PD("n","25"));
1367 iOfst = atoi(PD("x","0"));
@@ -1450,7 +1450,7 @@
1450 if( iCnt>0 ){
1451 @ </table></div>
1452 }else{
1453 @ <h1>No forum posts found</h1>
1454 }
1455 style_footer();
1456 }
1457
--- src/forum.c
+++ src/forum.c
@@ -878,11 +878,11 @@
878 /* Emit Forum Javascript. */
879 builtin_request_js("forum.js");
880 forum_emit_js();
881
882 /* Emit the page style. */
883 style_finish_page("forum");
884 }
885
886 /*
887 ** Return true if a forum post should be moderated.
888 */
@@ -1074,11 +1074,11 @@
1074 @ <input type="submit" value="Login">
1075 @ </form>
1076 @ <td>Log into an existing account
1077 @ </table>
1078 forum_emit_js();
1079 style_finish_page("forum");
1080 fossil_free(zGoto);
1081 }
1082
1083 /*
1084 ** Write the "From: USER" line on the webpage.
@@ -1135,11 +1135,11 @@
1135 @ Show query parameters</label>
1136 @ </div>
1137 }
1138 @ </form>
1139 forum_emit_js();
1140 style_finish_page("forum");
1141 }
1142
1143 /*
1144 ** WEBPAGE: forume2
1145 **
@@ -1315,11 +1315,11 @@
1315 @ Show query parameters</label>
1316 @ </div>
1317 }
1318 @ </form>
1319 forum_emit_js();
1320 style_finish_page("forum");
1321 }
1322
1323 /*
1324 ** WEBPAGE: forummain
1325 ** WEBPAGE: forum
@@ -1357,11 +1357,11 @@
1357 style_submenu_element("Moderation Requests", "%R/modreq");
1358 }
1359 if( (srchFlags & SRCH_FORUM)!=0 ){
1360 if( search_screen(SRCH_FORUM, 0) ){
1361 style_submenu_element("Recent Threads","%R/forum");
1362 style_finish_page("forum");
1363 return;
1364 }
1365 }
1366 iLimit = atoi(PD("n","25"));
1367 iOfst = atoi(PD("x","0"));
@@ -1450,7 +1450,7 @@
1450 if( iCnt>0 ){
1451 @ </table></div>
1452 }else{
1453 @ <h1>No forum posts found</h1>
1454 }
1455 style_finish_page("forum");
1456 }
1457
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -45,11 +45,11 @@
4545
/* Adds an Expand/Collapse toggle to all div.forumPostBody
4646
elements which are deemed "too large" (those for which
4747
scrolling is currently activated because they are taller than
4848
their max-height). */
4949
document.querySelectorAll(
50
- 'div.forumHier, div.forumTime, div.forumHierRoot, div.forumEdit'
50
+ 'div.forumTime, div.forumEdit'
5151
).forEach(function f(forumPostWrapper){
5252
const content = forumPostWrapper.querySelector('div.forumPostBody');
5353
if(!content || !scrollbarIsVisible(content)) return;
5454
const parent = content.parentElement,
5555
widget = D.addClass(
5656
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -45,11 +45,11 @@
45 /* Adds an Expand/Collapse toggle to all div.forumPostBody
46 elements which are deemed "too large" (those for which
47 scrolling is currently activated because they are taller than
48 their max-height). */
49 document.querySelectorAll(
50 'div.forumHier, div.forumTime, div.forumHierRoot, div.forumEdit'
51 ).forEach(function f(forumPostWrapper){
52 const content = forumPostWrapper.querySelector('div.forumPostBody');
53 if(!content || !scrollbarIsVisible(content)) return;
54 const parent = content.parentElement,
55 widget = D.addClass(
56
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -45,11 +45,11 @@
45 /* Adds an Expand/Collapse toggle to all div.forumPostBody
46 elements which are deemed "too large" (those for which
47 scrolling is currently activated because they are taller than
48 their max-height). */
49 document.querySelectorAll(
50 'div.forumTime, div.forumEdit'
51 ).forEach(function f(forumPostWrapper){
52 const content = forumPostWrapper.querySelector('div.forumPostBody');
53 if(!content || !scrollbarIsVisible(content)) return;
54 const parent = content.parentElement,
55 widget = D.addClass(
56
+16 -16
--- src/info.c
+++ src/info.c
@@ -503,11 +503,11 @@
503503
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
504504
rid = name_to_rid_www("name");
505505
if( rid==0 ){
506506
style_header("Check-in Information Error");
507507
@ No such object: %h(g.argv[2])
508
- style_footer();
508
+ style_finish_page("ci_tags");
509509
return;
510510
}
511511
zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
512512
style_header("Tags and Properties");
513513
@ <h1>Tags and Properties for Check-In \
@@ -595,11 +595,11 @@
595595
blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
596596
db_prepare(&q, "%s", blob_sql_text(&sql));
597597
www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
598598
0, 0, 0, rid, 0, 0);
599599
db_finalize(&q);
600
- style_footer();
600
+ style_finish_page("ci_tags");
601601
}
602602
603603
/*
604604
** WEBPAGE: vinfo
605605
** WEBPAGE: ci
@@ -634,11 +634,11 @@
634634
zName = P("name");
635635
rid = name_to_rid_www("name");
636636
if( rid==0 ){
637637
style_header("Check-in Information Error");
638638
@ No such object: %h(g.argv[2])
639
- style_footer();
639
+ style_finish_page("vinfo");
640640
return;
641641
}
642642
zRe = P("regex");
643643
if( zRe ) re_compile(&pRe, zRe, 0);
644644
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -940,11 +940,11 @@
940940
diffFlags,pRe,mperm);
941941
}
942942
db_finalize(&q3);
943943
append_diff_javascript(diffType==2);
944944
cookie_render();
945
- style_footer();
945
+ style_finish_page("vinfo");
946946
}
947947
948948
/*
949949
** WEBPAGE: winfo
950950
** URL: /winfo?name=HASH
@@ -966,11 +966,11 @@
966966
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
967967
rid = name_to_rid_www("name");
968968
if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
969969
style_header("Wiki Page Information Error");
970970
@ No such object: %h(P("name"))
971
- style_footer();
971
+ style_finish_page("winfo");
972972
return;
973973
}
974974
if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){
975975
if( strcmp(zModAction,"delete")==0 ){
976976
moderation_disapprove(rid);
@@ -1054,11 +1054,11 @@
10541054
safe_html_context(DOCSRC_WIKI);
10551055
wiki_render_by_mimetype(&wiki, pWiki->zMimetype);
10561056
blob_reset(&wiki);
10571057
manifest_destroy(pWiki);
10581058
document_emit_js();
1059
- style_footer();
1059
+ style_finish_page("winfo");
10601060
}
10611061
10621062
/*
10631063
** Find an check-in based on query parameter zParam and parse its
10641064
** manifest. Return the number of errors.
@@ -1327,11 +1327,11 @@
13271327
}
13281328
}
13291329
manifest_destroy(pFrom);
13301330
manifest_destroy(pTo);
13311331
append_diff_javascript(diffType==2);
1332
- style_footer();
1332
+ style_finish_page("vdiff");
13331333
}
13341334
13351335
#if INTERFACE
13361336
/*
13371337
** Possible return values from object_description()
@@ -1761,11 +1761,11 @@
17611761
@ are shown.</b>
17621762
}
17631763
@ <hr />
17641764
append_diff(zV1, zV2, diffFlags, pRe);
17651765
append_diff_javascript(diffType);
1766
- style_footer();
1766
+ style_finish_page("fdiff");
17671767
}
17681768
17691769
/*
17701770
** WEBPAGE: raw
17711771
** URL: /raw/ARTIFACTID
@@ -1965,11 +1965,11 @@
19651965
@ <hr />
19661966
content_get(rid, &content);
19671967
@ <blockquote><pre>
19681968
hexdump(&content);
19691969
@ </pre></blockquote>
1970
- style_footer();
1970
+ style_finish_page("hexdump");
19711971
}
19721972
19731973
/*
19741974
** Look for "ci" and "filename" query parameters. If found, try to
19751975
** use them to extract the record ID of an artifact for the file.
@@ -2263,11 +2263,11 @@
22632263
page_tree();
22642264
return;
22652265
}
22662266
style_header("Missing name= query parameter");
22672267
@ The name= query parameter is missing
2268
- style_footer();
2268
+ style_finish_page("artifact");
22692269
return;
22702270
}
22712271
22722272
url_initialize(&url, g.zPath);
22732273
url_add_parameter(&url, "name", zName);
@@ -2324,11 +2324,11 @@
23242324
}else{
23252325
style_header("No such artifact");
23262326
@ Artifact '%h(zName)' does not exist in this repository.
23272327
}
23282328
if( rid==0 ){
2329
- style_footer();
2329
+ style_finish_page("artifact");
23302330
return;
23312331
}
23322332
}
23332333
23342334
if( descOnly || P("verbose")!=0 ){
@@ -2529,11 +2529,11 @@
25292529
@ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
25302530
}
25312531
@ </blockquote>
25322532
}
25332533
}
2534
- style_footer();
2534
+ style_finish_page("artifact");
25352535
}
25362536
25372537
/*
25382538
** WEBPAGE: tinfo
25392539
** URL: /tinfo?name=ARTIFACTID
@@ -2636,11 +2636,11 @@
26362636
26372637
@ <div class="section">Changes</div>
26382638
@ <p>
26392639
ticket_output_change_artifact(pTktChng, 0, 1);
26402640
manifest_destroy(pTktChng);
2641
- style_footer();
2641
+ style_finish_page("tinfo");
26422642
}
26432643
26442644
26452645
/*
26462646
** WEBPAGE: info
@@ -2687,11 +2687,11 @@
26872687
@ <p>No such object: %h(zName)</p>
26882688
if( nLen<4 ){
26892689
@ <p>Object name should be no less than 4 characters. Ten or more
26902690
@ characters are recommended.</p>
26912691
}
2692
- style_footer();
2692
+ style_finish_page("info");
26932693
return;
26942694
}else if( rc==2 ){
26952695
cgi_set_parameter("src","info");
26962696
ambiguous_page();
26972697
return;
@@ -2699,11 +2699,11 @@
26992699
zName = blob_str(&uuid);
27002700
rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName);
27012701
if( rid==0 ){
27022702
style_header("Broken Link");
27032703
@ <p>No such object: %h(zName)</p>
2704
- style_footer();
2704
+ style_finish_page("info");
27052705
return;
27062706
}
27072707
if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
27082708
ci_page();
27092709
}else
@@ -3224,11 +3224,11 @@
32243224
}
32253225
@ </td></tr>
32263226
@ </table>
32273227
@ </div></form>
32283228
builtin_request_js("ci_edit.js");
3229
- style_footer();
3229
+ style_finish_page("ci_edit");
32303230
}
32313231
32323232
/*
32333233
** Prepare an ammended commit comment. Let the user modify it using the
32343234
** editor specified in the global_config table or either
32353235
--- src/info.c
+++ src/info.c
@@ -503,11 +503,11 @@
503 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
504 rid = name_to_rid_www("name");
505 if( rid==0 ){
506 style_header("Check-in Information Error");
507 @ No such object: %h(g.argv[2])
508 style_footer();
509 return;
510 }
511 zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
512 style_header("Tags and Properties");
513 @ <h1>Tags and Properties for Check-In \
@@ -595,11 +595,11 @@
595 blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
596 db_prepare(&q, "%s", blob_sql_text(&sql));
597 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
598 0, 0, 0, rid, 0, 0);
599 db_finalize(&q);
600 style_footer();
601 }
602
603 /*
604 ** WEBPAGE: vinfo
605 ** WEBPAGE: ci
@@ -634,11 +634,11 @@
634 zName = P("name");
635 rid = name_to_rid_www("name");
636 if( rid==0 ){
637 style_header("Check-in Information Error");
638 @ No such object: %h(g.argv[2])
639 style_footer();
640 return;
641 }
642 zRe = P("regex");
643 if( zRe ) re_compile(&pRe, zRe, 0);
644 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -940,11 +940,11 @@
940 diffFlags,pRe,mperm);
941 }
942 db_finalize(&q3);
943 append_diff_javascript(diffType==2);
944 cookie_render();
945 style_footer();
946 }
947
948 /*
949 ** WEBPAGE: winfo
950 ** URL: /winfo?name=HASH
@@ -966,11 +966,11 @@
966 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
967 rid = name_to_rid_www("name");
968 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
969 style_header("Wiki Page Information Error");
970 @ No such object: %h(P("name"))
971 style_footer();
972 return;
973 }
974 if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){
975 if( strcmp(zModAction,"delete")==0 ){
976 moderation_disapprove(rid);
@@ -1054,11 +1054,11 @@
1054 safe_html_context(DOCSRC_WIKI);
1055 wiki_render_by_mimetype(&wiki, pWiki->zMimetype);
1056 blob_reset(&wiki);
1057 manifest_destroy(pWiki);
1058 document_emit_js();
1059 style_footer();
1060 }
1061
1062 /*
1063 ** Find an check-in based on query parameter zParam and parse its
1064 ** manifest. Return the number of errors.
@@ -1327,11 +1327,11 @@
1327 }
1328 }
1329 manifest_destroy(pFrom);
1330 manifest_destroy(pTo);
1331 append_diff_javascript(diffType==2);
1332 style_footer();
1333 }
1334
1335 #if INTERFACE
1336 /*
1337 ** Possible return values from object_description()
@@ -1761,11 +1761,11 @@
1761 @ are shown.</b>
1762 }
1763 @ <hr />
1764 append_diff(zV1, zV2, diffFlags, pRe);
1765 append_diff_javascript(diffType);
1766 style_footer();
1767 }
1768
1769 /*
1770 ** WEBPAGE: raw
1771 ** URL: /raw/ARTIFACTID
@@ -1965,11 +1965,11 @@
1965 @ <hr />
1966 content_get(rid, &content);
1967 @ <blockquote><pre>
1968 hexdump(&content);
1969 @ </pre></blockquote>
1970 style_footer();
1971 }
1972
1973 /*
1974 ** Look for "ci" and "filename" query parameters. If found, try to
1975 ** use them to extract the record ID of an artifact for the file.
@@ -2263,11 +2263,11 @@
2263 page_tree();
2264 return;
2265 }
2266 style_header("Missing name= query parameter");
2267 @ The name= query parameter is missing
2268 style_footer();
2269 return;
2270 }
2271
2272 url_initialize(&url, g.zPath);
2273 url_add_parameter(&url, "name", zName);
@@ -2324,11 +2324,11 @@
2324 }else{
2325 style_header("No such artifact");
2326 @ Artifact '%h(zName)' does not exist in this repository.
2327 }
2328 if( rid==0 ){
2329 style_footer();
2330 return;
2331 }
2332 }
2333
2334 if( descOnly || P("verbose")!=0 ){
@@ -2529,11 +2529,11 @@
2529 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
2530 }
2531 @ </blockquote>
2532 }
2533 }
2534 style_footer();
2535 }
2536
2537 /*
2538 ** WEBPAGE: tinfo
2539 ** URL: /tinfo?name=ARTIFACTID
@@ -2636,11 +2636,11 @@
2636
2637 @ <div class="section">Changes</div>
2638 @ <p>
2639 ticket_output_change_artifact(pTktChng, 0, 1);
2640 manifest_destroy(pTktChng);
2641 style_footer();
2642 }
2643
2644
2645 /*
2646 ** WEBPAGE: info
@@ -2687,11 +2687,11 @@
2687 @ <p>No such object: %h(zName)</p>
2688 if( nLen<4 ){
2689 @ <p>Object name should be no less than 4 characters. Ten or more
2690 @ characters are recommended.</p>
2691 }
2692 style_footer();
2693 return;
2694 }else if( rc==2 ){
2695 cgi_set_parameter("src","info");
2696 ambiguous_page();
2697 return;
@@ -2699,11 +2699,11 @@
2699 zName = blob_str(&uuid);
2700 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName);
2701 if( rid==0 ){
2702 style_header("Broken Link");
2703 @ <p>No such object: %h(zName)</p>
2704 style_footer();
2705 return;
2706 }
2707 if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
2708 ci_page();
2709 }else
@@ -3224,11 +3224,11 @@
3224 }
3225 @ </td></tr>
3226 @ </table>
3227 @ </div></form>
3228 builtin_request_js("ci_edit.js");
3229 style_footer();
3230 }
3231
3232 /*
3233 ** Prepare an ammended commit comment. Let the user modify it using the
3234 ** editor specified in the global_config table or either
3235
--- src/info.c
+++ src/info.c
@@ -503,11 +503,11 @@
503 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
504 rid = name_to_rid_www("name");
505 if( rid==0 ){
506 style_header("Check-in Information Error");
507 @ No such object: %h(g.argv[2])
508 style_finish_page("ci_tags");
509 return;
510 }
511 zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
512 style_header("Tags and Properties");
513 @ <h1>Tags and Properties for Check-In \
@@ -595,11 +595,11 @@
595 blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
596 db_prepare(&q, "%s", blob_sql_text(&sql));
597 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
598 0, 0, 0, rid, 0, 0);
599 db_finalize(&q);
600 style_finish_page("ci_tags");
601 }
602
603 /*
604 ** WEBPAGE: vinfo
605 ** WEBPAGE: ci
@@ -634,11 +634,11 @@
634 zName = P("name");
635 rid = name_to_rid_www("name");
636 if( rid==0 ){
637 style_header("Check-in Information Error");
638 @ No such object: %h(g.argv[2])
639 style_finish_page("vinfo");
640 return;
641 }
642 zRe = P("regex");
643 if( zRe ) re_compile(&pRe, zRe, 0);
644 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -940,11 +940,11 @@
940 diffFlags,pRe,mperm);
941 }
942 db_finalize(&q3);
943 append_diff_javascript(diffType==2);
944 cookie_render();
945 style_finish_page("vinfo");
946 }
947
948 /*
949 ** WEBPAGE: winfo
950 ** URL: /winfo?name=HASH
@@ -966,11 +966,11 @@
966 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
967 rid = name_to_rid_www("name");
968 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
969 style_header("Wiki Page Information Error");
970 @ No such object: %h(P("name"))
971 style_finish_page("winfo");
972 return;
973 }
974 if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){
975 if( strcmp(zModAction,"delete")==0 ){
976 moderation_disapprove(rid);
@@ -1054,11 +1054,11 @@
1054 safe_html_context(DOCSRC_WIKI);
1055 wiki_render_by_mimetype(&wiki, pWiki->zMimetype);
1056 blob_reset(&wiki);
1057 manifest_destroy(pWiki);
1058 document_emit_js();
1059 style_finish_page("winfo");
1060 }
1061
1062 /*
1063 ** Find an check-in based on query parameter zParam and parse its
1064 ** manifest. Return the number of errors.
@@ -1327,11 +1327,11 @@
1327 }
1328 }
1329 manifest_destroy(pFrom);
1330 manifest_destroy(pTo);
1331 append_diff_javascript(diffType==2);
1332 style_finish_page("vdiff");
1333 }
1334
1335 #if INTERFACE
1336 /*
1337 ** Possible return values from object_description()
@@ -1761,11 +1761,11 @@
1761 @ are shown.</b>
1762 }
1763 @ <hr />
1764 append_diff(zV1, zV2, diffFlags, pRe);
1765 append_diff_javascript(diffType);
1766 style_finish_page("fdiff");
1767 }
1768
1769 /*
1770 ** WEBPAGE: raw
1771 ** URL: /raw/ARTIFACTID
@@ -1965,11 +1965,11 @@
1965 @ <hr />
1966 content_get(rid, &content);
1967 @ <blockquote><pre>
1968 hexdump(&content);
1969 @ </pre></blockquote>
1970 style_finish_page("hexdump");
1971 }
1972
1973 /*
1974 ** Look for "ci" and "filename" query parameters. If found, try to
1975 ** use them to extract the record ID of an artifact for the file.
@@ -2263,11 +2263,11 @@
2263 page_tree();
2264 return;
2265 }
2266 style_header("Missing name= query parameter");
2267 @ The name= query parameter is missing
2268 style_finish_page("artifact");
2269 return;
2270 }
2271
2272 url_initialize(&url, g.zPath);
2273 url_add_parameter(&url, "name", zName);
@@ -2324,11 +2324,11 @@
2324 }else{
2325 style_header("No such artifact");
2326 @ Artifact '%h(zName)' does not exist in this repository.
2327 }
2328 if( rid==0 ){
2329 style_finish_page("artifact");
2330 return;
2331 }
2332 }
2333
2334 if( descOnly || P("verbose")!=0 ){
@@ -2529,11 +2529,11 @@
2529 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
2530 }
2531 @ </blockquote>
2532 }
2533 }
2534 style_finish_page("artifact");
2535 }
2536
2537 /*
2538 ** WEBPAGE: tinfo
2539 ** URL: /tinfo?name=ARTIFACTID
@@ -2636,11 +2636,11 @@
2636
2637 @ <div class="section">Changes</div>
2638 @ <p>
2639 ticket_output_change_artifact(pTktChng, 0, 1);
2640 manifest_destroy(pTktChng);
2641 style_finish_page("tinfo");
2642 }
2643
2644
2645 /*
2646 ** WEBPAGE: info
@@ -2687,11 +2687,11 @@
2687 @ <p>No such object: %h(zName)</p>
2688 if( nLen<4 ){
2689 @ <p>Object name should be no less than 4 characters. Ten or more
2690 @ characters are recommended.</p>
2691 }
2692 style_finish_page("info");
2693 return;
2694 }else if( rc==2 ){
2695 cgi_set_parameter("src","info");
2696 ambiguous_page();
2697 return;
@@ -2699,11 +2699,11 @@
2699 zName = blob_str(&uuid);
2700 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName);
2701 if( rid==0 ){
2702 style_header("Broken Link");
2703 @ <p>No such object: %h(zName)</p>
2704 style_finish_page("info");
2705 return;
2706 }
2707 if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
2708 ci_page();
2709 }else
@@ -3224,11 +3224,11 @@
3224 }
3225 @ </td></tr>
3226 @ </table>
3227 @ </div></form>
3228 builtin_request_js("ci_edit.js");
3229 style_finish_page("ci_edit");
3230 }
3231
3232 /*
3233 ** Prepare an ammended commit comment. Let the user modify it using the
3234 ** editor specified in the global_config table or either
3235
+2 -2
--- src/interwiki.c
+++ src/interwiki.c
@@ -384,11 +384,11 @@
384384
@ No mappings are currently defined.
385385
}
386386
387387
if( !g.perm.Setup ){
388388
/* Do not show intermap editing fields to non-setup users */
389
- style_footer();
389
+ style_finish_page("interwiki");
390390
return;
391391
}
392392
393393
@ <p>To add a new mapping, fill out the form below providing a unique name
394394
@ for the tag. To edit an exist mapping, fill out the form and use the
@@ -417,7 +417,7 @@
417417
@ <tr><td></td>
418418
@ <td><input type="submit" name="submit" value="Apply Changes"></td></tr>
419419
@ </table>
420420
@ </form>
421421
422
- style_footer();
422
+ style_finish_page("interwiki");
423423
}
424424
--- src/interwiki.c
+++ src/interwiki.c
@@ -384,11 +384,11 @@
384 @ No mappings are currently defined.
385 }
386
387 if( !g.perm.Setup ){
388 /* Do not show intermap editing fields to non-setup users */
389 style_footer();
390 return;
391 }
392
393 @ <p>To add a new mapping, fill out the form below providing a unique name
394 @ for the tag. To edit an exist mapping, fill out the form and use the
@@ -417,7 +417,7 @@
417 @ <tr><td></td>
418 @ <td><input type="submit" name="submit" value="Apply Changes"></td></tr>
419 @ </table>
420 @ </form>
421
422 style_footer();
423 }
424
--- src/interwiki.c
+++ src/interwiki.c
@@ -384,11 +384,11 @@
384 @ No mappings are currently defined.
385 }
386
387 if( !g.perm.Setup ){
388 /* Do not show intermap editing fields to non-setup users */
389 style_finish_page("interwiki");
390 return;
391 }
392
393 @ <p>To add a new mapping, fill out the form below providing a unique name
394 @ for the tag. To edit an exist mapping, fill out the form and use the
@@ -417,7 +417,7 @@
417 @ <tr><td></td>
418 @ <td><input type="submit" name="submit" value="Apply Changes"></td></tr>
419 @ </table>
420 @ </form>
421
422 style_finish_page("interwiki");
423 }
424
+1 -1
--- src/loadctrl.c
+++ src/loadctrl.c
@@ -57,10 +57,10 @@
5757
style_header("Server Overload");
5858
@ <h2>The server load is currently too high.
5959
@ Please try again later.</h2>
6060
@ <p>Current load average: %f(load_average()).<br />
6161
@ Load average limit: %f(mxLoad)</p>
62
- style_footer();
62
+ style_finish_page("test");
6363
cgi_set_status(503,"Server Overload");
6464
cgi_reply();
6565
exit(0);
6666
}
6767
--- src/loadctrl.c
+++ src/loadctrl.c
@@ -57,10 +57,10 @@
57 style_header("Server Overload");
58 @ <h2>The server load is currently too high.
59 @ Please try again later.</h2>
60 @ <p>Current load average: %f(load_average()).<br />
61 @ Load average limit: %f(mxLoad)</p>
62 style_footer();
63 cgi_set_status(503,"Server Overload");
64 cgi_reply();
65 exit(0);
66 }
67
--- src/loadctrl.c
+++ src/loadctrl.c
@@ -57,10 +57,10 @@
57 style_header("Server Overload");
58 @ <h2>The server load is currently too high.
59 @ Please try again later.</h2>
60 @ <p>Current load average: %f(load_average()).<br />
61 @ Load average limit: %f(mxLoad)</p>
62 style_finish_page("test");
63 cgi_set_status(503,"Server Overload");
64 cgi_reply();
65 exit(0);
66 }
67
+4 -4
--- src/login.c
+++ src/login.c
@@ -794,11 +794,11 @@
794794
@ <td><input type="submit" value="Change Password" /></td></tr>
795795
@ </table>
796796
@ </form>
797797
}
798798
}
799
- style_footer();
799
+ style_finish_page("login");
800800
}
801801
802802
/*
803803
** Attempt to find login credentials for user zLogin on a peer repository
804804
** with project code zCode. Transfer those credentials to the local
@@ -1544,11 +1544,11 @@
15441544
int doAlerts = 0; /* True if subscription is wanted too */
15451545
if( !db_get_boolean("self-register", 0) ){
15461546
style_header("Registration not possible");
15471547
@ <p>This project does not allow user self-registration. Please contact the
15481548
@ project administrator to obtain an account.</p>
1549
- style_footer();
1549
+ style_finish_page("register");
15501550
return;
15511551
}
15521552
zPerms = db_get("default-perms", "u");
15531553
15541554
/* Prompt the user for email alerts if this repository is configured for
@@ -1703,11 +1703,11 @@
17031703
}
17041704
alert_sender_free(pSender);
17051705
if( zGoto ){
17061706
@ <p><a href='%h(zGoto)'>Continue</a>
17071707
}
1708
- style_footer();
1708
+ style_finish_page("register");
17091709
return;
17101710
}
17111711
redirect_to_g();
17121712
}
17131713
@@ -1795,11 +1795,11 @@
17951795
@ %h(zCaptcha)
17961796
@ </pre>
17971797
@ Enter this 8-letter code in the "Captcha" box above.
17981798
@ </td></tr></table></div>
17991799
@ </form>
1800
- style_footer();
1800
+ style_finish_page("register");
18011801
18021802
free(zCaptcha);
18031803
}
18041804
18051805
/*
18061806
--- src/login.c
+++ src/login.c
@@ -794,11 +794,11 @@
794 @ <td><input type="submit" value="Change Password" /></td></tr>
795 @ </table>
796 @ </form>
797 }
798 }
799 style_footer();
800 }
801
802 /*
803 ** Attempt to find login credentials for user zLogin on a peer repository
804 ** with project code zCode. Transfer those credentials to the local
@@ -1544,11 +1544,11 @@
1544 int doAlerts = 0; /* True if subscription is wanted too */
1545 if( !db_get_boolean("self-register", 0) ){
1546 style_header("Registration not possible");
1547 @ <p>This project does not allow user self-registration. Please contact the
1548 @ project administrator to obtain an account.</p>
1549 style_footer();
1550 return;
1551 }
1552 zPerms = db_get("default-perms", "u");
1553
1554 /* Prompt the user for email alerts if this repository is configured for
@@ -1703,11 +1703,11 @@
1703 }
1704 alert_sender_free(pSender);
1705 if( zGoto ){
1706 @ <p><a href='%h(zGoto)'>Continue</a>
1707 }
1708 style_footer();
1709 return;
1710 }
1711 redirect_to_g();
1712 }
1713
@@ -1795,11 +1795,11 @@
1795 @ %h(zCaptcha)
1796 @ </pre>
1797 @ Enter this 8-letter code in the "Captcha" box above.
1798 @ </td></tr></table></div>
1799 @ </form>
1800 style_footer();
1801
1802 free(zCaptcha);
1803 }
1804
1805 /*
1806
--- src/login.c
+++ src/login.c
@@ -794,11 +794,11 @@
794 @ <td><input type="submit" value="Change Password" /></td></tr>
795 @ </table>
796 @ </form>
797 }
798 }
799 style_finish_page("login");
800 }
801
802 /*
803 ** Attempt to find login credentials for user zLogin on a peer repository
804 ** with project code zCode. Transfer those credentials to the local
@@ -1544,11 +1544,11 @@
1544 int doAlerts = 0; /* True if subscription is wanted too */
1545 if( !db_get_boolean("self-register", 0) ){
1546 style_header("Registration not possible");
1547 @ <p>This project does not allow user self-registration. Please contact the
1548 @ project administrator to obtain an account.</p>
1549 style_finish_page("register");
1550 return;
1551 }
1552 zPerms = db_get("default-perms", "u");
1553
1554 /* Prompt the user for email alerts if this repository is configured for
@@ -1703,11 +1703,11 @@
1703 }
1704 alert_sender_free(pSender);
1705 if( zGoto ){
1706 @ <p><a href='%h(zGoto)'>Continue</a>
1707 }
1708 style_finish_page("register");
1709 return;
1710 }
1711 redirect_to_g();
1712 }
1713
@@ -1795,11 +1795,11 @@
1795 @ %h(zCaptcha)
1796 @ </pre>
1797 @ Enter this 8-letter code in the "Captcha" box above.
1798 @ </td></tr></table></div>
1799 @ </form>
1800 style_finish_page("register");
1801
1802 free(zCaptcha);
1803 }
1804
1805 /*
1806
+2 -2
--- src/main.c
+++ src/main.c
@@ -1308,11 +1308,11 @@
13081308
style_submenu_element("Stat", "stat");
13091309
fossil_version_blob(&versionInfo, verboseFlag);
13101310
@ <pre>
13111311
@ %h(blob_str(&versionInfo))
13121312
@ </pre>
1313
- style_footer();
1313
+ style_finish_page("version");
13141314
}
13151315
13161316
13171317
/*
13181318
** Set the g.zBaseURL value to the full URL for the toplevel of
@@ -3095,7 +3095,7 @@
30953095
cgi_reset_content();
30963096
webpage_error("Case 7 from /test-warning");
30973097
}
30983098
@ </ol>
30993099
@ <p>End of test</p>
3100
- style_footer();
3100
+ style_finish_page("test");
31013101
}
31023102
--- src/main.c
+++ src/main.c
@@ -1308,11 +1308,11 @@
1308 style_submenu_element("Stat", "stat");
1309 fossil_version_blob(&versionInfo, verboseFlag);
1310 @ <pre>
1311 @ %h(blob_str(&versionInfo))
1312 @ </pre>
1313 style_footer();
1314 }
1315
1316
1317 /*
1318 ** Set the g.zBaseURL value to the full URL for the toplevel of
@@ -3095,7 +3095,7 @@
3095 cgi_reset_content();
3096 webpage_error("Case 7 from /test-warning");
3097 }
3098 @ </ol>
3099 @ <p>End of test</p>
3100 style_footer();
3101 }
3102
--- src/main.c
+++ src/main.c
@@ -1308,11 +1308,11 @@
1308 style_submenu_element("Stat", "stat");
1309 fossil_version_blob(&versionInfo, verboseFlag);
1310 @ <pre>
1311 @ %h(blob_str(&versionInfo))
1312 @ </pre>
1313 style_finish_page("version");
1314 }
1315
1316
1317 /*
1318 ** Set the g.zBaseURL value to the full URL for the toplevel of
@@ -3095,7 +3095,7 @@
3095 cgi_reset_content();
3096 webpage_error("Case 7 from /test-warning");
3097 }
3098 @ </ol>
3099 @ <p>End of test</p>
3100 style_finish_page("test");
3101 }
3102
+1 -1
--- src/moderate.c
+++ src/moderate.c
@@ -189,11 +189,11 @@
189189
);
190190
db_prepare(&q, "%s", blob_sql_text(&sql));
191191
www_print_timeline(&q, 0, 0, 0, 0, 0, 0, 0);
192192
db_finalize(&q);
193193
}
194
- style_footer();
194
+ style_finish_page("modreq");
195195
}
196196
197197
/*
198198
** Disapproves any entries in the modreq table which belong to any
199199
** user whose name is no longer found in the user table. This is only
200200
--- src/moderate.c
+++ src/moderate.c
@@ -189,11 +189,11 @@
189 );
190 db_prepare(&q, "%s", blob_sql_text(&sql));
191 www_print_timeline(&q, 0, 0, 0, 0, 0, 0, 0);
192 db_finalize(&q);
193 }
194 style_footer();
195 }
196
197 /*
198 ** Disapproves any entries in the modreq table which belong to any
199 ** user whose name is no longer found in the user table. This is only
200
--- src/moderate.c
+++ src/moderate.c
@@ -189,11 +189,11 @@
189 );
190 db_prepare(&q, "%s", blob_sql_text(&sql));
191 www_print_timeline(&q, 0, 0, 0, 0, 0, 0, 0);
192 db_finalize(&q);
193 }
194 style_finish_page("modreq");
195 }
196
197 /*
198 ** Disapproves any entries in the modreq table which belong to any
199 ** user whose name is no longer found in the user table. This is only
200
+6 -6
--- src/name.c
+++ src/name.c
@@ -668,11 +668,11 @@
668668
@ </li></ul>
669669
@ </p></li>
670670
}
671671
@ </ol>
672672
db_finalize(&q);
673
- style_footer();
673
+ style_finish_page("ambiguous");
674674
}
675675
676676
/*
677677
** Convert the name in CGI parameter zParamName into a rid and return that
678678
** rid. If the CGI parameter is missing or is not a valid artifact tag,
@@ -1328,11 +1328,11 @@
13281328
for(i=1; i<=mx; i+=n){
13291329
@ <li> %z(href("%R/bloblist?s=%d&n=%d",i,n))
13301330
@ %d(i)..%d(i+n-1<mx?i+n-1:mx)</a>
13311331
}
13321332
@ </ul>
1333
- style_footer();
1333
+ style_finish_page("bloblist");
13341334
return;
13351335
}
13361336
if( phantomOnly || privOnly || mx>n ){
13371337
style_submenu_element("Index", "bloblist");
13381338
}
@@ -1407,11 +1407,11 @@
14071407
}
14081408
@ </tr>
14091409
}
14101410
@ </table>
14111411
db_finalize(&q);
1412
- style_footer();
1412
+ style_finish_page("bloblist");
14131413
}
14141414
14151415
/*
14161416
** Output HTML that shows a table of all public phantoms.
14171417
*/
@@ -1477,11 +1477,11 @@
14771477
}
14781478
if( g.perm.Write ){
14791479
style_submenu_element("Artifact Stats", "artifact_stats");
14801480
}
14811481
table_of_public_phantoms();
1482
- style_footer();
1482
+ style_finish_page("phantoms");
14831483
}
14841484
14851485
/*
14861486
** WEBPAGE: bigbloblist
14871487
**
@@ -1541,11 +1541,11 @@
15411541
@ </tr>
15421542
}
15431543
@ </tbody></table>
15441544
db_finalize(&q);
15451545
style_table_sorter();
1546
- style_footer();
1546
+ style_finish_page("bigbloblist");
15471547
}
15481548
15491549
/*
15501550
** COMMAND: test-unsent
15511551
**
@@ -1665,7 +1665,7 @@
16651665
collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
16661666
" FROM event WHERE event.type='ci'"
16671667
" ORDER BY 1");
16681668
@ <h1>Hash Prefix Collisions on All Artifacts</h1>
16691669
collision_report("SELECT uuid FROM blob ORDER BY 1");
1670
- style_footer();
1670
+ style_finish_page("hash-collisions");
16711671
}
16721672
--- src/name.c
+++ src/name.c
@@ -668,11 +668,11 @@
668 @ </li></ul>
669 @ </p></li>
670 }
671 @ </ol>
672 db_finalize(&q);
673 style_footer();
674 }
675
676 /*
677 ** Convert the name in CGI parameter zParamName into a rid and return that
678 ** rid. If the CGI parameter is missing or is not a valid artifact tag,
@@ -1328,11 +1328,11 @@
1328 for(i=1; i<=mx; i+=n){
1329 @ <li> %z(href("%R/bloblist?s=%d&n=%d",i,n))
1330 @ %d(i)..%d(i+n-1<mx?i+n-1:mx)</a>
1331 }
1332 @ </ul>
1333 style_footer();
1334 return;
1335 }
1336 if( phantomOnly || privOnly || mx>n ){
1337 style_submenu_element("Index", "bloblist");
1338 }
@@ -1407,11 +1407,11 @@
1407 }
1408 @ </tr>
1409 }
1410 @ </table>
1411 db_finalize(&q);
1412 style_footer();
1413 }
1414
1415 /*
1416 ** Output HTML that shows a table of all public phantoms.
1417 */
@@ -1477,11 +1477,11 @@
1477 }
1478 if( g.perm.Write ){
1479 style_submenu_element("Artifact Stats", "artifact_stats");
1480 }
1481 table_of_public_phantoms();
1482 style_footer();
1483 }
1484
1485 /*
1486 ** WEBPAGE: bigbloblist
1487 **
@@ -1541,11 +1541,11 @@
1541 @ </tr>
1542 }
1543 @ </tbody></table>
1544 db_finalize(&q);
1545 style_table_sorter();
1546 style_footer();
1547 }
1548
1549 /*
1550 ** COMMAND: test-unsent
1551 **
@@ -1665,7 +1665,7 @@
1665 collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
1666 " FROM event WHERE event.type='ci'"
1667 " ORDER BY 1");
1668 @ <h1>Hash Prefix Collisions on All Artifacts</h1>
1669 collision_report("SELECT uuid FROM blob ORDER BY 1");
1670 style_footer();
1671 }
1672
--- src/name.c
+++ src/name.c
@@ -668,11 +668,11 @@
668 @ </li></ul>
669 @ </p></li>
670 }
671 @ </ol>
672 db_finalize(&q);
673 style_finish_page("ambiguous");
674 }
675
676 /*
677 ** Convert the name in CGI parameter zParamName into a rid and return that
678 ** rid. If the CGI parameter is missing or is not a valid artifact tag,
@@ -1328,11 +1328,11 @@
1328 for(i=1; i<=mx; i+=n){
1329 @ <li> %z(href("%R/bloblist?s=%d&n=%d",i,n))
1330 @ %d(i)..%d(i+n-1<mx?i+n-1:mx)</a>
1331 }
1332 @ </ul>
1333 style_finish_page("bloblist");
1334 return;
1335 }
1336 if( phantomOnly || privOnly || mx>n ){
1337 style_submenu_element("Index", "bloblist");
1338 }
@@ -1407,11 +1407,11 @@
1407 }
1408 @ </tr>
1409 }
1410 @ </table>
1411 db_finalize(&q);
1412 style_finish_page("bloblist");
1413 }
1414
1415 /*
1416 ** Output HTML that shows a table of all public phantoms.
1417 */
@@ -1477,11 +1477,11 @@
1477 }
1478 if( g.perm.Write ){
1479 style_submenu_element("Artifact Stats", "artifact_stats");
1480 }
1481 table_of_public_phantoms();
1482 style_finish_page("phantoms");
1483 }
1484
1485 /*
1486 ** WEBPAGE: bigbloblist
1487 **
@@ -1541,11 +1541,11 @@
1541 @ </tr>
1542 }
1543 @ </tbody></table>
1544 db_finalize(&q);
1545 style_table_sorter();
1546 style_finish_page("bigbloblist");
1547 }
1548
1549 /*
1550 ** COMMAND: test-unsent
1551 **
@@ -1665,7 +1665,7 @@
1665 collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
1666 " FROM event WHERE event.type='ci'"
1667 " ORDER BY 1");
1668 @ <h1>Hash Prefix Collisions on All Artifacts</h1>
1669 collision_report("SELECT uuid FROM blob ORDER BY 1");
1670 style_finish_page("hash-collisions");
1671 }
1672
+1 -1
--- src/path.c
+++ src/path.c
@@ -651,7 +651,7 @@
651651
@ <td>%z(href("%R/info/%!S",zUuid))%S(zUuid)</a></td></tr>
652652
}
653653
@ </tbody></table>
654654
db_finalize(&q);
655655
style_table_sorter();
656
- style_footer();
656
+ style_finish_page("test");
657657
}
658658
--- src/path.c
+++ src/path.c
@@ -651,7 +651,7 @@
651 @ <td>%z(href("%R/info/%!S",zUuid))%S(zUuid)</a></td></tr>
652 }
653 @ </tbody></table>
654 db_finalize(&q);
655 style_table_sorter();
656 style_footer();
657 }
658
--- src/path.c
+++ src/path.c
@@ -651,7 +651,7 @@
651 @ <td>%z(href("%R/info/%!S",zUuid))%S(zUuid)</a></td></tr>
652 }
653 @ </tbody></table>
654 db_finalize(&q);
655 style_table_sorter();
656 style_finish_page("test");
657 }
658
+1 -1
--- src/piechart.c
+++ src/piechart.c
@@ -328,7 +328,7 @@
328328
@ <li> <a href='test-piechart?data=2,2,2,2,2,44,44,2,2,2,2,2'>Case 2</a>
329329
@ <li> <a href='test-piechart?data=20,2,2,2,2,2,2,2,2,2,2,80'>Case 3</a>
330330
@ <li> <a href='test-piechart?data=80,2,2,2,2,2,2,2,2,2,2,20'>Case 4</a>
331331
@ <li> <a href='test-piechart?data=2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2'>Case 5</a>
332332
@ </ul>
333
- style_footer();
333
+ style_finish_page("test");
334334
}
335335
--- src/piechart.c
+++ src/piechart.c
@@ -328,7 +328,7 @@
328 @ <li> <a href='test-piechart?data=2,2,2,2,2,44,44,2,2,2,2,2'>Case 2</a>
329 @ <li> <a href='test-piechart?data=20,2,2,2,2,2,2,2,2,2,2,80'>Case 3</a>
330 @ <li> <a href='test-piechart?data=80,2,2,2,2,2,2,2,2,2,2,20'>Case 4</a>
331 @ <li> <a href='test-piechart?data=2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2'>Case 5</a>
332 @ </ul>
333 style_footer();
334 }
335
--- src/piechart.c
+++ src/piechart.c
@@ -328,7 +328,7 @@
328 @ <li> <a href='test-piechart?data=2,2,2,2,2,44,44,2,2,2,2,2'>Case 2</a>
329 @ <li> <a href='test-piechart?data=20,2,2,2,2,2,2,2,2,2,2,80'>Case 3</a>
330 @ <li> <a href='test-piechart?data=80,2,2,2,2,2,2,2,2,2,2,20'>Case 4</a>
331 @ <li> <a href='test-piechart?data=2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2'>Case 5</a>
332 @ </ul>
333 style_finish_page("test");
334 }
335
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -373,11 +373,11 @@
373373
} CX("</div>"/*sbs-wrapper*/);
374374
builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
375375
"storage", "pikchr", 0);
376376
builtin_request_js("fossil.page.pikchrshow.js");
377377
builtin_fulfill_js_requests();
378
- style_footer();
378
+ style_finish_page("pikchrshow");
379379
}
380380
381381
/*
382382
** COMMAND: pikchr*
383383
**
384384
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -373,11 +373,11 @@
373 } CX("</div>"/*sbs-wrapper*/);
374 builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
375 "storage", "pikchr", 0);
376 builtin_request_js("fossil.page.pikchrshow.js");
377 builtin_fulfill_js_requests();
378 style_footer();
379 }
380
381 /*
382 ** COMMAND: pikchr*
383 **
384
--- src/pikchrshow.c
+++ src/pikchrshow.c
@@ -373,11 +373,11 @@
373 } CX("</div>"/*sbs-wrapper*/);
374 builtin_fossil_js_bundle_or("fetch", "copybutton", "popupwidget",
375 "storage", "pikchr", 0);
376 builtin_request_js("fossil.page.pikchrshow.js");
377 builtin_fulfill_js_requests();
378 style_finish_page("pikchrshow");
379 }
380
381 /*
382 ** COMMAND: pikchr*
383 **
384
+1 -1
--- src/printf.c
+++ src/printf.c
@@ -1101,11 +1101,11 @@
11011101
cgi_set_content_type("text/html");
11021102
style_header("Bad Request");
11031103
etag_cancel();
11041104
@ <p class="generalError">%h(z)</p>
11051105
cgi_set_status(400, "Bad Request");
1106
- style_footer();
1106
+ style_finish_page("error");
11071107
cgi_reply();
11081108
}else if( !g.fQuiet ){
11091109
fossil_force_newline();
11101110
fossil_trace("%s\n", z);
11111111
}
11121112
--- src/printf.c
+++ src/printf.c
@@ -1101,11 +1101,11 @@
1101 cgi_set_content_type("text/html");
1102 style_header("Bad Request");
1103 etag_cancel();
1104 @ <p class="generalError">%h(z)</p>
1105 cgi_set_status(400, "Bad Request");
1106 style_footer();
1107 cgi_reply();
1108 }else if( !g.fQuiet ){
1109 fossil_force_newline();
1110 fossil_trace("%s\n", z);
1111 }
1112
--- src/printf.c
+++ src/printf.c
@@ -1101,11 +1101,11 @@
1101 cgi_set_content_type("text/html");
1102 style_header("Bad Request");
1103 etag_cancel();
1104 @ <p class="generalError">%h(z)</p>
1105 cgi_set_status(400, "Bad Request");
1106 style_finish_page("error");
1107 cgi_reply();
1108 }else if( !g.fQuiet ){
1109 fossil_force_newline();
1110 fossil_trace("%s\n", z);
1111 }
1112
+1 -1
--- src/repolist.c
+++ src/repolist.c
@@ -248,11 +248,11 @@
248248
** for display. */
249249
login_check_credentials();
250250
style_header("Repository List");
251251
@ %s(blob_str(&html))
252252
style_table_sorter();
253
- style_footer();
253
+ style_finish_page("repolist");
254254
}else{
255255
/* If no repositories were found that had the "repolist_skin"
256256
** property set, then use a default skin */
257257
@ <html>
258258
@ <head>
259259
--- src/repolist.c
+++ src/repolist.c
@@ -248,11 +248,11 @@
248 ** for display. */
249 login_check_credentials();
250 style_header("Repository List");
251 @ %s(blob_str(&html))
252 style_table_sorter();
253 style_footer();
254 }else{
255 /* If no repositories were found that had the "repolist_skin"
256 ** property set, then use a default skin */
257 @ <html>
258 @ <head>
259
--- src/repolist.c
+++ src/repolist.c
@@ -248,11 +248,11 @@
248 ** for display. */
249 login_check_credentials();
250 style_header("Repository List");
251 @ %s(blob_str(&html))
252 style_table_sorter();
253 style_finish_page("repolist");
254 }else{
255 /* If no repositories were found that had the "repolist_skin"
256 ** property set, then use a default skin */
257 @ <html>
258 @ <head>
259
+7 -7
--- src/report.c
+++ src/report.c
@@ -97,11 +97,11 @@
9797
Th_Render(zScript);
9898
9999
blob_reset(&ril);
100100
if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1);
101101
102
- style_footer();
102
+ style_finish_page("reportlist");
103103
}
104104
105105
/*
106106
** Remove whitespace from both ends of a string.
107107
*/
@@ -319,11 +319,11 @@
319319
db_prepare(&q, "SELECT title, sqlcode, owner, cols "
320320
"FROM reportfmt WHERE rn=%d",rn);
321321
style_header("SQL For Report Format Number %d", rn);
322322
if( db_step(&q)!=SQLITE_ROW ){
323323
@ <p>Unknown report number: %d(rn)</p>
324
- style_footer();
324
+ style_finish_page("report");
325325
db_finalize(&q);
326326
return;
327327
}
328328
zTitle = db_column_text(&q, 0);
329329
zSQL = db_column_text(&q, 1);
@@ -341,11 +341,11 @@
341341
@ <td width=15></td><td valign="top">
342342
output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
343343
@ </td>
344344
@ </tr></table>
345345
report_format_hints();
346
- style_footer();
346
+ style_finish_page("report");
347347
db_finalize(&q);
348348
}
349349
350350
/*
351351
** WEBPAGE: rptnew
@@ -401,11 +401,11 @@
401401
@ <input type="hidden" name="rn" value="%d(rn)">
402402
login_insert_csrf_secret();
403403
@ <input type="submit" name="del2" value="Delete The Report">
404404
@ <input type="submit" name="can" value="Cancel">
405405
@ </form>
406
- style_footer();
406
+ style_finish_page("report");
407407
return;
408408
}else if( P("can") ){
409409
/* user cancelled */
410410
cgi_redirect("reportlist");
411411
return;
@@ -493,20 +493,20 @@
493493
if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){
494494
@ <p>This report format is owned by %h(zOwner). You are not allowed
495495
@ to change it.</p>
496496
@ </form>
497497
report_format_hints();
498
- style_footer();
498
+ style_finish_page("report");
499499
return;
500500
}
501501
@ <input type="submit" value="Apply Changes" />
502502
if( rn>0 ){
503503
@ <input type="submit" value="Delete This Report" name="del1" />
504504
}
505505
@ </div></form>
506506
report_format_hints();
507
- style_footer();
507
+ style_finish_page("report");
508508
}
509509
510510
/*
511511
** Output a bunch of text that provides information about report
512512
** formats
@@ -1048,11 +1048,11 @@
10481048
@ <p class="reportError">Error: %h(zErr1)</p>
10491049
}else if( zErr2 ){
10501050
@ <p class="reportError">Error: %h(zErr2)</p>
10511051
}
10521052
style_table_sorter();
1053
- style_footer();
1053
+ style_finish_page("report");
10541054
}else{
10551055
report_restrict_sql(&zErr1);
10561056
db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
10571057
report_unrestrict_sql();
10581058
cgi_set_content_type("text/plain");
10591059
--- src/report.c
+++ src/report.c
@@ -97,11 +97,11 @@
97 Th_Render(zScript);
98
99 blob_reset(&ril);
100 if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1);
101
102 style_footer();
103 }
104
105 /*
106 ** Remove whitespace from both ends of a string.
107 */
@@ -319,11 +319,11 @@
319 db_prepare(&q, "SELECT title, sqlcode, owner, cols "
320 "FROM reportfmt WHERE rn=%d",rn);
321 style_header("SQL For Report Format Number %d", rn);
322 if( db_step(&q)!=SQLITE_ROW ){
323 @ <p>Unknown report number: %d(rn)</p>
324 style_footer();
325 db_finalize(&q);
326 return;
327 }
328 zTitle = db_column_text(&q, 0);
329 zSQL = db_column_text(&q, 1);
@@ -341,11 +341,11 @@
341 @ <td width=15></td><td valign="top">
342 output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
343 @ </td>
344 @ </tr></table>
345 report_format_hints();
346 style_footer();
347 db_finalize(&q);
348 }
349
350 /*
351 ** WEBPAGE: rptnew
@@ -401,11 +401,11 @@
401 @ <input type="hidden" name="rn" value="%d(rn)">
402 login_insert_csrf_secret();
403 @ <input type="submit" name="del2" value="Delete The Report">
404 @ <input type="submit" name="can" value="Cancel">
405 @ </form>
406 style_footer();
407 return;
408 }else if( P("can") ){
409 /* user cancelled */
410 cgi_redirect("reportlist");
411 return;
@@ -493,20 +493,20 @@
493 if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){
494 @ <p>This report format is owned by %h(zOwner). You are not allowed
495 @ to change it.</p>
496 @ </form>
497 report_format_hints();
498 style_footer();
499 return;
500 }
501 @ <input type="submit" value="Apply Changes" />
502 if( rn>0 ){
503 @ <input type="submit" value="Delete This Report" name="del1" />
504 }
505 @ </div></form>
506 report_format_hints();
507 style_footer();
508 }
509
510 /*
511 ** Output a bunch of text that provides information about report
512 ** formats
@@ -1048,11 +1048,11 @@
1048 @ <p class="reportError">Error: %h(zErr1)</p>
1049 }else if( zErr2 ){
1050 @ <p class="reportError">Error: %h(zErr2)</p>
1051 }
1052 style_table_sorter();
1053 style_footer();
1054 }else{
1055 report_restrict_sql(&zErr1);
1056 db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
1057 report_unrestrict_sql();
1058 cgi_set_content_type("text/plain");
1059
--- src/report.c
+++ src/report.c
@@ -97,11 +97,11 @@
97 Th_Render(zScript);
98
99 blob_reset(&ril);
100 if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1);
101
102 style_finish_page("reportlist");
103 }
104
105 /*
106 ** Remove whitespace from both ends of a string.
107 */
@@ -319,11 +319,11 @@
319 db_prepare(&q, "SELECT title, sqlcode, owner, cols "
320 "FROM reportfmt WHERE rn=%d",rn);
321 style_header("SQL For Report Format Number %d", rn);
322 if( db_step(&q)!=SQLITE_ROW ){
323 @ <p>Unknown report number: %d(rn)</p>
324 style_finish_page("report");
325 db_finalize(&q);
326 return;
327 }
328 zTitle = db_column_text(&q, 0);
329 zSQL = db_column_text(&q, 1);
@@ -341,11 +341,11 @@
341 @ <td width=15></td><td valign="top">
342 output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
343 @ </td>
344 @ </tr></table>
345 report_format_hints();
346 style_finish_page("report");
347 db_finalize(&q);
348 }
349
350 /*
351 ** WEBPAGE: rptnew
@@ -401,11 +401,11 @@
401 @ <input type="hidden" name="rn" value="%d(rn)">
402 login_insert_csrf_secret();
403 @ <input type="submit" name="del2" value="Delete The Report">
404 @ <input type="submit" name="can" value="Cancel">
405 @ </form>
406 style_finish_page("report");
407 return;
408 }else if( P("can") ){
409 /* user cancelled */
410 cgi_redirect("reportlist");
411 return;
@@ -493,20 +493,20 @@
493 if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){
494 @ <p>This report format is owned by %h(zOwner). You are not allowed
495 @ to change it.</p>
496 @ </form>
497 report_format_hints();
498 style_finish_page("report");
499 return;
500 }
501 @ <input type="submit" value="Apply Changes" />
502 if( rn>0 ){
503 @ <input type="submit" value="Delete This Report" name="del1" />
504 }
505 @ </div></form>
506 report_format_hints();
507 style_finish_page("report");
508 }
509
510 /*
511 ** Output a bunch of text that provides information about report
512 ** formats
@@ -1048,11 +1048,11 @@
1048 @ <p class="reportError">Error: %h(zErr1)</p>
1049 }else if( zErr2 ){
1050 @ <p class="reportError">Error: %h(zErr2)</p>
1051 }
1052 style_table_sorter();
1053 style_finish_page("report");
1054 }else{
1055 report_restrict_sql(&zErr1);
1056 db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
1057 report_unrestrict_sql();
1058 cgi_set_content_type("text/plain");
1059
+5 -5
--- src/search.c
+++ src/search.c
@@ -1212,11 +1212,11 @@
12121212
*/
12131213
void search_page(void){
12141214
login_check_credentials();
12151215
style_header("Search");
12161216
search_screen(SRCH_ALL, 1);
1217
- style_footer();
1217
+ style_finish_page("search");
12181218
}
12191219
12201220
12211221
/*
12221222
** This is a helper function for search_stext(). Writing into pOut
@@ -1981,11 +1981,11 @@
19811981
int cnt1 = 0, cnt2 = 0, cnt3 = 0;
19821982
login_check_credentials();
19831983
if( !g.perm.Admin ){ login_needed(0); return; }
19841984
if( !search_index_exists() ){
19851985
@ <p>Indexed search is disabled
1986
- style_footer();
1986
+ style_finish_page("report");
19871987
return;
19881988
}
19891989
search_sql_setup(g.db);
19901990
style_submenu_element("Setup","%R/srchsetup");
19911991
if( zId!=0 && (id = atoi(zId))>0 ){
@@ -2025,11 +2025,11 @@
20252025
style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]);
20262026
zName = mprintf("Unindexed '%c' docs",zDocId[0]);
20272027
style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zDocId[0]);
20282028
}
20292029
db_finalize(&q);
2030
- style_footer();
2030
+ style_finish_page("test");
20312031
return;
20322032
}
20332033
if( zType!=0 && zType[0]!=0 && zType[1]==0 &&
20342034
zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0
20352035
){
@@ -2055,11 +2055,11 @@
20552055
@ <li> <a href='test-ftsdocs?id=%d(db_column_int(&q,0))'>
20562056
@ %h(db_column_text(&q,1))</a>
20572057
}
20582058
@ </ul>
20592059
db_finalize(&q);
2060
- style_footer();
2060
+ style_finish_page("test");
20612061
return;
20622062
}
20632063
style_header("Summary of ftsdocs");
20642064
db_prepare(&q,
20652065
"SELECT type, sum(idxed IS TRUE), sum(idxed IS FALSE), count(*)"
@@ -2099,7 +2099,7 @@
20992099
@ </tbody><tfooter>
21002100
@ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2)
21012101
@ <th align="right">%d(cnt3)
21022102
@ </tfooter>
21032103
@ </table>
2104
- style_footer();
2104
+ style_finish_page("test");
21052105
}
21062106
--- src/search.c
+++ src/search.c
@@ -1212,11 +1212,11 @@
1212 */
1213 void search_page(void){
1214 login_check_credentials();
1215 style_header("Search");
1216 search_screen(SRCH_ALL, 1);
1217 style_footer();
1218 }
1219
1220
1221 /*
1222 ** This is a helper function for search_stext(). Writing into pOut
@@ -1981,11 +1981,11 @@
1981 int cnt1 = 0, cnt2 = 0, cnt3 = 0;
1982 login_check_credentials();
1983 if( !g.perm.Admin ){ login_needed(0); return; }
1984 if( !search_index_exists() ){
1985 @ <p>Indexed search is disabled
1986 style_footer();
1987 return;
1988 }
1989 search_sql_setup(g.db);
1990 style_submenu_element("Setup","%R/srchsetup");
1991 if( zId!=0 && (id = atoi(zId))>0 ){
@@ -2025,11 +2025,11 @@
2025 style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]);
2026 zName = mprintf("Unindexed '%c' docs",zDocId[0]);
2027 style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zDocId[0]);
2028 }
2029 db_finalize(&q);
2030 style_footer();
2031 return;
2032 }
2033 if( zType!=0 && zType[0]!=0 && zType[1]==0 &&
2034 zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0
2035 ){
@@ -2055,11 +2055,11 @@
2055 @ <li> <a href='test-ftsdocs?id=%d(db_column_int(&q,0))'>
2056 @ %h(db_column_text(&q,1))</a>
2057 }
2058 @ </ul>
2059 db_finalize(&q);
2060 style_footer();
2061 return;
2062 }
2063 style_header("Summary of ftsdocs");
2064 db_prepare(&q,
2065 "SELECT type, sum(idxed IS TRUE), sum(idxed IS FALSE), count(*)"
@@ -2099,7 +2099,7 @@
2099 @ </tbody><tfooter>
2100 @ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2)
2101 @ <th align="right">%d(cnt3)
2102 @ </tfooter>
2103 @ </table>
2104 style_footer();
2105 }
2106
--- src/search.c
+++ src/search.c
@@ -1212,11 +1212,11 @@
1212 */
1213 void search_page(void){
1214 login_check_credentials();
1215 style_header("Search");
1216 search_screen(SRCH_ALL, 1);
1217 style_finish_page("search");
1218 }
1219
1220
1221 /*
1222 ** This is a helper function for search_stext(). Writing into pOut
@@ -1981,11 +1981,11 @@
1981 int cnt1 = 0, cnt2 = 0, cnt3 = 0;
1982 login_check_credentials();
1983 if( !g.perm.Admin ){ login_needed(0); return; }
1984 if( !search_index_exists() ){
1985 @ <p>Indexed search is disabled
1986 style_finish_page("report");
1987 return;
1988 }
1989 search_sql_setup(g.db);
1990 style_submenu_element("Setup","%R/srchsetup");
1991 if( zId!=0 && (id = atoi(zId))>0 ){
@@ -2025,11 +2025,11 @@
2025 style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]);
2026 zName = mprintf("Unindexed '%c' docs",zDocId[0]);
2027 style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zDocId[0]);
2028 }
2029 db_finalize(&q);
2030 style_finish_page("test");
2031 return;
2032 }
2033 if( zType!=0 && zType[0]!=0 && zType[1]==0 &&
2034 zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0
2035 ){
@@ -2055,11 +2055,11 @@
2055 @ <li> <a href='test-ftsdocs?id=%d(db_column_int(&q,0))'>
2056 @ %h(db_column_text(&q,1))</a>
2057 }
2058 @ </ul>
2059 db_finalize(&q);
2060 style_finish_page("test");
2061 return;
2062 }
2063 style_header("Summary of ftsdocs");
2064 db_prepare(&q,
2065 "SELECT type, sum(idxed IS TRUE), sum(idxed IS FALSE), count(*)"
@@ -2099,7 +2099,7 @@
2099 @ </tbody><tfooter>
2100 @ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2)
2101 @ <th align="right">%d(cnt3)
2102 @ </tfooter>
2103 @ </table>
2104 style_finish_page("test");
2105 }
2106
--- src/security_audit.c
+++ src/security_audit.c
@@ -585,11 +585,11 @@
585585
table_of_public_phantoms();
586586
@ </li>
587587
}
588588
589589
@ </ol>
590
- style_footer();
590
+ style_finish_page("secaudit");
591591
}
592592
593593
/*
594594
** WEBPAGE: takeitprivate
595595
**
@@ -627,11 +627,11 @@
627627
@ <form action="%s(g.zPath)" method="post">
628628
@ <input type="submit" name="apply" value="Make It Private">
629629
@ <input type="submit" name="cancel" value="Cancel">
630630
@ </form>
631631
632
- style_footer();
632
+ style_finish_page("takeitprivate");
633633
}
634634
635635
/*
636636
** The maximum number of bytes of log to show
637637
*/
@@ -668,11 +668,11 @@
668668
@ If the server is running using one of
669669
@ the "fossil http" or "fossil server" commands then add
670670
@ a command-line option "--errorlog <i>FILENAME</i>" to that
671671
@ command.
672672
@ </ol>
673
- style_footer();
673
+ style_finish_page("errorlog");
674674
return;
675675
}
676676
if( P("truncate1") && cgi_csrf_safe(1) ){
677677
fclose(fopen(g.zErrlog,"w"));
678678
}
@@ -688,20 +688,20 @@
688688
@ <form action="%R/errorlog" method="POST">
689689
@ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
690690
@ <input type="submit" name="truncate1" value="Confirm">
691691
@ <input type="submit" name="cancel" value="Cancel">
692692
@ </form>
693
- style_footer();
693
+ style_finish_page("errorlog");
694694
return;
695695
}
696696
@ <p>The server error log at "%h(g.zErrlog)" is %,lld(szFile) bytes in size.
697697
style_submenu_element("Download", "%R/errorlog?download");
698698
style_submenu_element("Truncate", "%R/errorlog?truncate");
699699
in = fossil_fopen(g.zErrlog, "rb");
700700
if( in==0 ){
701701
@ <p class='generalError'>Unable to open that file for reading!</p>
702
- style_footer();
702
+ style_finish_page("errorlog");
703703
return;
704704
}
705705
if( szFile>MXSHOWLOG && P("all")==0 ){
706706
@ <form action="%R/errorlog" method="POST">
707707
@ <p>Only the last %,d(MXSHOWLOG) bytes are shown.
@@ -714,7 +714,7 @@
714714
while( fgets(z, sizeof(z), in) ){
715715
@ %h(z)\
716716
}
717717
fclose(in);
718718
@ </pre>
719
- style_footer();
719
+ style_finish_page("errorlog");
720720
}
721721
--- src/security_audit.c
+++ src/security_audit.c
@@ -585,11 +585,11 @@
585 table_of_public_phantoms();
586 @ </li>
587 }
588
589 @ </ol>
590 style_footer();
591 }
592
593 /*
594 ** WEBPAGE: takeitprivate
595 **
@@ -627,11 +627,11 @@
627 @ <form action="%s(g.zPath)" method="post">
628 @ <input type="submit" name="apply" value="Make It Private">
629 @ <input type="submit" name="cancel" value="Cancel">
630 @ </form>
631
632 style_footer();
633 }
634
635 /*
636 ** The maximum number of bytes of log to show
637 */
@@ -668,11 +668,11 @@
668 @ If the server is running using one of
669 @ the "fossil http" or "fossil server" commands then add
670 @ a command-line option "--errorlog <i>FILENAME</i>" to that
671 @ command.
672 @ </ol>
673 style_footer();
674 return;
675 }
676 if( P("truncate1") && cgi_csrf_safe(1) ){
677 fclose(fopen(g.zErrlog,"w"));
678 }
@@ -688,20 +688,20 @@
688 @ <form action="%R/errorlog" method="POST">
689 @ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
690 @ <input type="submit" name="truncate1" value="Confirm">
691 @ <input type="submit" name="cancel" value="Cancel">
692 @ </form>
693 style_footer();
694 return;
695 }
696 @ <p>The server error log at "%h(g.zErrlog)" is %,lld(szFile) bytes in size.
697 style_submenu_element("Download", "%R/errorlog?download");
698 style_submenu_element("Truncate", "%R/errorlog?truncate");
699 in = fossil_fopen(g.zErrlog, "rb");
700 if( in==0 ){
701 @ <p class='generalError'>Unable to open that file for reading!</p>
702 style_footer();
703 return;
704 }
705 if( szFile>MXSHOWLOG && P("all")==0 ){
706 @ <form action="%R/errorlog" method="POST">
707 @ <p>Only the last %,d(MXSHOWLOG) bytes are shown.
@@ -714,7 +714,7 @@
714 while( fgets(z, sizeof(z), in) ){
715 @ %h(z)\
716 }
717 fclose(in);
718 @ </pre>
719 style_footer();
720 }
721
--- src/security_audit.c
+++ src/security_audit.c
@@ -585,11 +585,11 @@
585 table_of_public_phantoms();
586 @ </li>
587 }
588
589 @ </ol>
590 style_finish_page("secaudit");
591 }
592
593 /*
594 ** WEBPAGE: takeitprivate
595 **
@@ -627,11 +627,11 @@
627 @ <form action="%s(g.zPath)" method="post">
628 @ <input type="submit" name="apply" value="Make It Private">
629 @ <input type="submit" name="cancel" value="Cancel">
630 @ </form>
631
632 style_finish_page("takeitprivate");
633 }
634
635 /*
636 ** The maximum number of bytes of log to show
637 */
@@ -668,11 +668,11 @@
668 @ If the server is running using one of
669 @ the "fossil http" or "fossil server" commands then add
670 @ a command-line option "--errorlog <i>FILENAME</i>" to that
671 @ command.
672 @ </ol>
673 style_finish_page("errorlog");
674 return;
675 }
676 if( P("truncate1") && cgi_csrf_safe(1) ){
677 fclose(fopen(g.zErrlog,"w"));
678 }
@@ -688,20 +688,20 @@
688 @ <form action="%R/errorlog" method="POST">
689 @ <p>Confirm that you want to truncate the %,lld(szFile)-byte error log:
690 @ <input type="submit" name="truncate1" value="Confirm">
691 @ <input type="submit" name="cancel" value="Cancel">
692 @ </form>
693 style_finish_page("errorlog");
694 return;
695 }
696 @ <p>The server error log at "%h(g.zErrlog)" is %,lld(szFile) bytes in size.
697 style_submenu_element("Download", "%R/errorlog?download");
698 style_submenu_element("Truncate", "%R/errorlog?truncate");
699 in = fossil_fopen(g.zErrlog, "rb");
700 if( in==0 ){
701 @ <p class='generalError'>Unable to open that file for reading!</p>
702 style_finish_page("errorlog");
703 return;
704 }
705 if( szFile>MXSHOWLOG && P("all")==0 ){
706 @ <form action="%R/errorlog" method="POST">
707 @ <p>Only the last %,d(MXSHOWLOG) bytes are shown.
@@ -714,7 +714,7 @@
714 while( fgets(z, sizeof(z), in) ){
715 @ %h(z)\
716 }
717 fclose(in);
718 @ </pre>
719 style_finish_page("errorlog");
720 }
721
+15 -15
--- src/setup.c
+++ src/setup.c
@@ -175,11 +175,11 @@
175175
setup_menu_entry("TH1", "admin_th1",
176176
"Enter raw TH1 commands");
177177
}
178178
@ </table>
179179
180
- style_footer();
180
+ style_finish_page("setup");
181181
}
182182
183183
/*
184184
** Generate a checkbox for an attribute.
185185
*/
@@ -576,11 +576,11 @@
576576
577577
@ <hr />
578578
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
579579
@ </div></form>
580580
db_end_transaction(0);
581
- style_footer();
581
+ style_finish_page("setup");
582582
}
583583
584584
/*
585585
** WEBPAGE: setup_login_group
586586
**
@@ -704,11 +704,11 @@
704704
}
705705
db_finalize(&q);
706706
@ </tbody></table>
707707
style_table_sorter();
708708
}
709
- style_footer();
709
+ style_finish_page("setup");
710710
}
711711
712712
/*
713713
** WEBPAGE: setup_timeline
714714
**
@@ -843,11 +843,11 @@
843843
844844
@ <hr />
845845
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
846846
@ </div></form>
847847
db_end_transaction(0);
848
- style_footer();
848
+ style_finish_page("setup");
849849
}
850850
851851
/*
852852
** WEBPAGE: setup_settings
853853
**
@@ -936,11 +936,11 @@
936936
}
937937
}
938938
@ </td></tr></table>
939939
@ </div></form>
940940
db_end_transaction(0);
941
- style_footer();
941
+ style_finish_page("setup");
942942
}
943943
944944
/*
945945
** WEBPAGE: setup_config
946946
**
@@ -1032,11 +1032,11 @@
10321032
@ (Property: sitemap-contact)
10331033
@ <hr />
10341034
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
10351035
@ </div></form>
10361036
db_end_transaction(0);
1037
- style_footer();
1037
+ style_finish_page("setup");
10381038
}
10391039
10401040
/*
10411041
** WEBPAGE: setup_wiki
10421042
**
@@ -1108,11 +1108,11 @@
11081108
@ (Property: "wiki-use-html")
11091109
@ <hr />
11101110
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
11111111
@ </div></form>
11121112
db_end_transaction(0);
1113
- style_footer();
1113
+ style_finish_page("setup");
11141114
}
11151115
11161116
/*
11171117
** WEBPAGE: setup_modreq
11181118
**
@@ -1154,11 +1154,11 @@
11541154
11551155
@ <hr />
11561156
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
11571157
@ </div></form>
11581158
db_end_transaction(0);
1159
- style_footer();
1159
+ style_finish_page("setup");
11601160
11611161
}
11621162
11631163
/*
11641164
** WEBPAGE: setup_adunit
@@ -1235,11 +1235,11 @@
12351235
@ border: 1px solid #f11;
12361236
@ background-color: #fcc;
12371237
@ '&gt;Demo Ad&lt;/div&gt;
12381238
@ </pre></blockquote>
12391239
@ </li>
1240
- style_footer();
1240
+ style_finish_page("setup");
12411241
db_end_transaction(0);
12421242
}
12431243
12441244
/*
12451245
** WEBPAGE: setup_logo
@@ -1437,11 +1437,11 @@
14371437
@ <hr />
14381438
@
14391439
@ <p><span class="note">Note:</span> Your browser has probably cached these
14401440
@ images, so you may need to press the Reload button before changes will
14411441
@ take effect. </p>
1442
- style_footer();
1442
+ style_finish_page("setup");
14431443
db_end_transaction(0);
14441444
}
14451445
14461446
/*
14471447
** Prevent the RAW SQL feature from being used to ATTACH a different
@@ -1599,11 +1599,11 @@
15991599
}
16001600
sqlite3_finalize(pStmt);
16011601
@ </table>
16021602
}
16031603
}
1604
- style_footer();
1604
+ style_finish_page("setup");
16051605
}
16061606
16071607
16081608
/*
16091609
** WEBPAGE: admin_th1
@@ -1643,11 +1643,11 @@
16431643
@ <pre class="th1result">%h(zR)</pre>
16441644
}else{
16451645
@ <pre class="th1error">%h(zR)</pre>
16461646
}
16471647
}
1648
- style_footer();
1648
+ style_finish_page("setup");
16491649
}
16501650
16511651
/*
16521652
** WEBPAGE: admin_log
16531653
**
@@ -1710,11 +1710,11 @@
17101710
db_finalize(&stLog);
17111711
@ </tbody></table>
17121712
if( counter>ofst+limit ){
17131713
@ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p>
17141714
}
1715
- style_footer();
1715
+ style_finish_page("setup");
17161716
}
17171717
17181718
/*
17191719
** WEBPAGE: srchsetup
17201720
**
@@ -1790,11 +1790,11 @@
17901790
@ larger repositories.</p>
17911791
onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
17921792
@ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
17931793
}
17941794
@ </div></form>
1795
- style_footer();
1795
+ style_finish_page("setup");
17961796
}
17971797
17981798
/*
17991799
** A URL Alias originally called zOldName is now zNewName/zValue.
18001800
** Write SQL to make this change into pSql.
@@ -1948,7 +1948,7 @@
19481948
@ <p>To delete an entry from the alias table, change its name or value to an
19491949
@ empty string and press "Apply Changes".
19501950
@
19511951
@ <p>To add a new alias, fill in the name and value in the bottom row
19521952
@ of the table above and press "Apply Changes".
1953
- style_footer();
1953
+ style_finish_page("setup");
19541954
}
19551955
--- src/setup.c
+++ src/setup.c
@@ -175,11 +175,11 @@
175 setup_menu_entry("TH1", "admin_th1",
176 "Enter raw TH1 commands");
177 }
178 @ </table>
179
180 style_footer();
181 }
182
183 /*
184 ** Generate a checkbox for an attribute.
185 */
@@ -576,11 +576,11 @@
576
577 @ <hr />
578 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
579 @ </div></form>
580 db_end_transaction(0);
581 style_footer();
582 }
583
584 /*
585 ** WEBPAGE: setup_login_group
586 **
@@ -704,11 +704,11 @@
704 }
705 db_finalize(&q);
706 @ </tbody></table>
707 style_table_sorter();
708 }
709 style_footer();
710 }
711
712 /*
713 ** WEBPAGE: setup_timeline
714 **
@@ -843,11 +843,11 @@
843
844 @ <hr />
845 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
846 @ </div></form>
847 db_end_transaction(0);
848 style_footer();
849 }
850
851 /*
852 ** WEBPAGE: setup_settings
853 **
@@ -936,11 +936,11 @@
936 }
937 }
938 @ </td></tr></table>
939 @ </div></form>
940 db_end_transaction(0);
941 style_footer();
942 }
943
944 /*
945 ** WEBPAGE: setup_config
946 **
@@ -1032,11 +1032,11 @@
1032 @ (Property: sitemap-contact)
1033 @ <hr />
1034 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1035 @ </div></form>
1036 db_end_transaction(0);
1037 style_footer();
1038 }
1039
1040 /*
1041 ** WEBPAGE: setup_wiki
1042 **
@@ -1108,11 +1108,11 @@
1108 @ (Property: "wiki-use-html")
1109 @ <hr />
1110 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1111 @ </div></form>
1112 db_end_transaction(0);
1113 style_footer();
1114 }
1115
1116 /*
1117 ** WEBPAGE: setup_modreq
1118 **
@@ -1154,11 +1154,11 @@
1154
1155 @ <hr />
1156 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1157 @ </div></form>
1158 db_end_transaction(0);
1159 style_footer();
1160
1161 }
1162
1163 /*
1164 ** WEBPAGE: setup_adunit
@@ -1235,11 +1235,11 @@
1235 @ border: 1px solid #f11;
1236 @ background-color: #fcc;
1237 @ '&gt;Demo Ad&lt;/div&gt;
1238 @ </pre></blockquote>
1239 @ </li>
1240 style_footer();
1241 db_end_transaction(0);
1242 }
1243
1244 /*
1245 ** WEBPAGE: setup_logo
@@ -1437,11 +1437,11 @@
1437 @ <hr />
1438 @
1439 @ <p><span class="note">Note:</span> Your browser has probably cached these
1440 @ images, so you may need to press the Reload button before changes will
1441 @ take effect. </p>
1442 style_footer();
1443 db_end_transaction(0);
1444 }
1445
1446 /*
1447 ** Prevent the RAW SQL feature from being used to ATTACH a different
@@ -1599,11 +1599,11 @@
1599 }
1600 sqlite3_finalize(pStmt);
1601 @ </table>
1602 }
1603 }
1604 style_footer();
1605 }
1606
1607
1608 /*
1609 ** WEBPAGE: admin_th1
@@ -1643,11 +1643,11 @@
1643 @ <pre class="th1result">%h(zR)</pre>
1644 }else{
1645 @ <pre class="th1error">%h(zR)</pre>
1646 }
1647 }
1648 style_footer();
1649 }
1650
1651 /*
1652 ** WEBPAGE: admin_log
1653 **
@@ -1710,11 +1710,11 @@
1710 db_finalize(&stLog);
1711 @ </tbody></table>
1712 if( counter>ofst+limit ){
1713 @ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p>
1714 }
1715 style_footer();
1716 }
1717
1718 /*
1719 ** WEBPAGE: srchsetup
1720 **
@@ -1790,11 +1790,11 @@
1790 @ larger repositories.</p>
1791 onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
1792 @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
1793 }
1794 @ </div></form>
1795 style_footer();
1796 }
1797
1798 /*
1799 ** A URL Alias originally called zOldName is now zNewName/zValue.
1800 ** Write SQL to make this change into pSql.
@@ -1948,7 +1948,7 @@
1948 @ <p>To delete an entry from the alias table, change its name or value to an
1949 @ empty string and press "Apply Changes".
1950 @
1951 @ <p>To add a new alias, fill in the name and value in the bottom row
1952 @ of the table above and press "Apply Changes".
1953 style_footer();
1954 }
1955
--- src/setup.c
+++ src/setup.c
@@ -175,11 +175,11 @@
175 setup_menu_entry("TH1", "admin_th1",
176 "Enter raw TH1 commands");
177 }
178 @ </table>
179
180 style_finish_page("setup");
181 }
182
183 /*
184 ** Generate a checkbox for an attribute.
185 */
@@ -576,11 +576,11 @@
576
577 @ <hr />
578 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
579 @ </div></form>
580 db_end_transaction(0);
581 style_finish_page("setup");
582 }
583
584 /*
585 ** WEBPAGE: setup_login_group
586 **
@@ -704,11 +704,11 @@
704 }
705 db_finalize(&q);
706 @ </tbody></table>
707 style_table_sorter();
708 }
709 style_finish_page("setup");
710 }
711
712 /*
713 ** WEBPAGE: setup_timeline
714 **
@@ -843,11 +843,11 @@
843
844 @ <hr />
845 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
846 @ </div></form>
847 db_end_transaction(0);
848 style_finish_page("setup");
849 }
850
851 /*
852 ** WEBPAGE: setup_settings
853 **
@@ -936,11 +936,11 @@
936 }
937 }
938 @ </td></tr></table>
939 @ </div></form>
940 db_end_transaction(0);
941 style_finish_page("setup");
942 }
943
944 /*
945 ** WEBPAGE: setup_config
946 **
@@ -1032,11 +1032,11 @@
1032 @ (Property: sitemap-contact)
1033 @ <hr />
1034 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1035 @ </div></form>
1036 db_end_transaction(0);
1037 style_finish_page("setup");
1038 }
1039
1040 /*
1041 ** WEBPAGE: setup_wiki
1042 **
@@ -1108,11 +1108,11 @@
1108 @ (Property: "wiki-use-html")
1109 @ <hr />
1110 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1111 @ </div></form>
1112 db_end_transaction(0);
1113 style_finish_page("setup");
1114 }
1115
1116 /*
1117 ** WEBPAGE: setup_modreq
1118 **
@@ -1154,11 +1154,11 @@
1154
1155 @ <hr />
1156 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1157 @ </div></form>
1158 db_end_transaction(0);
1159 style_finish_page("setup");
1160
1161 }
1162
1163 /*
1164 ** WEBPAGE: setup_adunit
@@ -1235,11 +1235,11 @@
1235 @ border: 1px solid #f11;
1236 @ background-color: #fcc;
1237 @ '&gt;Demo Ad&lt;/div&gt;
1238 @ </pre></blockquote>
1239 @ </li>
1240 style_finish_page("setup");
1241 db_end_transaction(0);
1242 }
1243
1244 /*
1245 ** WEBPAGE: setup_logo
@@ -1437,11 +1437,11 @@
1437 @ <hr />
1438 @
1439 @ <p><span class="note">Note:</span> Your browser has probably cached these
1440 @ images, so you may need to press the Reload button before changes will
1441 @ take effect. </p>
1442 style_finish_page("setup");
1443 db_end_transaction(0);
1444 }
1445
1446 /*
1447 ** Prevent the RAW SQL feature from being used to ATTACH a different
@@ -1599,11 +1599,11 @@
1599 }
1600 sqlite3_finalize(pStmt);
1601 @ </table>
1602 }
1603 }
1604 style_finish_page("setup");
1605 }
1606
1607
1608 /*
1609 ** WEBPAGE: admin_th1
@@ -1643,11 +1643,11 @@
1643 @ <pre class="th1result">%h(zR)</pre>
1644 }else{
1645 @ <pre class="th1error">%h(zR)</pre>
1646 }
1647 }
1648 style_finish_page("setup");
1649 }
1650
1651 /*
1652 ** WEBPAGE: admin_log
1653 **
@@ -1710,11 +1710,11 @@
1710 db_finalize(&stLog);
1711 @ </tbody></table>
1712 if( counter>ofst+limit ){
1713 @ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p>
1714 }
1715 style_finish_page("setup");
1716 }
1717
1718 /*
1719 ** WEBPAGE: srchsetup
1720 **
@@ -1790,11 +1790,11 @@
1790 @ larger repositories.</p>
1791 onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0);
1792 @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
1793 }
1794 @ </div></form>
1795 style_finish_page("setup");
1796 }
1797
1798 /*
1799 ** A URL Alias originally called zOldName is now zNewName/zValue.
1800 ** Write SQL to make this change into pSql.
@@ -1948,7 +1948,7 @@
1948 @ <p>To delete an entry from the alias table, change its name or value to an
1949 @ empty string and press "Apply Changes".
1950 @
1951 @ <p>To add a new alias, fill in the name and value in the bottom row
1952 @ of the table above and press "Apply Changes".
1953 style_finish_page("setup");
1954 }
1955
+7 -7
--- src/setupuser.c
+++ src/setupuser.c
@@ -180,11 +180,11 @@
180180
fossil_free(zAge);
181181
}
182182
@ </tbody></table>
183183
db_finalize(&s);
184184
style_table_sorter();
185
- style_footer();
185
+ style_finish_page("setupuser");
186186
}
187187
188188
/*
189189
** WEBPAGE: setup_ulist_notes
190190
**
@@ -226,11 +226,11 @@
226226
@
227227
@ <li><p>The permission flags are as follows:</p>
228228
capabilities_table(CAPCLASS_ALL);
229229
@ </li>
230230
@ </ol>
231
- style_footer();
231
+ style_finish_page("setupuser");
232232
}
233233
234234
/*
235235
** WEBPAGE: setup_ucap_list
236236
**
@@ -253,11 +253,11 @@
253253
capabilities_table(CAPCLASS_WIKI);
254254
@ <h1>Administrative capabilities</h1>
255255
capabilities_table(CAPCLASS_SUPER);
256256
@ <h1>Miscellaneous capabilities</h1>
257257
capabilities_table(CAPCLASS_OTHER);
258
- style_footer();
258
+ style_finish_page("setupuser");
259259
}
260260
261261
/*
262262
** Return true if zPw is a valid password string. A valid
263263
** password string is:
@@ -387,11 +387,11 @@
387387
style_header("User Creation Error");
388388
@ <span class="loginError">Empty login not allowed.</span>
389389
@
390390
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
391391
@ [Bummer]</a></p>
392
- style_footer();
392
+ style_finish_page("setupuser");
393393
return;
394394
}
395395
if( isValidPwString(zPw) ){
396396
zPw = sha1_shared_secret(zPw, zLogin, 0);
397397
}else{
@@ -404,11 +404,11 @@
404404
@ <span class="loginError">Login "%h(zLogin)" is already used by
405405
@ a different user.</span>
406406
@
407407
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
408408
@ [Bummer]</a></p>
409
- style_footer();
409
+ style_finish_page("setupuser");
410410
return;
411411
}
412412
login_verify_csrf_secret();
413413
db_unprotect(PROTECT_USER);
414414
db_multi_exec(
@@ -456,11 +456,11 @@
456456
admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
457457
@ <span class="loginError">%h(zErr)</span>
458458
@
459459
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
460460
@ [Bummer]</a></p>
461
- style_footer();
461
+ style_finish_page("setupuser");
462462
return;
463463
}
464464
}
465465
cgi_redirect(cgi_referer("setup_ulist"));
466466
return;
@@ -874,7 +874,7 @@
874874
@ template for users who are allowed more access than
875875
@ <span class="usertype">anonymous</span>,
876876
@ but less than a <span class="usertype">developer</span>.
877877
@ </p></li>
878878
@ </ul>
879
- style_footer();
879
+ style_finish_page("setupuser");
880880
}
881881
--- src/setupuser.c
+++ src/setupuser.c
@@ -180,11 +180,11 @@
180 fossil_free(zAge);
181 }
182 @ </tbody></table>
183 db_finalize(&s);
184 style_table_sorter();
185 style_footer();
186 }
187
188 /*
189 ** WEBPAGE: setup_ulist_notes
190 **
@@ -226,11 +226,11 @@
226 @
227 @ <li><p>The permission flags are as follows:</p>
228 capabilities_table(CAPCLASS_ALL);
229 @ </li>
230 @ </ol>
231 style_footer();
232 }
233
234 /*
235 ** WEBPAGE: setup_ucap_list
236 **
@@ -253,11 +253,11 @@
253 capabilities_table(CAPCLASS_WIKI);
254 @ <h1>Administrative capabilities</h1>
255 capabilities_table(CAPCLASS_SUPER);
256 @ <h1>Miscellaneous capabilities</h1>
257 capabilities_table(CAPCLASS_OTHER);
258 style_footer();
259 }
260
261 /*
262 ** Return true if zPw is a valid password string. A valid
263 ** password string is:
@@ -387,11 +387,11 @@
387 style_header("User Creation Error");
388 @ <span class="loginError">Empty login not allowed.</span>
389 @
390 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
391 @ [Bummer]</a></p>
392 style_footer();
393 return;
394 }
395 if( isValidPwString(zPw) ){
396 zPw = sha1_shared_secret(zPw, zLogin, 0);
397 }else{
@@ -404,11 +404,11 @@
404 @ <span class="loginError">Login "%h(zLogin)" is already used by
405 @ a different user.</span>
406 @
407 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
408 @ [Bummer]</a></p>
409 style_footer();
410 return;
411 }
412 login_verify_csrf_secret();
413 db_unprotect(PROTECT_USER);
414 db_multi_exec(
@@ -456,11 +456,11 @@
456 admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
457 @ <span class="loginError">%h(zErr)</span>
458 @
459 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
460 @ [Bummer]</a></p>
461 style_footer();
462 return;
463 }
464 }
465 cgi_redirect(cgi_referer("setup_ulist"));
466 return;
@@ -874,7 +874,7 @@
874 @ template for users who are allowed more access than
875 @ <span class="usertype">anonymous</span>,
876 @ but less than a <span class="usertype">developer</span>.
877 @ </p></li>
878 @ </ul>
879 style_footer();
880 }
881
--- src/setupuser.c
+++ src/setupuser.c
@@ -180,11 +180,11 @@
180 fossil_free(zAge);
181 }
182 @ </tbody></table>
183 db_finalize(&s);
184 style_table_sorter();
185 style_finish_page("setupuser");
186 }
187
188 /*
189 ** WEBPAGE: setup_ulist_notes
190 **
@@ -226,11 +226,11 @@
226 @
227 @ <li><p>The permission flags are as follows:</p>
228 capabilities_table(CAPCLASS_ALL);
229 @ </li>
230 @ </ol>
231 style_finish_page("setupuser");
232 }
233
234 /*
235 ** WEBPAGE: setup_ucap_list
236 **
@@ -253,11 +253,11 @@
253 capabilities_table(CAPCLASS_WIKI);
254 @ <h1>Administrative capabilities</h1>
255 capabilities_table(CAPCLASS_SUPER);
256 @ <h1>Miscellaneous capabilities</h1>
257 capabilities_table(CAPCLASS_OTHER);
258 style_finish_page("setupuser");
259 }
260
261 /*
262 ** Return true if zPw is a valid password string. A valid
263 ** password string is:
@@ -387,11 +387,11 @@
387 style_header("User Creation Error");
388 @ <span class="loginError">Empty login not allowed.</span>
389 @
390 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
391 @ [Bummer]</a></p>
392 style_finish_page("setupuser");
393 return;
394 }
395 if( isValidPwString(zPw) ){
396 zPw = sha1_shared_secret(zPw, zLogin, 0);
397 }else{
@@ -404,11 +404,11 @@
404 @ <span class="loginError">Login "%h(zLogin)" is already used by
405 @ a different user.</span>
406 @
407 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
408 @ [Bummer]</a></p>
409 style_finish_page("setupuser");
410 return;
411 }
412 login_verify_csrf_secret();
413 db_unprotect(PROTECT_USER);
414 db_multi_exec(
@@ -456,11 +456,11 @@
456 admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
457 @ <span class="loginError">%h(zErr)</span>
458 @
459 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
460 @ [Bummer]</a></p>
461 style_finish_page("setupuser");
462 return;
463 }
464 }
465 cgi_redirect(cgi_referer("setup_ulist"));
466 return;
@@ -874,7 +874,7 @@
874 @ template for users who are allowed more access than
875 @ <span class="usertype">anonymous</span>,
876 @ but less than a <span class="usertype">developer</span>.
877 @ </p></li>
878 @ </ul>
879 style_finish_page("setupuser");
880 }
881
+7 -4
--- src/shell.c
+++ src/shell.c
@@ -20717,10 +20717,11 @@
2071720717
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
2071820718
" -sorterref SIZE sorter references threshold size\n"
2071920719
#endif
2072020720
" -stats print memory stats before each finalize\n"
2072120721
" -table set output mode to 'table'\n"
20722
+ " -tabs set output mode to 'tabs'\n"
2072220723
" -version show SQLite version\n"
2072320724
" -vfs NAME use NAME as the default VFS\n"
2072420725
#ifdef SQLITE_ENABLE_VFSTRACE
2072520726
" -vfstrace enable tracing of all VFS calls\n"
2072620727
#endif
@@ -21152,14 +21153,16 @@
2115221153
data.openMode = SHELL_OPEN_READONLY;
2115321154
}else if( strcmp(z,"-nofollow")==0 ){
2115421155
data.openFlags |= SQLITE_OPEN_NOFOLLOW;
2115521156
}else if( strcmp(z,"-ascii")==0 ){
2115621157
data.mode = MODE_Ascii;
21157
- sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
21158
- SEP_Unit);
21159
- sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
21160
- SEP_Record);
21158
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit);
21159
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record);
21160
+ }else if( strcmp(z,"-tabs")==0 ){
21161
+ data.mode = MODE_List;
21162
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab);
21163
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
2116121164
}else if( strcmp(z,"-separator")==0 ){
2116221165
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
2116321166
"%s",cmdline_option_value(argc,argv,++i));
2116421167
}else if( strcmp(z,"-newline")==0 ){
2116521168
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
2116621169
--- src/shell.c
+++ src/shell.c
@@ -20717,10 +20717,11 @@
20717 #ifdef SQLITE_ENABLE_SORTER_REFERENCES
20718 " -sorterref SIZE sorter references threshold size\n"
20719 #endif
20720 " -stats print memory stats before each finalize\n"
20721 " -table set output mode to 'table'\n"
 
20722 " -version show SQLite version\n"
20723 " -vfs NAME use NAME as the default VFS\n"
20724 #ifdef SQLITE_ENABLE_VFSTRACE
20725 " -vfstrace enable tracing of all VFS calls\n"
20726 #endif
@@ -21152,14 +21153,16 @@
21152 data.openMode = SHELL_OPEN_READONLY;
21153 }else if( strcmp(z,"-nofollow")==0 ){
21154 data.openFlags |= SQLITE_OPEN_NOFOLLOW;
21155 }else if( strcmp(z,"-ascii")==0 ){
21156 data.mode = MODE_Ascii;
21157 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
21158 SEP_Unit);
21159 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
21160 SEP_Record);
 
 
21161 }else if( strcmp(z,"-separator")==0 ){
21162 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
21163 "%s",cmdline_option_value(argc,argv,++i));
21164 }else if( strcmp(z,"-newline")==0 ){
21165 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
21166
--- src/shell.c
+++ src/shell.c
@@ -20717,10 +20717,11 @@
20717 #ifdef SQLITE_ENABLE_SORTER_REFERENCES
20718 " -sorterref SIZE sorter references threshold size\n"
20719 #endif
20720 " -stats print memory stats before each finalize\n"
20721 " -table set output mode to 'table'\n"
20722 " -tabs set output mode to 'tabs'\n"
20723 " -version show SQLite version\n"
20724 " -vfs NAME use NAME as the default VFS\n"
20725 #ifdef SQLITE_ENABLE_VFSTRACE
20726 " -vfstrace enable tracing of all VFS calls\n"
20727 #endif
@@ -21152,14 +21153,16 @@
21153 data.openMode = SHELL_OPEN_READONLY;
21154 }else if( strcmp(z,"-nofollow")==0 ){
21155 data.openFlags |= SQLITE_OPEN_NOFOLLOW;
21156 }else if( strcmp(z,"-ascii")==0 ){
21157 data.mode = MODE_Ascii;
21158 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit);
21159 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record);
21160 }else if( strcmp(z,"-tabs")==0 ){
21161 data.mode = MODE_List;
21162 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab);
21163 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
21164 }else if( strcmp(z,"-separator")==0 ){
21165 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
21166 "%s",cmdline_option_value(argc,argv,++i));
21167 }else if( strcmp(z,"-newline")==0 ){
21168 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
21169
+3 -3
--- src/shun.c
+++ src/shun.c
@@ -263,11 +263,11 @@
263263
if( cnt==0 ){
264264
@ <i>no artifacts are shunned on this server</i>
265265
}
266266
db_finalize(&q);
267267
@ </p></blockquote>
268
- style_footer();
268
+ style_finish_page("shun");
269269
fossil_free(zCanonical);
270270
}
271271
272272
/*
273273
** Remove from the BLOB table all artifacts that are in the SHUN table.
@@ -403,11 +403,11 @@
403403
@ </tr>
404404
}
405405
}
406406
db_finalize(&q);
407407
@ </table>
408
- style_footer();
408
+ style_finish_page("rcvfromlist");
409409
}
410410
411411
/*
412412
** WEBPAGE: rcvfrom
413413
**
@@ -549,7 +549,7 @@
549549
@ </td></tr>
550550
}
551551
}
552552
@ </table>
553553
db_finalize(&q);
554
- style_footer();
554
+ style_finish_page("rcvfrom");
555555
}
556556
--- src/shun.c
+++ src/shun.c
@@ -263,11 +263,11 @@
263 if( cnt==0 ){
264 @ <i>no artifacts are shunned on this server</i>
265 }
266 db_finalize(&q);
267 @ </p></blockquote>
268 style_footer();
269 fossil_free(zCanonical);
270 }
271
272 /*
273 ** Remove from the BLOB table all artifacts that are in the SHUN table.
@@ -403,11 +403,11 @@
403 @ </tr>
404 }
405 }
406 db_finalize(&q);
407 @ </table>
408 style_footer();
409 }
410
411 /*
412 ** WEBPAGE: rcvfrom
413 **
@@ -549,7 +549,7 @@
549 @ </td></tr>
550 }
551 }
552 @ </table>
553 db_finalize(&q);
554 style_footer();
555 }
556
--- src/shun.c
+++ src/shun.c
@@ -263,11 +263,11 @@
263 if( cnt==0 ){
264 @ <i>no artifacts are shunned on this server</i>
265 }
266 db_finalize(&q);
267 @ </p></blockquote>
268 style_finish_page("shun");
269 fossil_free(zCanonical);
270 }
271
272 /*
273 ** Remove from the BLOB table all artifacts that are in the SHUN table.
@@ -403,11 +403,11 @@
403 @ </tr>
404 }
405 }
406 db_finalize(&q);
407 @ </table>
408 style_finish_page("rcvfromlist");
409 }
410
411 /*
412 ** WEBPAGE: rcvfrom
413 **
@@ -549,7 +549,7 @@
549 @ </td></tr>
550 }
551 }
552 @ </table>
553 db_finalize(&q);
554 style_finish_page("rcvfrom");
555 }
556
+1 -1
--- src/sitemap.c
+++ src/sitemap.c
@@ -233,8 +233,8 @@
233233
@ colors assigned to branch names</a>
234234
@ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
235235
@ </ul></li>
236236
@ </ul>
237237
if( !isPopup ){
238
- style_footer();
238
+ style_finish_page("sitemap");
239239
}
240240
}
241241
--- src/sitemap.c
+++ src/sitemap.c
@@ -233,8 +233,8 @@
233 @ colors assigned to branch names</a>
234 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
235 @ </ul></li>
236 @ </ul>
237 if( !isPopup ){
238 style_footer();
239 }
240 }
241
--- src/sitemap.c
+++ src/sitemap.c
@@ -233,8 +233,8 @@
233 @ colors assigned to branch names</a>
234 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
235 @ </ul></li>
236 @ </ul>
237 if( !isPopup ){
238 style_finish_page("sitemap");
239 }
240 }
241
+6 -6
--- src/skins.c
+++ src/skins.c
@@ -401,11 +401,11 @@
401401
@ <input type="submit" name="rename" value="Rename">
402402
@ <input type="submit" name="canren" value="Cancel">
403403
@ </table>
404404
login_insert_csrf_secret();
405405
@ </div></form>
406
- style_footer();
406
+ style_finish_page("skins");
407407
return 1;
408408
}
409409
db_unprotect(PROTECT_CONFIG);
410410
db_multi_exec(
411411
"UPDATE config SET name='skin:%q' WHERE name='skin:%q';",
@@ -441,11 +441,11 @@
441441
@ <input type="submit" name="save" value="Save">
442442
@ <input type="submit" name="cansave" value="Cancel">
443443
@ </table>
444444
login_insert_csrf_secret();
445445
@ </div></form>
446
- style_footer();
446
+ style_finish_page("skins");
447447
return 1;
448448
}
449449
db_unprotect(PROTECT_CONFIG);
450450
db_multi_exec(
451451
"INSERT OR IGNORE INTO config(name, value, mtime)"
@@ -492,11 +492,11 @@
492492
@ <input type="hidden" name="sn" value="%h(P("sn"))" />
493493
@ <input type="submit" name="del2" value="Confirm - Delete The Skin" />
494494
@ <input type="submit" name="cancel" value="Cancel - Do Not Delete" />
495495
login_insert_csrf_secret();
496496
@ </div></form>
497
- style_footer();
497
+ style_finish_page("skins");
498498
db_end_transaction(1);
499499
return;
500500
}
501501
if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
502502
db_unprotect(PROTECT_CONFIG);
@@ -645,11 +645,11 @@
645645
@ </form></tr>
646646
}
647647
db_finalize(&q);
648648
649649
@ </table>
650
- style_footer();
650
+ style_finish_page("skins");
651651
db_end_transaction(0);
652652
}
653653
654654
/*
655655
** Generate HTML for a <select> that lists all the available skin names,
@@ -842,11 +842,11 @@
842842
blob_reset(&from);
843843
blob_reset(&to);
844844
blob_reset(&out);
845845
}
846846
@ </div></form>
847
- style_footer();
847
+ style_finish_page("skins");
848848
db_end_transaction(0);
849849
}
850850
851851
/*
852852
** Try to initialize draft skin iSkin to the built-in or preexisting
@@ -1120,7 +1120,7 @@
11201120
}else{
11211121
@ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page
11221122
@ for cleanup and recovery actions.
11231123
}
11241124
builtin_request_js("skin.js");
1125
- style_footer();
1125
+ style_finish_page("skins");
11261126
}
11271127
--- src/skins.c
+++ src/skins.c
@@ -401,11 +401,11 @@
401 @ <input type="submit" name="rename" value="Rename">
402 @ <input type="submit" name="canren" value="Cancel">
403 @ </table>
404 login_insert_csrf_secret();
405 @ </div></form>
406 style_footer();
407 return 1;
408 }
409 db_unprotect(PROTECT_CONFIG);
410 db_multi_exec(
411 "UPDATE config SET name='skin:%q' WHERE name='skin:%q';",
@@ -441,11 +441,11 @@
441 @ <input type="submit" name="save" value="Save">
442 @ <input type="submit" name="cansave" value="Cancel">
443 @ </table>
444 login_insert_csrf_secret();
445 @ </div></form>
446 style_footer();
447 return 1;
448 }
449 db_unprotect(PROTECT_CONFIG);
450 db_multi_exec(
451 "INSERT OR IGNORE INTO config(name, value, mtime)"
@@ -492,11 +492,11 @@
492 @ <input type="hidden" name="sn" value="%h(P("sn"))" />
493 @ <input type="submit" name="del2" value="Confirm - Delete The Skin" />
494 @ <input type="submit" name="cancel" value="Cancel - Do Not Delete" />
495 login_insert_csrf_secret();
496 @ </div></form>
497 style_footer();
498 db_end_transaction(1);
499 return;
500 }
501 if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
502 db_unprotect(PROTECT_CONFIG);
@@ -645,11 +645,11 @@
645 @ </form></tr>
646 }
647 db_finalize(&q);
648
649 @ </table>
650 style_footer();
651 db_end_transaction(0);
652 }
653
654 /*
655 ** Generate HTML for a <select> that lists all the available skin names,
@@ -842,11 +842,11 @@
842 blob_reset(&from);
843 blob_reset(&to);
844 blob_reset(&out);
845 }
846 @ </div></form>
847 style_footer();
848 db_end_transaction(0);
849 }
850
851 /*
852 ** Try to initialize draft skin iSkin to the built-in or preexisting
@@ -1120,7 +1120,7 @@
1120 }else{
1121 @ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page
1122 @ for cleanup and recovery actions.
1123 }
1124 builtin_request_js("skin.js");
1125 style_footer();
1126 }
1127
--- src/skins.c
+++ src/skins.c
@@ -401,11 +401,11 @@
401 @ <input type="submit" name="rename" value="Rename">
402 @ <input type="submit" name="canren" value="Cancel">
403 @ </table>
404 login_insert_csrf_secret();
405 @ </div></form>
406 style_finish_page("skins");
407 return 1;
408 }
409 db_unprotect(PROTECT_CONFIG);
410 db_multi_exec(
411 "UPDATE config SET name='skin:%q' WHERE name='skin:%q';",
@@ -441,11 +441,11 @@
441 @ <input type="submit" name="save" value="Save">
442 @ <input type="submit" name="cansave" value="Cancel">
443 @ </table>
444 login_insert_csrf_secret();
445 @ </div></form>
446 style_finish_page("skins");
447 return 1;
448 }
449 db_unprotect(PROTECT_CONFIG);
450 db_multi_exec(
451 "INSERT OR IGNORE INTO config(name, value, mtime)"
@@ -492,11 +492,11 @@
492 @ <input type="hidden" name="sn" value="%h(P("sn"))" />
493 @ <input type="submit" name="del2" value="Confirm - Delete The Skin" />
494 @ <input type="submit" name="cancel" value="Cancel - Do Not Delete" />
495 login_insert_csrf_secret();
496 @ </div></form>
497 style_finish_page("skins");
498 db_end_transaction(1);
499 return;
500 }
501 if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
502 db_unprotect(PROTECT_CONFIG);
@@ -645,11 +645,11 @@
645 @ </form></tr>
646 }
647 db_finalize(&q);
648
649 @ </table>
650 style_finish_page("skins");
651 db_end_transaction(0);
652 }
653
654 /*
655 ** Generate HTML for a <select> that lists all the available skin names,
@@ -842,11 +842,11 @@
842 blob_reset(&from);
843 blob_reset(&to);
844 blob_reset(&out);
845 }
846 @ </div></form>
847 style_finish_page("skins");
848 db_end_transaction(0);
849 }
850
851 /*
852 ** Try to initialize draft skin iSkin to the built-in or preexisting
@@ -1120,7 +1120,7 @@
1120 }else{
1121 @ <p>Visit the <a href='%R/setup_skin_admin'>Skin Admin</a> page
1122 @ for cleanup and recovery actions.
1123 }
1124 builtin_request_js("skin.js");
1125 style_finish_page("skins");
1126 }
1127
+2 -2
--- src/smtp.c
+++ src/smtp.c
@@ -805,11 +805,11 @@
805805
@ <form method="POST" action="%R/setup_smtp_route">
806806
@ <input type="submit" value="New">
807807
@ &larr; Add a new email address
808808
@ </form>
809809
@ </table>
810
- style_footer();
810
+ style_finish_page("smtp");
811811
db_end_transaction(0);
812812
}
813813
814814
/*
815815
** WEBPAGE: setup_smtp_route
@@ -924,11 +924,11 @@
924924
@ with USER.LOGIN=<i>login-name</i>.
925925
@ </ul>
926926
@
927927
@ <p>To delete a route &rarr; erase all text from the "Routing" field then
928928
@ press the "Apply" button.
929
- style_footer();
929
+ style_finish_page("smtp");
930930
}
931931
932932
#if LOCAL_INTERFACE
933933
/*
934934
** State information for the server
935935
--- src/smtp.c
+++ src/smtp.c
@@ -805,11 +805,11 @@
805 @ <form method="POST" action="%R/setup_smtp_route">
806 @ <input type="submit" value="New">
807 @ &larr; Add a new email address
808 @ </form>
809 @ </table>
810 style_footer();
811 db_end_transaction(0);
812 }
813
814 /*
815 ** WEBPAGE: setup_smtp_route
@@ -924,11 +924,11 @@
924 @ with USER.LOGIN=<i>login-name</i>.
925 @ </ul>
926 @
927 @ <p>To delete a route &rarr; erase all text from the "Routing" field then
928 @ press the "Apply" button.
929 style_footer();
930 }
931
932 #if LOCAL_INTERFACE
933 /*
934 ** State information for the server
935
--- src/smtp.c
+++ src/smtp.c
@@ -805,11 +805,11 @@
805 @ <form method="POST" action="%R/setup_smtp_route">
806 @ <input type="submit" value="New">
807 @ &larr; Add a new email address
808 @ </form>
809 @ </table>
810 style_finish_page("smtp");
811 db_end_transaction(0);
812 }
813
814 /*
815 ** WEBPAGE: setup_smtp_route
@@ -924,11 +924,11 @@
924 @ with USER.LOGIN=<i>login-name</i>.
925 @ </ul>
926 @
927 @ <p>To delete a route &rarr; erase all text from the "Routing" field then
928 @ press the "Apply" button.
929 style_finish_page("smtp");
930 }
931
932 #if LOCAL_INTERFACE
933 /*
934 ** State information for the server
935
+57 -15
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1171,11 +1171,11 @@
11711171
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
11721172
** [sqlite_version()] and [sqlite_source_id()].
11731173
*/
11741174
#define SQLITE_VERSION "3.34.0"
11751175
#define SQLITE_VERSION_NUMBER 3034000
1176
-#define SQLITE_SOURCE_ID "2020-10-19 20:49:54 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a196784d2d"
1176
+#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
11771177
11781178
/*
11791179
** CAPI3REF: Run-Time Library Version Numbers
11801180
** KEYWORDS: sqlite3_version sqlite3_sourceid
11811181
**
@@ -17621,10 +17621,11 @@
1762117621
** Index.aiRowLogEst[] values */
1762217622
#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */
1762317623
#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
1762417624
#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
1762517625
#define TF_Shadow 0x1000 /* True for a shadow table */
17626
+#define TF_HasStat4 0x2000 /* STAT4 info available for this table */
1762617627
1762717628
/*
1762817629
** Test to see whether or not a table is a virtual table. This is
1762917630
** done as a macro so that it will be optimized out when virtual
1763017631
** table support is omitted from the build.
@@ -27864,16 +27865,21 @@
2786427865
** xRoundup. */
2786527866
nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes);
2786627867
if( nOld==nNew ){
2786727868
pNew = pOld;
2786827869
}else if( sqlite3GlobalConfig.bMemstat ){
27870
+ sqlite3_int64 nUsed;
2786927871
sqlite3_mutex_enter(mem0.mutex);
2787027872
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
2787127873
nDiff = nNew - nOld;
27872
- if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
27874
+ if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >=
2787327875
mem0.alarmThreshold-nDiff ){
2787427876
sqlite3MallocAlarm(nDiff);
27877
+ if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
27878
+ sqlite3_mutex_leave(mem0.mutex);
27879
+ return 0;
27880
+ }
2787527881
}
2787627882
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
2787727883
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
2787827884
if( pNew==0 && mem0.alarmThreshold>0 ){
2787927885
sqlite3MallocAlarm((int)nBytes);
@@ -48529,12 +48535,16 @@
4852948535
if( iDb<0 ){
4853048536
rc = SQLITE_ERROR;
4853148537
goto end_deserialize;
4853248538
}
4853348539
zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
48534
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
48535
- sqlite3_free(zSql);
48540
+ if( zSql==0 ){
48541
+ rc = SQLITE_NOMEM;
48542
+ }else{
48543
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
48544
+ sqlite3_free(zSql);
48545
+ }
4853648546
if( rc ) goto end_deserialize;
4853748547
db->init.iDb = (u8)iDb;
4853848548
db->init.reopenMemdb = 1;
4853948549
rc = sqlite3_step(pStmt);
4854048550
db->init.reopenMemdb = 0;
@@ -78362,10 +78372,11 @@
7836278372
*/
7836378373
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
7836478374
int j;
7836578375
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
7836678376
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
78377
+ sqlite3MayAbort(p->pParse);
7836778378
}
7836878379
7836978380
/*
7837078381
** Add an opcode that includes the p4 value as an integer.
7837178382
*/
@@ -78590,11 +78601,11 @@
7859078601
while( (pOp = opIterNext(&sIter))!=0 ){
7859178602
int opcode = pOp->opcode;
7859278603
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
7859378604
|| opcode==OP_VDestroy
7859478605
|| opcode==OP_VCreate
78595
- || (opcode==OP_ParseSchema && pOp->p4.z==0)
78606
+ || opcode==OP_ParseSchema
7859678607
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
7859778608
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
7859878609
){
7859978610
hasAbort = 1;
7860078611
break;
@@ -79408,11 +79419,11 @@
7940879419
sqlite3_context *pCtx = pOp->p4.pCtx;
7940979420
if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){
7941079421
sqlite3_str_appendf(&x, "%d", v1);
7941179422
}else if( pCtx->argc>1 ){
7941279423
sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
79413
- }else{
79424
+ }else if( x.accError==0 ){
7941479425
assert( x.nChar>2 );
7941579426
x.nChar -= 2;
7941679427
ii++;
7941779428
}
7941879429
ii += 3;
@@ -107329,17 +107340,25 @@
107329107340
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
107330107341
if( pSrc ){
107331107342
int i;
107332107343
for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
107333107344
struct SrcList_item *p = &pSrc->a[i];
107334
- p->pTab = sqlite3LocateTableItem(pParse, 0, p);
107335107345
p->iCursor = pParse->nTab++;
107336
- if( p->pTab==0 ){
107337
- rc = SQLITE_ERROR;
107346
+ if( p->pSelect ){
107347
+ sqlite3SelectPrep(pParse, p->pSelect, 0);
107348
+ sqlite3ExpandSubquery(pParse, p);
107349
+ assert( i>0 );
107350
+ assert( pStep->pFrom->a[i-1].pSelect );
107351
+ sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0);
107338107352
}else{
107339
- p->pTab->nTabRef++;
107340
- rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
107353
+ p->pTab = sqlite3LocateTableItem(pParse, 0, p);
107354
+ if( p->pTab==0 ){
107355
+ rc = SQLITE_ERROR;
107356
+ }else{
107357
+ p->pTab->nTabRef++;
107358
+ rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
107359
+ }
107341107360
}
107342107361
}
107343107362
sNC.pSrcList = pSrc;
107344107363
if( rc==SQLITE_OK && pStep->pWhere ){
107345107364
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
@@ -107396,10 +107415,16 @@
107396107415
Upsert *pUpsert = pStep->pUpsert;
107397107416
sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget);
107398107417
sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet);
107399107418
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
107400107419
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
107420
+ }
107421
+ if( pStep->pFrom ){
107422
+ int i;
107423
+ for(i=0; i<pStep->pFrom->nSrc; i++){
107424
+ sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
107425
+ }
107401107426
}
107402107427
}
107403107428
}
107404107429
107405107430
/*
@@ -109655,10 +109680,11 @@
109655109680
sqlite3_finalize(pStmt);
109656109681
return SQLITE_NOMEM_BKPT;
109657109682
}
109658109683
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
109659109684
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
109685
+ pIdx->pTable->tabFlags |= TF_HasStat4;
109660109686
for(i=0; i<nSample; i++){
109661109687
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
109662109688
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
109663109689
pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
109664109690
}
@@ -149074,12 +149100,27 @@
149074149100
/* Integer primary key index */
149075149101
pNew->wsFlags = WHERE_IPK;
149076149102
149077149103
/* Full table scan */
149078149104
pNew->iSortIdx = b ? iSortIdx : 0;
149079
- /* TUNING: Cost of full table scan is (N*3.0). */
149105
+ /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an
149106
+ ** extra cost designed to discourage the use of full table scans,
149107
+ ** since index lookups have better worst-case performance if our
149108
+ ** stat guesses are wrong. Reduce the 3.0 penalty slightly
149109
+ ** (to 2.75) if we have valid STAT4 information for the table.
149110
+ ** At 2.75, a full table scan is preferred over using an index on
149111
+ ** a column with just two distinct values where each value has about
149112
+ ** an equal number of appearances. Without STAT4 data, we still want
149113
+ ** to use an index in that case, since the constraint might be for
149114
+ ** the scarcer of the two values, and in that case an index lookup is
149115
+ ** better.
149116
+ */
149117
+#ifdef SQLITE_ENABLE_STAT4
149118
+ pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0);
149119
+#else
149080149120
pNew->rRun = rSize + 16;
149121
+#endif
149081149122
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
149082149123
whereLoopOutputAdjust(pWC, pNew, rSize);
149083149124
rc = whereLoopInsert(pBuilder, pNew);
149084149125
pNew->nOut = rSize;
149085149126
if( rc ) break;
@@ -226638,11 +226679,11 @@
226638226679
int nArg, /* Number of args */
226639226680
sqlite3_value **apUnused /* Function arguments */
226640226681
){
226641226682
assert( nArg==0 );
226642226683
UNUSED_PARAM2(nArg, apUnused);
226643
- sqlite3_result_text(pCtx, "fts5: 2020-10-12 18:09:16 7e17c2f4b7dc9b563d0b4da949bb134dc7c4fc9c86ce03891432a884ca6409d5", -1, SQLITE_TRANSIENT);
226684
+ sqlite3_result_text(pCtx, "fts5: 2020-10-26 16:22:31 80eba105d6d1b49ba8ca2ad4e14ddec2de0bdc2f6686c2f8a1c1d24fc1fe846f", -1, SQLITE_TRANSIENT);
226644226685
}
226645226686
226646226687
/*
226647226688
** Return true if zName is the extension on one of the shadow tables used
226648226689
** by this module.
@@ -230121,10 +230162,11 @@
230121230162
for(; i<128 && i<n; i++){
230122230163
aAscii[i] = (u8)bToken;
230123230164
}
230124230165
iTbl++;
230125230166
}
230167
+ aAscii[0] = 0; /* 0x00 is never a token character */
230126230168
}
230127230169
230128230170
/*
230129230171
** 2015 May 30
230130230172
**
@@ -231560,12 +231602,12 @@
231560231602
}
231561231603
#endif /* SQLITE_CORE */
231562231604
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
231563231605
231564231606
/************** End of stmt.c ************************************************/
231565
-#if __LINE__!=231565
231607
+#if __LINE__!=231607
231566231608
#undef SQLITE_SOURCE_ID
231567
-#define SQLITE_SOURCE_ID "2020-10-19 20:49:54 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a19678alt2"
231609
+#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692alt2"
231568231610
#endif
231569231611
/* Return the source-id for this library */
231570231612
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
231571231613
/************************** End of sqlite3.c ******************************/
231572231614
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1171,11 +1171,11 @@
1171 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1172 ** [sqlite_version()] and [sqlite_source_id()].
1173 */
1174 #define SQLITE_VERSION "3.34.0"
1175 #define SQLITE_VERSION_NUMBER 3034000
1176 #define SQLITE_SOURCE_ID "2020-10-19 20:49:54 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a196784d2d"
1177
1178 /*
1179 ** CAPI3REF: Run-Time Library Version Numbers
1180 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1181 **
@@ -17621,10 +17621,11 @@
17621 ** Index.aiRowLogEst[] values */
17622 #define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */
17623 #define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
17624 #define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
17625 #define TF_Shadow 0x1000 /* True for a shadow table */
 
17626
17627 /*
17628 ** Test to see whether or not a table is a virtual table. This is
17629 ** done as a macro so that it will be optimized out when virtual
17630 ** table support is omitted from the build.
@@ -27864,16 +27865,21 @@
27864 ** xRoundup. */
27865 nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes);
27866 if( nOld==nNew ){
27867 pNew = pOld;
27868 }else if( sqlite3GlobalConfig.bMemstat ){
 
27869 sqlite3_mutex_enter(mem0.mutex);
27870 sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
27871 nDiff = nNew - nOld;
27872 if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
27873 mem0.alarmThreshold-nDiff ){
27874 sqlite3MallocAlarm(nDiff);
 
 
 
 
27875 }
27876 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27877 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
27878 if( pNew==0 && mem0.alarmThreshold>0 ){
27879 sqlite3MallocAlarm((int)nBytes);
@@ -48529,12 +48535,16 @@
48529 if( iDb<0 ){
48530 rc = SQLITE_ERROR;
48531 goto end_deserialize;
48532 }
48533 zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
48534 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
48535 sqlite3_free(zSql);
 
 
 
 
48536 if( rc ) goto end_deserialize;
48537 db->init.iDb = (u8)iDb;
48538 db->init.reopenMemdb = 1;
48539 rc = sqlite3_step(pStmt);
48540 db->init.reopenMemdb = 0;
@@ -78362,10 +78372,11 @@
78362 */
78363 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
78364 int j;
78365 sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
78366 for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
 
78367 }
78368
78369 /*
78370 ** Add an opcode that includes the p4 value as an integer.
78371 */
@@ -78590,11 +78601,11 @@
78590 while( (pOp = opIterNext(&sIter))!=0 ){
78591 int opcode = pOp->opcode;
78592 if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
78593 || opcode==OP_VDestroy
78594 || opcode==OP_VCreate
78595 || (opcode==OP_ParseSchema && pOp->p4.z==0)
78596 || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
78597 && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
78598 ){
78599 hasAbort = 1;
78600 break;
@@ -79408,11 +79419,11 @@
79408 sqlite3_context *pCtx = pOp->p4.pCtx;
79409 if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){
79410 sqlite3_str_appendf(&x, "%d", v1);
79411 }else if( pCtx->argc>1 ){
79412 sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
79413 }else{
79414 assert( x.nChar>2 );
79415 x.nChar -= 2;
79416 ii++;
79417 }
79418 ii += 3;
@@ -107329,17 +107340,25 @@
107329 SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
107330 if( pSrc ){
107331 int i;
107332 for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
107333 struct SrcList_item *p = &pSrc->a[i];
107334 p->pTab = sqlite3LocateTableItem(pParse, 0, p);
107335 p->iCursor = pParse->nTab++;
107336 if( p->pTab==0 ){
107337 rc = SQLITE_ERROR;
 
 
 
 
107338 }else{
107339 p->pTab->nTabRef++;
107340 rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
 
 
 
 
 
107341 }
107342 }
107343 sNC.pSrcList = pSrc;
107344 if( rc==SQLITE_OK && pStep->pWhere ){
107345 rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
@@ -107396,10 +107415,16 @@
107396 Upsert *pUpsert = pStep->pUpsert;
107397 sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget);
107398 sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet);
107399 sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
107400 sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
 
 
 
 
 
 
107401 }
107402 }
107403 }
107404
107405 /*
@@ -109655,10 +109680,11 @@
109655 sqlite3_finalize(pStmt);
109656 return SQLITE_NOMEM_BKPT;
109657 }
109658 pSpace = (tRowcnt*)&pIdx->aSample[nSample];
109659 pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
 
109660 for(i=0; i<nSample; i++){
109661 pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
109662 pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
109663 pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
109664 }
@@ -149074,12 +149100,27 @@
149074 /* Integer primary key index */
149075 pNew->wsFlags = WHERE_IPK;
149076
149077 /* Full table scan */
149078 pNew->iSortIdx = b ? iSortIdx : 0;
149079 /* TUNING: Cost of full table scan is (N*3.0). */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149080 pNew->rRun = rSize + 16;
 
149081 ApplyCostMultiplier(pNew->rRun, pTab->costMult);
149082 whereLoopOutputAdjust(pWC, pNew, rSize);
149083 rc = whereLoopInsert(pBuilder, pNew);
149084 pNew->nOut = rSize;
149085 if( rc ) break;
@@ -226638,11 +226679,11 @@
226638 int nArg, /* Number of args */
226639 sqlite3_value **apUnused /* Function arguments */
226640 ){
226641 assert( nArg==0 );
226642 UNUSED_PARAM2(nArg, apUnused);
226643 sqlite3_result_text(pCtx, "fts5: 2020-10-12 18:09:16 7e17c2f4b7dc9b563d0b4da949bb134dc7c4fc9c86ce03891432a884ca6409d5", -1, SQLITE_TRANSIENT);
226644 }
226645
226646 /*
226647 ** Return true if zName is the extension on one of the shadow tables used
226648 ** by this module.
@@ -230121,10 +230162,11 @@
230121 for(; i<128 && i<n; i++){
230122 aAscii[i] = (u8)bToken;
230123 }
230124 iTbl++;
230125 }
 
230126 }
230127
230128 /*
230129 ** 2015 May 30
230130 **
@@ -231560,12 +231602,12 @@
231560 }
231561 #endif /* SQLITE_CORE */
231562 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
231563
231564 /************** End of stmt.c ************************************************/
231565 #if __LINE__!=231565
231566 #undef SQLITE_SOURCE_ID
231567 #define SQLITE_SOURCE_ID "2020-10-19 20:49:54 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a19678alt2"
231568 #endif
231569 /* Return the source-id for this library */
231570 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
231571 /************************** End of sqlite3.c ******************************/
231572
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1171,11 +1171,11 @@
1171 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
1172 ** [sqlite_version()] and [sqlite_source_id()].
1173 */
1174 #define SQLITE_VERSION "3.34.0"
1175 #define SQLITE_VERSION_NUMBER 3034000
1176 #define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
1177
1178 /*
1179 ** CAPI3REF: Run-Time Library Version Numbers
1180 ** KEYWORDS: sqlite3_version sqlite3_sourceid
1181 **
@@ -17621,10 +17621,11 @@
17621 ** Index.aiRowLogEst[] values */
17622 #define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */
17623 #define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
17624 #define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
17625 #define TF_Shadow 0x1000 /* True for a shadow table */
17626 #define TF_HasStat4 0x2000 /* STAT4 info available for this table */
17627
17628 /*
17629 ** Test to see whether or not a table is a virtual table. This is
17630 ** done as a macro so that it will be optimized out when virtual
17631 ** table support is omitted from the build.
@@ -27864,16 +27865,21 @@
27865 ** xRoundup. */
27866 nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes);
27867 if( nOld==nNew ){
27868 pNew = pOld;
27869 }else if( sqlite3GlobalConfig.bMemstat ){
27870 sqlite3_int64 nUsed;
27871 sqlite3_mutex_enter(mem0.mutex);
27872 sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
27873 nDiff = nNew - nOld;
27874 if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >=
27875 mem0.alarmThreshold-nDiff ){
27876 sqlite3MallocAlarm(nDiff);
27877 if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
27878 sqlite3_mutex_leave(mem0.mutex);
27879 return 0;
27880 }
27881 }
27882 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27883 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
27884 if( pNew==0 && mem0.alarmThreshold>0 ){
27885 sqlite3MallocAlarm((int)nBytes);
@@ -48529,12 +48535,16 @@
48535 if( iDb<0 ){
48536 rc = SQLITE_ERROR;
48537 goto end_deserialize;
48538 }
48539 zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
48540 if( zSql==0 ){
48541 rc = SQLITE_NOMEM;
48542 }else{
48543 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
48544 sqlite3_free(zSql);
48545 }
48546 if( rc ) goto end_deserialize;
48547 db->init.iDb = (u8)iDb;
48548 db->init.reopenMemdb = 1;
48549 rc = sqlite3_step(pStmt);
48550 db->init.reopenMemdb = 0;
@@ -78362,10 +78372,11 @@
78372 */
78373 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
78374 int j;
78375 sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
78376 for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
78377 sqlite3MayAbort(p->pParse);
78378 }
78379
78380 /*
78381 ** Add an opcode that includes the p4 value as an integer.
78382 */
@@ -78590,11 +78601,11 @@
78601 while( (pOp = opIterNext(&sIter))!=0 ){
78602 int opcode = pOp->opcode;
78603 if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
78604 || opcode==OP_VDestroy
78605 || opcode==OP_VCreate
78606 || opcode==OP_ParseSchema
78607 || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
78608 && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
78609 ){
78610 hasAbort = 1;
78611 break;
@@ -79408,11 +79419,11 @@
79419 sqlite3_context *pCtx = pOp->p4.pCtx;
79420 if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){
79421 sqlite3_str_appendf(&x, "%d", v1);
79422 }else if( pCtx->argc>1 ){
79423 sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
79424 }else if( x.accError==0 ){
79425 assert( x.nChar>2 );
79426 x.nChar -= 2;
79427 ii++;
79428 }
79429 ii += 3;
@@ -107329,17 +107340,25 @@
107340 SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
107341 if( pSrc ){
107342 int i;
107343 for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
107344 struct SrcList_item *p = &pSrc->a[i];
 
107345 p->iCursor = pParse->nTab++;
107346 if( p->pSelect ){
107347 sqlite3SelectPrep(pParse, p->pSelect, 0);
107348 sqlite3ExpandSubquery(pParse, p);
107349 assert( i>0 );
107350 assert( pStep->pFrom->a[i-1].pSelect );
107351 sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0);
107352 }else{
107353 p->pTab = sqlite3LocateTableItem(pParse, 0, p);
107354 if( p->pTab==0 ){
107355 rc = SQLITE_ERROR;
107356 }else{
107357 p->pTab->nTabRef++;
107358 rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
107359 }
107360 }
107361 }
107362 sNC.pSrcList = pSrc;
107363 if( rc==SQLITE_OK && pStep->pWhere ){
107364 rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
@@ -107396,10 +107415,16 @@
107415 Upsert *pUpsert = pStep->pUpsert;
107416 sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget);
107417 sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet);
107418 sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
107419 sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
107420 }
107421 if( pStep->pFrom ){
107422 int i;
107423 for(i=0; i<pStep->pFrom->nSrc; i++){
107424 sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
107425 }
107426 }
107427 }
107428 }
107429
107430 /*
@@ -109655,10 +109680,11 @@
109680 sqlite3_finalize(pStmt);
109681 return SQLITE_NOMEM_BKPT;
109682 }
109683 pSpace = (tRowcnt*)&pIdx->aSample[nSample];
109684 pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
109685 pIdx->pTable->tabFlags |= TF_HasStat4;
109686 for(i=0; i<nSample; i++){
109687 pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
109688 pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
109689 pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
109690 }
@@ -149074,12 +149100,27 @@
149100 /* Integer primary key index */
149101 pNew->wsFlags = WHERE_IPK;
149102
149103 /* Full table scan */
149104 pNew->iSortIdx = b ? iSortIdx : 0;
149105 /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an
149106 ** extra cost designed to discourage the use of full table scans,
149107 ** since index lookups have better worst-case performance if our
149108 ** stat guesses are wrong. Reduce the 3.0 penalty slightly
149109 ** (to 2.75) if we have valid STAT4 information for the table.
149110 ** At 2.75, a full table scan is preferred over using an index on
149111 ** a column with just two distinct values where each value has about
149112 ** an equal number of appearances. Without STAT4 data, we still want
149113 ** to use an index in that case, since the constraint might be for
149114 ** the scarcer of the two values, and in that case an index lookup is
149115 ** better.
149116 */
149117 #ifdef SQLITE_ENABLE_STAT4
149118 pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0);
149119 #else
149120 pNew->rRun = rSize + 16;
149121 #endif
149122 ApplyCostMultiplier(pNew->rRun, pTab->costMult);
149123 whereLoopOutputAdjust(pWC, pNew, rSize);
149124 rc = whereLoopInsert(pBuilder, pNew);
149125 pNew->nOut = rSize;
149126 if( rc ) break;
@@ -226638,11 +226679,11 @@
226679 int nArg, /* Number of args */
226680 sqlite3_value **apUnused /* Function arguments */
226681 ){
226682 assert( nArg==0 );
226683 UNUSED_PARAM2(nArg, apUnused);
226684 sqlite3_result_text(pCtx, "fts5: 2020-10-26 16:22:31 80eba105d6d1b49ba8ca2ad4e14ddec2de0bdc2f6686c2f8a1c1d24fc1fe846f", -1, SQLITE_TRANSIENT);
226685 }
226686
226687 /*
226688 ** Return true if zName is the extension on one of the shadow tables used
226689 ** by this module.
@@ -230121,10 +230162,11 @@
230162 for(; i<128 && i<n; i++){
230163 aAscii[i] = (u8)bToken;
230164 }
230165 iTbl++;
230166 }
230167 aAscii[0] = 0; /* 0x00 is never a token character */
230168 }
230169
230170 /*
230171 ** 2015 May 30
230172 **
@@ -231560,12 +231602,12 @@
231602 }
231603 #endif /* SQLITE_CORE */
231604 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
231605
231606 /************** End of stmt.c ************************************************/
231607 #if __LINE__!=231607
231608 #undef SQLITE_SOURCE_ID
231609 #define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692alt2"
231610 #endif
231611 /* Return the source-id for this library */
231612 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
231613 /************************** End of sqlite3.c ******************************/
231614
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123123
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124124
** [sqlite_version()] and [sqlite_source_id()].
125125
*/
126126
#define SQLITE_VERSION "3.34.0"
127127
#define SQLITE_VERSION_NUMBER 3034000
128
-#define SQLITE_SOURCE_ID "2020-10-19 20:49:54 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a196784d2d"
128
+#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
129129
130130
/*
131131
** CAPI3REF: Run-Time Library Version Numbers
132132
** KEYWORDS: sqlite3_version sqlite3_sourceid
133133
**
134134
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.34.0"
127 #define SQLITE_VERSION_NUMBER 3034000
128 #define SQLITE_SOURCE_ID "2020-10-19 20:49:54 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a196784d2d"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.34.0"
127 #define SQLITE_VERSION_NUMBER 3034000
128 #define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d"
129
130 /*
131 ** CAPI3REF: Run-Time Library Version Numbers
132 ** KEYWORDS: sqlite3_version sqlite3_sourceid
133 **
134
+7 -7
--- src/stat.c
+++ src/stat.c
@@ -288,11 +288,11 @@
288288
if( g.perm.Admin && alert_enabled() ){
289289
stats_for_email();
290290
}
291291
292292
@ </table>
293
- style_footer();
293
+ style_finish_page("stat");
294294
}
295295
296296
/*
297297
** COMMAND: dbstat
298298
**
@@ -507,11 +507,11 @@
507507
}else{
508508
@ <p>%h(zRemote)</p>
509509
}
510510
@ </div>
511511
}
512
- style_footer();
512
+ style_finish_page("stat");
513513
}
514514
515515
/*
516516
** WEBPAGE: repo_schema
517517
**
@@ -565,11 +565,11 @@
565565
db_finalize(&q);
566566
}else{
567567
style_submenu_element("Stat1","repo_stat1");
568568
}
569569
}
570
- style_footer();
570
+ style_finish_page("stat");
571571
}
572572
573573
/*
574574
** WEBPAGE: repo_stat1
575575
**
@@ -597,11 +597,11 @@
597597
@ INSERT INTO sqlite_stat1 VALUES('%z(zUrl)%h(zTab)</a>','%h(zIdx)','%h(zStat)');
598598
}
599599
@ </pre>
600600
db_finalize(&q);
601601
}
602
- style_footer();
602
+ style_finish_page("stat");
603603
}
604604
605605
/*
606606
** WEBPAGE: repo-tabsize
607607
**
@@ -669,11 +669,11 @@
669669
@ <h2>%h(file_tail(g.zLocalDbName)) Size: %s(zBuf)</h2>
670670
@ <center><svg width='800' height='500'>
671671
piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
672672
@ </svg></center>
673673
}
674
- style_footer();
674
+ style_finish_page("stat");
675675
}
676676
677677
/*
678678
** Gather statistics on artifact types, counts, and sizes.
679679
**
@@ -810,11 +810,11 @@
810810
sumCmpr = db_column_int64(&q, 4);
811811
sumExp = db_column_int64(&q, 5);
812812
db_finalize(&q);
813813
if( nTotal==0 ){
814814
@ No artifacts in this repository!
815
- style_footer();
815
+ style_finish_page("stat");
816816
return;
817817
}
818818
avgCmpr = (double)sumCmpr/nTotal;
819819
avgExp = (double)sumExp/nTotal;
820820
@@ -955,7 +955,7 @@
955955
}
956956
@ </tbody></table></div>
957957
db_finalize(&q);
958958
}
959959
style_table_sorter();
960
- style_footer();
960
+ style_finish_page("stat");
961961
}
962962
--- src/stat.c
+++ src/stat.c
@@ -288,11 +288,11 @@
288 if( g.perm.Admin && alert_enabled() ){
289 stats_for_email();
290 }
291
292 @ </table>
293 style_footer();
294 }
295
296 /*
297 ** COMMAND: dbstat
298 **
@@ -507,11 +507,11 @@
507 }else{
508 @ <p>%h(zRemote)</p>
509 }
510 @ </div>
511 }
512 style_footer();
513 }
514
515 /*
516 ** WEBPAGE: repo_schema
517 **
@@ -565,11 +565,11 @@
565 db_finalize(&q);
566 }else{
567 style_submenu_element("Stat1","repo_stat1");
568 }
569 }
570 style_footer();
571 }
572
573 /*
574 ** WEBPAGE: repo_stat1
575 **
@@ -597,11 +597,11 @@
597 @ INSERT INTO sqlite_stat1 VALUES('%z(zUrl)%h(zTab)</a>','%h(zIdx)','%h(zStat)');
598 }
599 @ </pre>
600 db_finalize(&q);
601 }
602 style_footer();
603 }
604
605 /*
606 ** WEBPAGE: repo-tabsize
607 **
@@ -669,11 +669,11 @@
669 @ <h2>%h(file_tail(g.zLocalDbName)) Size: %s(zBuf)</h2>
670 @ <center><svg width='800' height='500'>
671 piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
672 @ </svg></center>
673 }
674 style_footer();
675 }
676
677 /*
678 ** Gather statistics on artifact types, counts, and sizes.
679 **
@@ -810,11 +810,11 @@
810 sumCmpr = db_column_int64(&q, 4);
811 sumExp = db_column_int64(&q, 5);
812 db_finalize(&q);
813 if( nTotal==0 ){
814 @ No artifacts in this repository!
815 style_footer();
816 return;
817 }
818 avgCmpr = (double)sumCmpr/nTotal;
819 avgExp = (double)sumExp/nTotal;
820
@@ -955,7 +955,7 @@
955 }
956 @ </tbody></table></div>
957 db_finalize(&q);
958 }
959 style_table_sorter();
960 style_footer();
961 }
962
--- src/stat.c
+++ src/stat.c
@@ -288,11 +288,11 @@
288 if( g.perm.Admin && alert_enabled() ){
289 stats_for_email();
290 }
291
292 @ </table>
293 style_finish_page("stat");
294 }
295
296 /*
297 ** COMMAND: dbstat
298 **
@@ -507,11 +507,11 @@
507 }else{
508 @ <p>%h(zRemote)</p>
509 }
510 @ </div>
511 }
512 style_finish_page("stat");
513 }
514
515 /*
516 ** WEBPAGE: repo_schema
517 **
@@ -565,11 +565,11 @@
565 db_finalize(&q);
566 }else{
567 style_submenu_element("Stat1","repo_stat1");
568 }
569 }
570 style_finish_page("stat");
571 }
572
573 /*
574 ** WEBPAGE: repo_stat1
575 **
@@ -597,11 +597,11 @@
597 @ INSERT INTO sqlite_stat1 VALUES('%z(zUrl)%h(zTab)</a>','%h(zIdx)','%h(zStat)');
598 }
599 @ </pre>
600 db_finalize(&q);
601 }
602 style_finish_page("stat");
603 }
604
605 /*
606 ** WEBPAGE: repo-tabsize
607 **
@@ -669,11 +669,11 @@
669 @ <h2>%h(file_tail(g.zLocalDbName)) Size: %s(zBuf)</h2>
670 @ <center><svg width='800' height='500'>
671 piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
672 @ </svg></center>
673 }
674 style_finish_page("stat");
675 }
676
677 /*
678 ** Gather statistics on artifact types, counts, and sizes.
679 **
@@ -810,11 +810,11 @@
810 sumCmpr = db_column_int64(&q, 4);
811 sumExp = db_column_int64(&q, 5);
812 db_finalize(&q);
813 if( nTotal==0 ){
814 @ No artifacts in this repository!
815 style_finish_page("stat");
816 return;
817 }
818 avgCmpr = (double)sumCmpr/nTotal;
819 avgExp = (double)sumExp/nTotal;
820
@@ -955,7 +955,7 @@
955 }
956 @ </tbody></table></div>
957 db_finalize(&q);
958 }
959 style_table_sorter();
960 style_finish_page("stat");
961 }
962
+1 -1
--- src/statrep.c
+++ src/statrep.c
@@ -825,7 +825,7 @@
825825
break;
826826
case RPT_LASTCHNG:
827827
stats_report_last_change();
828828
break;
829829
}
830
- style_footer();
830
+ style_finish_page("reports");
831831
}
832832
--- src/statrep.c
+++ src/statrep.c
@@ -825,7 +825,7 @@
825 break;
826 case RPT_LASTCHNG:
827 stats_report_last_change();
828 break;
829 }
830 style_footer();
831 }
832
--- src/statrep.c
+++ src/statrep.c
@@ -825,7 +825,7 @@
825 break;
826 case RPT_LASTCHNG:
827 stats_report_last_change();
828 break;
829 }
830 style_finish_page("reports");
831 }
832
+26 -17
--- src/style.c
+++ src/style.c
@@ -736,13 +736,28 @@
736736
@ </script>
737737
builtin_fulfill_js_requests();
738738
}
739739
740740
/*
741
-** Draw the footer at the bottom of the page.
741
+** Invoke this routine after all of the content for a webpage has been
742
+** generated. This routine should be called once for every webpage, at
743
+** or near the end of page generation. This routine does the following:
744
+**
745
+** * Populates the header of the page, including setting up appropriate
746
+** submenu elements. The header generation is deferred until this point
747
+** so that we know that all style_submenu_element() and similar have
748
+** been received.
749
+**
750
+** * Finalizes the page content.
751
+**
752
+** * Appends the footer.
753
+**
754
+** The zPageType argument is a class name inserted in the <div> that
755
+** surrounds the page content. CSS can use this to have different styles
756
+** according to the page type.
742757
*/
743
-void style_footer(void){
758
+void style_finish_page(const char* zPageType){
744759
const char *zFooter;
745760
const char *zAd = 0;
746761
unsigned int mAdFlags = 0;
747762
748763
if( !headerHasBeenGenerated ) return;
@@ -864,31 +879,25 @@
864879
if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
865880
@ <div class="content adunit_right_container">
866881
@ <div class="adunit_right">
867882
cgi_append_content(zAd, -1);
868883
@ </div>
869
- }else{
870
- if( zAd ){
871
- @ <div class="adunit_banner">
872
- cgi_append_content(zAd, -1);
873
- @ </div>
874
- }
875
- @ <div class="content"><span id="debugMsg"></span>
876
- }
884
+ }else if( zAd ){
885
+ @ <div class="adunit_banner">
886
+ cgi_append_content(zAd, -1);
887
+ @ </div>
888
+ }
889
+
890
+ @ <div class="content %s(zPageType)"><span id="debugMsg"></span>
877891
cgi_destination(CGI_BODY);
878892
879893
if( sideboxUsed ){
880
- /* Put the footer at the bottom of the page.
881
- ** the additional clear/both is needed to extend the content
882
- ** part to the end of an optional sidebox.
883
- */
884894
@ <div class="endContent"></div>
885895
}
886896
@ </div>
887897
888
-
889
-
898
+ /* Put the footer at the bottom of the page. */
890899
zFooter = skin_get("footer");
891900
if( sqlite3_strlike("%</body>%", zFooter, 0)==0 ){
892901
style_load_all_js_files();
893902
}
894903
if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
@@ -1195,11 +1204,11 @@
11951204
@ <pre>
11961205
@ %h(blob_str(&g.httpHeader))
11971206
@ </pre>
11981207
}
11991208
}
1200
- style_footer();
1209
+ style_finish_page("error");
12011210
if( zErr ){
12021211
cgi_reply();
12031212
fossil_exit(1);
12041213
}
12051214
}
12061215
--- src/style.c
+++ src/style.c
@@ -736,13 +736,28 @@
736 @ </script>
737 builtin_fulfill_js_requests();
738 }
739
740 /*
741 ** Draw the footer at the bottom of the page.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
742 */
743 void style_footer(void){
744 const char *zFooter;
745 const char *zAd = 0;
746 unsigned int mAdFlags = 0;
747
748 if( !headerHasBeenGenerated ) return;
@@ -864,31 +879,25 @@
864 if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
865 @ <div class="content adunit_right_container">
866 @ <div class="adunit_right">
867 cgi_append_content(zAd, -1);
868 @ </div>
869 }else{
870 if( zAd ){
871 @ <div class="adunit_banner">
872 cgi_append_content(zAd, -1);
873 @ </div>
874 }
875 @ <div class="content"><span id="debugMsg"></span>
876 }
877 cgi_destination(CGI_BODY);
878
879 if( sideboxUsed ){
880 /* Put the footer at the bottom of the page.
881 ** the additional clear/both is needed to extend the content
882 ** part to the end of an optional sidebox.
883 */
884 @ <div class="endContent"></div>
885 }
886 @ </div>
887
888
889
890 zFooter = skin_get("footer");
891 if( sqlite3_strlike("%</body>%", zFooter, 0)==0 ){
892 style_load_all_js_files();
893 }
894 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
@@ -1195,11 +1204,11 @@
1195 @ <pre>
1196 @ %h(blob_str(&g.httpHeader))
1197 @ </pre>
1198 }
1199 }
1200 style_footer();
1201 if( zErr ){
1202 cgi_reply();
1203 fossil_exit(1);
1204 }
1205 }
1206
--- src/style.c
+++ src/style.c
@@ -736,13 +736,28 @@
736 @ </script>
737 builtin_fulfill_js_requests();
738 }
739
740 /*
741 ** Invoke this routine after all of the content for a webpage has been
742 ** generated. This routine should be called once for every webpage, at
743 ** or near the end of page generation. This routine does the following:
744 **
745 ** * Populates the header of the page, including setting up appropriate
746 ** submenu elements. The header generation is deferred until this point
747 ** so that we know that all style_submenu_element() and similar have
748 ** been received.
749 **
750 ** * Finalizes the page content.
751 **
752 ** * Appends the footer.
753 **
754 ** The zPageType argument is a class name inserted in the <div> that
755 ** surrounds the page content. CSS can use this to have different styles
756 ** according to the page type.
757 */
758 void style_finish_page(const char* zPageType){
759 const char *zFooter;
760 const char *zAd = 0;
761 unsigned int mAdFlags = 0;
762
763 if( !headerHasBeenGenerated ) return;
@@ -864,31 +879,25 @@
879 if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){
880 @ <div class="content adunit_right_container">
881 @ <div class="adunit_right">
882 cgi_append_content(zAd, -1);
883 @ </div>
884 }else if( zAd ){
885 @ <div class="adunit_banner">
886 cgi_append_content(zAd, -1);
887 @ </div>
888 }
889
890 @ <div class="content %s(zPageType)"><span id="debugMsg"></span>
 
891 cgi_destination(CGI_BODY);
892
893 if( sideboxUsed ){
 
 
 
 
894 @ <div class="endContent"></div>
895 }
896 @ </div>
897
898 /* Put the footer at the bottom of the page. */
 
899 zFooter = skin_get("footer");
900 if( sqlite3_strlike("%</body>%", zFooter, 0)==0 ){
901 style_load_all_js_files();
902 }
903 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
@@ -1195,11 +1204,11 @@
1204 @ <pre>
1205 @ %h(blob_str(&g.httpHeader))
1206 @ </pre>
1207 }
1208 }
1209 style_finish_page("error");
1210 if( zErr ){
1211 cgi_reply();
1212 fossil_exit(1);
1213 }
1214 }
1215
+2 -2
--- src/tag.c
+++ src/tag.c
@@ -724,11 +724,11 @@
724724
@ <li><span class="tagDsp">%h(zName)</span></li>
725725
}
726726
}
727727
@ </ul>
728728
db_finalize(&q);
729
- style_footer();
729
+ style_finish_page("taglist");
730730
}
731731
732732
/*
733733
** WEBPAGE: /tagtimeline
734734
**
@@ -781,7 +781,7 @@
781781
if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
782782
if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
783783
www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
784784
db_finalize(&q);
785785
@ <br />
786
- style_footer();
786
+ style_finish_page("tagtimeline");
787787
}
788788
--- src/tag.c
+++ src/tag.c
@@ -724,11 +724,11 @@
724 @ <li><span class="tagDsp">%h(zName)</span></li>
725 }
726 }
727 @ </ul>
728 db_finalize(&q);
729 style_footer();
730 }
731
732 /*
733 ** WEBPAGE: /tagtimeline
734 **
@@ -781,7 +781,7 @@
781 if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
782 if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
783 www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
784 db_finalize(&q);
785 @ <br />
786 style_footer();
787 }
788
--- src/tag.c
+++ src/tag.c
@@ -724,11 +724,11 @@
724 @ <li><span class="tagDsp">%h(zName)</span></li>
725 }
726 }
727 @ </ul>
728 db_finalize(&q);
729 style_finish_page("taglist");
730 }
731
732 /*
733 ** WEBPAGE: /tagtimeline
734 **
@@ -781,7 +781,7 @@
781 if( PB("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;
782 if( PB("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;
783 www_print_timeline(&q, tmFlags, 0, 0, 0, 0, 0, 0);
784 db_finalize(&q);
785 @ <br />
786 style_finish_page("tagtimeline");
787 }
788
+2 -2
--- src/tar.c
+++ src/tar.c
@@ -785,11 +785,11 @@
785785
}
786786
if( zExclude ){
787787
@ zExclude = "%h(zExclude)"<br />
788788
}
789789
@ zKey = "%h(zKey)"
790
- style_footer();
790
+ style_finish_page("tarball");
791791
return;
792792
}
793793
if( referred_from_login() ){
794794
style_header("Tarball Download");
795795
@ <form action='%R/tarball/%h(zName).tar.gz'>
@@ -796,11 +796,11 @@
796796
cgi_query_parameters_to_hidden();
797797
@ <p>Tarball named <b>%h(zName).tar.gz</b> holding the content
798798
@ of check-in <b>%h(zRid)</b>:
799799
@ <input type="submit" value="Download" />
800800
@ </form>
801
- style_footer();
801
+ style_finish_page("tarball");
802802
return;
803803
}
804804
blob_zero(&tarball);
805805
if( cache_read(&tarball, zKey)==0 ){
806806
tarball_of_checkin(rid, &tarball, zName, pInclude, pExclude);
807807
--- src/tar.c
+++ src/tar.c
@@ -785,11 +785,11 @@
785 }
786 if( zExclude ){
787 @ zExclude = "%h(zExclude)"<br />
788 }
789 @ zKey = "%h(zKey)"
790 style_footer();
791 return;
792 }
793 if( referred_from_login() ){
794 style_header("Tarball Download");
795 @ <form action='%R/tarball/%h(zName).tar.gz'>
@@ -796,11 +796,11 @@
796 cgi_query_parameters_to_hidden();
797 @ <p>Tarball named <b>%h(zName).tar.gz</b> holding the content
798 @ of check-in <b>%h(zRid)</b>:
799 @ <input type="submit" value="Download" />
800 @ </form>
801 style_footer();
802 return;
803 }
804 blob_zero(&tarball);
805 if( cache_read(&tarball, zKey)==0 ){
806 tarball_of_checkin(rid, &tarball, zName, pInclude, pExclude);
807
--- src/tar.c
+++ src/tar.c
@@ -785,11 +785,11 @@
785 }
786 if( zExclude ){
787 @ zExclude = "%h(zExclude)"<br />
788 }
789 @ zKey = "%h(zKey)"
790 style_finish_page("tarball");
791 return;
792 }
793 if( referred_from_login() ){
794 style_header("Tarball Download");
795 @ <form action='%R/tarball/%h(zName).tar.gz'>
@@ -796,11 +796,11 @@
796 cgi_query_parameters_to_hidden();
797 @ <p>Tarball named <b>%h(zName).tar.gz</b> holding the content
798 @ of check-in <b>%h(zRid)</b>:
799 @ <input type="submit" value="Download" />
800 @ </form>
801 style_finish_page("tarball");
802 return;
803 }
804 blob_zero(&tarball);
805 if( cache_read(&tarball, zKey)==0 ){
806 tarball_of_checkin(rid, &tarball, zName, pInclude, pExclude);
807
+1 -1
--- src/th_main.c
+++ src/th_main.c
@@ -1478,11 +1478,11 @@
14781478
){
14791479
if( argc!=1 ){
14801480
return Th_WrongNumArgs(interp, "styleFooter");
14811481
}
14821482
if( Th_IsRepositoryOpen() ){
1483
- style_footer();
1483
+ style_finish_page("th1"); /* TODO: add optional parameter to pass along? */
14841484
Th_SetResult(interp, 0, 0);
14851485
return TH_OK;
14861486
}else{
14871487
Th_SetResult(interp, "repository unavailable", -1);
14881488
return TH_ERROR;
14891489
--- src/th_main.c
+++ src/th_main.c
@@ -1478,11 +1478,11 @@
1478 ){
1479 if( argc!=1 ){
1480 return Th_WrongNumArgs(interp, "styleFooter");
1481 }
1482 if( Th_IsRepositoryOpen() ){
1483 style_footer();
1484 Th_SetResult(interp, 0, 0);
1485 return TH_OK;
1486 }else{
1487 Th_SetResult(interp, "repository unavailable", -1);
1488 return TH_ERROR;
1489
--- src/th_main.c
+++ src/th_main.c
@@ -1478,11 +1478,11 @@
1478 ){
1479 if( argc!=1 ){
1480 return Th_WrongNumArgs(interp, "styleFooter");
1481 }
1482 if( Th_IsRepositoryOpen() ){
1483 style_finish_page("th1"); /* TODO: add optional parameter to pass along? */
1484 Th_SetResult(interp, 0, 0);
1485 return TH_OK;
1486 }else{
1487 Th_SetResult(interp, "repository unavailable", -1);
1488 return TH_ERROR;
1489
+4 -4
--- src/timeline.c
+++ src/timeline.c
@@ -214,11 +214,11 @@
214214
zBr = P(zNm);
215215
@ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br />
216216
}
217217
@ <input type="submit">
218218
@ </form>
219
- style_footer();
219
+ style_finish_page("test");
220220
}
221221
222222
/*
223223
** Return a new timelineTable id.
224224
*/
@@ -2625,11 +2625,11 @@
26252625
db_finalize(&q);
26262626
if( zOlderButton ){
26272627
@ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
26282628
}
26292629
document_emit_js(/*handles pikchrs rendered above*/);
2630
- style_footer();
2630
+ style_finish_page("timeline");
26312631
}
26322632
26332633
/*
26342634
** The input query q selects various records. Print a human-readable
26352635
** summary of those records.
@@ -3117,11 +3117,11 @@
31173117
@ <small>%z(href("%R/timeline?c=%t",zId))(more context)</a>\
31183118
@ </small></h2>
31193119
www_print_timeline(&q, TIMELINE_GRAPH, 0, 0, 0, 0, 0, 0);
31203120
}
31213121
db_finalize(&q);
3122
- style_footer();
3122
+ style_finish_page("timeline");
31233123
}
31243124
31253125
31263126
/*
31273127
** COMMAND: test-timewarp-list
@@ -3223,7 +3223,7 @@
32233223
if( cnt==0 ){
32243224
@ <p>No timewarps in this repository</p>
32253225
}else{
32263226
@ </tbody></table></div>
32273227
}
3228
- style_footer();
3228
+ style_finish_page("timewarps");
32293229
}
32303230
--- src/timeline.c
+++ src/timeline.c
@@ -214,11 +214,11 @@
214 zBr = P(zNm);
215 @ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br />
216 }
217 @ <input type="submit">
218 @ </form>
219 style_footer();
220 }
221
222 /*
223 ** Return a new timelineTable id.
224 */
@@ -2625,11 +2625,11 @@
2625 db_finalize(&q);
2626 if( zOlderButton ){
2627 @ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
2628 }
2629 document_emit_js(/*handles pikchrs rendered above*/);
2630 style_footer();
2631 }
2632
2633 /*
2634 ** The input query q selects various records. Print a human-readable
2635 ** summary of those records.
@@ -3117,11 +3117,11 @@
3117 @ <small>%z(href("%R/timeline?c=%t",zId))(more context)</a>\
3118 @ </small></h2>
3119 www_print_timeline(&q, TIMELINE_GRAPH, 0, 0, 0, 0, 0, 0);
3120 }
3121 db_finalize(&q);
3122 style_footer();
3123 }
3124
3125
3126 /*
3127 ** COMMAND: test-timewarp-list
@@ -3223,7 +3223,7 @@
3223 if( cnt==0 ){
3224 @ <p>No timewarps in this repository</p>
3225 }else{
3226 @ </tbody></table></div>
3227 }
3228 style_footer();
3229 }
3230
--- src/timeline.c
+++ src/timeline.c
@@ -214,11 +214,11 @@
214 zBr = P(zNm);
215 @ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br />
216 }
217 @ <input type="submit">
218 @ </form>
219 style_finish_page("test");
220 }
221
222 /*
223 ** Return a new timelineTable id.
224 */
@@ -2625,11 +2625,11 @@
2625 db_finalize(&q);
2626 if( zOlderButton ){
2627 @ %z(chref("button","%z",zOlderButton))More&nbsp;&darr;</a>
2628 }
2629 document_emit_js(/*handles pikchrs rendered above*/);
2630 style_finish_page("timeline");
2631 }
2632
2633 /*
2634 ** The input query q selects various records. Print a human-readable
2635 ** summary of those records.
@@ -3117,11 +3117,11 @@
3117 @ <small>%z(href("%R/timeline?c=%t",zId))(more context)</a>\
3118 @ </small></h2>
3119 www_print_timeline(&q, TIMELINE_GRAPH, 0, 0, 0, 0, 0, 0);
3120 }
3121 db_finalize(&q);
3122 style_finish_page("timeline");
3123 }
3124
3125
3126 /*
3127 ** COMMAND: test-timewarp-list
@@ -3223,7 +3223,7 @@
3223 if( cnt==0 ){
3224 @ <p>No timewarps in this repository</p>
3225 }else{
3226 @ </tbody></table></div>
3227 }
3228 style_finish_page("timewarps");
3229 }
3230
+11 -11
--- src/tkt.c
+++ src/tkt.c
@@ -617,11 +617,11 @@
617617
" WHERE tkt_uuid GLOB '%q*'", zUuid);
618618
if( zFullName ){
619619
attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>");
620620
}
621621
622
- style_footer();
622
+ style_finish_page("tkt");
623623
}
624624
625625
/*
626626
** TH1 command: append_field FIELD STRING
627627
**
@@ -840,11 +840,11 @@
840840
return;
841841
}
842842
captcha_generate(0);
843843
@ </form>
844844
if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
845
- style_footer();
845
+ style_finish_page("tkt");
846846
}
847847
848848
/*
849849
** WEBPAGE: tktedit
850850
** WEBPAGE: debug_tktedit
@@ -873,24 +873,24 @@
873873
}
874874
style_header("Edit Ticket");
875875
if( zName==0 || (nName = strlen(zName))<4 || nName>HNAME_LEN_SHA1
876876
|| !validate16(zName,nName) ){
877877
@ <span class="tktError">Not a valid ticket id: "%h(zName)"</span>
878
- style_footer();
878
+ style_finish_page("tkt");
879879
return;
880880
}
881881
nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'",
882882
zName);
883883
if( nRec==0 ){
884884
@ <span class="tktError">No such ticket: "%h(zName)"</span>
885
- style_footer();
885
+ style_finish_page("tkt");
886886
return;
887887
}
888888
if( nRec>1 ){
889889
@ <span class="tktError">%d(nRec) tickets begin with:
890890
@ "%h(zName)"</span>
891
- style_footer();
891
+ style_finish_page("tkt");
892892
return;
893893
}
894894
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
895895
ticket_init();
896896
getAllTicketFields();
@@ -911,11 +911,11 @@
911911
return;
912912
}
913913
captcha_generate(0);
914914
@ </form>
915915
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
916
- style_footer();
916
+ style_finish_page("tkt");
917917
}
918918
919919
/*
920920
** Check the ticket table schema in zSchema to see if it appears to
921921
** be well-formed. If everything is OK, return NULL. If something is
@@ -1041,15 +1041,15 @@
10411041
sqlite3_snprintf(6, zGlobPattern, "%s", zUuid);
10421042
canonical16(zGlobPattern, strlen(zGlobPattern));
10431043
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
10441044
if( tagid==0 ){
10451045
@ No such ticket: %h(zUuid)
1046
- style_footer();
1046
+ style_finish_page("tkt");
10471047
return;
10481048
}
10491049
tkt_draw_timeline(tagid, zType);
1050
- style_footer();
1050
+ style_finish_page("tkt");
10511051
}
10521052
10531053
/*
10541054
** WEBPAGE: tkthistory
10551055
** URL: /tkthistory?name=TICKETUUID
@@ -1088,11 +1088,11 @@
10881088
style_header("%z", zTitle);
10891089
10901090
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
10911091
if( tagid==0 ){
10921092
@ No such ticket: %h(zUuid)
1093
- style_footer();
1093
+ style_finish_page("tkt");
10941094
return;
10951095
}
10961096
if( P("raw")!=0 ){
10971097
@ <h2>Raw Artifacts Associated With Ticket %h(zUuid)</h2>
10981098
}else{
@@ -1161,11 +1161,11 @@
11611161
}
11621162
db_finalize(&q);
11631163
if( nChng ){
11641164
@ </ol>
11651165
}
1166
- style_footer();
1166
+ style_finish_page("tkt");
11671167
}
11681168
11691169
/*
11701170
** Return TRUE if the given BLOB contains a newline character.
11711171
*/
@@ -1613,7 +1613,7 @@
16131613
void tkt_srchpage(void){
16141614
login_check_credentials();
16151615
style_header("Ticket Search");
16161616
ticket_standard_submenu(T_ALL_BUT(T_SRCH));
16171617
search_screen(SRCH_TKT, 0);
1618
- style_footer();
1618
+ style_finish_page("tkt");
16191619
}
16201620
--- src/tkt.c
+++ src/tkt.c
@@ -617,11 +617,11 @@
617 " WHERE tkt_uuid GLOB '%q*'", zUuid);
618 if( zFullName ){
619 attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>");
620 }
621
622 style_footer();
623 }
624
625 /*
626 ** TH1 command: append_field FIELD STRING
627 **
@@ -840,11 +840,11 @@
840 return;
841 }
842 captcha_generate(0);
843 @ </form>
844 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
845 style_footer();
846 }
847
848 /*
849 ** WEBPAGE: tktedit
850 ** WEBPAGE: debug_tktedit
@@ -873,24 +873,24 @@
873 }
874 style_header("Edit Ticket");
875 if( zName==0 || (nName = strlen(zName))<4 || nName>HNAME_LEN_SHA1
876 || !validate16(zName,nName) ){
877 @ <span class="tktError">Not a valid ticket id: "%h(zName)"</span>
878 style_footer();
879 return;
880 }
881 nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'",
882 zName);
883 if( nRec==0 ){
884 @ <span class="tktError">No such ticket: "%h(zName)"</span>
885 style_footer();
886 return;
887 }
888 if( nRec>1 ){
889 @ <span class="tktError">%d(nRec) tickets begin with:
890 @ "%h(zName)"</span>
891 style_footer();
892 return;
893 }
894 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
895 ticket_init();
896 getAllTicketFields();
@@ -911,11 +911,11 @@
911 return;
912 }
913 captcha_generate(0);
914 @ </form>
915 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
916 style_footer();
917 }
918
919 /*
920 ** Check the ticket table schema in zSchema to see if it appears to
921 ** be well-formed. If everything is OK, return NULL. If something is
@@ -1041,15 +1041,15 @@
1041 sqlite3_snprintf(6, zGlobPattern, "%s", zUuid);
1042 canonical16(zGlobPattern, strlen(zGlobPattern));
1043 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
1044 if( tagid==0 ){
1045 @ No such ticket: %h(zUuid)
1046 style_footer();
1047 return;
1048 }
1049 tkt_draw_timeline(tagid, zType);
1050 style_footer();
1051 }
1052
1053 /*
1054 ** WEBPAGE: tkthistory
1055 ** URL: /tkthistory?name=TICKETUUID
@@ -1088,11 +1088,11 @@
1088 style_header("%z", zTitle);
1089
1090 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
1091 if( tagid==0 ){
1092 @ No such ticket: %h(zUuid)
1093 style_footer();
1094 return;
1095 }
1096 if( P("raw")!=0 ){
1097 @ <h2>Raw Artifacts Associated With Ticket %h(zUuid)</h2>
1098 }else{
@@ -1161,11 +1161,11 @@
1161 }
1162 db_finalize(&q);
1163 if( nChng ){
1164 @ </ol>
1165 }
1166 style_footer();
1167 }
1168
1169 /*
1170 ** Return TRUE if the given BLOB contains a newline character.
1171 */
@@ -1613,7 +1613,7 @@
1613 void tkt_srchpage(void){
1614 login_check_credentials();
1615 style_header("Ticket Search");
1616 ticket_standard_submenu(T_ALL_BUT(T_SRCH));
1617 search_screen(SRCH_TKT, 0);
1618 style_footer();
1619 }
1620
--- src/tkt.c
+++ src/tkt.c
@@ -617,11 +617,11 @@
617 " WHERE tkt_uuid GLOB '%q*'", zUuid);
618 if( zFullName ){
619 attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>");
620 }
621
622 style_finish_page("tkt");
623 }
624
625 /*
626 ** TH1 command: append_field FIELD STRING
627 **
@@ -840,11 +840,11 @@
840 return;
841 }
842 captcha_generate(0);
843 @ </form>
844 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
845 style_finish_page("tkt");
846 }
847
848 /*
849 ** WEBPAGE: tktedit
850 ** WEBPAGE: debug_tktedit
@@ -873,24 +873,24 @@
873 }
874 style_header("Edit Ticket");
875 if( zName==0 || (nName = strlen(zName))<4 || nName>HNAME_LEN_SHA1
876 || !validate16(zName,nName) ){
877 @ <span class="tktError">Not a valid ticket id: "%h(zName)"</span>
878 style_finish_page("tkt");
879 return;
880 }
881 nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'",
882 zName);
883 if( nRec==0 ){
884 @ <span class="tktError">No such ticket: "%h(zName)"</span>
885 style_finish_page("tkt");
886 return;
887 }
888 if( nRec>1 ){
889 @ <span class="tktError">%d(nRec) tickets begin with:
890 @ "%h(zName)"</span>
891 style_finish_page("tkt");
892 return;
893 }
894 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
895 ticket_init();
896 getAllTicketFields();
@@ -911,11 +911,11 @@
911 return;
912 }
913 captcha_generate(0);
914 @ </form>
915 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
916 style_finish_page("tkt");
917 }
918
919 /*
920 ** Check the ticket table schema in zSchema to see if it appears to
921 ** be well-formed. If everything is OK, return NULL. If something is
@@ -1041,15 +1041,15 @@
1041 sqlite3_snprintf(6, zGlobPattern, "%s", zUuid);
1042 canonical16(zGlobPattern, strlen(zGlobPattern));
1043 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
1044 if( tagid==0 ){
1045 @ No such ticket: %h(zUuid)
1046 style_finish_page("tkt");
1047 return;
1048 }
1049 tkt_draw_timeline(tagid, zType);
1050 style_finish_page("tkt");
1051 }
1052
1053 /*
1054 ** WEBPAGE: tkthistory
1055 ** URL: /tkthistory?name=TICKETUUID
@@ -1088,11 +1088,11 @@
1088 style_header("%z", zTitle);
1089
1090 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
1091 if( tagid==0 ){
1092 @ No such ticket: %h(zUuid)
1093 style_finish_page("tkt");
1094 return;
1095 }
1096 if( P("raw")!=0 ){
1097 @ <h2>Raw Artifacts Associated With Ticket %h(zUuid)</h2>
1098 }else{
@@ -1161,11 +1161,11 @@
1161 }
1162 db_finalize(&q);
1163 if( nChng ){
1164 @ </ol>
1165 }
1166 style_finish_page("tkt");
1167 }
1168
1169 /*
1170 ** Return TRUE if the given BLOB contains a newline character.
1171 */
@@ -1613,7 +1613,7 @@
1613 void tkt_srchpage(void){
1614 login_check_credentials();
1615 style_header("Ticket Search");
1616 ticket_standard_submenu(T_ALL_BUT(T_SRCH));
1617 search_screen(SRCH_TKT, 0);
1618 style_finish_page("tkt");
1619 }
1620
+3 -3
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -54,11 +54,11 @@
5454
setup_menu_entry("Report Template", "tktsetup_rpttplt",
5555
"The default ticket report format.");
5656
setup_menu_entry("Key Template", "tktsetup_keytplt",
5757
"The default color key for reports.");
5858
@ </table>
59
- style_footer();
59
+ style_finish_page("tktsetup");
6060
}
6161
6262
/*
6363
** NOTE: When changing the table definition below, also change the
6464
** equivalent definition found in schema.c.
@@ -163,11 +163,11 @@
163163
@ <hr />
164164
@ <h2>Default %s(zTitle)</h2>
165165
@ <blockquote><pre>
166166
@ %h(zDfltValue)
167167
@ </pre></blockquote>
168
- style_footer();
168
+ style_finish_page("tktsetup");
169169
}
170170
171171
/*
172172
** WEBPAGE: tktsetup_tab
173173
** Administrative page for defining the "ticket" table used
@@ -934,8 +934,8 @@
934934
@ <input type="submit" name="submit" value="Apply Changes" />
935935
@ <input type="submit" name="setup" value="Cancel" />
936936
@ </p>
937937
@ </div></form>
938938
db_end_transaction(0);
939
- style_footer();
939
+ style_finish_page("tktsetup");
940940
941941
}
942942
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -54,11 +54,11 @@
54 setup_menu_entry("Report Template", "tktsetup_rpttplt",
55 "The default ticket report format.");
56 setup_menu_entry("Key Template", "tktsetup_keytplt",
57 "The default color key for reports.");
58 @ </table>
59 style_footer();
60 }
61
62 /*
63 ** NOTE: When changing the table definition below, also change the
64 ** equivalent definition found in schema.c.
@@ -163,11 +163,11 @@
163 @ <hr />
164 @ <h2>Default %s(zTitle)</h2>
165 @ <blockquote><pre>
166 @ %h(zDfltValue)
167 @ </pre></blockquote>
168 style_footer();
169 }
170
171 /*
172 ** WEBPAGE: tktsetup_tab
173 ** Administrative page for defining the "ticket" table used
@@ -934,8 +934,8 @@
934 @ <input type="submit" name="submit" value="Apply Changes" />
935 @ <input type="submit" name="setup" value="Cancel" />
936 @ </p>
937 @ </div></form>
938 db_end_transaction(0);
939 style_footer();
940
941 }
942
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -54,11 +54,11 @@
54 setup_menu_entry("Report Template", "tktsetup_rpttplt",
55 "The default ticket report format.");
56 setup_menu_entry("Key Template", "tktsetup_keytplt",
57 "The default color key for reports.");
58 @ </table>
59 style_finish_page("tktsetup");
60 }
61
62 /*
63 ** NOTE: When changing the table definition below, also change the
64 ** equivalent definition found in schema.c.
@@ -163,11 +163,11 @@
163 @ <hr />
164 @ <h2>Default %s(zTitle)</h2>
165 @ <blockquote><pre>
166 @ %h(zDfltValue)
167 @ </pre></blockquote>
168 style_finish_page("tktsetup");
169 }
170
171 /*
172 ** WEBPAGE: tktsetup_tab
173 ** Administrative page for defining the "ticket" table used
@@ -934,8 +934,8 @@
934 @ <input type="submit" name="submit" value="Apply Changes" />
935 @ <input type="submit" name="setup" value="Cancel" />
936 @ </p>
937 @ </div></form>
938 db_end_transaction(0);
939 style_finish_page("tktsetup");
940
941 }
942
--- src/unversioned.c
+++ src/unversioned.c
@@ -546,11 +546,11 @@
546546
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
547547
etag_check(ETAG_DATA,0);
548548
style_header("Unversioned Files");
549549
if( !db_table_exists("repository","unversioned") ){
550550
@ No unversioned files on this server
551
- style_footer();
551
+ style_finish_page("uvlist");
552552
return;
553553
}
554554
if( PB("byage") ) zOrderBy = "mtime DESC";
555555
if( PB("showdel") ) showDel = 1;
556556
db_prepare(&q,
@@ -632,11 +632,11 @@
632632
@ </tfoot>
633633
@ </table></div>
634634
}else{
635635
@ No unversioned files on this server.
636636
}
637
- style_footer();
637
+ style_finish_page("uvlist");
638638
}
639639
640640
/*
641641
** WEBPAGE: juvlist
642642
**
643643
--- src/unversioned.c
+++ src/unversioned.c
@@ -546,11 +546,11 @@
546 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
547 etag_check(ETAG_DATA,0);
548 style_header("Unversioned Files");
549 if( !db_table_exists("repository","unversioned") ){
550 @ No unversioned files on this server
551 style_footer();
552 return;
553 }
554 if( PB("byage") ) zOrderBy = "mtime DESC";
555 if( PB("showdel") ) showDel = 1;
556 db_prepare(&q,
@@ -632,11 +632,11 @@
632 @ </tfoot>
633 @ </table></div>
634 }else{
635 @ No unversioned files on this server.
636 }
637 style_footer();
638 }
639
640 /*
641 ** WEBPAGE: juvlist
642 **
643
--- src/unversioned.c
+++ src/unversioned.c
@@ -546,11 +546,11 @@
546 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
547 etag_check(ETAG_DATA,0);
548 style_header("Unversioned Files");
549 if( !db_table_exists("repository","unversioned") ){
550 @ No unversioned files on this server
551 style_finish_page("uvlist");
552 return;
553 }
554 if( PB("byage") ) zOrderBy = "mtime DESC";
555 if( PB("showdel") ) showDel = 1;
556 db_prepare(&q,
@@ -632,11 +632,11 @@
632 @ </tfoot>
633 @ </table></div>
634 }else{
635 @ No unversioned files on this server.
636 }
637 style_finish_page("uvlist");
638 }
639
640 /*
641 ** WEBPAGE: juvlist
642 **
643
+49
--- src/url.c
+++ src/url.c
@@ -628,5 +628,54 @@
628628
&& isatty(fileno(stdin))
629629
){
630630
url_prompt_for_password();
631631
}
632632
}
633
+
634
+/*
635
+** Given a URL for a remote repository clone point, try to come up with a
636
+** reasonable basename of a local clone of that repository.
637
+**
638
+** * If the URL has a path, use the tail of the path, with any suffix
639
+** elided.
640
+**
641
+** * If the URL is just a domain name, without a path, then use the
642
+** first element of the domain name, except skip over "www." if
643
+** present.
644
+**
645
+** The string returned is obtained from fossil_malloc(). NULL might be
646
+** returned if there is an error.
647
+*/
648
+char *url_to_repo_basename(const char *zUrl){
649
+ const char *zTail = 0;
650
+ int i;
651
+ if( zUrl==0 ) return 0;
652
+ for(i=0; zUrl[i]; i++){
653
+ if( zUrl[i]=='?' ) break;
654
+ if( (zUrl[i]=='/' || zUrl[i]=='@') && zUrl[i+1]!=0 ) zTail = &zUrl[i+1];
655
+ }
656
+ if( zTail==0 ) return 0;
657
+ if( sqlite3_strnicmp(zTail, "www.", 4)==0 ) zTail += 4;
658
+ if( zTail[0]==0 ) return 0;
659
+ for(i=0; zTail[i] && zTail[i]!='.' && zTail[i]!='?'; i++){}
660
+ if( i==0 ) return 0;
661
+ return mprintf("%.*s", i, zTail);
662
+}
663
+
664
+/*
665
+** COMMAND: test-url-basename
666
+** Usage: %fossil test-url-basenames URL ...
667
+**
668
+** This command is used for unit testing of the url_to_repo_basename()
669
+** routine. The command-line arguments are URL, presumably for remote
670
+** Fossil repositories. This command runs url_to_repo_basename() on each
671
+** of those inputs and displays the result.
672
+*/
673
+void cmd_test_url_basename(void){
674
+ int i;
675
+ char *z;
676
+ for(i=2; i<g.argc; i++){
677
+ z = url_to_repo_basename(g.argv[i]);
678
+ fossil_print("%s -> %s\n", g.argv[i], z);
679
+ fossil_free(z);
680
+ }
681
+}
633682
--- src/url.c
+++ src/url.c
@@ -628,5 +628,54 @@
628 && isatty(fileno(stdin))
629 ){
630 url_prompt_for_password();
631 }
632 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
633
--- src/url.c
+++ src/url.c
@@ -628,5 +628,54 @@
628 && isatty(fileno(stdin))
629 ){
630 url_prompt_for_password();
631 }
632 }
633
634 /*
635 ** Given a URL for a remote repository clone point, try to come up with a
636 ** reasonable basename of a local clone of that repository.
637 **
638 ** * If the URL has a path, use the tail of the path, with any suffix
639 ** elided.
640 **
641 ** * If the URL is just a domain name, without a path, then use the
642 ** first element of the domain name, except skip over "www." if
643 ** present.
644 **
645 ** The string returned is obtained from fossil_malloc(). NULL might be
646 ** returned if there is an error.
647 */
648 char *url_to_repo_basename(const char *zUrl){
649 const char *zTail = 0;
650 int i;
651 if( zUrl==0 ) return 0;
652 for(i=0; zUrl[i]; i++){
653 if( zUrl[i]=='?' ) break;
654 if( (zUrl[i]=='/' || zUrl[i]=='@') && zUrl[i+1]!=0 ) zTail = &zUrl[i+1];
655 }
656 if( zTail==0 ) return 0;
657 if( sqlite3_strnicmp(zTail, "www.", 4)==0 ) zTail += 4;
658 if( zTail[0]==0 ) return 0;
659 for(i=0; zTail[i] && zTail[i]!='.' && zTail[i]!='?'; i++){}
660 if( i==0 ) return 0;
661 return mprintf("%.*s", i, zTail);
662 }
663
664 /*
665 ** COMMAND: test-url-basename
666 ** Usage: %fossil test-url-basenames URL ...
667 **
668 ** This command is used for unit testing of the url_to_repo_basename()
669 ** routine. The command-line arguments are URL, presumably for remote
670 ** Fossil repositories. This command runs url_to_repo_basename() on each
671 ** of those inputs and displays the result.
672 */
673 void cmd_test_url_basename(void){
674 int i;
675 char *z;
676 for(i=2; i<g.argc; i++){
677 z = url_to_repo_basename(g.argv[i]);
678 fossil_print("%s -> %s\n", g.argv[i], z);
679 fossil_free(z);
680 }
681 }
682
+24 -2
--- src/user.c
+++ src/user.c
@@ -335,10 +335,14 @@
335335
**
336336
** > fossil user capabilities USERNAME ?STRING?
337337
**
338338
** Query or set the capabilities for user USERNAME
339339
**
340
+** > fossil user contact USERNAME ?CONTACT-INFO?
341
+**
342
+** Query or set contact information for user USERNAME
343
+**
340344
** > fossil user default ?USERNAME?
341345
**
342346
** Query or set the default user. The default user is the
343347
** user for command-line interaction.
344348
**
@@ -458,13 +462,31 @@
458462
g.argv[4], uid
459463
);
460464
db_protect_pop();
461465
}
462466
fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid));
467
+ }else if( n>=2 && strncmp(g.argv[2], "contact", 2)==0 ){
468
+ int uid;
469
+ if( g.argc!=4 && g.argc!=5 ){
470
+ usage("contact USERNAME ?CONTACT-INFO?");
471
+ }
472
+ uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
473
+ if( uid==0 ){
474
+ fossil_fatal("no such user: %s", g.argv[3]);
475
+ }
476
+ if( g.argc==5 ){
477
+ db_unprotect(PROTECT_USER);
478
+ db_multi_exec(
479
+ "UPDATE user SET info=%Q, mtime=now() WHERE uid=%d",
480
+ g.argv[4], uid
481
+ );
482
+ db_protect_pop();
483
+ }
484
+ fossil_print("%s\n", db_text(0, "SELECT info FROM user WHERE uid=%d", uid));
463485
}else{
464486
fossil_fatal("user subcommand should be one of: "
465
- "capabilities default list new password");
487
+ "capabilities contact default list new password");
466488
}
467489
}
468490
469491
/*
470492
** Attempt to set the user to zLogin
@@ -750,7 +772,7 @@
750772
@ <label><input type="checkbox" name="delall">
751773
@ Delete all entries</input></label>
752774
@ <input type="submit" name="delallbtn" value="Delete"></input>
753775
@ </form>
754776
style_table_sorter();
755
- style_footer();
777
+ style_finish_page("access_log");
756778
}
757779
--- src/user.c
+++ src/user.c
@@ -335,10 +335,14 @@
335 **
336 ** > fossil user capabilities USERNAME ?STRING?
337 **
338 ** Query or set the capabilities for user USERNAME
339 **
 
 
 
 
340 ** > fossil user default ?USERNAME?
341 **
342 ** Query or set the default user. The default user is the
343 ** user for command-line interaction.
344 **
@@ -458,13 +462,31 @@
458 g.argv[4], uid
459 );
460 db_protect_pop();
461 }
462 fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463 }else{
464 fossil_fatal("user subcommand should be one of: "
465 "capabilities default list new password");
466 }
467 }
468
469 /*
470 ** Attempt to set the user to zLogin
@@ -750,7 +772,7 @@
750 @ <label><input type="checkbox" name="delall">
751 @ Delete all entries</input></label>
752 @ <input type="submit" name="delallbtn" value="Delete"></input>
753 @ </form>
754 style_table_sorter();
755 style_footer();
756 }
757
--- src/user.c
+++ src/user.c
@@ -335,10 +335,14 @@
335 **
336 ** > fossil user capabilities USERNAME ?STRING?
337 **
338 ** Query or set the capabilities for user USERNAME
339 **
340 ** > fossil user contact USERNAME ?CONTACT-INFO?
341 **
342 ** Query or set contact information for user USERNAME
343 **
344 ** > fossil user default ?USERNAME?
345 **
346 ** Query or set the default user. The default user is the
347 ** user for command-line interaction.
348 **
@@ -458,13 +462,31 @@
462 g.argv[4], uid
463 );
464 db_protect_pop();
465 }
466 fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid));
467 }else if( n>=2 && strncmp(g.argv[2], "contact", 2)==0 ){
468 int uid;
469 if( g.argc!=4 && g.argc!=5 ){
470 usage("contact USERNAME ?CONTACT-INFO?");
471 }
472 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
473 if( uid==0 ){
474 fossil_fatal("no such user: %s", g.argv[3]);
475 }
476 if( g.argc==5 ){
477 db_unprotect(PROTECT_USER);
478 db_multi_exec(
479 "UPDATE user SET info=%Q, mtime=now() WHERE uid=%d",
480 g.argv[4], uid
481 );
482 db_protect_pop();
483 }
484 fossil_print("%s\n", db_text(0, "SELECT info FROM user WHERE uid=%d", uid));
485 }else{
486 fossil_fatal("user subcommand should be one of: "
487 "capabilities contact default list new password");
488 }
489 }
490
491 /*
492 ** Attempt to set the user to zLogin
@@ -750,7 +772,7 @@
772 @ <label><input type="checkbox" name="delall">
773 @ Delete all entries</input></label>
774 @ <input type="submit" name="delallbtn" value="Delete"></input>
775 @ </form>
776 style_table_sorter();
777 style_finish_page("access_log");
778 }
779
+5 -5
--- src/webmail.c
+++ src/webmail.c
@@ -513,11 +513,11 @@
513513
style_submenu_element("Delete", "%s",
514514
url_render(pUrl,"trash","1",zENum,"1"));
515515
}
516516
517517
db_end_transaction(0);
518
- style_footer();
518
+ style_finish_page("webmail");
519519
return;
520520
}
521521
522522
/*
523523
** Scan the query parameters looking for parameters with name of the
@@ -613,11 +613,11 @@
613613
return;
614614
}
615615
if( !db_table_exists("repository","emailbox") ){
616616
style_header("Webmail Not Available");
617617
@ <p>This repository is not configured to provide webmail</p>
618
- style_footer();
618
+ style_finish_page("webmail");
619619
return;
620620
}
621621
add_content_sql_commands(g.db);
622622
emailid = atoi(PD("id","0"));
623623
url_initialize(&url, "webmail");
@@ -757,11 +757,11 @@
757757
@ for(i=0; i<x.length; i++){
758758
@ x[i].checked = true;
759759
@ }
760760
@ }
761761
@ </script>
762
- style_footer();
762
+ style_finish_page("webmail");
763763
db_end_transaction(0);
764764
}
765765
766766
/*
767767
** WEBPAGE: emailblob
@@ -854,11 +854,11 @@
854854
}
855855
@ </tbody></table>
856856
db_finalize(&q);
857857
style_table_sorter();
858858
}
859
- style_footer();
859
+ style_finish_page("webmail");
860860
}
861861
862862
/*
863863
** WEBPAGE: emailoutq
864864
**
@@ -911,7 +911,7 @@
911911
}
912912
}
913913
@ </tbody></table>
914914
db_finalize(&q);
915915
style_table_sorter();
916
- style_footer();
916
+ style_finish_page("webmail");
917917
}
918918
--- src/webmail.c
+++ src/webmail.c
@@ -513,11 +513,11 @@
513 style_submenu_element("Delete", "%s",
514 url_render(pUrl,"trash","1",zENum,"1"));
515 }
516
517 db_end_transaction(0);
518 style_footer();
519 return;
520 }
521
522 /*
523 ** Scan the query parameters looking for parameters with name of the
@@ -613,11 +613,11 @@
613 return;
614 }
615 if( !db_table_exists("repository","emailbox") ){
616 style_header("Webmail Not Available");
617 @ <p>This repository is not configured to provide webmail</p>
618 style_footer();
619 return;
620 }
621 add_content_sql_commands(g.db);
622 emailid = atoi(PD("id","0"));
623 url_initialize(&url, "webmail");
@@ -757,11 +757,11 @@
757 @ for(i=0; i<x.length; i++){
758 @ x[i].checked = true;
759 @ }
760 @ }
761 @ </script>
762 style_footer();
763 db_end_transaction(0);
764 }
765
766 /*
767 ** WEBPAGE: emailblob
@@ -854,11 +854,11 @@
854 }
855 @ </tbody></table>
856 db_finalize(&q);
857 style_table_sorter();
858 }
859 style_footer();
860 }
861
862 /*
863 ** WEBPAGE: emailoutq
864 **
@@ -911,7 +911,7 @@
911 }
912 }
913 @ </tbody></table>
914 db_finalize(&q);
915 style_table_sorter();
916 style_footer();
917 }
918
--- src/webmail.c
+++ src/webmail.c
@@ -513,11 +513,11 @@
513 style_submenu_element("Delete", "%s",
514 url_render(pUrl,"trash","1",zENum,"1"));
515 }
516
517 db_end_transaction(0);
518 style_finish_page("webmail");
519 return;
520 }
521
522 /*
523 ** Scan the query parameters looking for parameters with name of the
@@ -613,11 +613,11 @@
613 return;
614 }
615 if( !db_table_exists("repository","emailbox") ){
616 style_header("Webmail Not Available");
617 @ <p>This repository is not configured to provide webmail</p>
618 style_finish_page("webmail");
619 return;
620 }
621 add_content_sql_commands(g.db);
622 emailid = atoi(PD("id","0"));
623 url_initialize(&url, "webmail");
@@ -757,11 +757,11 @@
757 @ for(i=0; i<x.length; i++){
758 @ x[i].checked = true;
759 @ }
760 @ }
761 @ </script>
762 style_finish_page("webmail");
763 db_end_transaction(0);
764 }
765
766 /*
767 ** WEBPAGE: emailblob
@@ -854,11 +854,11 @@
854 }
855 @ </tbody></table>
856 db_finalize(&q);
857 style_table_sorter();
858 }
859 style_finish_page("webmail");
860 }
861
862 /*
863 ** WEBPAGE: emailoutq
864 **
@@ -911,7 +911,7 @@
911 }
912 }
913 @ </tbody></table>
914 db_finalize(&q);
915 style_table_sorter();
916 style_finish_page("webmail");
917 }
918
+15 -15
--- src/wiki.c
+++ src/wiki.c
@@ -66,11 +66,11 @@
6666
if( !wiki_name_is_wellformed((const unsigned char *)z) ){
6767
style_header("Wiki Page Name Error");
6868
@ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed.
6969
@ Rules for wiki page names:
7070
well_formed_wiki_name_rules();
71
- style_footer();
71
+ style_finish_page("wiki");
7272
return 1;
7373
}
7474
return 0;
7575
}
7676
@@ -141,11 +141,11 @@
141141
@ To fill in this page, first go to
142142
@ %z(href("%R/setup_config"))setup/config</a>
143143
@ and establish a "Project Name". Then create a
144144
@ wiki page with that name. The content of that wiki page
145145
@ will be displayed in place of this message.</p>
146
- style_footer();
146
+ style_finish_page("wiki");
147147
}
148148
149149
/*
150150
** Return true if the given pagename is the name of the sandbox
151151
*/
@@ -242,11 +242,11 @@
242242
blob_materialize(&x);
243243
interwiki_append_map_table(&x);
244244
safe_html_context(DOCSRC_TRUSTED);
245245
wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
246246
blob_reset(&x);
247
- style_footer();
247
+ style_finish_page("wiki");
248248
}
249249
250250
/*
251251
** WEBPAGE: wiki_rules
252252
**
@@ -266,11 +266,11 @@
266266
blob_materialize(&x);
267267
interwiki_append_map_table(&x);
268268
safe_html_context(DOCSRC_TRUSTED);
269269
wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki");
270270
blob_reset(&x);
271
- style_footer();
271
+ style_finish_page("wiki");
272272
}
273273
274274
/*
275275
** WEBPAGE: markup_help
276276
**
@@ -280,11 +280,11 @@
280280
style_header("Fossil Markup Styles");
281281
@ <ul>
282282
@ <li><p>%z(href("%R/wiki_rules"))Fossil Wiki Formatting Rules</a></p></li>
283283
@ <li><p>%z(href("%R/md_rules"))Markdown Formatting Rules</a></p></li>
284284
@ </ul>
285
- style_footer();
285
+ style_finish_page("wiki");
286286
}
287287
288288
/*
289289
** Returns non-zero if moderation is required for wiki changes and wiki
290290
** attachments.
@@ -369,11 +369,11 @@
369369
if( search_restrict(SRCH_WIKI)!=0 ){
370370
@ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
371371
@ words</li>
372372
}
373373
@ </ul>
374
- style_footer();
374
+ style_finish_page("wiki");
375375
return;
376376
}
377377
378378
/*
379379
** WEBPAGE: wikisrch
@@ -384,11 +384,11 @@
384384
void wiki_srchpage(void){
385385
login_check_credentials();
386386
style_header("Wiki Search");
387387
wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
388388
search_screen(SRCH_WIKI, 0);
389
- style_footer();
389
+ style_finish_page("wiki");
390390
}
391391
392392
/* Return values from wiki_page_type() */
393393
#if INTERFACE
394394
# define WIKITYPE_UNKNOWN (-1)
@@ -597,11 +597,11 @@
597597
blob_reset(&wiki);
598598
}
599599
attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
600600
manifest_destroy(pWiki);
601601
document_emit_js(/*for optional pikchr support*/);
602
- style_footer();
602
+ style_finish_page("wiki");
603603
}
604604
605605
/*
606606
** Write a wiki artifact into the repository
607607
*/
@@ -1344,11 +1344,11 @@
13441344
CX("}catch(e){"
13451345
"fossil.error(e); console.error('Exception:',e);"
13461346
"}\n");
13471347
CX("});\n"/*fossil.onPageLoad()*/);
13481348
style_script_end();
1349
- style_footer();
1349
+ style_finish_page("wiki");
13501350
}
13511351
13521352
/*
13531353
** WEBPAGE: wikinew
13541354
** URL /wikinew
@@ -1382,11 +1382,11 @@
13821382
@ </p></form>
13831383
if( zName[0] ){
13841384
@ <p><span class="wikiError">
13851385
@ "%h(zName)" is not a valid wiki page name!</span></p>
13861386
}
1387
- style_footer();
1387
+ style_finish_page("wiki");
13881388
}
13891389
13901390
13911391
/*
13921392
** Append the wiki text for an remark to the end of the given BLOB.
@@ -1544,11 +1544,11 @@
15441544
@ <input type="submit" name="preview" value="Preview Your Comment" />
15451545
@ <input type="submit" name="submit" value="Append Your Changes" />
15461546
@ <input type="submit" name="cancel" value="Cancel" />
15471547
captcha_generate(0);
15481548
@ </form>
1549
- style_footer();
1549
+ style_finish_page("wiki");
15501550
}
15511551
15521552
/*
15531553
** WEBPAGE: whistory
15541554
** URL: /whistory?name=PAGENAME
@@ -1634,11 +1634,11 @@
16341634
}
16351635
@ </tbody></table></div>
16361636
db_finalize(&q);
16371637
builtin_request_js("fossil.page.whistory.js");
16381638
/* style_table_sorter(); */
1639
- style_footer();
1639
+ style_finish_page("wiki");
16401640
}
16411641
16421642
/*
16431643
** WEBPAGE: wdiff
16441644
**
@@ -1706,11 +1706,11 @@
17061706
@ <pre class="udiff">
17071707
@ %s(blob_str(&d))
17081708
@ <pre>
17091709
manifest_destroy(pW1);
17101710
manifest_destroy(pW2);
1711
- style_footer();
1711
+ style_finish_page("wiki");
17121712
}
17131713
17141714
/*
17151715
** A query that returns information about all wiki pages.
17161716
**
@@ -1808,11 +1808,11 @@
18081808
fossil_free(zWDisplayName);
18091809
}
18101810
@ </tbody></table></div>
18111811
db_finalize(&q);
18121812
style_table_sorter();
1813
- style_footer();
1813
+ style_finish_page("wiki");
18141814
}
18151815
18161816
/*
18171817
** WEBPAGE: wfind
18181818
**
@@ -1835,11 +1835,11 @@
18351835
const char *zName = db_column_text(&q, 0);
18361836
@ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
18371837
}
18381838
db_finalize(&q);
18391839
@ </ul>
1840
- style_footer();
1840
+ style_finish_page("wiki");
18411841
}
18421842
18431843
/*
18441844
** Add a new wiki page to the repository. The page name is
18451845
** given by the zPageName parameter. rid must be zero to create
18461846
--- src/wiki.c
+++ src/wiki.c
@@ -66,11 +66,11 @@
66 if( !wiki_name_is_wellformed((const unsigned char *)z) ){
67 style_header("Wiki Page Name Error");
68 @ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed.
69 @ Rules for wiki page names:
70 well_formed_wiki_name_rules();
71 style_footer();
72 return 1;
73 }
74 return 0;
75 }
76
@@ -141,11 +141,11 @@
141 @ To fill in this page, first go to
142 @ %z(href("%R/setup_config"))setup/config</a>
143 @ and establish a "Project Name". Then create a
144 @ wiki page with that name. The content of that wiki page
145 @ will be displayed in place of this message.</p>
146 style_footer();
147 }
148
149 /*
150 ** Return true if the given pagename is the name of the sandbox
151 */
@@ -242,11 +242,11 @@
242 blob_materialize(&x);
243 interwiki_append_map_table(&x);
244 safe_html_context(DOCSRC_TRUSTED);
245 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
246 blob_reset(&x);
247 style_footer();
248 }
249
250 /*
251 ** WEBPAGE: wiki_rules
252 **
@@ -266,11 +266,11 @@
266 blob_materialize(&x);
267 interwiki_append_map_table(&x);
268 safe_html_context(DOCSRC_TRUSTED);
269 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki");
270 blob_reset(&x);
271 style_footer();
272 }
273
274 /*
275 ** WEBPAGE: markup_help
276 **
@@ -280,11 +280,11 @@
280 style_header("Fossil Markup Styles");
281 @ <ul>
282 @ <li><p>%z(href("%R/wiki_rules"))Fossil Wiki Formatting Rules</a></p></li>
283 @ <li><p>%z(href("%R/md_rules"))Markdown Formatting Rules</a></p></li>
284 @ </ul>
285 style_footer();
286 }
287
288 /*
289 ** Returns non-zero if moderation is required for wiki changes and wiki
290 ** attachments.
@@ -369,11 +369,11 @@
369 if( search_restrict(SRCH_WIKI)!=0 ){
370 @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
371 @ words</li>
372 }
373 @ </ul>
374 style_footer();
375 return;
376 }
377
378 /*
379 ** WEBPAGE: wikisrch
@@ -384,11 +384,11 @@
384 void wiki_srchpage(void){
385 login_check_credentials();
386 style_header("Wiki Search");
387 wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
388 search_screen(SRCH_WIKI, 0);
389 style_footer();
390 }
391
392 /* Return values from wiki_page_type() */
393 #if INTERFACE
394 # define WIKITYPE_UNKNOWN (-1)
@@ -597,11 +597,11 @@
597 blob_reset(&wiki);
598 }
599 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
600 manifest_destroy(pWiki);
601 document_emit_js(/*for optional pikchr support*/);
602 style_footer();
603 }
604
605 /*
606 ** Write a wiki artifact into the repository
607 */
@@ -1344,11 +1344,11 @@
1344 CX("}catch(e){"
1345 "fossil.error(e); console.error('Exception:',e);"
1346 "}\n");
1347 CX("});\n"/*fossil.onPageLoad()*/);
1348 style_script_end();
1349 style_footer();
1350 }
1351
1352 /*
1353 ** WEBPAGE: wikinew
1354 ** URL /wikinew
@@ -1382,11 +1382,11 @@
1382 @ </p></form>
1383 if( zName[0] ){
1384 @ <p><span class="wikiError">
1385 @ "%h(zName)" is not a valid wiki page name!</span></p>
1386 }
1387 style_footer();
1388 }
1389
1390
1391 /*
1392 ** Append the wiki text for an remark to the end of the given BLOB.
@@ -1544,11 +1544,11 @@
1544 @ <input type="submit" name="preview" value="Preview Your Comment" />
1545 @ <input type="submit" name="submit" value="Append Your Changes" />
1546 @ <input type="submit" name="cancel" value="Cancel" />
1547 captcha_generate(0);
1548 @ </form>
1549 style_footer();
1550 }
1551
1552 /*
1553 ** WEBPAGE: whistory
1554 ** URL: /whistory?name=PAGENAME
@@ -1634,11 +1634,11 @@
1634 }
1635 @ </tbody></table></div>
1636 db_finalize(&q);
1637 builtin_request_js("fossil.page.whistory.js");
1638 /* style_table_sorter(); */
1639 style_footer();
1640 }
1641
1642 /*
1643 ** WEBPAGE: wdiff
1644 **
@@ -1706,11 +1706,11 @@
1706 @ <pre class="udiff">
1707 @ %s(blob_str(&d))
1708 @ <pre>
1709 manifest_destroy(pW1);
1710 manifest_destroy(pW2);
1711 style_footer();
1712 }
1713
1714 /*
1715 ** A query that returns information about all wiki pages.
1716 **
@@ -1808,11 +1808,11 @@
1808 fossil_free(zWDisplayName);
1809 }
1810 @ </tbody></table></div>
1811 db_finalize(&q);
1812 style_table_sorter();
1813 style_footer();
1814 }
1815
1816 /*
1817 ** WEBPAGE: wfind
1818 **
@@ -1835,11 +1835,11 @@
1835 const char *zName = db_column_text(&q, 0);
1836 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
1837 }
1838 db_finalize(&q);
1839 @ </ul>
1840 style_footer();
1841 }
1842
1843 /*
1844 ** Add a new wiki page to the repository. The page name is
1845 ** given by the zPageName parameter. rid must be zero to create
1846
--- src/wiki.c
+++ src/wiki.c
@@ -66,11 +66,11 @@
66 if( !wiki_name_is_wellformed((const unsigned char *)z) ){
67 style_header("Wiki Page Name Error");
68 @ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed.
69 @ Rules for wiki page names:
70 well_formed_wiki_name_rules();
71 style_finish_page("wiki");
72 return 1;
73 }
74 return 0;
75 }
76
@@ -141,11 +141,11 @@
141 @ To fill in this page, first go to
142 @ %z(href("%R/setup_config"))setup/config</a>
143 @ and establish a "Project Name". Then create a
144 @ wiki page with that name. The content of that wiki page
145 @ will be displayed in place of this message.</p>
146 style_finish_page("wiki");
147 }
148
149 /*
150 ** Return true if the given pagename is the name of the sandbox
151 */
@@ -242,11 +242,11 @@
242 blob_materialize(&x);
243 interwiki_append_map_table(&x);
244 safe_html_context(DOCSRC_TRUSTED);
245 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
246 blob_reset(&x);
247 style_finish_page("wiki");
248 }
249
250 /*
251 ** WEBPAGE: wiki_rules
252 **
@@ -266,11 +266,11 @@
266 blob_materialize(&x);
267 interwiki_append_map_table(&x);
268 safe_html_context(DOCSRC_TRUSTED);
269 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki");
270 blob_reset(&x);
271 style_finish_page("wiki");
272 }
273
274 /*
275 ** WEBPAGE: markup_help
276 **
@@ -280,11 +280,11 @@
280 style_header("Fossil Markup Styles");
281 @ <ul>
282 @ <li><p>%z(href("%R/wiki_rules"))Fossil Wiki Formatting Rules</a></p></li>
283 @ <li><p>%z(href("%R/md_rules"))Markdown Formatting Rules</a></p></li>
284 @ </ul>
285 style_finish_page("wiki");
286 }
287
288 /*
289 ** Returns non-zero if moderation is required for wiki changes and wiki
290 ** attachments.
@@ -369,11 +369,11 @@
369 if( search_restrict(SRCH_WIKI)!=0 ){
370 @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
371 @ words</li>
372 }
373 @ </ul>
374 style_finish_page("wiki");
375 return;
376 }
377
378 /*
379 ** WEBPAGE: wikisrch
@@ -384,11 +384,11 @@
384 void wiki_srchpage(void){
385 login_check_credentials();
386 style_header("Wiki Search");
387 wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
388 search_screen(SRCH_WIKI, 0);
389 style_finish_page("wiki");
390 }
391
392 /* Return values from wiki_page_type() */
393 #if INTERFACE
394 # define WIKITYPE_UNKNOWN (-1)
@@ -597,11 +597,11 @@
597 blob_reset(&wiki);
598 }
599 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
600 manifest_destroy(pWiki);
601 document_emit_js(/*for optional pikchr support*/);
602 style_finish_page("wiki");
603 }
604
605 /*
606 ** Write a wiki artifact into the repository
607 */
@@ -1344,11 +1344,11 @@
1344 CX("}catch(e){"
1345 "fossil.error(e); console.error('Exception:',e);"
1346 "}\n");
1347 CX("});\n"/*fossil.onPageLoad()*/);
1348 style_script_end();
1349 style_finish_page("wiki");
1350 }
1351
1352 /*
1353 ** WEBPAGE: wikinew
1354 ** URL /wikinew
@@ -1382,11 +1382,11 @@
1382 @ </p></form>
1383 if( zName[0] ){
1384 @ <p><span class="wikiError">
1385 @ "%h(zName)" is not a valid wiki page name!</span></p>
1386 }
1387 style_finish_page("wiki");
1388 }
1389
1390
1391 /*
1392 ** Append the wiki text for an remark to the end of the given BLOB.
@@ -1544,11 +1544,11 @@
1544 @ <input type="submit" name="preview" value="Preview Your Comment" />
1545 @ <input type="submit" name="submit" value="Append Your Changes" />
1546 @ <input type="submit" name="cancel" value="Cancel" />
1547 captcha_generate(0);
1548 @ </form>
1549 style_finish_page("wiki");
1550 }
1551
1552 /*
1553 ** WEBPAGE: whistory
1554 ** URL: /whistory?name=PAGENAME
@@ -1634,11 +1634,11 @@
1634 }
1635 @ </tbody></table></div>
1636 db_finalize(&q);
1637 builtin_request_js("fossil.page.whistory.js");
1638 /* style_table_sorter(); */
1639 style_finish_page("wiki");
1640 }
1641
1642 /*
1643 ** WEBPAGE: wdiff
1644 **
@@ -1706,11 +1706,11 @@
1706 @ <pre class="udiff">
1707 @ %s(blob_str(&d))
1708 @ <pre>
1709 manifest_destroy(pW1);
1710 manifest_destroy(pW2);
1711 style_finish_page("wiki");
1712 }
1713
1714 /*
1715 ** A query that returns information about all wiki pages.
1716 **
@@ -1808,11 +1808,11 @@
1808 fossil_free(zWDisplayName);
1809 }
1810 @ </tbody></table></div>
1811 db_finalize(&q);
1812 style_table_sorter();
1813 style_finish_page("wiki");
1814 }
1815
1816 /*
1817 ** WEBPAGE: wfind
1818 **
@@ -1835,11 +1835,11 @@
1835 const char *zName = db_column_text(&q, 0);
1836 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
1837 }
1838 db_finalize(&q);
1839 @ </ul>
1840 style_finish_page("wiki");
1841 }
1842
1843 /*
1844 ** Add a new wiki page to the repository. The page name is
1845 ** given by the zPageName parameter. rid must be zero to create
1846
+15 -15
--- src/wiki.c
+++ src/wiki.c
@@ -66,11 +66,11 @@
6666
if( !wiki_name_is_wellformed((const unsigned char *)z) ){
6767
style_header("Wiki Page Name Error");
6868
@ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed.
6969
@ Rules for wiki page names:
7070
well_formed_wiki_name_rules();
71
- style_footer();
71
+ style_finish_page("wiki");
7272
return 1;
7373
}
7474
return 0;
7575
}
7676
@@ -141,11 +141,11 @@
141141
@ To fill in this page, first go to
142142
@ %z(href("%R/setup_config"))setup/config</a>
143143
@ and establish a "Project Name". Then create a
144144
@ wiki page with that name. The content of that wiki page
145145
@ will be displayed in place of this message.</p>
146
- style_footer();
146
+ style_finish_page("wiki");
147147
}
148148
149149
/*
150150
** Return true if the given pagename is the name of the sandbox
151151
*/
@@ -242,11 +242,11 @@
242242
blob_materialize(&x);
243243
interwiki_append_map_table(&x);
244244
safe_html_context(DOCSRC_TRUSTED);
245245
wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
246246
blob_reset(&x);
247
- style_footer();
247
+ style_finish_page("wiki");
248248
}
249249
250250
/*
251251
** WEBPAGE: wiki_rules
252252
**
@@ -266,11 +266,11 @@
266266
blob_materialize(&x);
267267
interwiki_append_map_table(&x);
268268
safe_html_context(DOCSRC_TRUSTED);
269269
wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki");
270270
blob_reset(&x);
271
- style_footer();
271
+ style_finish_page("wiki");
272272
}
273273
274274
/*
275275
** WEBPAGE: markup_help
276276
**
@@ -280,11 +280,11 @@
280280
style_header("Fossil Markup Styles");
281281
@ <ul>
282282
@ <li><p>%z(href("%R/wiki_rules"))Fossil Wiki Formatting Rules</a></p></li>
283283
@ <li><p>%z(href("%R/md_rules"))Markdown Formatting Rules</a></p></li>
284284
@ </ul>
285
- style_footer();
285
+ style_finish_page("wiki");
286286
}
287287
288288
/*
289289
** Returns non-zero if moderation is required for wiki changes and wiki
290290
** attachments.
@@ -369,11 +369,11 @@
369369
if( search_restrict(SRCH_WIKI)!=0 ){
370370
@ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
371371
@ words</li>
372372
}
373373
@ </ul>
374
- style_footer();
374
+ style_finish_page("wiki");
375375
return;
376376
}
377377
378378
/*
379379
** WEBPAGE: wikisrch
@@ -384,11 +384,11 @@
384384
void wiki_srchpage(void){
385385
login_check_credentials();
386386
style_header("Wiki Search");
387387
wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
388388
search_screen(SRCH_WIKI, 0);
389
- style_footer();
389
+ style_finish_page("wiki");
390390
}
391391
392392
/* Return values from wiki_page_type() */
393393
#if INTERFACE
394394
# define WIKITYPE_UNKNOWN (-1)
@@ -597,11 +597,11 @@
597597
blob_reset(&wiki);
598598
}
599599
attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
600600
manifest_destroy(pWiki);
601601
document_emit_js(/*for optional pikchr support*/);
602
- style_footer();
602
+ style_finish_page("wiki");
603603
}
604604
605605
/*
606606
** Write a wiki artifact into the repository
607607
*/
@@ -1344,11 +1344,11 @@
13441344
CX("}catch(e){"
13451345
"fossil.error(e); console.error('Exception:',e);"
13461346
"}\n");
13471347
CX("});\n"/*fossil.onPageLoad()*/);
13481348
style_script_end();
1349
- style_footer();
1349
+ style_finish_page("wiki");
13501350
}
13511351
13521352
/*
13531353
** WEBPAGE: wikinew
13541354
** URL /wikinew
@@ -1382,11 +1382,11 @@
13821382
@ </p></form>
13831383
if( zName[0] ){
13841384
@ <p><span class="wikiError">
13851385
@ "%h(zName)" is not a valid wiki page name!</span></p>
13861386
}
1387
- style_footer();
1387
+ style_finish_page("wiki");
13881388
}
13891389
13901390
13911391
/*
13921392
** Append the wiki text for an remark to the end of the given BLOB.
@@ -1544,11 +1544,11 @@
15441544
@ <input type="submit" name="preview" value="Preview Your Comment" />
15451545
@ <input type="submit" name="submit" value="Append Your Changes" />
15461546
@ <input type="submit" name="cancel" value="Cancel" />
15471547
captcha_generate(0);
15481548
@ </form>
1549
- style_footer();
1549
+ style_finish_page("wiki");
15501550
}
15511551
15521552
/*
15531553
** WEBPAGE: whistory
15541554
** URL: /whistory?name=PAGENAME
@@ -1634,11 +1634,11 @@
16341634
}
16351635
@ </tbody></table></div>
16361636
db_finalize(&q);
16371637
builtin_request_js("fossil.page.whistory.js");
16381638
/* style_table_sorter(); */
1639
- style_footer();
1639
+ style_finish_page("wiki");
16401640
}
16411641
16421642
/*
16431643
** WEBPAGE: wdiff
16441644
**
@@ -1706,11 +1706,11 @@
17061706
@ <pre class="udiff">
17071707
@ %s(blob_str(&d))
17081708
@ <pre>
17091709
manifest_destroy(pW1);
17101710
manifest_destroy(pW2);
1711
- style_footer();
1711
+ style_finish_page("wiki");
17121712
}
17131713
17141714
/*
17151715
** A query that returns information about all wiki pages.
17161716
**
@@ -1808,11 +1808,11 @@
18081808
fossil_free(zWDisplayName);
18091809
}
18101810
@ </tbody></table></div>
18111811
db_finalize(&q);
18121812
style_table_sorter();
1813
- style_footer();
1813
+ style_finish_page("wiki");
18141814
}
18151815
18161816
/*
18171817
** WEBPAGE: wfind
18181818
**
@@ -1835,11 +1835,11 @@
18351835
const char *zName = db_column_text(&q, 0);
18361836
@ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
18371837
}
18381838
db_finalize(&q);
18391839
@ </ul>
1840
- style_footer();
1840
+ style_finish_page("wiki");
18411841
}
18421842
18431843
/*
18441844
** Add a new wiki page to the repository. The page name is
18451845
** given by the zPageName parameter. rid must be zero to create
18461846
--- src/wiki.c
+++ src/wiki.c
@@ -66,11 +66,11 @@
66 if( !wiki_name_is_wellformed((const unsigned char *)z) ){
67 style_header("Wiki Page Name Error");
68 @ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed.
69 @ Rules for wiki page names:
70 well_formed_wiki_name_rules();
71 style_footer();
72 return 1;
73 }
74 return 0;
75 }
76
@@ -141,11 +141,11 @@
141 @ To fill in this page, first go to
142 @ %z(href("%R/setup_config"))setup/config</a>
143 @ and establish a "Project Name". Then create a
144 @ wiki page with that name. The content of that wiki page
145 @ will be displayed in place of this message.</p>
146 style_footer();
147 }
148
149 /*
150 ** Return true if the given pagename is the name of the sandbox
151 */
@@ -242,11 +242,11 @@
242 blob_materialize(&x);
243 interwiki_append_map_table(&x);
244 safe_html_context(DOCSRC_TRUSTED);
245 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
246 blob_reset(&x);
247 style_footer();
248 }
249
250 /*
251 ** WEBPAGE: wiki_rules
252 **
@@ -266,11 +266,11 @@
266 blob_materialize(&x);
267 interwiki_append_map_table(&x);
268 safe_html_context(DOCSRC_TRUSTED);
269 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki");
270 blob_reset(&x);
271 style_footer();
272 }
273
274 /*
275 ** WEBPAGE: markup_help
276 **
@@ -280,11 +280,11 @@
280 style_header("Fossil Markup Styles");
281 @ <ul>
282 @ <li><p>%z(href("%R/wiki_rules"))Fossil Wiki Formatting Rules</a></p></li>
283 @ <li><p>%z(href("%R/md_rules"))Markdown Formatting Rules</a></p></li>
284 @ </ul>
285 style_footer();
286 }
287
288 /*
289 ** Returns non-zero if moderation is required for wiki changes and wiki
290 ** attachments.
@@ -369,11 +369,11 @@
369 if( search_restrict(SRCH_WIKI)!=0 ){
370 @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
371 @ words</li>
372 }
373 @ </ul>
374 style_footer();
375 return;
376 }
377
378 /*
379 ** WEBPAGE: wikisrch
@@ -384,11 +384,11 @@
384 void wiki_srchpage(void){
385 login_check_credentials();
386 style_header("Wiki Search");
387 wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
388 search_screen(SRCH_WIKI, 0);
389 style_footer();
390 }
391
392 /* Return values from wiki_page_type() */
393 #if INTERFACE
394 # define WIKITYPE_UNKNOWN (-1)
@@ -597,11 +597,11 @@
597 blob_reset(&wiki);
598 }
599 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
600 manifest_destroy(pWiki);
601 document_emit_js(/*for optional pikchr support*/);
602 style_footer();
603 }
604
605 /*
606 ** Write a wiki artifact into the repository
607 */
@@ -1344,11 +1344,11 @@
1344 CX("}catch(e){"
1345 "fossil.error(e); console.error('Exception:',e);"
1346 "}\n");
1347 CX("});\n"/*fossil.onPageLoad()*/);
1348 style_script_end();
1349 style_footer();
1350 }
1351
1352 /*
1353 ** WEBPAGE: wikinew
1354 ** URL /wikinew
@@ -1382,11 +1382,11 @@
1382 @ </p></form>
1383 if( zName[0] ){
1384 @ <p><span class="wikiError">
1385 @ "%h(zName)" is not a valid wiki page name!</span></p>
1386 }
1387 style_footer();
1388 }
1389
1390
1391 /*
1392 ** Append the wiki text for an remark to the end of the given BLOB.
@@ -1544,11 +1544,11 @@
1544 @ <input type="submit" name="preview" value="Preview Your Comment" />
1545 @ <input type="submit" name="submit" value="Append Your Changes" />
1546 @ <input type="submit" name="cancel" value="Cancel" />
1547 captcha_generate(0);
1548 @ </form>
1549 style_footer();
1550 }
1551
1552 /*
1553 ** WEBPAGE: whistory
1554 ** URL: /whistory?name=PAGENAME
@@ -1634,11 +1634,11 @@
1634 }
1635 @ </tbody></table></div>
1636 db_finalize(&q);
1637 builtin_request_js("fossil.page.whistory.js");
1638 /* style_table_sorter(); */
1639 style_footer();
1640 }
1641
1642 /*
1643 ** WEBPAGE: wdiff
1644 **
@@ -1706,11 +1706,11 @@
1706 @ <pre class="udiff">
1707 @ %s(blob_str(&d))
1708 @ <pre>
1709 manifest_destroy(pW1);
1710 manifest_destroy(pW2);
1711 style_footer();
1712 }
1713
1714 /*
1715 ** A query that returns information about all wiki pages.
1716 **
@@ -1808,11 +1808,11 @@
1808 fossil_free(zWDisplayName);
1809 }
1810 @ </tbody></table></div>
1811 db_finalize(&q);
1812 style_table_sorter();
1813 style_footer();
1814 }
1815
1816 /*
1817 ** WEBPAGE: wfind
1818 **
@@ -1835,11 +1835,11 @@
1835 const char *zName = db_column_text(&q, 0);
1836 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
1837 }
1838 db_finalize(&q);
1839 @ </ul>
1840 style_footer();
1841 }
1842
1843 /*
1844 ** Add a new wiki page to the repository. The page name is
1845 ** given by the zPageName parameter. rid must be zero to create
1846
--- src/wiki.c
+++ src/wiki.c
@@ -66,11 +66,11 @@
66 if( !wiki_name_is_wellformed((const unsigned char *)z) ){
67 style_header("Wiki Page Name Error");
68 @ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed.
69 @ Rules for wiki page names:
70 well_formed_wiki_name_rules();
71 style_finish_page("wiki");
72 return 1;
73 }
74 return 0;
75 }
76
@@ -141,11 +141,11 @@
141 @ To fill in this page, first go to
142 @ %z(href("%R/setup_config"))setup/config</a>
143 @ and establish a "Project Name". Then create a
144 @ wiki page with that name. The content of that wiki page
145 @ will be displayed in place of this message.</p>
146 style_finish_page("wiki");
147 }
148
149 /*
150 ** Return true if the given pagename is the name of the sandbox
151 */
@@ -242,11 +242,11 @@
242 blob_materialize(&x);
243 interwiki_append_map_table(&x);
244 safe_html_context(DOCSRC_TRUSTED);
245 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-markdown");
246 blob_reset(&x);
247 style_finish_page("wiki");
248 }
249
250 /*
251 ** WEBPAGE: wiki_rules
252 **
@@ -266,11 +266,11 @@
266 blob_materialize(&x);
267 interwiki_append_map_table(&x);
268 safe_html_context(DOCSRC_TRUSTED);
269 wiki_render_by_mimetype(&x, fTxt ? "text/plain" : "text/x-fossil-wiki");
270 blob_reset(&x);
271 style_finish_page("wiki");
272 }
273
274 /*
275 ** WEBPAGE: markup_help
276 **
@@ -280,11 +280,11 @@
280 style_header("Fossil Markup Styles");
281 @ <ul>
282 @ <li><p>%z(href("%R/wiki_rules"))Fossil Wiki Formatting Rules</a></p></li>
283 @ <li><p>%z(href("%R/md_rules"))Markdown Formatting Rules</a></p></li>
284 @ </ul>
285 style_finish_page("wiki");
286 }
287
288 /*
289 ** Returns non-zero if moderation is required for wiki changes and wiki
290 ** attachments.
@@ -369,11 +369,11 @@
369 if( search_restrict(SRCH_WIKI)!=0 ){
370 @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
371 @ words</li>
372 }
373 @ </ul>
374 style_finish_page("wiki");
375 return;
376 }
377
378 /*
379 ** WEBPAGE: wikisrch
@@ -384,11 +384,11 @@
384 void wiki_srchpage(void){
385 login_check_credentials();
386 style_header("Wiki Search");
387 wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
388 search_screen(SRCH_WIKI, 0);
389 style_finish_page("wiki");
390 }
391
392 /* Return values from wiki_page_type() */
393 #if INTERFACE
394 # define WIKITYPE_UNKNOWN (-1)
@@ -597,11 +597,11 @@
597 blob_reset(&wiki);
598 }
599 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
600 manifest_destroy(pWiki);
601 document_emit_js(/*for optional pikchr support*/);
602 style_finish_page("wiki");
603 }
604
605 /*
606 ** Write a wiki artifact into the repository
607 */
@@ -1344,11 +1344,11 @@
1344 CX("}catch(e){"
1345 "fossil.error(e); console.error('Exception:',e);"
1346 "}\n");
1347 CX("});\n"/*fossil.onPageLoad()*/);
1348 style_script_end();
1349 style_finish_page("wiki");
1350 }
1351
1352 /*
1353 ** WEBPAGE: wikinew
1354 ** URL /wikinew
@@ -1382,11 +1382,11 @@
1382 @ </p></form>
1383 if( zName[0] ){
1384 @ <p><span class="wikiError">
1385 @ "%h(zName)" is not a valid wiki page name!</span></p>
1386 }
1387 style_finish_page("wiki");
1388 }
1389
1390
1391 /*
1392 ** Append the wiki text for an remark to the end of the given BLOB.
@@ -1544,11 +1544,11 @@
1544 @ <input type="submit" name="preview" value="Preview Your Comment" />
1545 @ <input type="submit" name="submit" value="Append Your Changes" />
1546 @ <input type="submit" name="cancel" value="Cancel" />
1547 captcha_generate(0);
1548 @ </form>
1549 style_finish_page("wiki");
1550 }
1551
1552 /*
1553 ** WEBPAGE: whistory
1554 ** URL: /whistory?name=PAGENAME
@@ -1634,11 +1634,11 @@
1634 }
1635 @ </tbody></table></div>
1636 db_finalize(&q);
1637 builtin_request_js("fossil.page.whistory.js");
1638 /* style_table_sorter(); */
1639 style_finish_page("wiki");
1640 }
1641
1642 /*
1643 ** WEBPAGE: wdiff
1644 **
@@ -1706,11 +1706,11 @@
1706 @ <pre class="udiff">
1707 @ %s(blob_str(&d))
1708 @ <pre>
1709 manifest_destroy(pW1);
1710 manifest_destroy(pW2);
1711 style_finish_page("wiki");
1712 }
1713
1714 /*
1715 ** A query that returns information about all wiki pages.
1716 **
@@ -1808,11 +1808,11 @@
1808 fossil_free(zWDisplayName);
1809 }
1810 @ </tbody></table></div>
1811 db_finalize(&q);
1812 style_table_sorter();
1813 style_finish_page("wiki");
1814 }
1815
1816 /*
1817 ** WEBPAGE: wfind
1818 **
@@ -1835,11 +1835,11 @@
1835 const char *zName = db_column_text(&q, 0);
1836 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
1837 }
1838 db_finalize(&q);
1839 @ </ul>
1840 style_finish_page("wiki");
1841 }
1842
1843 /*
1844 ** Add a new wiki page to the repository. The page name is
1845 ** given by the zPageName parameter. rid must be zero to create
1846
+18 -15
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -63,10 +63,11 @@
6363
ATTR_SIZE,
6464
ATTR_SRC,
6565
ATTR_START,
6666
ATTR_STYLE,
6767
ATTR_TARGET,
68
+ ATTR_TITLE,
6869
ATTR_TYPE,
6970
ATTR_VALIGN,
7071
ATTR_VALUE,
7172
ATTR_VSPACE,
7273
ATTR_WIDTH
@@ -82,24 +83,24 @@
8283
AMSK_CLASS = 0x00000040,
8384
AMSK_CLEAR = 0x00000080,
8485
AMSK_COLOR = 0x00000100,
8586
AMSK_COLSPAN = 0x00000200,
8687
AMSK_COMPACT = 0x00000400,
87
- /* re-use = 0x00000800, */
88
- AMSK_FACE = 0x00001000,
89
- AMSK_HEIGHT = 0x00002000,
90
- AMSK_HREF = 0x00004000,
91
- AMSK_HSPACE = 0x00008000,
92
- AMSK_ID = 0x00010000,
93
- AMSK_LINKS = 0x00020000,
94
- AMSK_NAME = 0x00040000,
95
- AMSK_ROWSPAN = 0x00080000,
96
- AMSK_SIZE = 0x00100000,
97
- AMSK_SRC = 0x00200000,
98
- AMSK_START = 0x00400000,
99
- AMSK_STYLE = 0x00800000,
100
- AMSK_TARGET = 0x01000000,
88
+ AMSK_FACE = 0x00000800,
89
+ AMSK_HEIGHT = 0x00001000,
90
+ AMSK_HREF = 0x00002000,
91
+ AMSK_HSPACE = 0x00004000,
92
+ AMSK_ID = 0x00008000,
93
+ AMSK_LINKS = 0x00010000,
94
+ AMSK_NAME = 0x00020000,
95
+ AMSK_ROWSPAN = 0x00040000,
96
+ AMSK_SIZE = 0x00080000,
97
+ AMSK_SRC = 0x00100000,
98
+ AMSK_START = 0x00200000,
99
+ AMSK_STYLE = 0x00400000,
100
+ AMSK_TARGET = 0x00800000,
101
+ AMSK_TITLE = 0x01000000,
101102
AMSK_TYPE = 0x02000000,
102103
AMSK_VALIGN = 0x04000000,
103104
AMSK_VALUE = 0x08000000,
104105
AMSK_VSPACE = 0x10000000,
105106
AMSK_WIDTH = 0x20000000
@@ -135,10 +136,11 @@
135136
{ "size", AMSK_SIZE },
136137
{ "src", AMSK_SRC },
137138
{ "start", AMSK_START },
138139
{ "style", AMSK_STYLE },
139140
{ "target", AMSK_TARGET },
141
+ { "title", AMSK_TITLE },
140142
{ "type", AMSK_TYPE },
141143
{ "valign", AMSK_VALIGN },
142144
{ "value", AMSK_VALUE },
143145
{ "vspace", AMSK_VSPACE },
144146
{ "width", AMSK_WIDTH },
@@ -273,11 +275,12 @@
273275
short int iType; /* The MUTYPE_* code */
274276
int allowedAttr; /* Allowed attributes on this markup */
275277
} aMarkup[] = {
276278
{ 0, MARKUP_INVALID, 0, 0 },
277279
{ "a", MARKUP_A, MUTYPE_HYPERLINK,
278
- AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE },
280
+ AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
281
+ AMSK_TITLE},
279282
{ "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
280283
{ "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
281284
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
282285
{ "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
283286
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
284287
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -63,10 +63,11 @@
63 ATTR_SIZE,
64 ATTR_SRC,
65 ATTR_START,
66 ATTR_STYLE,
67 ATTR_TARGET,
 
68 ATTR_TYPE,
69 ATTR_VALIGN,
70 ATTR_VALUE,
71 ATTR_VSPACE,
72 ATTR_WIDTH
@@ -82,24 +83,24 @@
82 AMSK_CLASS = 0x00000040,
83 AMSK_CLEAR = 0x00000080,
84 AMSK_COLOR = 0x00000100,
85 AMSK_COLSPAN = 0x00000200,
86 AMSK_COMPACT = 0x00000400,
87 /* re-use = 0x00000800, */
88 AMSK_FACE = 0x00001000,
89 AMSK_HEIGHT = 0x00002000,
90 AMSK_HREF = 0x00004000,
91 AMSK_HSPACE = 0x00008000,
92 AMSK_ID = 0x00010000,
93 AMSK_LINKS = 0x00020000,
94 AMSK_NAME = 0x00040000,
95 AMSK_ROWSPAN = 0x00080000,
96 AMSK_SIZE = 0x00100000,
97 AMSK_SRC = 0x00200000,
98 AMSK_START = 0x00400000,
99 AMSK_STYLE = 0x00800000,
100 AMSK_TARGET = 0x01000000,
101 AMSK_TYPE = 0x02000000,
102 AMSK_VALIGN = 0x04000000,
103 AMSK_VALUE = 0x08000000,
104 AMSK_VSPACE = 0x10000000,
105 AMSK_WIDTH = 0x20000000
@@ -135,10 +136,11 @@
135 { "size", AMSK_SIZE },
136 { "src", AMSK_SRC },
137 { "start", AMSK_START },
138 { "style", AMSK_STYLE },
139 { "target", AMSK_TARGET },
 
140 { "type", AMSK_TYPE },
141 { "valign", AMSK_VALIGN },
142 { "value", AMSK_VALUE },
143 { "vspace", AMSK_VSPACE },
144 { "width", AMSK_WIDTH },
@@ -273,11 +275,12 @@
273 short int iType; /* The MUTYPE_* code */
274 int allowedAttr; /* Allowed attributes on this markup */
275 } aMarkup[] = {
276 { 0, MARKUP_INVALID, 0, 0 },
277 { "a", MARKUP_A, MUTYPE_HYPERLINK,
278 AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE },
 
279 { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
280 { "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
281 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
282 { "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
283 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
284
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -63,10 +63,11 @@
63 ATTR_SIZE,
64 ATTR_SRC,
65 ATTR_START,
66 ATTR_STYLE,
67 ATTR_TARGET,
68 ATTR_TITLE,
69 ATTR_TYPE,
70 ATTR_VALIGN,
71 ATTR_VALUE,
72 ATTR_VSPACE,
73 ATTR_WIDTH
@@ -82,24 +83,24 @@
83 AMSK_CLASS = 0x00000040,
84 AMSK_CLEAR = 0x00000080,
85 AMSK_COLOR = 0x00000100,
86 AMSK_COLSPAN = 0x00000200,
87 AMSK_COMPACT = 0x00000400,
88 AMSK_FACE = 0x00000800,
89 AMSK_HEIGHT = 0x00001000,
90 AMSK_HREF = 0x00002000,
91 AMSK_HSPACE = 0x00004000,
92 AMSK_ID = 0x00008000,
93 AMSK_LINKS = 0x00010000,
94 AMSK_NAME = 0x00020000,
95 AMSK_ROWSPAN = 0x00040000,
96 AMSK_SIZE = 0x00080000,
97 AMSK_SRC = 0x00100000,
98 AMSK_START = 0x00200000,
99 AMSK_STYLE = 0x00400000,
100 AMSK_TARGET = 0x00800000,
101 AMSK_TITLE = 0x01000000,
102 AMSK_TYPE = 0x02000000,
103 AMSK_VALIGN = 0x04000000,
104 AMSK_VALUE = 0x08000000,
105 AMSK_VSPACE = 0x10000000,
106 AMSK_WIDTH = 0x20000000
@@ -135,10 +136,11 @@
136 { "size", AMSK_SIZE },
137 { "src", AMSK_SRC },
138 { "start", AMSK_START },
139 { "style", AMSK_STYLE },
140 { "target", AMSK_TARGET },
141 { "title", AMSK_TITLE },
142 { "type", AMSK_TYPE },
143 { "valign", AMSK_VALIGN },
144 { "value", AMSK_VALUE },
145 { "vspace", AMSK_VSPACE },
146 { "width", AMSK_WIDTH },
@@ -273,11 +275,12 @@
275 short int iType; /* The MUTYPE_* code */
276 int allowedAttr; /* Allowed attributes on this markup */
277 } aMarkup[] = {
278 { 0, MARKUP_INVALID, 0, 0 },
279 { "a", MARKUP_A, MUTYPE_HYPERLINK,
280 AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
281 AMSK_TITLE},
282 { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
283 { "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
284 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
285 { "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
286 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
287
+2 -2
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -85,11 +85,11 @@
8585
client_sync(syncFlags, 0, 0, 0);
8686
@ </pre>
8787
}
8888
}
8989
90
- style_footer();
90
+ style_finish_page("xfersetup");
9191
}
9292
9393
/*
9494
** Common implementation for the transfer setup editor pages.
9595
*/
@@ -150,11 +150,11 @@
150150
@ <h2>Default %s(zTitle)</h2>
151151
@ <blockquote><pre>
152152
@ %h(zDfltValue)
153153
@ </pre></blockquote>
154154
}
155
- style_footer();
155
+ style_finish_page("xfersetup");
156156
}
157157
158158
static const char *zDefaultXferCommon = 0;
159159
160160
/*
161161
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -85,11 +85,11 @@
85 client_sync(syncFlags, 0, 0, 0);
86 @ </pre>
87 }
88 }
89
90 style_footer();
91 }
92
93 /*
94 ** Common implementation for the transfer setup editor pages.
95 */
@@ -150,11 +150,11 @@
150 @ <h2>Default %s(zTitle)</h2>
151 @ <blockquote><pre>
152 @ %h(zDfltValue)
153 @ </pre></blockquote>
154 }
155 style_footer();
156 }
157
158 static const char *zDefaultXferCommon = 0;
159
160 /*
161
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -85,11 +85,11 @@
85 client_sync(syncFlags, 0, 0, 0);
86 @ </pre>
87 }
88 }
89
90 style_finish_page("xfersetup");
91 }
92
93 /*
94 ** Common implementation for the transfer setup editor pages.
95 */
@@ -150,11 +150,11 @@
150 @ <h2>Default %s(zTitle)</h2>
151 @ <blockquote><pre>
152 @ %h(zDfltValue)
153 @ </pre></blockquote>
154 }
155 style_finish_page("xfersetup");
156 }
157
158 static const char *zDefaultXferCommon = 0;
159
160 /*
161
+2 -2
--- src/zip.c
+++ src/zip.c
@@ -955,11 +955,11 @@
955955
}
956956
if( zExclude ){
957957
@ zExclude = "%h(zExclude)"<br />
958958
}
959959
@ zKey = "%h(zKey)"
960
- style_footer();
960
+ style_finish_page("zip");
961961
return;
962962
}
963963
if( referred_from_login() ){
964964
style_header("%s Archive Download", zType);
965965
@ <form action='%R/%s(g.zPath)/%h(zName).%s(g.zPath)'>
@@ -966,11 +966,11 @@
966966
cgi_query_parameters_to_hidden();
967967
@ <p>%s(zType) Archive named <b>%h(zName).%s(g.zPath)</b>
968968
@ holding the content of check-in <b>%h(zRid)</b>:
969969
@ <input type="submit" value="Download" />
970970
@ </form>
971
- style_footer();
971
+ style_finish_page("zip");
972972
return;
973973
}
974974
blob_zero(&zip);
975975
if( cache_read(&zip, zKey)==0 ){
976976
zip_of_checkin(eType, rid, &zip, zName, pInclude, pExclude);
977977
--- src/zip.c
+++ src/zip.c
@@ -955,11 +955,11 @@
955 }
956 if( zExclude ){
957 @ zExclude = "%h(zExclude)"<br />
958 }
959 @ zKey = "%h(zKey)"
960 style_footer();
961 return;
962 }
963 if( referred_from_login() ){
964 style_header("%s Archive Download", zType);
965 @ <form action='%R/%s(g.zPath)/%h(zName).%s(g.zPath)'>
@@ -966,11 +966,11 @@
966 cgi_query_parameters_to_hidden();
967 @ <p>%s(zType) Archive named <b>%h(zName).%s(g.zPath)</b>
968 @ holding the content of check-in <b>%h(zRid)</b>:
969 @ <input type="submit" value="Download" />
970 @ </form>
971 style_footer();
972 return;
973 }
974 blob_zero(&zip);
975 if( cache_read(&zip, zKey)==0 ){
976 zip_of_checkin(eType, rid, &zip, zName, pInclude, pExclude);
977
--- src/zip.c
+++ src/zip.c
@@ -955,11 +955,11 @@
955 }
956 if( zExclude ){
957 @ zExclude = "%h(zExclude)"<br />
958 }
959 @ zKey = "%h(zKey)"
960 style_finish_page("zip");
961 return;
962 }
963 if( referred_from_login() ){
964 style_header("%s Archive Download", zType);
965 @ <form action='%R/%s(g.zPath)/%h(zName).%s(g.zPath)'>
@@ -966,11 +966,11 @@
966 cgi_query_parameters_to_hidden();
967 @ <p>%s(zType) Archive named <b>%h(zName).%s(g.zPath)</b>
968 @ holding the content of check-in <b>%h(zRid)</b>:
969 @ <input type="submit" value="Download" />
970 @ </form>
971 style_finish_page("zip");
972 return;
973 }
974 blob_zero(&zip);
975 if( cache_read(&zip, zKey)==0 ){
976 zip_of_checkin(eType, rid, &zip, zName, pInclude, pExclude);
977
+48 -40
--- www/backup.md
+++ www/backup.md
@@ -1,11 +1,11 @@
11
# Backing Up a Remote Fossil Repository
22
33
One of the great benefits of Fossil and other [distributed version control systems][dvcs]
44
is that cloning a repository makes a backup. If you are running a project with multiple
55
developers who share their work using a [central server][server] and the server hardware
6
-catches fire or otherwise becomes unavailable, the clones of the repository on each developer
6
+catches fire, the clones of the repository on each developer
77
workstation *may* serve as a suitable backup.
88
99
[dvcs]: wikipedia:/wiki/Distributed_version_control
1010
[server]: ./server/whyuseaserver.wiki
1111
@@ -15,20 +15,20 @@
1515
that, a Fossil repository typically contains
1616
other useful information that is not always shared as part of a clone, which might need
1717
to be backed up separately. To wit:
1818
1919
20
-## Sensitive Information
20
+## <a id="pii"></a> Sensitive Information
2121
2222
Fossil purposefully does not clone certain sensitive information unless
23
-you’re logged in as a user with [setup] capability. As an example, a local clone
23
+you’re logged in as a user with [Setup] capability. As an example, a local clone
2424
may have a different `user` table than the remote, because only a
2525
Setup user is allowed to see the full version for privacy and security
2626
reasons.
2727
2828
29
-## Configuration Drift
29
+## <a id="config"></a> Configuration Drift
3030
3131
Fossil allows the local configuration in certain areas to differ from
3232
that of the remote. With the exception of the prior item, you get a copy
3333
of these configuration areas on initial clone, but after that, some
3434
remote configuration changes don’t sync down automatically, such as the
@@ -35,37 +35,37 @@
3535
remote’s skin. You can ask for updates by running the
3636
[`fossil config pull skin`](./help?cmd=config) command, but that
3737
does not happen automatically during the course of normal development.
3838
3939
40
-## Private Branches
40
+## <a id="private"></a> Private Branches
4141
4242
The very nature of Fossil’s [private branch feature][pbr] ensures that
4343
remote clones don’t get a copy of those branches. Normally this is
4444
exactly what you want, but in the case of making backups, you probably
4545
want to back up these branches as well. One of the two backup methods below
4646
provides this.
4747
4848
49
-## Shunned Artifacts
49
+## <a id="shun"></a> Shunned Artifacts
5050
5151
Fossil purposefully doesn’t sync [shunned artifacts][shun]. If you want
5252
your local clone to be a precise match to the remote, it needs to track
5353
changes to the shun table as well.
5454
5555
56
-## Unversioned Artifacts
56
+## <a id="uv"></a> Unversioned Artifacts
5757
5858
Data in Fossil’s [unversioned artifacts table][uv] doesn’t sync down by
5959
default unless you specifically ask for it. Like local configuration
6060
data, it doesn’t get pulled as part of a normal `fossil sync`, but
6161
*unlike* the config data, you don’t get unversioned files as part of the
6262
initial clone unless you ask for it by passing the `--unversioned/-u`
6363
flag.
6464
6565
66
-## Autosync Is Intransitive
66
+## <a id="ait"></a>Autosync Is Intransitive
6767
6868
If you’re using Fossil in a truly distributed mode, rather than the
6969
simple central-and-clones model that is more common, there may be no
7070
single source of truth in the network because Fossil’s autosync feature
7171
isn’t transitive.
@@ -92,11 +92,11 @@
9292
source of truth, those users still syncing with `svr2` won’t have their
9393
commits pushed up to `svr1` unless you’ve set up bidirectional sync,
9494
rather than have the two backup servers do `pull` only.
9595
9696
97
-# Solutions
97
+# Solution 1: Explicit Pulls
9898
9999
The following script solves most of the above problems for the use case
100100
where you want a *nearly-complete* clone of the remote repository using nothing
101101
but the normal Fossil sync protocol. It only does so if you are logged into
102102
the remote as a user with Setup capability, however.
@@ -118,11 +118,14 @@
118118
out of existence, your backup will be “more than complete” in the sense
119119
that it will continue to have information that the remote says should
120120
not exist any more. That would be not so much a “backup” as an
121121
“archive,” which might not be what you want.
122122
123
-This method doesn’t get you a copy of the remote’s
123
+
124
+# Solution 2: SQL-Level Backup
125
+
126
+The first method doesn’t get you a copy of the remote’s
124127
[private branches][pbr], on purpose. It may also miss other info on the
125128
remote, such as SQL-level customizations that the sync protocol can’t
126129
see. (Some [ticket system customization][tkt] schemes rely on this ability, for example.) You can
127130
solve such problems if you have access to the remote server, which
128131
allows you to get a SQL-level backup. This requires Fossil 2.12 or
@@ -139,12 +142,20 @@
139142
bf=repo-$(date +%Y-%m-%d).fossil
140143
ssh example.com "cd museum ; fossil backup -R repo.fossil backups/$bf" &&
141144
scp example.com:museum/backups/$bf ~/museum/backups
142145
```
143146
147
+----
148
+
149
+Beware that this method does not solve [the intransitive sync
150
+problem](#ait), in and of itself: if you do a SQL-level backup of a
151
+stale repo DB, you have a *stale backup!* You should therefore run this
152
+on every node that may need to serve as a backup so that at least *one*
153
+of the backups is also up-to-date.
154
+
144155
145
-## Encrypted Off-Site Backups
156
+# <a id="enc"></a> Encrypted Off-Site Backups
146157
147158
A useful refinement that you can apply to both methods above is
148159
encrypted off-site backups. You may wish to store backups of your
149160
repositories off-site on a service such as Dropbox, Google Drive, iCloud,
150161
or Microsoft OneDrive, where you don’t fully trust the service not to
@@ -165,24 +176,10 @@
165176
166177
If you’re adding this to the first script above, remove the
167178
“`-R repo-name`” bit so you get a dump of the repository backing the
168179
current working directory.
169180
170
-This requires OpenSSL 1.1 or higher. If you’re on 1.0 or older, you
171
-won’t have the `-pbkdf2` and `-iter` options, and you may have to choose
172
-a different cipher algorithm; both changes are likely to weaken the
173
-encryption significantly, so you should install a newer version rather
174
-than work around the lack of these features.
175
-
176
-If you’re on macOS, which
177
-still ships 1.0 as of the time of this writing, [Homebrew][hb] offers
178
-the current version of OpenSSL, but to avoid a conflict with the platform
179
-version it’s [unlinked][hbul] by default, so you have to give an explicit
180
-path to its “cellar” directory:
181
-
182
- /usr/local/Cellar/openssl\@1.1/1.1.1g/bin/openssl ...
183
-
184181
Change the `pass` value to some other long random string, and change the
185182
`iter` value to something between 10000 and 100000. A good source for
186183
the first is [here][grcp], and for the second, [here][rint].
187184
188185
Compressing the data before encrypting it removes redundancies that can
@@ -192,21 +189,33 @@
192189
compression algorithm that takes less CPU power, such as [`lz4`][lz4].
193190
Changing up the compression algorithm also provides some
194191
security-thru-obscurity, which is useless on its own, but it *is* a
195192
useful adjunct to strong encryption.
196193
194
+This requires OpenSSL 1.1 or higher. If you’re on 1.0 or older, you
195
+won’t have the `-pbkdf2` and `-iter` options, and you may have to choose
196
+a different cipher algorithm; both changes are likely to weaken the
197
+encryption significantly, so you should install a newer version rather
198
+than work around the lack of these features. If you’re on macOS, which
199
+still ships 1.0 as of the time of this writing, [Homebrew][hb] offers
200
+the current version of OpenSSL, but to avoid a conflict with the platform
201
+version, it’s [unlinked][hbul] by default, so you have to give an explicit
202
+path to its “cellar” directory:
203
+
204
+ /usr/local/Cellar/openssl\@1.1/1.1.1g/bin/openssl ...
205
+
197206
198
-## Restoring From An Encrypted Backup
207
+## <a id="rest"></a> Restoring From An Encrypted Backup
199208
200209
The “restore” script for the above fragment is basically an inverse of
201210
it, but it’s worth showing it because there are some subtleties to take
202211
care of. If all variables defined in earlier scripts are available, then
203212
restoration is:
204213
205214
```
206215
openssl enc -d -aes-256-cbc -pbkdf2 -iter 52830 -pass pass:"$pass" -in "$gd" |
207
- xz -d | sqlite3 ~/museum/restored-repo.fossil
216
+ xz -d | fossil --no-repository ~/museum/restored-repo.fossil
208217
```
209218
210219
We changed the `-e` to `-d` on the `openssl` command to get decryption,
211220
and we changed the `-out` to `-in` so it reads from the encrypted backup
212221
file and writes the result to stdout.
@@ -213,30 +222,29 @@
213222
214223
The decompression step is trivial.
215224
216225
The last change is tricky: we used `fossil sql` above to ensure that
217226
we’re using the same version of SQLite to write the encrypted backup DB
218
-as was used to maintain the repository, but unfortunately, we can’t get
219
-the built-in SQLite shell to write a backup into an empty database.
220
-(As soon as it starts up, it goes looking for tables created by
221
-`fossil init` and fails with an error.)
222
-Therefore, we have to either run the restoration against a
223
-possibly-different version of SQLite and hope there are no
224
-incompatibilities, or we have to go out of our way to build a matching
225
-version of `sqlite3` before we can safely do the restoration.
226
-
227
-Keep in mind that Fossil often acts as a dogfooding project for SQLite,
228
-making use of the latest features, so it is quite likely that a given
227
+as was used to maintain the repository. We must also do that on
228
+restoration:
229
+Fossil serves as a dogfooding project for SQLite,
230
+often making use of the latest features, so it is quite likely that a given
229231
random `sqlite3` binary in your `PATH` will be unable to understand the
230
-file created by “`fossil sql .dump`”!
232
+file created by “`fossil sql .dump`”! The tricky bit is, you can’t just
233
+pipe the decrpted SQL dump into `fossil sql`, because on startup, Fossil
234
+normally goes looking for tables created by `fossil init`, and it won’t
235
+find them in a newly-created repo DB. We get around this by passing
236
+the `--no-repository` flag, which suppresses this behavior. Doing it
237
+this way saves you from needing to go and build a matching version of
238
+`sqlite3` just to restore the backup.
231239
232240
[bu]: /help?cmd=backup
233241
[grcp]: https://www.grc.com/passwords.htm
234242
[hb]: https://brew.sh
235243
[hbul]: https://docs.brew.sh/FAQ#what-does-keg-only-mean
236244
[lz4]: https://lz4.github.io/lz4/
237245
[pbr]: ./private.wiki
238246
[rint]: https://www.random.org/integers/?num=1&min=10000&max=100000&col=5&base=10&format=html&rnd=new
239
-[setup]: ./caps/admin-v-setup.md#apsu
247
+[Setup]: ./caps/admin-v-setup.md#apsu
240248
[shun]: ./shunning.wiki
241249
[tkt]: ./tickets.wiki
242250
[uv]: ./unvers.wiki
243251
--- www/backup.md
+++ www/backup.md
@@ -1,11 +1,11 @@
1 # Backing Up a Remote Fossil Repository
2
3 One of the great benefits of Fossil and other [distributed version control systems][dvcs]
4 is that cloning a repository makes a backup. If you are running a project with multiple
5 developers who share their work using a [central server][server] and the server hardware
6 catches fire or otherwise becomes unavailable, the clones of the repository on each developer
7 workstation *may* serve as a suitable backup.
8
9 [dvcs]: wikipedia:/wiki/Distributed_version_control
10 [server]: ./server/whyuseaserver.wiki
11
@@ -15,20 +15,20 @@
15 that, a Fossil repository typically contains
16 other useful information that is not always shared as part of a clone, which might need
17 to be backed up separately. To wit:
18
19
20 ## Sensitive Information
21
22 Fossil purposefully does not clone certain sensitive information unless
23 you’re logged in as a user with [setup] capability. As an example, a local clone
24 may have a different `user` table than the remote, because only a
25 Setup user is allowed to see the full version for privacy and security
26 reasons.
27
28
29 ## Configuration Drift
30
31 Fossil allows the local configuration in certain areas to differ from
32 that of the remote. With the exception of the prior item, you get a copy
33 of these configuration areas on initial clone, but after that, some
34 remote configuration changes don’t sync down automatically, such as the
@@ -35,37 +35,37 @@
35 remote’s skin. You can ask for updates by running the
36 [`fossil config pull skin`](./help?cmd=config) command, but that
37 does not happen automatically during the course of normal development.
38
39
40 ## Private Branches
41
42 The very nature of Fossil’s [private branch feature][pbr] ensures that
43 remote clones don’t get a copy of those branches. Normally this is
44 exactly what you want, but in the case of making backups, you probably
45 want to back up these branches as well. One of the two backup methods below
46 provides this.
47
48
49 ## Shunned Artifacts
50
51 Fossil purposefully doesn’t sync [shunned artifacts][shun]. If you want
52 your local clone to be a precise match to the remote, it needs to track
53 changes to the shun table as well.
54
55
56 ## Unversioned Artifacts
57
58 Data in Fossil’s [unversioned artifacts table][uv] doesn’t sync down by
59 default unless you specifically ask for it. Like local configuration
60 data, it doesn’t get pulled as part of a normal `fossil sync`, but
61 *unlike* the config data, you don’t get unversioned files as part of the
62 initial clone unless you ask for it by passing the `--unversioned/-u`
63 flag.
64
65
66 ## Autosync Is Intransitive
67
68 If you’re using Fossil in a truly distributed mode, rather than the
69 simple central-and-clones model that is more common, there may be no
70 single source of truth in the network because Fossil’s autosync feature
71 isn’t transitive.
@@ -92,11 +92,11 @@
92 source of truth, those users still syncing with `svr2` won’t have their
93 commits pushed up to `svr1` unless you’ve set up bidirectional sync,
94 rather than have the two backup servers do `pull` only.
95
96
97 # Solutions
98
99 The following script solves most of the above problems for the use case
100 where you want a *nearly-complete* clone of the remote repository using nothing
101 but the normal Fossil sync protocol. It only does so if you are logged into
102 the remote as a user with Setup capability, however.
@@ -118,11 +118,14 @@
118 out of existence, your backup will be “more than complete” in the sense
119 that it will continue to have information that the remote says should
120 not exist any more. That would be not so much a “backup” as an
121 “archive,” which might not be what you want.
122
123 This method doesn’t get you a copy of the remote’s
 
 
 
124 [private branches][pbr], on purpose. It may also miss other info on the
125 remote, such as SQL-level customizations that the sync protocol can’t
126 see. (Some [ticket system customization][tkt] schemes rely on this ability, for example.) You can
127 solve such problems if you have access to the remote server, which
128 allows you to get a SQL-level backup. This requires Fossil 2.12 or
@@ -139,12 +142,20 @@
139 bf=repo-$(date +%Y-%m-%d).fossil
140 ssh example.com "cd museum ; fossil backup -R repo.fossil backups/$bf" &&
141 scp example.com:museum/backups/$bf ~/museum/backups
142 ```
143
 
 
 
 
 
 
 
 
144
145 ## Encrypted Off-Site Backups
146
147 A useful refinement that you can apply to both methods above is
148 encrypted off-site backups. You may wish to store backups of your
149 repositories off-site on a service such as Dropbox, Google Drive, iCloud,
150 or Microsoft OneDrive, where you don’t fully trust the service not to
@@ -165,24 +176,10 @@
165
166 If you’re adding this to the first script above, remove the
167 “`-R repo-name`” bit so you get a dump of the repository backing the
168 current working directory.
169
170 This requires OpenSSL 1.1 or higher. If you’re on 1.0 or older, you
171 won’t have the `-pbkdf2` and `-iter` options, and you may have to choose
172 a different cipher algorithm; both changes are likely to weaken the
173 encryption significantly, so you should install a newer version rather
174 than work around the lack of these features.
175
176 If you’re on macOS, which
177 still ships 1.0 as of the time of this writing, [Homebrew][hb] offers
178 the current version of OpenSSL, but to avoid a conflict with the platform
179 version it’s [unlinked][hbul] by default, so you have to give an explicit
180 path to its “cellar” directory:
181
182 /usr/local/Cellar/openssl\@1.1/1.1.1g/bin/openssl ...
183
184 Change the `pass` value to some other long random string, and change the
185 `iter` value to something between 10000 and 100000. A good source for
186 the first is [here][grcp], and for the second, [here][rint].
187
188 Compressing the data before encrypting it removes redundancies that can
@@ -192,21 +189,33 @@
192 compression algorithm that takes less CPU power, such as [`lz4`][lz4].
193 Changing up the compression algorithm also provides some
194 security-thru-obscurity, which is useless on its own, but it *is* a
195 useful adjunct to strong encryption.
196
 
 
 
 
 
 
 
 
 
 
 
 
197
198 ## Restoring From An Encrypted Backup
199
200 The “restore” script for the above fragment is basically an inverse of
201 it, but it’s worth showing it because there are some subtleties to take
202 care of. If all variables defined in earlier scripts are available, then
203 restoration is:
204
205 ```
206 openssl enc -d -aes-256-cbc -pbkdf2 -iter 52830 -pass pass:"$pass" -in "$gd" |
207 xz -d | sqlite3 ~/museum/restored-repo.fossil
208 ```
209
210 We changed the `-e` to `-d` on the `openssl` command to get decryption,
211 and we changed the `-out` to `-in` so it reads from the encrypted backup
212 file and writes the result to stdout.
@@ -213,30 +222,29 @@
213
214 The decompression step is trivial.
215
216 The last change is tricky: we used `fossil sql` above to ensure that
217 we’re using the same version of SQLite to write the encrypted backup DB
218 as was used to maintain the repository, but unfortunately, we can’t get
219 the built-in SQLite shell to write a backup into an empty database.
220 (As soon as it starts up, it goes looking for tables created by
221 `fossil init` and fails with an error.)
222 Therefore, we have to either run the restoration against a
223 possibly-different version of SQLite and hope there are no
224 incompatibilities, or we have to go out of our way to build a matching
225 version of `sqlite3` before we can safely do the restoration.
226
227 Keep in mind that Fossil often acts as a dogfooding project for SQLite,
228 making use of the latest features, so it is quite likely that a given
229 random `sqlite3` binary in your `PATH` will be unable to understand the
230 file created by “`fossil sql .dump`”!
 
 
 
 
 
 
231
232 [bu]: /help?cmd=backup
233 [grcp]: https://www.grc.com/passwords.htm
234 [hb]: https://brew.sh
235 [hbul]: https://docs.brew.sh/FAQ#what-does-keg-only-mean
236 [lz4]: https://lz4.github.io/lz4/
237 [pbr]: ./private.wiki
238 [rint]: https://www.random.org/integers/?num=1&min=10000&max=100000&col=5&base=10&format=html&rnd=new
239 [setup]: ./caps/admin-v-setup.md#apsu
240 [shun]: ./shunning.wiki
241 [tkt]: ./tickets.wiki
242 [uv]: ./unvers.wiki
243
--- www/backup.md
+++ www/backup.md
@@ -1,11 +1,11 @@
1 # Backing Up a Remote Fossil Repository
2
3 One of the great benefits of Fossil and other [distributed version control systems][dvcs]
4 is that cloning a repository makes a backup. If you are running a project with multiple
5 developers who share their work using a [central server][server] and the server hardware
6 catches fire, the clones of the repository on each developer
7 workstation *may* serve as a suitable backup.
8
9 [dvcs]: wikipedia:/wiki/Distributed_version_control
10 [server]: ./server/whyuseaserver.wiki
11
@@ -15,20 +15,20 @@
15 that, a Fossil repository typically contains
16 other useful information that is not always shared as part of a clone, which might need
17 to be backed up separately. To wit:
18
19
20 ## <a id="pii"></a> Sensitive Information
21
22 Fossil purposefully does not clone certain sensitive information unless
23 you’re logged in as a user with [Setup] capability. As an example, a local clone
24 may have a different `user` table than the remote, because only a
25 Setup user is allowed to see the full version for privacy and security
26 reasons.
27
28
29 ## <a id="config"></a> Configuration Drift
30
31 Fossil allows the local configuration in certain areas to differ from
32 that of the remote. With the exception of the prior item, you get a copy
33 of these configuration areas on initial clone, but after that, some
34 remote configuration changes don’t sync down automatically, such as the
@@ -35,37 +35,37 @@
35 remote’s skin. You can ask for updates by running the
36 [`fossil config pull skin`](./help?cmd=config) command, but that
37 does not happen automatically during the course of normal development.
38
39
40 ## <a id="private"></a> Private Branches
41
42 The very nature of Fossil’s [private branch feature][pbr] ensures that
43 remote clones don’t get a copy of those branches. Normally this is
44 exactly what you want, but in the case of making backups, you probably
45 want to back up these branches as well. One of the two backup methods below
46 provides this.
47
48
49 ## <a id="shun"></a> Shunned Artifacts
50
51 Fossil purposefully doesn’t sync [shunned artifacts][shun]. If you want
52 your local clone to be a precise match to the remote, it needs to track
53 changes to the shun table as well.
54
55
56 ## <a id="uv"></a> Unversioned Artifacts
57
58 Data in Fossil’s [unversioned artifacts table][uv] doesn’t sync down by
59 default unless you specifically ask for it. Like local configuration
60 data, it doesn’t get pulled as part of a normal `fossil sync`, but
61 *unlike* the config data, you don’t get unversioned files as part of the
62 initial clone unless you ask for it by passing the `--unversioned/-u`
63 flag.
64
65
66 ## <a id="ait"></a>Autosync Is Intransitive
67
68 If you’re using Fossil in a truly distributed mode, rather than the
69 simple central-and-clones model that is more common, there may be no
70 single source of truth in the network because Fossil’s autosync feature
71 isn’t transitive.
@@ -92,11 +92,11 @@
92 source of truth, those users still syncing with `svr2` won’t have their
93 commits pushed up to `svr1` unless you’ve set up bidirectional sync,
94 rather than have the two backup servers do `pull` only.
95
96
97 # Solution 1: Explicit Pulls
98
99 The following script solves most of the above problems for the use case
100 where you want a *nearly-complete* clone of the remote repository using nothing
101 but the normal Fossil sync protocol. It only does so if you are logged into
102 the remote as a user with Setup capability, however.
@@ -118,11 +118,14 @@
118 out of existence, your backup will be “more than complete” in the sense
119 that it will continue to have information that the remote says should
120 not exist any more. That would be not so much a “backup” as an
121 “archive,” which might not be what you want.
122
123
124 # Solution 2: SQL-Level Backup
125
126 The first method doesn’t get you a copy of the remote’s
127 [private branches][pbr], on purpose. It may also miss other info on the
128 remote, such as SQL-level customizations that the sync protocol can’t
129 see. (Some [ticket system customization][tkt] schemes rely on this ability, for example.) You can
130 solve such problems if you have access to the remote server, which
131 allows you to get a SQL-level backup. This requires Fossil 2.12 or
@@ -139,12 +142,20 @@
142 bf=repo-$(date +%Y-%m-%d).fossil
143 ssh example.com "cd museum ; fossil backup -R repo.fossil backups/$bf" &&
144 scp example.com:museum/backups/$bf ~/museum/backups
145 ```
146
147 ----
148
149 Beware that this method does not solve [the intransitive sync
150 problem](#ait), in and of itself: if you do a SQL-level backup of a
151 stale repo DB, you have a *stale backup!* You should therefore run this
152 on every node that may need to serve as a backup so that at least *one*
153 of the backups is also up-to-date.
154
155
156 # <a id="enc"></a> Encrypted Off-Site Backups
157
158 A useful refinement that you can apply to both methods above is
159 encrypted off-site backups. You may wish to store backups of your
160 repositories off-site on a service such as Dropbox, Google Drive, iCloud,
161 or Microsoft OneDrive, where you don’t fully trust the service not to
@@ -165,24 +176,10 @@
176
177 If you’re adding this to the first script above, remove the
178 “`-R repo-name`” bit so you get a dump of the repository backing the
179 current working directory.
180
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181 Change the `pass` value to some other long random string, and change the
182 `iter` value to something between 10000 and 100000. A good source for
183 the first is [here][grcp], and for the second, [here][rint].
184
185 Compressing the data before encrypting it removes redundancies that can
@@ -192,21 +189,33 @@
189 compression algorithm that takes less CPU power, such as [`lz4`][lz4].
190 Changing up the compression algorithm also provides some
191 security-thru-obscurity, which is useless on its own, but it *is* a
192 useful adjunct to strong encryption.
193
194 This requires OpenSSL 1.1 or higher. If you’re on 1.0 or older, you
195 won’t have the `-pbkdf2` and `-iter` options, and you may have to choose
196 a different cipher algorithm; both changes are likely to weaken the
197 encryption significantly, so you should install a newer version rather
198 than work around the lack of these features. If you’re on macOS, which
199 still ships 1.0 as of the time of this writing, [Homebrew][hb] offers
200 the current version of OpenSSL, but to avoid a conflict with the platform
201 version, it’s [unlinked][hbul] by default, so you have to give an explicit
202 path to its “cellar” directory:
203
204 /usr/local/Cellar/openssl\@1.1/1.1.1g/bin/openssl ...
205
206
207 ## <a id="rest"></a> Restoring From An Encrypted Backup
208
209 The “restore” script for the above fragment is basically an inverse of
210 it, but it’s worth showing it because there are some subtleties to take
211 care of. If all variables defined in earlier scripts are available, then
212 restoration is:
213
214 ```
215 openssl enc -d -aes-256-cbc -pbkdf2 -iter 52830 -pass pass:"$pass" -in "$gd" |
216 xz -d | fossil --no-repository ~/museum/restored-repo.fossil
217 ```
218
219 We changed the `-e` to `-d` on the `openssl` command to get decryption,
220 and we changed the `-out` to `-in` so it reads from the encrypted backup
221 file and writes the result to stdout.
@@ -213,30 +222,29 @@
222
223 The decompression step is trivial.
224
225 The last change is tricky: we used `fossil sql` above to ensure that
226 we’re using the same version of SQLite to write the encrypted backup DB
227 as was used to maintain the repository. We must also do that on
228 restoration:
229 Fossil serves as a dogfooding project for SQLite,
230 often making use of the latest features, so it is quite likely that a given
 
 
 
 
 
 
 
231 random `sqlite3` binary in your `PATH` will be unable to understand the
232 file created by “`fossil sql .dump`”! The tricky bit is, you can’t just
233 pipe the decrpted SQL dump into `fossil sql`, because on startup, Fossil
234 normally goes looking for tables created by `fossil init`, and it won’t
235 find them in a newly-created repo DB. We get around this by passing
236 the `--no-repository` flag, which suppresses this behavior. Doing it
237 this way saves you from needing to go and build a matching version of
238 `sqlite3` just to restore the backup.
239
240 [bu]: /help?cmd=backup
241 [grcp]: https://www.grc.com/passwords.htm
242 [hb]: https://brew.sh
243 [hbul]: https://docs.brew.sh/FAQ#what-does-keg-only-mean
244 [lz4]: https://lz4.github.io/lz4/
245 [pbr]: ./private.wiki
246 [rint]: https://www.random.org/integers/?num=1&min=10000&max=100000&col=5&base=10&format=html&rnd=new
247 [Setup]: ./caps/admin-v-setup.md#apsu
248 [shun]: ./shunning.wiki
249 [tkt]: ./tickets.wiki
250 [uv]: ./unvers.wiki
251
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,17 @@
11
<title>Change Log</title>
22
3
+<a name='v2_14'></a>
4
+<h2>Changes for Version 2.14 (pending)</h2>
5
+
6
+ * The "[/help?cmd=clone|fossil clone]" command is enhanced so that
7
+ if the repository filename is omitted, an appropriate name is derived
8
+ from the remote URL and the newly cloned repo is opened. This makes
9
+ the clone command work more like Git, thus making it easier for
10
+ people transitioning from Git.
11
+ * Add the "contact" sub-command to [/help?cmd=user|fossil user].
12
+
313
<a name='v2_13'></a>
414
<h2>Changes for Version 2.13 (2020-11-01)</h2>
515
616
* Added support for [./interwiki.md|interwiki links].
717
* Enable &lt;del&gt; and &lt;ins&gt; markup in wiki.
818
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,17 @@
1 <title>Change Log</title>
2
 
 
 
 
 
 
 
 
 
 
3 <a name='v2_13'></a>
4 <h2>Changes for Version 2.13 (2020-11-01)</h2>
5
6 * Added support for [./interwiki.md|interwiki links].
7 * Enable &lt;del&gt; and &lt;ins&gt; markup in wiki.
8
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,17 @@
1 <title>Change Log</title>
2
3 <a name='v2_14'></a>
4 <h2>Changes for Version 2.14 (pending)</h2>
5
6 * The "[/help?cmd=clone|fossil clone]" command is enhanced so that
7 if the repository filename is omitted, an appropriate name is derived
8 from the remote URL and the newly cloned repo is opened. This makes
9 the clone command work more like Git, thus making it easier for
10 people transitioning from Git.
11 * Add the "contact" sub-command to [/help?cmd=user|fossil user].
12
13 <a name='v2_13'></a>
14 <h2>Changes for Version 2.13 (2020-11-01)</h2>
15
16 * Added support for [./interwiki.md|interwiki links].
17 * Enable &lt;del&gt; and &lt;ins&gt; markup in wiki.
18
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -296,6 +296,6 @@
296296
# [#tag-ts | TAGNAME:timestamp]
297297
# Full artifact hash or hash prefix.
298298
# Any other type of symbolic name that Fossil extracts from
299299
artifacts.
300300
301
-<div style="height:40em" id="this-space-intentionally-left-blank"></div>
301
+<div style="height:50em" id="this-space-intentionally-left-blank"></div>
302302
303303
ADDED www/ckout-workflows.md
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -296,6 +296,6 @@
296 # [#tag-ts | TAGNAME:timestamp]
297 # Full artifact hash or hash prefix.
298 # Any other type of symbolic name that Fossil extracts from
299 artifacts.
300
301 <div style="height:40em" id="this-space-intentionally-left-blank"></div>
302
303 DDED www/ckout-workflows.md
--- www/checkin_names.wiki
+++ www/checkin_names.wiki
@@ -296,6 +296,6 @@
296 # [#tag-ts | TAGNAME:timestamp]
297 # Full artifact hash or hash prefix.
298 # Any other type of symbolic name that Fossil extracts from
299 artifacts.
300
301 <div style="height:50em" id="this-space-intentionally-left-blank"></div>
302
303 DDED www/ckout-workflows.md
--- a/www/ckout-workflows.md
+++ b/www/ckout-workflows.md
@@ -0,0 +1,33 @@
1
+# Check-Out WorWith Fossil 2.14 �# Check-Out Workflows
2
+
3
+Be # Check-Out Workflows
4
+
5
+Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d , leaving its `git-workWith Git’s typicalFossil working model,
6
+With the clone done as in [the prior section](#mdw), the most idiomatic
7
+The Clone-and-Open Wayhat allows you to get clbehavior:
8
+The use of [`fossil openclone`][clone]
9
+is likely to surprise a Git user. When we were [discussing][caod]
10
+this, we considered following the Git command style, but we decided
11
+against it because it goes against this core Fossil design principle:
12
+given that the Fossil repo is separate from the check-out, why would you
13
+expect asking for a repo clone to also create a check-out directory for
14
+you? We view commingled repository + check-out as a design error in
15
+Git, so why would we repeat the error?
16
+
17
+To see why we see this behavior is error-prone, consider that
18
+`git clean` must have an exception to avoid nuking the `.git` directory.
19
+We had to add that complication to `fossil clean` when we added the
20
+`fossil open URI` feature: it won’t nuke the repo DB file.
21
+
22
+[clone]: /help?cmd=clone
23
+[open]: /help?cmd=openThe Git Clone Way
24
+
25
+This feature didn’t placate many Git fans, though, so w# Check-Out WorWithi# Check-Out WorWith Fossil 2# Check-Out Wokflows
26
+
27
+Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d # Check-Out WorWik-Out Workflows
28
+
29
+Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d # Check-Out WorWith Fossil 2.14 �# Check-Out Workflows
30
+
31
+Be # Check-Out Workflows
32
+
33
+Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d rum/forumpost/3f143cec74
--- a/www/ckout-workflows.md
+++ b/www/ckout-workflows.md
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/ckout-workflows.md
+++ b/www/ckout-workflows.md
@@ -0,0 +1,33 @@
1 # Check-Out WorWith Fossil 2.14 �# Check-Out Workflows
2
3 Be # Check-Out Workflows
4
5 Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d , leaving its `git-workWith Git’s typicalFossil working model,
6 With the clone done as in [the prior section](#mdw), the most idiomatic
7 The Clone-and-Open Wayhat allows you to get clbehavior:
8 The use of [`fossil openclone`][clone]
9 is likely to surprise a Git user. When we were [discussing][caod]
10 this, we considered following the Git command style, but we decided
11 against it because it goes against this core Fossil design principle:
12 given that the Fossil repo is separate from the check-out, why would you
13 expect asking for a repo clone to also create a check-out directory for
14 you? We view commingled repository + check-out as a design error in
15 Git, so why would we repeat the error?
16
17 To see why we see this behavior is error-prone, consider that
18 `git clean` must have an exception to avoid nuking the `.git` directory.
19 We had to add that complication to `fossil clean` when we added the
20 `fossil open URI` feature: it won’t nuke the repo DB file.
21
22 [clone]: /help?cmd=clone
23 [open]: /help?cmd=openThe Git Clone Way
24
25 This feature didn’t placate many Git fans, though, so w# Check-Out WorWithi# Check-Out WorWith Fossil 2# Check-Out Wokflows
26
27 Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d # Check-Out WorWik-Out Workflows
28
29 Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d # Check-Out WorWith Fossil 2.14 �# Check-Out Workflows
30
31 Be # Check-Out Workflows
32
33 Because Fossil separates the concept of “check-out d e Fossil separates the concept of “check-out d rum/forumpost/3f143cec74
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -25,10 +25,13 @@
2525
we try to be fair, the information here
2626
might be biased in favor of Fossil, if only because we spend most of our
2727
time using Fossil, not Git. Ask around for second opinions from
2828
people who have used <em>both</em> Fossil and Git.
2929
30
+If you want a more practical, less philosophical guide to moving from
31
+Git to Fossil, see our [./gitusers.md | Git to Fossil Translation Guide].
32
+
3033
3134
<h2>2.0 Differences Between Fossil And Git</h2>
3235
3336
Differences between Fossil and Git are summarized by the following table,
3437
with further description in the text that follows.
@@ -645,21 +648,20 @@
645648
standard advice is to use a switch-in-place workflow in Fossil when
646649
the disturbance from switching branches is small, and to use multiple
647650
checkouts when you have long-lived working branches that are different
648651
enough that switching in place is disruptive.
649652
650
-You can use Git in the Fossil style, either by manually symlinking the
651
-<tt>.git</tt> directory from one working directory to another or by use
652
-of the <tt>[https://git-scm.com/docs/git-worktree|git-worktree]</tt>
653
-feature. Nevertheless, Git's default tie between working directory and
653
+While you can [./gitusers.md#worktree | use Git in the Fossil style],
654
+Git's default tie between working directory and
654655
repository means the standard method for working with a Git repo is to
655656
have one working directory only. Most Git tutorials teach this style, so
656657
it is how most people learn to use Git. Because relatively few people
657658
use Git with multiple working directories per repository, there are
658659
[https://duckduckgo.com/?q=git+worktree+problem | several known
659660
problems] with that way of working, problems which don't happen in Fossil because of
660
-the clear separation between repository and working directory.
661
+the clear [./ckout-workflows.md | separation] between a Fossil repository and
662
+each working directory.
661663
662664
This distinction matters because switching branches inside a single working directory loses local context
663665
on each switch.
664666
665667
For instance, in any software project where the runnable program must be
@@ -695,13 +697,16 @@
695697
696698
<h3 id="history">2.7 What you should have done vs. What you actually did</h3>
697699
698700
Git puts a lot of emphasis on maintaining
699701
a "clean" check-in history. Extraneous and experimental branches by
700
-individual developers often never make it into the main repository. And
701
-branches are often rebased before being pushed, to make
702
-it appear as if development had been linear. Git strives to record what
702
+individual developers often never make it into the main repository.
703
+Branches may be rebased before being pushed to make
704
+it appear as if development had been linear, or "squashed" to make it
705
+appear that multiple commits were made as a single commit.
706
+There are [https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History |
707
+other history rewriting mechanisms in Git] as well. Git strives to record what
703708
the development of a project should have looked like had there been no
704709
mistakes.
705710
706711
Fossil, in contrast, puts more emphasis on recording exactly what happened,
707712
including all of the messy errors, dead-ends, experimental branches, and
@@ -714,69 +719,117 @@
714719
Like Git, Fossil has an [/help?cmd=amend|amend command] for modifying
715720
prior commits, but unlike in Git, this works not by replacing data in
716721
the repository, but by adding a correction record to the repository that
717722
affects how later Fossil operations present the corrected data. The old
718723
information is still there in the repository, it is just overridden from
719
-the amendment point forward. For extreme situations, Fossil adds the
720
-[/doc/trunk/www/shunning.wiki|shunning mechanism], but it has strict
721
-limitations that prevent global history rewrites.
724
+the amendment point forward.
725
+
726
+Fossil lacks almost every other history rewriting mechanism listed on
727
+the Git documentation page linked above. [./rebaseharm.md | There is no
728
+rebase] in Fossil, on purpose, thus no way to reorder or copy commits
729
+around in the commit hash tree. There is no commit squashing, dropping,
730
+or interactive patch-based cherry-picking of commit elements in Fossil.
731
+There is nothing like Git's <tt>filter-branch</tt> in Fossil.
732
+
733
+The lone exception is deleting commits. Fossil has two methods for doing
734
+that, both of which have stringent limitations, on purpose.
735
+
736
+The first is [/doc/trunk/www/shunning.wiki | shunning]. See that
737
+document for details, but briefly, you only get mandatory compliance
738
+for shun requests within a single repository. Shun requests do not
739
+propagate automatically between repository clones. A Fossil repository
740
+administrator can <i>cooperatively</i> pull another repo's shun requests
741
+across a sync boundary, so that two admins can get together and agree to
742
+shun certain committed artifacts, but a person cannot force their local
743
+shun requests into another repo without having admin-level control over
744
+the receiving repo as well. Fossil's shun feature isn't for fixing up
745
+everyday bad commits, it's for dealing with extreme situations: public
746
+commits of secret material, ticket/wiki/forum spam, law enforcement
747
+takedown demands, etc.
748
+
749
+There is also the experimental [/help?cmd=purge | <tt>purge</tt>
750
+command], which differs from shunning in ways that aren't especially
751
+important in the context of this document. At a 30000 foot level, you
752
+can think of purging as useful only when you've turned off Fossil's
753
+autosync feature and want to pluck artifacts out of its hash tree before
754
+they get pushed. In that sense, it's approximately the same as
755
+<tt>git rebase -i, drop</tt>. However, given that Fossil defaults to
756
+having autosync enabled [#devorg | for good reason], the purge command
757
+isn't very useful in practice: once a commit has been pushed into
758
+another repo, shunning is more useful if you need to delete it from
759
+history.
760
+
761
+If these accommodations strike you as incoherent with respect to
762
+Fossil's philosophy of durable, unchanging commits, realize that if
763
+shunning and purging were removed from Fossil, you could still remove
764
+artifacts from the repository with SQL <tt>DELETE</tt> statements; the
765
+repository database file is, after all, directly modifiable, being
766
+writable by your user. Where the Fossil philosophy really takes hold is
767
+in making it difficult to violate the integrity of the hash tree.
768
+It's somewhat tangential, but the document [./blockchain.md | "Is Fossil
769
+a Blockchain?"] touches on this and related topics.
722770
723771
One commentator characterized Git as recording history according to
724772
the victors, whereas Fossil records history as it actually happened.
725773
726
-We go into more detail on this topic in a separate article,
727
-[./rebaseharm.md | Rebase Considered Harmful].
728
-
729774
730775
<h3 id="testing">2.8 Test Before Commit</h3>
731776
732777
One of the things that falls out of Git's default separation of commit
733778
from push is that there are several Git sub-commands that jump straight
734779
to the commit step before a change could possibly be tested. Fossil, by
735780
contrast, makes the equivalent change to the local working check-out
736781
only, requiring a separate check-in step to commit the change. This
737782
design difference falls naturally out of Fossil's default-enabled
738
-autosync feature.
783
+autosync feature and its philosophy of [#history | not offering history
784
+rewriting features].
739785
740786
The prime example in Git is rebasing: the change happens to the local
741787
repository immediately if successful, even though you haven't tested the
742788
change yet. It's possible to argue for such a design in a tool like Git
743
-which doesn't automatically push the change up to its parent, because
744
-you can still test the change before pushing local changes to the parent
745
-repo, but in the meantime you've made a durable change to your local Git
746
-repository. You must do something drastic like <tt>git
747
-reset --hard</tt> to revert that rebase if it causes a problem. If you
748
-push your rebased local repo up to the parent without testing first,
749
-you've now committed the error on a public branch, effectively a
750
-violation of
789
+since it lacks an autosync feature, because you can still test the
790
+change before pushing local changes to the parent repo, but in the
791
+meantime you've made a durable change to your local Git repository. You
792
+must do something drastic like <tt>git reset --hard</tt> to revert that
793
+rebase or rewrite history before pushing it if the rebase causes a
794
+problem. If you push your rebased local repo up to the parent without
795
+testing first, you cannot fix it without violating
751796
[https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
752797
| the golden rule of rebasing].
753798
754799
Lesser examples are the Git <tt>merge</tt>, <tt>cherry-pick</tt>, and
755800
<tt>revert</tt> commands, all of which apply work from one branch onto
756
-another, and all of which do their work immediately without giving you
757
-an opportunity to test the change first locally unless you give the
758
-<tt>--no-commit</tt> option.
801
+another, and all of which commit their change to the local repository
802
+immediately without giving you
803
+an opportunity to test the change first unless you give the
804
+<tt>--no-commit</tt> option. Otherwise, you're back in the same boat:
805
+reset the local repository or rewrite history to fix things, then maybe
806
+retry.
759807
760808
Fossil cannot sensibly work that way because of its default-enabled
761
-autosync feature. Instead of jumping straight to the commit step, Fossil
809
+autosync feature and its purposeful paucity of commands for modifying
810
+commits, as discussed in [#history | the prior section].
811
+
812
+Instead of jumping straight to the commit step, Fossil
762813
applies the proposed merge to the local working directory only,
763814
requiring a separate check-in step before the change is committed to the
764815
repository. This gives you a chance to test the change first,
765816
either manually or by running your software's automatic tests. (Ideally,
766
-both!)
817
+both!) Thus, Fossil doesn't need rebase, squashing,
818
+<tt>reset --hard</tt>, or other Git commit mutating mechanisms.
767819
768
-Another difference is that because Fossil requires an explicit commit
769
-for a merge, it makes you give an explicit commit <i>message</i> for
770
-each merge, whereas Git writes that commit message itself by default
820
+Because Fossil requires an explicit commit for a merge, it has the nice
821
+side benefit that it makes you give an explicit commit <i>message</i>
822
+for each merge, whereas Git writes that commit message itself by default
771823
unless you give the optional <tt>--edit</tt> flag to override it.
772824
773825
We don't look at this difference as a workaround in Fossil for autosync,
774
-but instead as a test-first philosophical difference. When every commit
775
-is pushed to the parent repo by default, it encourages a working style
776
-in which every commit is tested first. We think this is an inherently
777
-good thing.
826
+but instead as a test-first philosophical difference:
827
+<tt>fossil commit</tt> is a <i>commitment</i>. When every commit is
828
+pushed to the parent repo by default, it encourages a working style in
829
+which every commit is tested first. It encourages thinking before
830
+acting. We believe this is an inherently good thing.
778831
779832
Incidentally, this is a good example of Git's messy command design.
780833
These three commands:
781834
782835
<pre>
783836
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -25,10 +25,13 @@
25 we try to be fair, the information here
26 might be biased in favor of Fossil, if only because we spend most of our
27 time using Fossil, not Git. Ask around for second opinions from
28 people who have used <em>both</em> Fossil and Git.
29
 
 
 
30
31 <h2>2.0 Differences Between Fossil And Git</h2>
32
33 Differences between Fossil and Git are summarized by the following table,
34 with further description in the text that follows.
@@ -645,21 +648,20 @@
645 standard advice is to use a switch-in-place workflow in Fossil when
646 the disturbance from switching branches is small, and to use multiple
647 checkouts when you have long-lived working branches that are different
648 enough that switching in place is disruptive.
649
650 You can use Git in the Fossil style, either by manually symlinking the
651 <tt>.git</tt> directory from one working directory to another or by use
652 of the <tt>[https://git-scm.com/docs/git-worktree|git-worktree]</tt>
653 feature. Nevertheless, Git's default tie between working directory and
654 repository means the standard method for working with a Git repo is to
655 have one working directory only. Most Git tutorials teach this style, so
656 it is how most people learn to use Git. Because relatively few people
657 use Git with multiple working directories per repository, there are
658 [https://duckduckgo.com/?q=git+worktree+problem | several known
659 problems] with that way of working, problems which don't happen in Fossil because of
660 the clear separation between repository and working directory.
 
661
662 This distinction matters because switching branches inside a single working directory loses local context
663 on each switch.
664
665 For instance, in any software project where the runnable program must be
@@ -695,13 +697,16 @@
695
696 <h3 id="history">2.7 What you should have done vs. What you actually did</h3>
697
698 Git puts a lot of emphasis on maintaining
699 a "clean" check-in history. Extraneous and experimental branches by
700 individual developers often never make it into the main repository. And
701 branches are often rebased before being pushed, to make
702 it appear as if development had been linear. Git strives to record what
 
 
 
703 the development of a project should have looked like had there been no
704 mistakes.
705
706 Fossil, in contrast, puts more emphasis on recording exactly what happened,
707 including all of the messy errors, dead-ends, experimental branches, and
@@ -714,69 +719,117 @@
714 Like Git, Fossil has an [/help?cmd=amend|amend command] for modifying
715 prior commits, but unlike in Git, this works not by replacing data in
716 the repository, but by adding a correction record to the repository that
717 affects how later Fossil operations present the corrected data. The old
718 information is still there in the repository, it is just overridden from
719 the amendment point forward. For extreme situations, Fossil adds the
720 [/doc/trunk/www/shunning.wiki|shunning mechanism], but it has strict
721 limitations that prevent global history rewrites.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
722
723 One commentator characterized Git as recording history according to
724 the victors, whereas Fossil records history as it actually happened.
725
726 We go into more detail on this topic in a separate article,
727 [./rebaseharm.md | Rebase Considered Harmful].
728
729
730 <h3 id="testing">2.8 Test Before Commit</h3>
731
732 One of the things that falls out of Git's default separation of commit
733 from push is that there are several Git sub-commands that jump straight
734 to the commit step before a change could possibly be tested. Fossil, by
735 contrast, makes the equivalent change to the local working check-out
736 only, requiring a separate check-in step to commit the change. This
737 design difference falls naturally out of Fossil's default-enabled
738 autosync feature.
 
739
740 The prime example in Git is rebasing: the change happens to the local
741 repository immediately if successful, even though you haven't tested the
742 change yet. It's possible to argue for such a design in a tool like Git
743 which doesn't automatically push the change up to its parent, because
744 you can still test the change before pushing local changes to the parent
745 repo, but in the meantime you've made a durable change to your local Git
746 repository. You must do something drastic like <tt>git
747 reset --hard</tt> to revert that rebase if it causes a problem. If you
748 push your rebased local repo up to the parent without testing first,
749 you've now committed the error on a public branch, effectively a
750 violation of
751 [https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
752 | the golden rule of rebasing].
753
754 Lesser examples are the Git <tt>merge</tt>, <tt>cherry-pick</tt>, and
755 <tt>revert</tt> commands, all of which apply work from one branch onto
756 another, and all of which do their work immediately without giving you
757 an opportunity to test the change first locally unless you give the
758 <tt>--no-commit</tt> option.
 
 
 
759
760 Fossil cannot sensibly work that way because of its default-enabled
761 autosync feature. Instead of jumping straight to the commit step, Fossil
 
 
 
762 applies the proposed merge to the local working directory only,
763 requiring a separate check-in step before the change is committed to the
764 repository. This gives you a chance to test the change first,
765 either manually or by running your software's automatic tests. (Ideally,
766 both!)
 
767
768 Another difference is that because Fossil requires an explicit commit
769 for a merge, it makes you give an explicit commit <i>message</i> for
770 each merge, whereas Git writes that commit message itself by default
771 unless you give the optional <tt>--edit</tt> flag to override it.
772
773 We don't look at this difference as a workaround in Fossil for autosync,
774 but instead as a test-first philosophical difference. When every commit
775 is pushed to the parent repo by default, it encourages a working style
776 in which every commit is tested first. We think this is an inherently
777 good thing.
 
778
779 Incidentally, this is a good example of Git's messy command design.
780 These three commands:
781
782 <pre>
783
--- www/fossil-v-git.wiki
+++ www/fossil-v-git.wiki
@@ -25,10 +25,13 @@
25 we try to be fair, the information here
26 might be biased in favor of Fossil, if only because we spend most of our
27 time using Fossil, not Git. Ask around for second opinions from
28 people who have used <em>both</em> Fossil and Git.
29
30 If you want a more practical, less philosophical guide to moving from
31 Git to Fossil, see our [./gitusers.md | Git to Fossil Translation Guide].
32
33
34 <h2>2.0 Differences Between Fossil And Git</h2>
35
36 Differences between Fossil and Git are summarized by the following table,
37 with further description in the text that follows.
@@ -645,21 +648,20 @@
648 standard advice is to use a switch-in-place workflow in Fossil when
649 the disturbance from switching branches is small, and to use multiple
650 checkouts when you have long-lived working branches that are different
651 enough that switching in place is disruptive.
652
653 While you can [./gitusers.md#worktree | use Git in the Fossil style],
654 Git's default tie between working directory and
 
 
655 repository means the standard method for working with a Git repo is to
656 have one working directory only. Most Git tutorials teach this style, so
657 it is how most people learn to use Git. Because relatively few people
658 use Git with multiple working directories per repository, there are
659 [https://duckduckgo.com/?q=git+worktree+problem | several known
660 problems] with that way of working, problems which don't happen in Fossil because of
661 the clear [./ckout-workflows.md | separation] between a Fossil repository and
662 each working directory.
663
664 This distinction matters because switching branches inside a single working directory loses local context
665 on each switch.
666
667 For instance, in any software project where the runnable program must be
@@ -695,13 +697,16 @@
697
698 <h3 id="history">2.7 What you should have done vs. What you actually did</h3>
699
700 Git puts a lot of emphasis on maintaining
701 a "clean" check-in history. Extraneous and experimental branches by
702 individual developers often never make it into the main repository.
703 Branches may be rebased before being pushed to make
704 it appear as if development had been linear, or "squashed" to make it
705 appear that multiple commits were made as a single commit.
706 There are [https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History |
707 other history rewriting mechanisms in Git] as well. Git strives to record what
708 the development of a project should have looked like had there been no
709 mistakes.
710
711 Fossil, in contrast, puts more emphasis on recording exactly what happened,
712 including all of the messy errors, dead-ends, experimental branches, and
@@ -714,69 +719,117 @@
719 Like Git, Fossil has an [/help?cmd=amend|amend command] for modifying
720 prior commits, but unlike in Git, this works not by replacing data in
721 the repository, but by adding a correction record to the repository that
722 affects how later Fossil operations present the corrected data. The old
723 information is still there in the repository, it is just overridden from
724 the amendment point forward.
725
726 Fossil lacks almost every other history rewriting mechanism listed on
727 the Git documentation page linked above. [./rebaseharm.md | There is no
728 rebase] in Fossil, on purpose, thus no way to reorder or copy commits
729 around in the commit hash tree. There is no commit squashing, dropping,
730 or interactive patch-based cherry-picking of commit elements in Fossil.
731 There is nothing like Git's <tt>filter-branch</tt> in Fossil.
732
733 The lone exception is deleting commits. Fossil has two methods for doing
734 that, both of which have stringent limitations, on purpose.
735
736 The first is [/doc/trunk/www/shunning.wiki | shunning]. See that
737 document for details, but briefly, you only get mandatory compliance
738 for shun requests within a single repository. Shun requests do not
739 propagate automatically between repository clones. A Fossil repository
740 administrator can <i>cooperatively</i> pull another repo's shun requests
741 across a sync boundary, so that two admins can get together and agree to
742 shun certain committed artifacts, but a person cannot force their local
743 shun requests into another repo without having admin-level control over
744 the receiving repo as well. Fossil's shun feature isn't for fixing up
745 everyday bad commits, it's for dealing with extreme situations: public
746 commits of secret material, ticket/wiki/forum spam, law enforcement
747 takedown demands, etc.
748
749 There is also the experimental [/help?cmd=purge | <tt>purge</tt>
750 command], which differs from shunning in ways that aren't especially
751 important in the context of this document. At a 30000 foot level, you
752 can think of purging as useful only when you've turned off Fossil's
753 autosync feature and want to pluck artifacts out of its hash tree before
754 they get pushed. In that sense, it's approximately the same as
755 <tt>git rebase -i, drop</tt>. However, given that Fossil defaults to
756 having autosync enabled [#devorg | for good reason], the purge command
757 isn't very useful in practice: once a commit has been pushed into
758 another repo, shunning is more useful if you need to delete it from
759 history.
760
761 If these accommodations strike you as incoherent with respect to
762 Fossil's philosophy of durable, unchanging commits, realize that if
763 shunning and purging were removed from Fossil, you could still remove
764 artifacts from the repository with SQL <tt>DELETE</tt> statements; the
765 repository database file is, after all, directly modifiable, being
766 writable by your user. Where the Fossil philosophy really takes hold is
767 in making it difficult to violate the integrity of the hash tree.
768 It's somewhat tangential, but the document [./blockchain.md | "Is Fossil
769 a Blockchain?"] touches on this and related topics.
770
771 One commentator characterized Git as recording history according to
772 the victors, whereas Fossil records history as it actually happened.
773
 
 
 
774
775 <h3 id="testing">2.8 Test Before Commit</h3>
776
777 One of the things that falls out of Git's default separation of commit
778 from push is that there are several Git sub-commands that jump straight
779 to the commit step before a change could possibly be tested. Fossil, by
780 contrast, makes the equivalent change to the local working check-out
781 only, requiring a separate check-in step to commit the change. This
782 design difference falls naturally out of Fossil's default-enabled
783 autosync feature and its philosophy of [#history | not offering history
784 rewriting features].
785
786 The prime example in Git is rebasing: the change happens to the local
787 repository immediately if successful, even though you haven't tested the
788 change yet. It's possible to argue for such a design in a tool like Git
789 since it lacks an autosync feature, because you can still test the
790 change before pushing local changes to the parent repo, but in the
791 meantime you've made a durable change to your local Git repository. You
792 must do something drastic like <tt>git reset --hard</tt> to revert that
793 rebase or rewrite history before pushing it if the rebase causes a
794 problem. If you push your rebased local repo up to the parent without
795 testing first, you cannot fix it without violating
 
796 [https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
797 | the golden rule of rebasing].
798
799 Lesser examples are the Git <tt>merge</tt>, <tt>cherry-pick</tt>, and
800 <tt>revert</tt> commands, all of which apply work from one branch onto
801 another, and all of which commit their change to the local repository
802 immediately without giving you
803 an opportunity to test the change first unless you give the
804 <tt>--no-commit</tt> option. Otherwise, you're back in the same boat:
805 reset the local repository or rewrite history to fix things, then maybe
806 retry.
807
808 Fossil cannot sensibly work that way because of its default-enabled
809 autosync feature and its purposeful paucity of commands for modifying
810 commits, as discussed in [#history | the prior section].
811
812 Instead of jumping straight to the commit step, Fossil
813 applies the proposed merge to the local working directory only,
814 requiring a separate check-in step before the change is committed to the
815 repository. This gives you a chance to test the change first,
816 either manually or by running your software's automatic tests. (Ideally,
817 both!) Thus, Fossil doesn't need rebase, squashing,
818 <tt>reset --hard</tt>, or other Git commit mutating mechanisms.
819
820 Because Fossil requires an explicit commit for a merge, it has the nice
821 side benefit that it makes you give an explicit commit <i>message</i>
822 for each merge, whereas Git writes that commit message itself by default
823 unless you give the optional <tt>--edit</tt> flag to override it.
824
825 We don't look at this difference as a workaround in Fossil for autosync,
826 but instead as a test-first philosophical difference:
827 <tt>fossil commit</tt> is a <i>commitment</i>. When every commit is
828 pushed to the parent repo by default, it encourages a working style in
829 which every commit is tested first. It encourages thinking before
830 acting. We believe this is an inherently good thing.
831
832 Incidentally, this is a good example of Git's messy command design.
833 These three commands:
834
835 <pre>
836
+705 -202
--- www/gitusers.md
+++ www/gitusers.md
@@ -1,187 +1,462 @@
1
-# Hints For Users With Prior Git Experience
2
-
3
-This document is a semi-random collection of hints intended to help
4
-new users of Fossil who have had prior exposure to Git. In other words,
5
-this document tries to describe the differences in how Fossil works
6
-from the perspective of Git users.
7
-
8
-
9
-## Help Improve This Document
10
-
11
-If you have a lot of prior Git experience, and you are new to Fossil
12
-and are struggling with some concepts, please ask for help on the
13
-[Fossil Forum][1]. The people who write this document are intimately
14
-familiar with Fossil and less familiar with Git. It is difficult for
15
-us to anticipate the perspective of people who are initimately familiar
16
-with Git and less familiar with Fossil. Asking questions on the Forum
17
-will help us to improve the document.
18
-
19
-[1]: https://fossil-scm.org/forum
20
-
21
-Specific suggestions on how to improve this document are also welcomed,
22
-of course.
23
-
24
-
25
-
26
-## <a id="term"></a> Terminology
1
+# Git to Fossil Translation Guide
2
+
3
+## Introduction
4
+
5
+This document attempts to provide equivalents for common Git commands
6
+and workflows where possible, and where not, to explain those cases.
7
+
8
+Although Fossil shares many similarities with Git, there are enough
9
+differences that we can’t provide a simple “translation dictionary” for
10
+some commands. This document is more concerned with those cases than the
11
+simple 1:1 mappings, which you can likely find on your own. In many
12
+cases, the sub-commands are identical: [`fossil bisect`][bis] does essentially
13
+the same thing as `git bisect`, for example.
14
+
15
+We present this from the perspective of Git users moving to Fossil, but
16
+it is also possible to read this document as a Fossil user who speaks
17
+only pidgin Git, who may often have questions of the form, “Now how do I
18
+do X in Git again?”
19
+
20
+This document’s authors are intimately familiar with Fossil, so it is
21
+difficult for us to anticipate the perspective of people who are
22
+intimately familiar with Git. If you have a lot of prior Git
23
+experience, we welcome your contributions and questions on the [Fossil
24
+Forum][ffor].
2725
2826
While we do try to explain Fossil-specific terminology inline here
2927
as-needed, you may find it helpful to skim [the Fossil glossary][gloss].
3028
It will give you another take on our definitions here, and it may help
3129
you to understand some of the other Fossil docs better.
3230
31
+We focus more on practical command examples here than on [the
32
+philosophical underpinnings][fvg] that drive these differences.
3333
-----
34
+[bis]: /help?cmd=bisect
35
+[ffor]: https://fossil-scm.org/forum
36
+[fvg]: ./fossil-v-git.wiki
3437
3538
3639
<a id="mwd"></a>
3740
## Repositories And Checkouts Are Distinct
3841
3942
A repository and a check-out are distinct concepts in Fossil, whereas
40
-the two are collocated by default with Git.
41
-
42
-A Fossil repository is a SQLite database storing
43
-the entire history of a project. A Fossil check-out is a
44
-directory that contains a snapshot of your project that you
45
-are currently working on, extracted for you from that database by the
46
-`fossil` program.
47
-
48
-With Git, cloning a repository gets you what Fossil would call a
49
-check-out directory with the repository stored in a `.git` subdirectory
50
-of that check-out. There are methods to get additional working directories
51
-pointing at that same Git repository, but because it’s not designed into
52
-the core concept of the tool, Git tutorials usually advocate a
53
-switch-in-place working mode instead, so that is how most users end up
54
-working with it.
55
-
56
-You can use Fossil the same way, switching between versions in a
57
-single check-out directory:
58
-
59
- fossil clone https://example.com/repo /path/to/repo.fossil
60
- mkdir work-dir
61
- cd work-dir
62
- fossil open /path/to/repo.fossil
63
- ...work on trunk...
64
- fossil update my-other-branch # like “git checkout”
65
- ...work on your other branch in the same directory...
66
-
67
-As of Fossil 2.12, you can ask it to clone-and-open into a single directory, as Git
68
-always has done:
69
-
70
- mkdir work-dir
71
- cd work-dir
72
- fossil open https://example.com/repo
73
-
74
-Now you have “trunk” open in `work-dir`, with the repo file stored as
75
-`repo.fossil` in that same directory.
76
-
77
-You may be expecting [`fossil clone`][clone] to create a directory for
78
-you like Git does, but because the repository is separate from the
79
-working directory, it does not do that, on purpose: you have to tell it
80
-where to store the repository file.
81
-
82
-The [`fossil open URI`][open] syntax is our compromise for users wanting
83
-a clone-and-open command. But, because Fossil’s `open` command
84
-historically opens into the current directory, and it won’t open a
85
-repository into a non-empty directory by default — as of Fossil 2.12,
86
-anyway — you have to create the directory manually and `cd` into it
87
-before opening it. If `fossil open URI` worked like `git clone`, that
88
-would mean `fossil open` has two different ways of working depending on
89
-the argument, which is a non-Fossil sort of thing to do. We strive for
90
-consistent behavior across commands and modes.
91
-
92
-The Fossil repository file can be named anything you want, with a single
93
-exception: if you’re going to use the [`fossil server DIRECTORY`][server]
94
-feature, the repositories need to have a "`.fossil`" suffix. That aside,
95
-you can follow any other convention that makes sense to you.
96
-
97
-Many Fossil users gather all of their Fossil repositories
98
-in a single directory on their machine, such as "`~/museum`" or
99
-"`C:\Fossils`". This can help humans to keep their repositories
100
-organized, but Fossil itself doesn't really care. (Why “museum”?
101
-Because that is where one stores valuable fossils.)
102
-
103
-Because Fossil cleanly separates the repository from the check-out, it
104
-is routine to have multiple check-outs from the same repository:
105
-
106
- mkdir -p ~/src/my-project/trunk
107
- cd ~/src/my-project/trunk
108
- fossil open /path/to/repo.fossil # implicitly opens “trunk”
109
- mkdir ../my-other-branch
110
- cd ../my-other-branch
111
- fossil open /path/to/repo.fossil my-other-branch
112
- mkdir ../release
113
- cd ../release
114
- fossil open /path/to/repo.fossil release
115
- mkdir ../scratch
116
- cd ../scratch
117
- fossil open /path/to/repo.fossil abcd1234
118
- mkdir ../test
119
- cd ../test
120
- fossil open /path/to/repo.fossil 2019-04-01
121
-
122
-Now you have five separate check-out directories: one each for trunk, an
123
-alternate branch you’re working on, the latest tagged public release, a
124
-“scratch” directory for experiments or brief bits of work you don’t want
125
-to do in the other check-out directories, and a directory for testing a
126
-user report of a bug in the trunk version as of last April Fool’s Day.
127
-Each check-out operates independently of the others.
128
-
129
-This multiple-checkouts working style is especially useful when Fossil stores source code in programming languages
130
-where there is a “build” step that transforms source files into files
131
-you actually run or distribute. With Git’s typical switch-in-place workflow,
132
-you have to rebuild all outputs from the source files
133
-that differ between those versions whenever you switch versions. In the above Fossil working model,
134
-you switch versions with a “`cd`” command instead, so that you only have
135
-to rebuild outputs from files you yourself change.
136
-
137
-This style is also useful when a check-out directory may be tied up with
138
-some long-running process, as with the “test” example above, where you
139
-might need to run an hours-long brute-force replication script to tickle
140
-a [Heisenbug][hb], forcing it to show itself. While that runs, you can
141
-open a new terminal tab, “`cd ../trunk`”, and get back
142
-to work.
143
-
144
-Git users may be initially confused by the `.fslckout` file at the root
145
-of a check-out directory.
146
-This is not the same thing as `.git`. It’s a per-checkout SQLite
43
+the two are collocated by default with Git. This difference shows up in
44
+several separate places when it comes to moving from Git to Fossil.
45
+
46
+
47
+
48
+#### <a id="cwork" name="scw"></a> Checkout Workflows
49
+
50
+A Fossil repository is a SQLite database storing the entire history of a
51
+project. It is not normally stored inside the working tree.
52
+A Fossil working tree — also called a check-out — is a directory
53
+that contains a snapshot of your project that you are currently working
54
+on, extracted for you from the repository database file by the `fossil`
55
+program.
56
+
57
+Git commingles these two by default, with the repository stored in a
58
+`.git` subdirectory underneath your working directory. There are ways to
59
+[emulate the Fossil working style in Git](#worktree), but because they’re not
60
+designed into the core concept of the tool, Git tutorials usually
61
+advocate a switch-in-place working mode instead, so that is how most
62
+users end up working with Git. Contrast [Fossil’s check-out workflow
63
+document][ckwf] to see the practical differences.
64
+
65
+There is one Git-specific detail we wish to add beyond what that
66
+document already covers. This command:
67
+
68
+ git checkout some-branch
69
+
70
+…is best given as:
71
+
72
+ fossil update some-branch
73
+
74
+…in Fossil. There is a `fossil checkout` command, but it has two
75
+restrictions that push you toward using `fossil update` instead:
76
+
77
+1. Several features in `fossil update` do not exist in
78
+ `fossil checkout`.
79
+
80
+2. The lone exception is `fossil checkout --keep`, a rarely-needed
81
+ operation.
82
+
83
+3. Fossil will have you typing “`fossil up`” frequently anyway to pull
84
+ remote changes and merge them into the local check-out directory.
85
+ Adding a `VERSION` string for the cases where you mean something
86
+ other than “tip of the current branch” is an easy habit to develop.
87
+
88
+Neither command is an alias for the other. They overlap enough that they
89
+can be used interchangeably for everyday use cases, but since `update`
90
+is more powerful, we recommend that you break the habit of typing
91
+`checkout`.
92
+
93
+[ckwf]: ./ckout-workflows.md
94
+
95
+
96
+#### <a id="rname"></a> Naming Repositories
97
+
98
+The Fossil repository database file can be named anything
99
+you want, with a single exception: if you’re going to use the
100
+[`fossil server DIRECTORY`][server] feature, the repositories you wish
101
+to serve need to be stored together in a flat directory and have
102
+"`.fossil`" suffixes. That aside, you can follow any other convention that
103
+makes sense to you.
104
+
105
+This author uses a scheme like the following on mobile machines that
106
+shuttle between home and the office:
107
+
108
+``` pikchr toggle indent
109
+box "~/museum/" fit
110
+move right 0.1
111
+line right dotted
112
+move right 0.05
113
+box invis "where one stores valuable fossils" ljust
114
+
115
+arrow down 50% from first box.s then right 50%
116
+box "work/" fit
117
+move right 0.1
118
+line dotted
119
+move right 0.05
120
+box invis "projects from $dayjob" ljust
121
+
122
+arrow down 50% from 2nd vertex of previous arrow then right 50%
123
+box "home/" fit
124
+move right 0.1
125
+line dotted right until even with previous line.end
126
+move right 0.05
127
+box invis "personal at-home projects" ljust
128
+
129
+arrow down 50% from 2nd vertex of previous arrow then right 50%
130
+box "other/" fit
131
+move right 0.1
132
+line dotted right until even with previous line.end
133
+move right 0.05
134
+box invis "clones of Fossil itself, SQLite, etc." ljust
135
+```
136
+
137
+On a Windows box, you might instead choose "`C:\Fossils`"
138
+and do without the subdirectory scheme, for example.
139
+
140
+
141
+#### <a id="close" name="dotfile"></a> Closing A Check-Out
142
+
143
+The [`fossil close`][close] command dissociates a check-out directory from the
144
+Fossil repository database, nondestructively inverting [`fossil open`][open]. It
145
+won’t remove the managed files, and unless you give the `--force`
146
+option, it won’t let you close the check-out with uncommitted changes to
147
+those managed files.
148
+
149
+The `close` command refuses to run without `--force` when you have
150
+certain precious per-checkout data, which Fossil stores in the
151
+`.fslckout` file at the root of a check-out directory. This is a SQLite
147152
database that keeps track of local state such as what version you have
148153
checked out, the contents of the [stash] for that working directory, the
149
-[undo] buffers, per-checkout [settings][set], and so forth. Largely what Fossil
150
-does when you ask it to [close] a check-out is to remove this file after
151
-making certain safety checks.
154
+[undo] buffers, per-checkout [settings][set], and so forth. The stash
155
+and undo buffers are considered precious uncommitted changes,
156
+so you have to force Fossil to discard these as part of closing the
157
+check-out.
152158
153
-(In native Windows builds of Fossil, this file is called `_FOSSIL_`
159
+Thus, `.fslckout` is not the same thing as `.git`!
160
+
161
+In native Windows builds of Fossil — that is, excluding Cygwin and WSL
162
+builds, which follow POSIX conventions — this file is called `_FOSSIL_`
154163
instead to get around the historical 3-character extension limit with
155
-certain legacy filesystems. “Native” here is a distinction to exclude
156
-Cygwin and WSL builds, which use `.fslckout`.)
164
+certain legacy filesystems.
165
+
166
+Closing a check-out directory is a rare operation. One use case
167
+is that you’re about to delete the directory, so you want Fossil to forget about it
168
+for the purposes of commands like [`fossil all`][all]. Even that isn’t
169
+necessary, because Fossil will detect that this has happened and forget
170
+the working directory for you.
171
+
172
+[all]: /help?cmd=all
173
+
174
+
175
+#### <a id="worktree"></a> Git Worktrees
176
+
177
+There are at least three different ways to get [Fossil-style multiple
178
+check-out directories][mcw] with Git.
179
+
180
+The old way is to simply symlink the `.git` directory between working
181
+trees:
182
+
183
+ mkdir ../foo-branch
184
+ ln -s ../actual-clone-dir/.git .
185
+ git checkout foo-branch
186
+
187
+The symlink trick has a number of problems, the largest being that
188
+symlinks weren’t available on Windows until Vista, and until the Windows
189
+10 Creators Update was released in spring of 2017, you had to be an
190
+Administrator to use the feature besides. ([Source][wsyml]) Git solved
191
+this problem two years earlier with the `git-worktree` command in Git
192
+2.5:
193
+
194
+ git worktree add ../foo-branch foo-branch
195
+ cd ../foo-branch
196
+
197
+That is approximately equivalent to this in Fossil:
198
+
199
+ mkdir ../foo-branch
200
+ fossil open /path/to/repo.fossil foo-branch
201
+
202
+That then leads us to the closest equivalent in Git to [closing a Fossil
203
+check-out](#close):
204
+
205
+ git worktree remove .
206
+
207
+Note, however, that unlike `fossil close`, once the Git command
208
+determines that there are no uncommitted changes, it blows away all of
209
+the checked-out files! Fossil’s alternative is shorter, easier to
210
+remember, and safer.
211
+
212
+There’s another way to get Fossil-like separate worktrees in Git:
213
+
214
+ git clone --separate-git-dir repo.git https://example.com/repo
215
+
216
+This allows you to have your Git repository directory entirely separate
217
+from your working tree, with `.git` in the check-out directory being a
218
+file that points to `../repo.git`, in this example.
219
+
220
+As of Fossil 2.14, there is a direct equivalent:
221
+
222
+ fossil clone https://example.com/repo
223
+
224
+It’s a shorter command because we deduce `repo.fossil` and the `repo/`
225
+working directory from the last element of the path in the URI. If you
226
+wanted to override both deductions, you’d say:
227
+
228
+ fossil clone --workdir foo https://example.com/repo/bar
229
+
230
+That gets you `bar.fossil` with a `foo/` working directory alongside it.
231
+
232
+[mcw]: ./ckout-workflows.md#mcw
233
+[wsyml]: https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
234
+
235
+
236
+#### <a id="iip"></a> Init In Place
237
+
238
+To illustrate the differences that Fossil’s separation of repository
239
+from working directory creates in practice, consider this common Git “init in place”
240
+method for creating a new repository from an existing tree of files,
241
+perhaps because you are placing that project under version control for
242
+the first time:
243
+
244
+ cd long-established-project
245
+ git init
246
+ git add *
247
+ git commit -m "Initial commit of project."
248
+
249
+The closest equivalent in Fossil is:
250
+
251
+ cd long-established-project
252
+ fossil init .fsl
253
+ fossil open --force .fsl
254
+ fossil add *
255
+ fossil ci -m "Initial commit of project."
256
+
257
+Note that unlike in Git, you can abbreviate the “`commit`” command in
258
+Fossil as “`ci`” for compatibility with CVS, Subversion, etc.
259
+
260
+This creates a `.fsl` repo DB at the root of the project check-out to
261
+emulate the `.git` repo dir. We have to use the `--force` flag on
262
+opening the new repo because Fossil expects you to open a repo into an
263
+empty directory in order to avoid spamming the contents of a repo over
264
+an existing directory full of files. Here, we know the directory
265
+contains files that will soon belong in the repository, though, so we
266
+override this check. From then on, Fossil works like Git, for the
267
+purposes of this example.
268
+
269
+We’ve drawn this example to create a tight parallel between Fossil and
270
+Git, not to commend this `.fsl`-at-project-root trick to you. A better
271
+choice would be `~/museum/home/long-established-project.fossil`, if
272
+you’re following [the directory scheme exemplified above](#rname). That said, it
273
+does emphasize an earlier point: Fossil doesn’t care where you put the
274
+repo DB file or what you name it.
275
+
157276
158277
[clone]: /help?cmd=clone
159278
[close]: /help?cmd=close
160279
[gloss]: ./whyusefossil.wiki#definitions
161
-[hb]: https://en.wikipedia.org/wiki/Heisenbug
162280
[open]: /help?cmd=open
163281
[set]: /help?cmd=setting
164282
[server]: /help?cmd=server
165283
[stash]: /help?cmd=stash
166284
[undo]: /help?cmd=undo
167285
168286
169
-## <a id="log"></a> Fossil’s Timeline is the “Log”
287
+## <a id="log"></a> Fossil’s Timeline Is The “Log”
170288
171
-Git users often need to use the `git log` command to grovel through
172
-commit histories due to its [weak data model][wdm].
289
+Git users often need to use the `git log` command to dig linearly through
290
+commit histories due to its [weak data model][wdm], giving [O(n)
291
+performance][ocomp].
173292
174293
Fossil parses a huge amount of information out of commits that allow it
175
-to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw],
176
-which generally have the info you would have to manually extract from
177
-`git log`.
294
+to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw]
295
+using indexed SQL lookups, which generally have the info you would have
296
+to manually extract from `git log`, produced much more quickly than Git
297
+can, all else being equal: operations over [SQLite’s B-tree data structures][btree]
298
+generally run in O(log n) time, faster than O(n) for equal *n* when the
299
+constants are equal. Yet the constants are *not* equal because Fossil
300
+reads from a single disk file rather than visit potentially many
301
+files in sequence as Git must, so the OS’s buffer cache can result in
302
+[still better performance][35pct].
178303
179
-[tlc]: /help?cmd=timeline
180
-[tlw]: /help?cmd=/timeline
181
-[wdm]: ./fossil-v-git.wiki#durable
304
+Unlike Git’s log, Fossil’s timeline shows info across branches by
305
+default, a feature for maintaining better situational awareness. The
306
+`fossil timeline` command has no way to show a single branch’s commits,
307
+but you can restrict your view like this using the web UI equivalent by
308
+clicking the name of a branch on the `/timeline` or `/brlist` page. (Or
309
+manually, by adding the `r=` query parameter.) Note that even in this
310
+case, the Fossil timeline still shows other branches where they interact
311
+with the one you’ve referenced in this way; again, better situational
312
+awareness.
313
+
314
+
315
+#### <a id="emu-log"></a> Emulating `git log`
316
+
317
+If you truly need a backwards-in-time-only view of history in Fossil to
318
+emulate `git log`, this is as close as you can currently come:
319
+
320
+ fossil timeline parents current
321
+
322
+Again, though, this isn’t restricted to a single branch, as `git log`
323
+is.
324
+
325
+Another useful rough equivalent is:
326
+
327
+ git log --raw
328
+ fossil time -v
329
+
330
+This shows what changed in each version, though Fossil’s view is more a
331
+summary than a list of raw changes. To dig deeper into single commits,
332
+you can use Fossil’s [`info` command][infoc] or its [`/info` view][infow].
333
+
334
+Inversely, you may more exactly emulate the default `fossil timeline`
335
+output with `git log --name-status`.
336
+
337
+
338
+#### <a id="whatchanged"></a> What Changed?
339
+
340
+A related — though deprecated — command is `git whatchanged`, which gives results similar to
341
+`git log --raw`, so we cover it here.
342
+
343
+Though there is no `fossil whatchanged` command, the same sort of
344
+information is available. For example, to pull the current changes from
345
+the remote repository and then inspect them before updating the local
346
+working directory, you might say this in Git:
347
+
348
+ git fetch
349
+ git whatchanged ..@{u}
350
+
351
+…which you can approximate in Fossil as:
352
+
353
+ fossil pull
354
+ fossil up -n
355
+ fossil diff --from tip
356
+
357
+To invert the `diff` to show a more natural patch, the command needs to
358
+be a bit more complicated, since you can’t currently give `--to`
359
+without `--from`.
360
+
361
+ fossil diff --from current --to tip
362
+
363
+Rather than use the “dry run” form of [the `update` command][up], you can
364
+say:
365
+
366
+ fossil timeline after current
367
+
368
+…or if you want to restrict the output to the current branch:
369
+
370
+ fossil timeline descendants current
371
+
372
+
373
+#### <a id="ckin-names"></a> Symbolic Check-In Names
374
+
375
+Note the use of [human-readable symbolic version names][scin] in Fossil
376
+rather than [Git’s cryptic notations][gcn].
377
+
378
+For a more dramatic example of this, let us ask Git, “What changed since the
379
+beginning of last month?” being October 2020 as I write this:
380
+
381
+ git log master@{2020-10-01}..HEAD
382
+
383
+That’s rather obscure! Fossil answers the same question with a simpler
384
+command:
385
+
386
+ fossil timeline after 2020-10-01
387
+
388
+You may need to add `-n 0` to bypass the default output limit of
389
+`fossil timeline`, 20 entries. Without that, this command reads
390
+almost like English.
391
+
392
+Some Git users like to write commands like the above so:
393
+
394
+ git log @{2020-10-01}..@
395
+
396
+Is that better? “@” now means two different things: an at-time reference
397
+and a shortcut for `HEAD`!
398
+
399
+If you are one of those that like short commands, Fossil’s method is
400
+less cryptic: it lets you shorten words in most cases up to the point
401
+that they become ambiguous. For example, you may abbreviate the last
402
+`fossil` command in the prior section:
403
+
404
+ fossil tim d c
405
+
406
+…beyond which the `timeline` command becomes ambiguous with `ticket`.
407
+
408
+Some Fossil users employ shell aliases, symlinks, or scripts to shorten
409
+the command still further:
410
+
411
+ alias f=fossil
412
+ f tim d c
413
+
414
+Granted, that’s rather obscure, but you you can also choose something
415
+intermediate like “`f time desc curr`”, which is reasonably clear.
416
+
417
+[35pct]: https://www.sqlite.org/fasterthanfs.html
418
+[btree]: https://sqlite.org/btreemodule.html
419
+[gcn]: https://git-scm.com/docs/gitrevisions
420
+[infoc]: /help?cmd=info
421
+[infow]: /help?cmd=/info
422
+[ocomp]: https://www.bigocheatsheet.com/
423
+[tlc]: /help?cmd=timeline
424
+[tlw]: /help?cmd=/timeline
425
+[up]: /help?cmd=update
426
+[wdm]: ./fossil-v-git.wiki#durable
427
+
428
+
429
+## <a id="dhead"></a> Detached HEAD State
430
+
431
+The SQL indexes in Fossil which we brought up above have a very useful
432
+side benefit: you cannot have a [detached HEAD state][gdh] in Fossil,
433
+the source of untold pain and data loss in Git. It simply cannot be done
434
+in Fossil, because the indexes always let us find our way back into the
435
+hash tree.
436
+
437
+
438
+## <a id="slcom"></a> Summary Line Convention In Commit Comments
439
+
440
+The Git convention of a [length-limited summary line][lsl] at the start
441
+of commit comments has no equivalent in Fossil. You’re welcome to style
442
+your commit comments thus, but the convention isn’t used or enforced
443
+anywhere in Fossil. For instance, setting `EDITOR=vim` and making a
444
+commit doesn’t do syntax highlighting on the commit message to warn that
445
+you’ve gone over the conventional limit on the first line, and the
446
+Fossil web timeline display doesn’t show the summary line in bold.
447
+
448
+If you wish to follow such conventions in a Fossil project, you may want
449
+to enable the “Allow block-markup in timeline” setting under Admin →
450
+Timeline in the web UI to prevent Fossil from showing the message as a
451
+single paragraph, sans line breaks. [Skin customization][cskin] would
452
+allow you to style the first line of the commit message in bold in
453
+`/timeline` views.
454
+
455
+[cskin]: ./customskin.md
456
+[lsl]: https://chris.beams.io/posts/git-commit/#limit-50
457
+
182458
183459
184460
<a id="staging"></a>
185461
## There Is No Staging Area
186462
@@ -192,35 +467,40 @@
192467
If you only want to commit _some_ of the changes, list the names
193468
of the files or directories you want to commit as arguments, like this:
194469
195470
fossil commit src/feature.c doc/feature.md examples/feature
196471
472
+There are currently no interactive patching features in Fossil like
473
+`git add --patch/-p` or `git commit -p`. [Contributions welcome!][ctrb]
474
+
475
+[ctrb]: https://fossil-scm.org/fossil/doc/trunk/www/contribute.wiki
476
+
197477
198478
<a id="bneed"></a>
199479
## Create Branches At Point Of Need, Rather Than Ahead of Need
200480
201481
Fossil prefers that you create new branches as part of the first commit
202482
on that branch:
203483
204
- fossil commit --branch my-new-branch
484
+ fossil commit --branch my-new-branch
205485
206486
If that commit is successful, your local check-out directory is then
207487
switched to the tip of that branch, so subsequent commits don’t need the
208488
“`--branch`” option. You simply say `fossil commit` again to continue
209489
adding commits to the tip of that branch.
210490
211491
To switch back to the parent branch, say something like:
212492
213
- fossil update trunk # like “git checkout”
493
+ fossil update trunk # ≅ git checkout master
214494
215495
Fossil does also support the Git style, creating the branch ahead of
216496
need:
217497
218
- fossil branch new my-new-branch
219
- fossil update my-new-branch
220
- ...work on first commit...
221
- fossil commit
498
+ fossil branch new my-new-branch
499
+ fossil update my-new-branch
500
+ ...work on first commit...
501
+ fossil commit
222502
223503
This is more verbose, but it has the same effect: put the first commit
224504
onto `my-new-branch` and switch the check-out directory to that branch so
225505
subsequent commits are descendants of that initial branch commit.
226506
@@ -228,13 +508,14 @@
228508
*after* you commit it, using the "`fossil amend`" command.
229509
For example:
230510
231511
fossil amend current --branch my-new-branch
232512
233
-(“current” is one of the [special check-in names][scin] in Fossil. See
513
+(The version string “current” is one of the [special check-in names][scin] in Fossil. See
234514
that document for the many other names you can give to “`amend`”, or
235
-indeed to any other Fossil command that accepts a “version” string.)
515
+indeed to any other Fossil command documented to accept a `VERSION` or
516
+`NAME` string.)
236517
237518
[scin]: ./checkin_names.wiki
238519
239520
240521
<a id="autosync"></a>
@@ -264,11 +545,11 @@
264545
2. It provides immediate off-machine backup of your commits. Unlike
265546
centralized version control, though, you can still work while
266547
disconnected; your changes will sync up with the remote once you get
267548
back online.
268549
269
-3. Because there is little distinction betwen the clones in the Fossil
550
+3. Because there is little distinction between the clones in the Fossil
270551
model — unlike in Git, where clones often quickly diverge from each
271552
other, quite possibly on purpose — the backup advantage applies in inverse
272553
as well: if the remote server falls over dead, one of those with a
273554
clone of that repository can stand it back up, and everyone can get
274555
back to work simply by re-pointing their local repo at the new
@@ -285,44 +566,49 @@
285566
286567
<a id="syncall"></a>
287568
## Sync Is All-Or-Nothing
288569
289570
Fossil does not support the concept of syncing, pushing, or pulling
290
-individual branches. When you sync/push/pull in Fossil, you
291
-sync/push/pull everything stored as artifacts in its hash tree:
571
+individual branches. When you sync/push/pull in Fossil, it
572
+processes all artifacts in its hash tree:
292573
branches, tags, wiki articles, tickets, forum posts, technotes…
293
-[Almost everything][bu].
574
+This is [not quite “everything,” full stop][bu], but it’s close.
294575
295576
Furthermore, branch *names* sync automatically in Fossil, not just the
296
-content of those branches. This means this common Git command:
577
+content of those branches. That means this common Git command:
297578
298579
git push origin master
299580
300
-is simply this in Fossil:
581
+…is simply this in Fossil:
301582
302583
fossil push
303584
304585
Fossil doesn’t need to be told what to push or where to push it: it just
305
-keeps using the same remote server URL and branch name you gave it last,
306
-until you tell it to do something different.
586
+keeps using the same remote server URL you gave it last
587
+until you [tell it to do something different][rem], and it pushes all
588
+branches, not just one named local branch.
589
+
590
+[rem]: /help?cmd=remote
307591
308592
309593
<a id="trunk"></a>
310594
## The Main Branch Is Called "`trunk`"
311595
312
-In Fossil, the traditional name and the default name for the main branch
596
+In Fossil, the default name for the main branch
313597
is "`trunk`". The "`trunk`" branch in Fossil corresponds to the
314
-"`master`" branch in stock Git or the "`main`" branch in GitHub.
598
+"`master`" branch in stock Git or to [the “`main`” branch in GitHub][mbgh].
315599
316600
Because the `fossil git export` command has to work with both stock Git
317
-and with GitHub, Fossil uses Git’s default: your Fossil repo’s “trunk”
318
-branch becomes “master” on GitHub, not “main,” as in new GitHub repos.
319
-It is not known what happens on subsequent exports if you
320
-[later rename it][ghmain].
601
+and with GitHub, Fossil uses Git’s traditional default rather than
602
+GitHub’s new default: your Fossil repo’s “trunk” branch becomes “master”
603
+when [mirroring to GitHub][mirgh], not “main.”
321604
322
-[6]: ./mirrortogithub.md
323
-[ghmain]: https://github.com/github/renaming
605
+We do not know what happens on subsequent exports if you later rename
606
+this branch on the GitHub side.
607
+
608
+[mbgh]: https://github.com/github/renaming
609
+[mirgh]: ./mirrortogithub.md
324610
325611
326612
<a id="unmanaged"></a>
327613
## The "`fossil status`" Command Does Not Show Unmanaged Files
328614
@@ -348,30 +634,106 @@
348634
come up with a new objection that we haven’t already considered and
349635
addressed there.
350636
351637
[3]: ./rebaseharm.md
352638
639
+
640
+## <a id="show"></a> Showing Information About Commits
641
+
642
+While there is no direct equivalent to Git’s “`show`” command, similar
643
+functionality may be present in Fossil under other commands:
644
+
645
+
646
+#### <a name="patch"></a> Show A Patch For A Commit
647
+
648
+ git show -p COMMIT_ID
649
+
650
+…gives much the same output as
651
+
652
+ fossil diff --checkin COMMIT_ID
653
+
654
+…only without the patch email header. Git comes out of the [LKML] world,
655
+where emailing a patch is a normal thing to do. Fossil is [designed for
656
+cohesive teams][devorg] where such drive-by patches are rarer.
657
+
658
+You can use any of [Fossil’s special check-in names][scin] in place of
659
+the `COMMIT_ID` in this and later examples. Fossil docs usually say
660
+“`VERSION`” or “`NAME`” where this is allowed, since the version string
661
+or name might not refer to a commit ID, but instead to a forum post, a
662
+wiki document, etc. The following command answers the question “What did
663
+I just commit?”
664
+
665
+ fossil diff --checkin tip
666
+
667
+[devorg]: ./fossil-v-git.wiki#devorg
668
+[LKML]: https://lkml.org/
669
+
670
+
671
+#### <a name="cmsg"></a> Show A Specific Commit Message
672
+
673
+ git show -s COMMIT_ID
674
+
675
+
676
+…is
677
+
678
+ fossil time -n 1 COMMIT_ID
679
+
680
+…or with a shorter, more obvious command, though with more verbose output:
681
+
682
+ fossil info COMMIT_ID
683
+
684
+The `fossil info` command isn’t otherwise a good equivalent to
685
+`git show`; it just overlaps its functionality in some areas. Much of
686
+what’s missing is present in the corresponding [`/info` web
687
+view][infow], though.
688
+
689
+
690
+#### <a name="dstat"></a> Diff Statistics
691
+
692
+Fossil doesn’t have an internal equivalent to commands like
693
+`git show --stat`, but it’s easily remedied by using
694
+[the widely-available `diffstat` tool][dst]:
695
+
696
+ fossil diff -i --from 2020-04-01 | diffstat
697
+
698
+We gave the `-i` flag here to force Fossil to use its internal diff
699
+implementation, bypassing [your local `diff-command` setting][dcset].
700
+If you had that set to [`colordiff`][cdiff], for example, its output
701
+would confuse `diffstat`.
702
+
703
+[cdiff]: https://www.colordiff.org/
704
+[dcset]: https://fossil-scm.org/home/help?cmd=diff-command
705
+[dst]: https://invisible-island.net/diffstat/diffstat.html
706
+
353707
354708
<a id="btnames"></a>
355
-## Branch and Tag Names
709
+## Branch And Tag Names
356710
357711
Fossil has no special restrictions on the names of tags and branches,
358
-though you might want to keep [Git's tag and branch name restrictions][4]
359
-in mind if you plan on mirroring your Fossil repository to GitHub.
360
-
361
-[4]: https://git-scm.com/docs/git-check-ref-format
712
+though you might want to keep [Git's tag and branch name restrictions][gcrf]
713
+in mind if you plan on [mirroring your Fossil repository to GitHub][mirgh].
362714
363715
Fossil does not require tag and branch names to be unique. It is
364716
common, for example, to put a "`release`" tag on every release for a
365717
Fossil-hosted project. This does not create a conflict in Fossil, since
366
-Fossil resolves such conflicts in a predictable way: the newest match
718
+Fossil resolves the ambiguity in a predictable way: the newest match
367719
wins. Therefore, “`fossil up release`” always gets you the current
368720
release in a project that uses this tagging convention.
369721
722
+[The `fossil git export` command][fge] squashes repeated tags down to a
723
+single instance to avoid confusing Git, exporting only the newest tag,
724
+emulating Fossil’s own ambiguity resolution rule as best it can within
725
+Git’s limitations.
726
+
727
+[fge]: /help?cmd=git
728
+[gcrf]: https://git-scm.com/docs/git-check-ref-format
729
+
730
+
731
+
370732
371733
<a id="cpickrev"></a>
372
-## Cherry-Picking and Reverting Commits
734
+## Cherry-Picking And Reverting Commits
373735
374736
Git’s separate "`git cherry-pick`" and “`git revert`” commands are
375737
options to the [`fossil merge` command][merge]: `--cherrypick` and
376738
`--backout`, respectively.
377739
@@ -390,35 +752,175 @@
390752
default: they do not actually rename or delete the files in your
391753
check-out.
392754
393755
If you don’t like that default, you can change it globally:
394756
395
- fossil setting --global mv-rm-files 1
757
+ fossil setting --global mv-rm-files 1
396758
397759
Now these commands behave like in Git in any Fossil repository where
398760
this setting hasn’t been overridden locally.
399761
400762
If you want to keep Fossil’s soft `mv/rm` behavior most of the time, you
401763
can cast it away on a per-command basis:
402764
403
- fossil mv --hard old-name new-name
765
+ fossil mv --hard old-name new-name
404766
405767
[mv]: /help?cmd=mv
406768
[rm]: /help?cmd=rm
407769
408770
409771
----
410772
411773
412
-<a id="morigin"></a>
413
-## Multiple "origin" Servers
414
-
415
-In this final section of the document, we’ll go into a lot more detail
416
-to illustrate the points above, not just give a quick summary of this
417
-single difference.
418
-
419
-Consider a common use case at the time of this writing — during the
774
+## <a id="cvdate" name="cs1"></a> Case Study 1: Checking Out A Version By Date
775
+
776
+Let’s get into something a bit more complicated: a case study showing
777
+how the concepts lined out above cause Fossil to materially differ in
778
+day-to-day operation from Git.
779
+
780
+Why would you want to check out a version of a project by date? Perhaps
781
+because your customer gave you a vague bug report referencing only a
782
+date rather than a version. Or, you may be poking semi-randomly through
783
+history to find a “good” version to anchor the start point of a
784
+[`bisect`][bis] operation.
785
+
786
+My search engine’s first result for “git checkout by date” is [this
787
+highly-upvoted accepted Stack Overflow answer][gcod]. The first command
788
+it gives is based on Git’s [`rev-parse` feature][grp]:
789
+
790
+ git checkout master@{2020-03-17}
791
+
792
+There are a number of weaknesses in this command. From least to most
793
+critical:
794
+
795
+1. It’s a bit cryptic. Leave off the refname or punctuation, and it
796
+ means something else. You cannot simplify the cryptic incantation in
797
+ the typical use case.
798
+
799
+2. A date string in Git without a time will be interpreted as
800
+ “[at localtime on that date][gapxd],” so the command means something
801
+ different from one second to the next! If there are multiple commits
802
+ on that date, that command can give different results depending on
803
+ the time of day you run it.
804
+
805
+3. It gives misleading output if there is no close match for the date
806
+ in target commit in the local [reflog]. On a fresh clone, the reflog
807
+ is empty, and even on a well-established clone, Git [automatically
808
+ prunes][gle] the reflog to 90 days of history by default. This means
809
+ the command above can give different results from one machine to the
810
+ next, or even from one day to the next on the same clone.
811
+
812
+ The command won’t fail outright if the reflog can’t resolve the
813
+ given date: it simply gives the closest commit it can come up with,
814
+ even if it’s months or years out from your target! Sometimes it
815
+ gives a warning about the reflog not going back far enough to give a
816
+ useful result, and sometimes it doesn’t. If you’re on a fresh clone,
817
+ you are likely to get the “tip” commit’s revision ID no matter what
818
+ date value you give.
819
+
820
+ Git tries its best, but because it’s working from a purgeable and
821
+ possibly-stale local cache, you cannot trust its results.
822
+
823
+We cannot recommend this command at all. It’s unreliable even in the
824
+best case.
825
+
826
+That same Stack Overflow answer therefore goes on to recommend an
827
+entirely different command:
828
+
829
+ git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)
830
+
831
+We believe you get such answers to Git help requests in part
832
+because of its lack of an always-up-to-date [index into its log](#log) and in
833
+part because of its “small tools loosely joined” design philosophy. This
834
+sort of command is therefore composed piece by piece:
835
+
836
+<center>◆  ◆  ◆</center>
837
+
838
+“Oh, I know, I’ll search the rev-list, which outputs commit IDs by
839
+parsing the log backwards from `HEAD`! Easy!”
840
+
841
+ git rev-list --before=2020-03-17
842
+
843
+“Blast! Forgot the commit ID!”
844
+
845
+ git rev-list --before=2020-03-17 master
846
+
847
+“Double blast! It just spammed my terminal with revision IDs! I need to
848
+limit it to the single closest match:
849
+
850
+ git rev-list -n 1 --before=2020-03-17 master
851
+
852
+“Okay, it gives me a single revision ID now, but is it what I’m after?
853
+Let’s take a look…”
854
+
855
+ git show $(git rev-list -n 1 --before=2020-03-17 master)
856
+
857
+“Oops, that’s giving me a merge commit, not what I want.
858
+Off to search the web… Okay, it says I need to give either the
859
+`--first-parent` or `--no-merges` flag to show only regular commits,
860
+not merge-commits. Let’s try the first one:”
861
+
862
+ git show $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
863
+
864
+“Better. Let’s check it out:”
865
+
866
+ git checkout $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
867
+
868
+“Success, I guess?”
869
+
870
+<center>◆  ◆  ◆</center>
871
+
872
+This vignette is meant to explain some of Git’s popularity: it rewards
873
+the sort of people who enjoy puzzles, many of whom are software
874
+developers and thus need a tool like Git. Too bad if you’re just a
875
+normal user.
876
+
877
+And too bad if you’re a Windows user who doesn’t want to use [Git
878
+Bash][gbash], since neither of the stock OS command shells have a
879
+command interpolation feature needed to run that horrid command.
880
+
881
+This alternative command still has weakness #2 above: if you run the
882
+second `git show` command above on [Git’s own repository][gitgh], your
883
+results may vary because there were four non-merge commits to Git on the
884
+17th of March, 2020.
885
+
886
+You may be asking with an exasperated huff, “What is your *point*, man?”
887
+The point is that the equivalent in Fossil is simply:
888
+
889
+ fossil up 2020-03-17
890
+
891
+…which will *always* give the commit closest to midnight UTC on the 17th
892
+of March, 2020, no matter whether you do it on a fresh clone or a stale
893
+one. The answer won’t shift about from one clone to the next or from
894
+one local time of day to the next. We owe this reliability and stability
895
+to three Fossil design choices:
896
+
897
+* Parse timestamps from all commits on clone into a local commit index,
898
+ then maintain that index through subsequent commits and syncs.
899
+
900
+* Use an indexed SQL `ORDER BY` query to match timestamps to commit
901
+ IDs for a fast and consistent result.
902
+
903
+* Round timestamp strings up using [rules][frud] consistent across
904
+ computers and local time of day.
905
+
906
+[frud]: https://fossil-scm.org/home/file/src/name.c?ci=d2a59b03727bc3&ln=122-141
907
+[gbash]: https://appuals.com/what-is-git-bash/
908
+[gapxd]: https://github.com/git/git/blob/7f7ebe054a/date.c#L1298-L1300
909
+[gcod]: https://stackoverflow.com/a/6990682/142454
910
+[gdh]: https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit/
911
+[gitgh]: https://github.com/git/git/
912
+[gle]: https://git-scm.com/docs/git-reflog#_options_for_expire
913
+[gmc]: https://github.com/git/git/commit/67b0a24910fbb23c8f5e7a2c61c339818bc68296
914
+[grp]: https://git-scm.com/docs/git-rev-parse
915
+[reflog]: https://git-scm.com/docs/git-reflog
916
+
917
+----
918
+
919
+## <a id="morigin" name="cs2"></a> Case Study 2: Multiple "origin" Servers
920
+
921
+Now let us consider a common use case at the time of this writing — during the
420922
COVID-19 pandemic — where you’re working from home a lot, going into the
421923
office one part-day a week only to do things that have to be done
422924
on-site at the office. Let us also say you have no remote
423925
access back into the work LAN, such as because your site IT is paranoid
424926
about security. You may still want off-machine backups of your commits
@@ -448,20 +950,20 @@
448950
449951
ssh my-nas.local 'git init --bare /SHARES/dayjob/repo.git'
450952
git push --all ssh://my-nas.local//SHARES/dayjob/repo.git
451953
452954
Realize that this is carefully optimized down to these two long
453
-commands. In practice, typing these commands by hand, from memory, we’d
454
-expect a normal user to need to give four or more commands here instead.
955
+commands. In practice, we’d expect a user typing these commands by hand from memory
956
+to need to give four or more commands here instead.
455957
Packing the “`git init`” call into the “`ssh`” call is something more
456958
often done in scripts and documentation examples than done interactively,
457959
which then necessitates a third command before the push, “`exit`”.
458960
There’s also a good chance that you’ll forget the need for the `--bare`
459961
option here to avoid a fatal complaint from Git that the laptop can’t
460962
push into a non-empty repo. If you fall into this trap, among the many
461963
that Git lays for newbies, you have to nuke the incorrectly initted
462
-repo, search the web and docs to find out about `--bare`, and try again.
964
+repo, search the web or Git man pages to find out about `--bare`, and try again.
463965
464966
Having navigated that little minefield,
465967
we can tell Git that there is a second origin, a “home” repo in
466968
addition to the named “work” repo we set up earlier:
467969
@@ -469,11 +971,11 @@
469971
git config master.remote home
470972
471973
We don’t have to push or pull because the remote repo is a complete
472974
clone of the repo on the laptop at this point, so we can just get to
473975
work now, committing along the way to get our work safely off-machine
474
-and onto the NAS, like so:
976
+and onto our home NAS, like so:
475977
476978
git add
477979
git commit
478980
git push
479981
@@ -493,38 +995,38 @@
493995
that when returning home, you’d have to manually reset the upstream
494996
again.
495997
496998
This example also shows a consequence of that fact that
497999
[Git doesn’t sync branch names](#syncall): you have to keep repeating
498
-yourself, “master, master.”
1000
+yourself like an obsequious supplicant: “Master, master.” Didn’t we
1001
+invent computers to serve humans, rather than the other way around?
4991002
5001003
5011004
#### Fossil Method
5021005
503
-Now we’re going to do the same thing as above using Fossil. We’ve broken
504
-the commands up into blocks corresponding to those above for comparison.
1006
+Now we’re going to do the same thing using Fossil, with
1007
+the commands arranged in blocks corresponding to those above for comparison.
5051008
5061009
We start the same way, cloning the work repo down to the laptop:
5071010
508
- mkdir repo
1011
+ fossil clone https://dev-server.example.com/repo
5091012
cd repo
510
- fossil open https://dev-server.example.com/repo
5111013
fossil remote add work https://dev-server.example.com/repo
5121014
513
-We’ve chosen the “`fossil open URI`” syntax here rather than separate
1015
+We’ve chosen the new “`fossil clone URI`” syntax added in Fossil 2.14 rather than separate
5141016
`clone` and `open` commands to make the parallel with Git clearer. [See
5151017
above](#mwd) for more on that topic.
5161018
517
-The final command is longer than the Git equivalent because
1019
+Our [`remote` command][rem] is longer than the Git equivalent because
5181020
Fossil currently has no short command
5191021
to rename an existing remote. Worse, unlike with Git, we can’t just keep
5201022
using the default remote name because Fossil uses that slot in its
5211023
configuration database to store the *current* remote name, so on
5221024
switching from work to home, the home URL will overwrite the work URL if
5231025
we don’t give it an explicit name first.
5241026
525
-So far, the Fossil commands are longer, but keep these costs in perspective:
1027
+Although the Fossil commands are longer, so far, keep it in perspective:
5261028
they’re one-time setup costs,
5271029
easily amortized to insignificance by the shorter day-to-day commands
5281030
below.
5291031
5301032
On first beginning to work from home, we reverse-clone the Fossil repo
5311033
--- www/gitusers.md
+++ www/gitusers.md
@@ -1,187 +1,462 @@
1 # Hints For Users With Prior Git Experience
2
3 This document is a semi-random collection of hints intended to help
4 new users of Fossil who have had prior exposure to Git. In other words,
5 this document tries to describe the differences in how Fossil works
6 from the perspective of Git users.
7
8
9 ## Help Improve This Document
10
11 If you have a lot of prior Git experience, and you are new to Fossil
12 and are struggling with some concepts, please ask for help on the
13 [Fossil Forum][1]. The people who write this document are intimately
14 familiar with Fossil and less familiar with Git. It is difficult for
15 us to anticipate the perspective of people who are initimately familiar
16 with Git and less familiar with Fossil. Asking questions on the Forum
17 will help us to improve the document.
18
19 [1]: https://fossil-scm.org/forum
20
21 Specific suggestions on how to improve this document are also welcomed,
22 of course.
23
24
25
26 ## <a id="term"></a> Terminology
27
28 While we do try to explain Fossil-specific terminology inline here
29 as-needed, you may find it helpful to skim [the Fossil glossary][gloss].
30 It will give you another take on our definitions here, and it may help
31 you to understand some of the other Fossil docs better.
32
 
 
33
-----
 
 
 
34
35
36 <a id="mwd"></a>
37 ## Repositories And Checkouts Are Distinct
38
39 A repository and a check-out are distinct concepts in Fossil, whereas
40 the two are collocated by default with Git.
41
42 A Fossil repository is a SQLite database storing
43 the entire history of a project. A Fossil check-out is a
44 directory that contains a snapshot of your project that you
45 are currently working on, extracted for you from that database by the
46 `fossil` program.
47
48 With Git, cloning a repository gets you what Fossil would call a
49 check-out directory with the repository stored in a `.git` subdirectory
50 of that check-out. There are methods to get additional working directories
51 pointing at that same Git repository, but because it’s not designed into
52 the core concept of the tool, Git tutorials usually advocate a
53 switch-in-place working mode instead, so that is how most users end up
54 working with it.
55
56 You can use Fossil the same way, switching between versions in a
57 single check-out directory:
58
59 fossil clone https://example.com/repo /path/to/repo.fossil
60 mkdir work-dir
61 cd work-dir
62 fossil open /path/to/repo.fossil
63 ...work on trunk...
64 fossil update my-other-branch # like “git checkout”
65 ...work on your other branch in the same directory...
66
67 As of Fossil 2.12, you can ask it to clone-and-open into a single directory, as Git
68 always has done:
69
70 mkdir work-dir
71 cd work-dir
72 fossil open https://example.com/repo
73
74 Now you have “trunk” open in `work-dir`, with the repo file stored as
75 `repo.fossil` in that same directory.
76
77 You may be expecting [`fossil clone`][clone] to create a directory for
78 you like Git does, but because the repository is separate from the
79 working directory, it does not do that, on purpose: you have to tell it
80 where to store the repository file.
81
82 The [`fossil open URI`][open] syntax is our compromise for users wanting
83 a clone-and-open command. But, because Fossil’s `open` command
84 historically opens into the current directory, and it won’t open a
85 repository into a non-empty directory by default — as of Fossil 2.12,
86 anyway — you have to create the directory manually and `cd` into it
87 before opening it. If `fossil open URI` worked like `git clone`, that
88 would mean `fossil open` has two different ways of working depending on
89 the argument, which is a non-Fossil sort of thing to do. We strive for
90 consistent behavior across commands and modes.
91
92 The Fossil repository file can be named anything you want, with a single
93 exception: if you’re going to use the [`fossil server DIRECTORY`][server]
94 feature, the repositories need to have a "`.fossil`" suffix. That aside,
95 you can follow any other convention that makes sense to you.
96
97 Many Fossil users gather all of their Fossil repositories
98 in a single directory on their machine, such as "`~/museum`" or
99 "`C:\Fossils`". This can help humans to keep their repositories
100 organized, but Fossil itself doesn't really care. (Why “museum”?
101 Because that is where one stores valuable fossils.)
102
103 Because Fossil cleanly separates the repository from the check-out, it
104 is routine to have multiple check-outs from the same repository:
105
106 mkdir -p ~/src/my-project/trunk
107 cd ~/src/my-project/trunk
108 fossil open /path/to/repo.fossil # implicitly opens “trunk”
109 mkdir ../my-other-branch
110 cd ../my-other-branch
111 fossil open /path/to/repo.fossil my-other-branch
112 mkdir ../release
113 cd ../release
114 fossil open /path/to/repo.fossil release
115 mkdir ../scratch
116 cd ../scratch
117 fossil open /path/to/repo.fossil abcd1234
118 mkdir ../test
119 cd ../test
120 fossil open /path/to/repo.fossil 2019-04-01
121
122 Now you have five separate check-out directories: one each for trunk, an
123 alternate branch you’re working on, the latest tagged public release, a
124 “scratch” directory for experiments or brief bits of work you don’t want
125 to do in the other check-out directories, and a directory for testing a
126 user report of a bug in the trunk version as of last April Fool’s Day.
127 Each check-out operates independently of the others.
128
129 This multiple-checkouts working style is especially useful when Fossil stores source code in programming languages
130 where there is a “build” step that transforms source files into files
131 you actually run or distribute. With Git’s typical switch-in-place workflow,
132 you have to rebuild all outputs from the source files
133 that differ between those versions whenever you switch versions. In the above Fossil working model,
134 you switch versions with a “`cd`” command instead, so that you only have
135 to rebuild outputs from files you yourself change.
136
137 This style is also useful when a check-out directory may be tied up with
138 some long-running process, as with the “test” example above, where you
139 might need to run an hours-long brute-force replication script to tickle
140 a [Heisenbug][hb], forcing it to show itself. While that runs, you can
141 open a new terminal tab, “`cd ../trunk`”, and get back
142 to work.
143
144 Git users may be initially confused by the `.fslckout` file at the root
145 of a check-out directory.
146 This is not the same thing as `.git`. It’s a per-checkout SQLite
 
 
147 database that keeps track of local state such as what version you have
148 checked out, the contents of the [stash] for that working directory, the
149 [undo] buffers, per-checkout [settings][set], and so forth. Largely what Fossil
150 does when you ask it to [close] a check-out is to remove this file after
151 making certain safety checks.
 
152
153 (In native Windows builds of Fossil, this file is called `_FOSSIL_`
 
 
 
154 instead to get around the historical 3-character extension limit with
155 certain legacy filesystems. “Native” here is a distinction to exclude
156 Cygwin and WSL builds, which use `.fslckout`.)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
158 [clone]: /help?cmd=clone
159 [close]: /help?cmd=close
160 [gloss]: ./whyusefossil.wiki#definitions
161 [hb]: https://en.wikipedia.org/wiki/Heisenbug
162 [open]: /help?cmd=open
163 [set]: /help?cmd=setting
164 [server]: /help?cmd=server
165 [stash]: /help?cmd=stash
166 [undo]: /help?cmd=undo
167
168
169 ## <a id="log"></a> Fossil’s Timeline is the “Log”
170
171 Git users often need to use the `git log` command to grovel through
172 commit histories due to its [weak data model][wdm].
 
173
174 Fossil parses a huge amount of information out of commits that allow it
175 to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw],
176 which generally have the info you would have to manually extract from
177 `git log`.
 
 
 
 
 
 
178
179 [tlc]: /help?cmd=timeline
180 [tlw]: /help?cmd=/timeline
181 [wdm]: ./fossil-v-git.wiki#durable
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
183
184 <a id="staging"></a>
185 ## There Is No Staging Area
186
@@ -192,35 +467,40 @@
192 If you only want to commit _some_ of the changes, list the names
193 of the files or directories you want to commit as arguments, like this:
194
195 fossil commit src/feature.c doc/feature.md examples/feature
196
 
 
 
 
 
197
198 <a id="bneed"></a>
199 ## Create Branches At Point Of Need, Rather Than Ahead of Need
200
201 Fossil prefers that you create new branches as part of the first commit
202 on that branch:
203
204 fossil commit --branch my-new-branch
205
206 If that commit is successful, your local check-out directory is then
207 switched to the tip of that branch, so subsequent commits don’t need the
208 “`--branch`” option. You simply say `fossil commit` again to continue
209 adding commits to the tip of that branch.
210
211 To switch back to the parent branch, say something like:
212
213 fossil update trunk # like “git checkout”
214
215 Fossil does also support the Git style, creating the branch ahead of
216 need:
217
218 fossil branch new my-new-branch
219 fossil update my-new-branch
220 ...work on first commit...
221 fossil commit
222
223 This is more verbose, but it has the same effect: put the first commit
224 onto `my-new-branch` and switch the check-out directory to that branch so
225 subsequent commits are descendants of that initial branch commit.
226
@@ -228,13 +508,14 @@
228 *after* you commit it, using the "`fossil amend`" command.
229 For example:
230
231 fossil amend current --branch my-new-branch
232
233 (“current” is one of the [special check-in names][scin] in Fossil. See
234 that document for the many other names you can give to “`amend`”, or
235 indeed to any other Fossil command that accepts a “version” string.)
 
236
237 [scin]: ./checkin_names.wiki
238
239
240 <a id="autosync"></a>
@@ -264,11 +545,11 @@
264 2. It provides immediate off-machine backup of your commits. Unlike
265 centralized version control, though, you can still work while
266 disconnected; your changes will sync up with the remote once you get
267 back online.
268
269 3. Because there is little distinction betwen the clones in the Fossil
270 model — unlike in Git, where clones often quickly diverge from each
271 other, quite possibly on purpose — the backup advantage applies in inverse
272 as well: if the remote server falls over dead, one of those with a
273 clone of that repository can stand it back up, and everyone can get
274 back to work simply by re-pointing their local repo at the new
@@ -285,44 +566,49 @@
285
286 <a id="syncall"></a>
287 ## Sync Is All-Or-Nothing
288
289 Fossil does not support the concept of syncing, pushing, or pulling
290 individual branches. When you sync/push/pull in Fossil, you
291 sync/push/pull everything stored as artifacts in its hash tree:
292 branches, tags, wiki articles, tickets, forum posts, technotes…
293 [Almost everything][bu].
294
295 Furthermore, branch *names* sync automatically in Fossil, not just the
296 content of those branches. This means this common Git command:
297
298 git push origin master
299
300 is simply this in Fossil:
301
302 fossil push
303
304 Fossil doesn’t need to be told what to push or where to push it: it just
305 keeps using the same remote server URL and branch name you gave it last,
306 until you tell it to do something different.
 
 
 
307
308
309 <a id="trunk"></a>
310 ## The Main Branch Is Called "`trunk`"
311
312 In Fossil, the traditional name and the default name for the main branch
313 is "`trunk`". The "`trunk`" branch in Fossil corresponds to the
314 "`master`" branch in stock Git or the "`main`" branch in GitHub.
315
316 Because the `fossil git export` command has to work with both stock Git
317 and with GitHub, Fossil uses Git’s default: your Fossil repo’s “trunk”
318 branch becomes “master” on GitHub, not “main,” as in new GitHub repos.
319 It is not known what happens on subsequent exports if you
320 [later rename it][ghmain].
321
322 [6]: ./mirrortogithub.md
323 [ghmain]: https://github.com/github/renaming
 
 
 
324
325
326 <a id="unmanaged"></a>
327 ## The "`fossil status`" Command Does Not Show Unmanaged Files
328
@@ -348,30 +634,106 @@
348 come up with a new objection that we haven’t already considered and
349 addressed there.
350
351 [3]: ./rebaseharm.md
352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
354 <a id="btnames"></a>
355 ## Branch and Tag Names
356
357 Fossil has no special restrictions on the names of tags and branches,
358 though you might want to keep [Git's tag and branch name restrictions][4]
359 in mind if you plan on mirroring your Fossil repository to GitHub.
360
361 [4]: https://git-scm.com/docs/git-check-ref-format
362
363 Fossil does not require tag and branch names to be unique. It is
364 common, for example, to put a "`release`" tag on every release for a
365 Fossil-hosted project. This does not create a conflict in Fossil, since
366 Fossil resolves such conflicts in a predictable way: the newest match
367 wins. Therefore, “`fossil up release`” always gets you the current
368 release in a project that uses this tagging convention.
369
 
 
 
 
 
 
 
 
 
 
370
371 <a id="cpickrev"></a>
372 ## Cherry-Picking and Reverting Commits
373
374 Git’s separate "`git cherry-pick`" and “`git revert`” commands are
375 options to the [`fossil merge` command][merge]: `--cherrypick` and
376 `--backout`, respectively.
377
@@ -390,35 +752,175 @@
390 default: they do not actually rename or delete the files in your
391 check-out.
392
393 If you don’t like that default, you can change it globally:
394
395 fossil setting --global mv-rm-files 1
396
397 Now these commands behave like in Git in any Fossil repository where
398 this setting hasn’t been overridden locally.
399
400 If you want to keep Fossil’s soft `mv/rm` behavior most of the time, you
401 can cast it away on a per-command basis:
402
403 fossil mv --hard old-name new-name
404
405 [mv]: /help?cmd=mv
406 [rm]: /help?cmd=rm
407
408
409 ----
410
411
412 <a id="morigin"></a>
413 ## Multiple "origin" Servers
414
415 In this final section of the document, we’ll go into a lot more detail
416 to illustrate the points above, not just give a quick summary of this
417 single difference.
418
419 Consider a common use case at the time of this writing — during the
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420 COVID-19 pandemic — where you’re working from home a lot, going into the
421 office one part-day a week only to do things that have to be done
422 on-site at the office. Let us also say you have no remote
423 access back into the work LAN, such as because your site IT is paranoid
424 about security. You may still want off-machine backups of your commits
@@ -448,20 +950,20 @@
448
449 ssh my-nas.local 'git init --bare /SHARES/dayjob/repo.git'
450 git push --all ssh://my-nas.local//SHARES/dayjob/repo.git
451
452 Realize that this is carefully optimized down to these two long
453 commands. In practice, typing these commands by hand, from memory, we’d
454 expect a normal user to need to give four or more commands here instead.
455 Packing the “`git init`” call into the “`ssh`” call is something more
456 often done in scripts and documentation examples than done interactively,
457 which then necessitates a third command before the push, “`exit`”.
458 There’s also a good chance that you’ll forget the need for the `--bare`
459 option here to avoid a fatal complaint from Git that the laptop can’t
460 push into a non-empty repo. If you fall into this trap, among the many
461 that Git lays for newbies, you have to nuke the incorrectly initted
462 repo, search the web and docs to find out about `--bare`, and try again.
463
464 Having navigated that little minefield,
465 we can tell Git that there is a second origin, a “home” repo in
466 addition to the named “work” repo we set up earlier:
467
@@ -469,11 +971,11 @@
469 git config master.remote home
470
471 We don’t have to push or pull because the remote repo is a complete
472 clone of the repo on the laptop at this point, so we can just get to
473 work now, committing along the way to get our work safely off-machine
474 and onto the NAS, like so:
475
476 git add
477 git commit
478 git push
479
@@ -493,38 +995,38 @@
493 that when returning home, you’d have to manually reset the upstream
494 again.
495
496 This example also shows a consequence of that fact that
497 [Git doesn’t sync branch names](#syncall): you have to keep repeating
498 yourself, “master, master.”
 
499
500
501 #### Fossil Method
502
503 Now we’re going to do the same thing as above using Fossil. We’ve broken
504 the commands up into blocks corresponding to those above for comparison.
505
506 We start the same way, cloning the work repo down to the laptop:
507
508 mkdir repo
509 cd repo
510 fossil open https://dev-server.example.com/repo
511 fossil remote add work https://dev-server.example.com/repo
512
513 We’ve chosen the “`fossil open URI`” syntax here rather than separate
514 `clone` and `open` commands to make the parallel with Git clearer. [See
515 above](#mwd) for more on that topic.
516
517 The final command is longer than the Git equivalent because
518 Fossil currently has no short command
519 to rename an existing remote. Worse, unlike with Git, we can’t just keep
520 using the default remote name because Fossil uses that slot in its
521 configuration database to store the *current* remote name, so on
522 switching from work to home, the home URL will overwrite the work URL if
523 we don’t give it an explicit name first.
524
525 So far, the Fossil commands are longer, but keep these costs in perspective:
526 they’re one-time setup costs,
527 easily amortized to insignificance by the shorter day-to-day commands
528 below.
529
530 On first beginning to work from home, we reverse-clone the Fossil repo
531
--- www/gitusers.md
+++ www/gitusers.md
@@ -1,187 +1,462 @@
1 # Git to Fossil Translation Guide
2
3 ## Introduction
4
5 This document attempts to provide equivalents for common Git commands
6 and workflows where possible, and where not, to explain those cases.
7
8 Although Fossil shares many similarities with Git, there are enough
9 differences that we can’t provide a simple “translation dictionary” for
10 some commands. This document is more concerned with those cases than the
11 simple 1:1 mappings, which you can likely find on your own. In many
12 cases, the sub-commands are identical: [`fossil bisect`][bis] does essentially
13 the same thing as `git bisect`, for example.
14
15 We present this from the perspective of Git users moving to Fossil, but
16 it is also possible to read this document as a Fossil user who speaks
17 only pidgin Git, who may often have questions of the form, “Now how do I
18 do X in Git again?”
19
20 This document’s authors are intimately familiar with Fossil, so it is
21 difficult for us to anticipate the perspective of people who are
22 intimately familiar with Git. If you have a lot of prior Git
23 experience, we welcome your contributions and questions on the [Fossil
24 Forum][ffor].
 
 
25
26 While we do try to explain Fossil-specific terminology inline here
27 as-needed, you may find it helpful to skim [the Fossil glossary][gloss].
28 It will give you another take on our definitions here, and it may help
29 you to understand some of the other Fossil docs better.
30
31 We focus more on practical command examples here than on [the
32 philosophical underpinnings][fvg] that drive these differences.
33
-----
34 [bis]: /help?cmd=bisect
35 [ffor]: https://fossil-scm.org/forum
36 [fvg]: ./fossil-v-git.wiki
37
38
39 <a id="mwd"></a>
40 ## Repositories And Checkouts Are Distinct
41
42 A repository and a check-out are distinct concepts in Fossil, whereas
43 the two are collocated by default with Git. This difference shows up in
44 several separate places when it comes to moving from Git to Fossil.
45
46
47
48 #### <a id="cwork" name="scw"></a> Checkout Workflows
49
50 A Fossil repository is a SQLite database storing the entire history of a
51 project. It is not normally stored inside the working tree.
52 A Fossil working tree — also called a check-out — is a directory
53 that contains a snapshot of your project that you are currently working
54 on, extracted for you from the repository database file by the `fossil`
55 program.
56
57 Git commingles these two by default, with the repository stored in a
58 `.git` subdirectory underneath your working directory. There are ways to
59 [emulate the Fossil working style in Git](#worktree), but because they’re not
60 designed into the core concept of the tool, Git tutorials usually
61 advocate a switch-in-place working mode instead, so that is how most
62 users end up working with Git. Contrast [Fossil’s check-out workflow
63 document][ckwf] to see the practical differences.
64
65 There is one Git-specific detail we wish to add beyond what that
66 document already covers. This command:
67
68 git checkout some-branch
69
70 …is best given as:
71
72 fossil update some-branch
73
74 …in Fossil. There is a `fossil checkout` command, but it has two
75 restrictions that push you toward using `fossil update` instead:
76
77 1. Several features in `fossil update` do not exist in
78 `fossil checkout`.
79
80 2. The lone exception is `fossil checkout --keep`, a rarely-needed
81 operation.
82
83 3. Fossil will have you typing “`fossil up`” frequently anyway to pull
84 remote changes and merge them into the local check-out directory.
85 Adding a `VERSION` string for the cases where you mean something
86 other than “tip of the current branch” is an easy habit to develop.
87
88 Neither command is an alias for the other. They overlap enough that they
89 can be used interchangeably for everyday use cases, but since `update`
90 is more powerful, we recommend that you break the habit of typing
91 `checkout`.
92
93 [ckwf]: ./ckout-workflows.md
94
95
96 #### <a id="rname"></a> Naming Repositories
97
98 The Fossil repository database file can be named anything
99 you want, with a single exception: if you’re going to use the
100 [`fossil server DIRECTORY`][server] feature, the repositories you wish
101 to serve need to be stored together in a flat directory and have
102 "`.fossil`" suffixes. That aside, you can follow any other convention that
103 makes sense to you.
104
105 This author uses a scheme like the following on mobile machines that
106 shuttle between home and the office:
107
108 ``` pikchr toggle indent
109 box "~/museum/" fit
110 move right 0.1
111 line right dotted
112 move right 0.05
113 box invis "where one stores valuable fossils" ljust
114
115 arrow down 50% from first box.s then right 50%
116 box "work/" fit
117 move right 0.1
118 line dotted
119 move right 0.05
120 box invis "projects from $dayjob" ljust
121
122 arrow down 50% from 2nd vertex of previous arrow then right 50%
123 box "home/" fit
124 move right 0.1
125 line dotted right until even with previous line.end
126 move right 0.05
127 box invis "personal at-home projects" ljust
128
129 arrow down 50% from 2nd vertex of previous arrow then right 50%
130 box "other/" fit
131 move right 0.1
132 line dotted right until even with previous line.end
133 move right 0.05
134 box invis "clones of Fossil itself, SQLite, etc." ljust
135 ```
136
137 On a Windows box, you might instead choose "`C:\Fossils`"
138 and do without the subdirectory scheme, for example.
139
140
141 #### <a id="close" name="dotfile"></a> Closing A Check-Out
142
143 The [`fossil close`][close] command dissociates a check-out directory from the
144 Fossil repository database, nondestructively inverting [`fossil open`][open]. It
145 won’t remove the managed files, and unless you give the `--force`
146 option, it won’t let you close the check-out with uncommitted changes to
147 those managed files.
148
149 The `close` command refuses to run without `--force` when you have
150 certain precious per-checkout data, which Fossil stores in the
151 `.fslckout` file at the root of a check-out directory. This is a SQLite
152 database that keeps track of local state such as what version you have
153 checked out, the contents of the [stash] for that working directory, the
154 [undo] buffers, per-checkout [settings][set], and so forth. The stash
155 and undo buffers are considered precious uncommitted changes,
156 so you have to force Fossil to discard these as part of closing the
157 check-out.
158
159 Thus, `.fslckout` is not the same thing as `.git`!
160
161 In native Windows builds of Fossil — that is, excluding Cygwin and WSL
162 builds, which follow POSIX conventions — this file is called `_FOSSIL_`
163 instead to get around the historical 3-character extension limit with
164 certain legacy filesystems.
165
166 Closing a check-out directory is a rare operation. One use case
167 is that you’re about to delete the directory, so you want Fossil to forget about it
168 for the purposes of commands like [`fossil all`][all]. Even that isn’t
169 necessary, because Fossil will detect that this has happened and forget
170 the working directory for you.
171
172 [all]: /help?cmd=all
173
174
175 #### <a id="worktree"></a> Git Worktrees
176
177 There are at least three different ways to get [Fossil-style multiple
178 check-out directories][mcw] with Git.
179
180 The old way is to simply symlink the `.git` directory between working
181 trees:
182
183 mkdir ../foo-branch
184 ln -s ../actual-clone-dir/.git .
185 git checkout foo-branch
186
187 The symlink trick has a number of problems, the largest being that
188 symlinks weren’t available on Windows until Vista, and until the Windows
189 10 Creators Update was released in spring of 2017, you had to be an
190 Administrator to use the feature besides. ([Source][wsyml]) Git solved
191 this problem two years earlier with the `git-worktree` command in Git
192 2.5:
193
194 git worktree add ../foo-branch foo-branch
195 cd ../foo-branch
196
197 That is approximately equivalent to this in Fossil:
198
199 mkdir ../foo-branch
200 fossil open /path/to/repo.fossil foo-branch
201
202 That then leads us to the closest equivalent in Git to [closing a Fossil
203 check-out](#close):
204
205 git worktree remove .
206
207 Note, however, that unlike `fossil close`, once the Git command
208 determines that there are no uncommitted changes, it blows away all of
209 the checked-out files! Fossil’s alternative is shorter, easier to
210 remember, and safer.
211
212 There’s another way to get Fossil-like separate worktrees in Git:
213
214 git clone --separate-git-dir repo.git https://example.com/repo
215
216 This allows you to have your Git repository directory entirely separate
217 from your working tree, with `.git` in the check-out directory being a
218 file that points to `../repo.git`, in this example.
219
220 As of Fossil 2.14, there is a direct equivalent:
221
222 fossil clone https://example.com/repo
223
224 It’s a shorter command because we deduce `repo.fossil` and the `repo/`
225 working directory from the last element of the path in the URI. If you
226 wanted to override both deductions, you’d say:
227
228 fossil clone --workdir foo https://example.com/repo/bar
229
230 That gets you `bar.fossil` with a `foo/` working directory alongside it.
231
232 [mcw]: ./ckout-workflows.md#mcw
233 [wsyml]: https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
234
235
236 #### <a id="iip"></a> Init In Place
237
238 To illustrate the differences that Fossil’s separation of repository
239 from working directory creates in practice, consider this common Git “init in place”
240 method for creating a new repository from an existing tree of files,
241 perhaps because you are placing that project under version control for
242 the first time:
243
244 cd long-established-project
245 git init
246 git add *
247 git commit -m "Initial commit of project."
248
249 The closest equivalent in Fossil is:
250
251 cd long-established-project
252 fossil init .fsl
253 fossil open --force .fsl
254 fossil add *
255 fossil ci -m "Initial commit of project."
256
257 Note that unlike in Git, you can abbreviate the “`commit`” command in
258 Fossil as “`ci`” for compatibility with CVS, Subversion, etc.
259
260 This creates a `.fsl` repo DB at the root of the project check-out to
261 emulate the `.git` repo dir. We have to use the `--force` flag on
262 opening the new repo because Fossil expects you to open a repo into an
263 empty directory in order to avoid spamming the contents of a repo over
264 an existing directory full of files. Here, we know the directory
265 contains files that will soon belong in the repository, though, so we
266 override this check. From then on, Fossil works like Git, for the
267 purposes of this example.
268
269 We’ve drawn this example to create a tight parallel between Fossil and
270 Git, not to commend this `.fsl`-at-project-root trick to you. A better
271 choice would be `~/museum/home/long-established-project.fossil`, if
272 you’re following [the directory scheme exemplified above](#rname). That said, it
273 does emphasize an earlier point: Fossil doesn’t care where you put the
274 repo DB file or what you name it.
275
276
277 [clone]: /help?cmd=clone
278 [close]: /help?cmd=close
279 [gloss]: ./whyusefossil.wiki#definitions
 
280 [open]: /help?cmd=open
281 [set]: /help?cmd=setting
282 [server]: /help?cmd=server
283 [stash]: /help?cmd=stash
284 [undo]: /help?cmd=undo
285
286
287 ## <a id="log"></a> Fossil’s Timeline Is The “Log”
288
289 Git users often need to use the `git log` command to dig linearly through
290 commit histories due to its [weak data model][wdm], giving [O(n)
291 performance][ocomp].
292
293 Fossil parses a huge amount of information out of commits that allow it
294 to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw]
295 using indexed SQL lookups, which generally have the info you would have
296 to manually extract from `git log`, produced much more quickly than Git
297 can, all else being equal: operations over [SQLite’s B-tree data structures][btree]
298 generally run in O(log n) time, faster than O(n) for equal *n* when the
299 constants are equal. Yet the constants are *not* equal because Fossil
300 reads from a single disk file rather than visit potentially many
301 files in sequence as Git must, so the OS’s buffer cache can result in
302 [still better performance][35pct].
303
304 Unlike Git’s log, Fossil’s timeline shows info across branches by
305 default, a feature for maintaining better situational awareness. The
306 `fossil timeline` command has no way to show a single branch’s commits,
307 but you can restrict your view like this using the web UI equivalent by
308 clicking the name of a branch on the `/timeline` or `/brlist` page. (Or
309 manually, by adding the `r=` query parameter.) Note that even in this
310 case, the Fossil timeline still shows other branches where they interact
311 with the one you’ve referenced in this way; again, better situational
312 awareness.
313
314
315 #### <a id="emu-log"></a> Emulating `git log`
316
317 If you truly need a backwards-in-time-only view of history in Fossil to
318 emulate `git log`, this is as close as you can currently come:
319
320 fossil timeline parents current
321
322 Again, though, this isn’t restricted to a single branch, as `git log`
323 is.
324
325 Another useful rough equivalent is:
326
327 git log --raw
328 fossil time -v
329
330 This shows what changed in each version, though Fossil’s view is more a
331 summary than a list of raw changes. To dig deeper into single commits,
332 you can use Fossil’s [`info` command][infoc] or its [`/info` view][infow].
333
334 Inversely, you may more exactly emulate the default `fossil timeline`
335 output with `git log --name-status`.
336
337
338 #### <a id="whatchanged"></a> What Changed?
339
340 A related — though deprecated — command is `git whatchanged`, which gives results similar to
341 `git log --raw`, so we cover it here.
342
343 Though there is no `fossil whatchanged` command, the same sort of
344 information is available. For example, to pull the current changes from
345 the remote repository and then inspect them before updating the local
346 working directory, you might say this in Git:
347
348 git fetch
349 git whatchanged ..@{u}
350
351 …which you can approximate in Fossil as:
352
353 fossil pull
354 fossil up -n
355 fossil diff --from tip
356
357 To invert the `diff` to show a more natural patch, the command needs to
358 be a bit more complicated, since you can’t currently give `--to`
359 without `--from`.
360
361 fossil diff --from current --to tip
362
363 Rather than use the “dry run” form of [the `update` command][up], you can
364 say:
365
366 fossil timeline after current
367
368 …or if you want to restrict the output to the current branch:
369
370 fossil timeline descendants current
371
372
373 #### <a id="ckin-names"></a> Symbolic Check-In Names
374
375 Note the use of [human-readable symbolic version names][scin] in Fossil
376 rather than [Git’s cryptic notations][gcn].
377
378 For a more dramatic example of this, let us ask Git, “What changed since the
379 beginning of last month?” being October 2020 as I write this:
380
381 git log master@{2020-10-01}..HEAD
382
383 That’s rather obscure! Fossil answers the same question with a simpler
384 command:
385
386 fossil timeline after 2020-10-01
387
388 You may need to add `-n 0` to bypass the default output limit of
389 `fossil timeline`, 20 entries. Without that, this command reads
390 almost like English.
391
392 Some Git users like to write commands like the above so:
393
394 git log @{2020-10-01}..@
395
396 Is that better? “@” now means two different things: an at-time reference
397 and a shortcut for `HEAD`!
398
399 If you are one of those that like short commands, Fossil’s method is
400 less cryptic: it lets you shorten words in most cases up to the point
401 that they become ambiguous. For example, you may abbreviate the last
402 `fossil` command in the prior section:
403
404 fossil tim d c
405
406 …beyond which the `timeline` command becomes ambiguous with `ticket`.
407
408 Some Fossil users employ shell aliases, symlinks, or scripts to shorten
409 the command still further:
410
411 alias f=fossil
412 f tim d c
413
414 Granted, that’s rather obscure, but you you can also choose something
415 intermediate like “`f time desc curr`”, which is reasonably clear.
416
417 [35pct]: https://www.sqlite.org/fasterthanfs.html
418 [btree]: https://sqlite.org/btreemodule.html
419 [gcn]: https://git-scm.com/docs/gitrevisions
420 [infoc]: /help?cmd=info
421 [infow]: /help?cmd=/info
422 [ocomp]: https://www.bigocheatsheet.com/
423 [tlc]: /help?cmd=timeline
424 [tlw]: /help?cmd=/timeline
425 [up]: /help?cmd=update
426 [wdm]: ./fossil-v-git.wiki#durable
427
428
429 ## <a id="dhead"></a> Detached HEAD State
430
431 The SQL indexes in Fossil which we brought up above have a very useful
432 side benefit: you cannot have a [detached HEAD state][gdh] in Fossil,
433 the source of untold pain and data loss in Git. It simply cannot be done
434 in Fossil, because the indexes always let us find our way back into the
435 hash tree.
436
437
438 ## <a id="slcom"></a> Summary Line Convention In Commit Comments
439
440 The Git convention of a [length-limited summary line][lsl] at the start
441 of commit comments has no equivalent in Fossil. You’re welcome to style
442 your commit comments thus, but the convention isn’t used or enforced
443 anywhere in Fossil. For instance, setting `EDITOR=vim` and making a
444 commit doesn’t do syntax highlighting on the commit message to warn that
445 you’ve gone over the conventional limit on the first line, and the
446 Fossil web timeline display doesn’t show the summary line in bold.
447
448 If you wish to follow such conventions in a Fossil project, you may want
449 to enable the “Allow block-markup in timeline” setting under Admin →
450 Timeline in the web UI to prevent Fossil from showing the message as a
451 single paragraph, sans line breaks. [Skin customization][cskin] would
452 allow you to style the first line of the commit message in bold in
453 `/timeline` views.
454
455 [cskin]: ./customskin.md
456 [lsl]: https://chris.beams.io/posts/git-commit/#limit-50
457
458
459
460 <a id="staging"></a>
461 ## There Is No Staging Area
462
@@ -192,35 +467,40 @@
467 If you only want to commit _some_ of the changes, list the names
468 of the files or directories you want to commit as arguments, like this:
469
470 fossil commit src/feature.c doc/feature.md examples/feature
471
472 There are currently no interactive patching features in Fossil like
473 `git add --patch/-p` or `git commit -p`. [Contributions welcome!][ctrb]
474
475 [ctrb]: https://fossil-scm.org/fossil/doc/trunk/www/contribute.wiki
476
477
478 <a id="bneed"></a>
479 ## Create Branches At Point Of Need, Rather Than Ahead of Need
480
481 Fossil prefers that you create new branches as part of the first commit
482 on that branch:
483
484 fossil commit --branch my-new-branch
485
486 If that commit is successful, your local check-out directory is then
487 switched to the tip of that branch, so subsequent commits don’t need the
488 “`--branch`” option. You simply say `fossil commit` again to continue
489 adding commits to the tip of that branch.
490
491 To switch back to the parent branch, say something like:
492
493 fossil update trunk # ≅ git checkout master
494
495 Fossil does also support the Git style, creating the branch ahead of
496 need:
497
498 fossil branch new my-new-branch
499 fossil update my-new-branch
500 ...work on first commit...
501 fossil commit
502
503 This is more verbose, but it has the same effect: put the first commit
504 onto `my-new-branch` and switch the check-out directory to that branch so
505 subsequent commits are descendants of that initial branch commit.
506
@@ -228,13 +508,14 @@
508 *after* you commit it, using the "`fossil amend`" command.
509 For example:
510
511 fossil amend current --branch my-new-branch
512
513 (The version string “current” is one of the [special check-in names][scin] in Fossil. See
514 that document for the many other names you can give to “`amend`”, or
515 indeed to any other Fossil command documented to accept a `VERSION` or
516 `NAME` string.)
517
518 [scin]: ./checkin_names.wiki
519
520
521 <a id="autosync"></a>
@@ -264,11 +545,11 @@
545 2. It provides immediate off-machine backup of your commits. Unlike
546 centralized version control, though, you can still work while
547 disconnected; your changes will sync up with the remote once you get
548 back online.
549
550 3. Because there is little distinction between the clones in the Fossil
551 model — unlike in Git, where clones often quickly diverge from each
552 other, quite possibly on purpose — the backup advantage applies in inverse
553 as well: if the remote server falls over dead, one of those with a
554 clone of that repository can stand it back up, and everyone can get
555 back to work simply by re-pointing their local repo at the new
@@ -285,44 +566,49 @@
566
567 <a id="syncall"></a>
568 ## Sync Is All-Or-Nothing
569
570 Fossil does not support the concept of syncing, pushing, or pulling
571 individual branches. When you sync/push/pull in Fossil, it
572 processes all artifacts in its hash tree:
573 branches, tags, wiki articles, tickets, forum posts, technotes…
574 This is [not quite “everything,” full stop][bu], but it’s close.
575
576 Furthermore, branch *names* sync automatically in Fossil, not just the
577 content of those branches. That means this common Git command:
578
579 git push origin master
580
581 …is simply this in Fossil:
582
583 fossil push
584
585 Fossil doesn’t need to be told what to push or where to push it: it just
586 keeps using the same remote server URL you gave it last
587 until you [tell it to do something different][rem], and it pushes all
588 branches, not just one named local branch.
589
590 [rem]: /help?cmd=remote
591
592
593 <a id="trunk"></a>
594 ## The Main Branch Is Called "`trunk`"
595
596 In Fossil, the default name for the main branch
597 is "`trunk`". The "`trunk`" branch in Fossil corresponds to the
598 "`master`" branch in stock Git or to [the “`main`” branch in GitHub][mbgh].
599
600 Because the `fossil git export` command has to work with both stock Git
601 and with GitHub, Fossil uses Git’s traditional default rather than
602 GitHub’s new default: your Fossil repo’s “trunk” branch becomes “master”
603 when [mirroring to GitHub][mirgh], not “main.”
 
604
605 We do not know what happens on subsequent exports if you later rename
606 this branch on the GitHub side.
607
608 [mbgh]: https://github.com/github/renaming
609 [mirgh]: ./mirrortogithub.md
610
611
612 <a id="unmanaged"></a>
613 ## The "`fossil status`" Command Does Not Show Unmanaged Files
614
@@ -348,30 +634,106 @@
634 come up with a new objection that we haven’t already considered and
635 addressed there.
636
637 [3]: ./rebaseharm.md
638
639
640 ## <a id="show"></a> Showing Information About Commits
641
642 While there is no direct equivalent to Git’s “`show`” command, similar
643 functionality may be present in Fossil under other commands:
644
645
646 #### <a name="patch"></a> Show A Patch For A Commit
647
648 git show -p COMMIT_ID
649
650 …gives much the same output as
651
652 fossil diff --checkin COMMIT_ID
653
654 …only without the patch email header. Git comes out of the [LKML] world,
655 where emailing a patch is a normal thing to do. Fossil is [designed for
656 cohesive teams][devorg] where such drive-by patches are rarer.
657
658 You can use any of [Fossil’s special check-in names][scin] in place of
659 the `COMMIT_ID` in this and later examples. Fossil docs usually say
660 “`VERSION`” or “`NAME`” where this is allowed, since the version string
661 or name might not refer to a commit ID, but instead to a forum post, a
662 wiki document, etc. The following command answers the question “What did
663 I just commit?”
664
665 fossil diff --checkin tip
666
667 [devorg]: ./fossil-v-git.wiki#devorg
668 [LKML]: https://lkml.org/
669
670
671 #### <a name="cmsg"></a> Show A Specific Commit Message
672
673 git show -s COMMIT_ID
674
675
676 …is
677
678 fossil time -n 1 COMMIT_ID
679
680 …or with a shorter, more obvious command, though with more verbose output:
681
682 fossil info COMMIT_ID
683
684 The `fossil info` command isn’t otherwise a good equivalent to
685 `git show`; it just overlaps its functionality in some areas. Much of
686 what’s missing is present in the corresponding [`/info` web
687 view][infow], though.
688
689
690 #### <a name="dstat"></a> Diff Statistics
691
692 Fossil doesn’t have an internal equivalent to commands like
693 `git show --stat`, but it’s easily remedied by using
694 [the widely-available `diffstat` tool][dst]:
695
696 fossil diff -i --from 2020-04-01 | diffstat
697
698 We gave the `-i` flag here to force Fossil to use its internal diff
699 implementation, bypassing [your local `diff-command` setting][dcset].
700 If you had that set to [`colordiff`][cdiff], for example, its output
701 would confuse `diffstat`.
702
703 [cdiff]: https://www.colordiff.org/
704 [dcset]: https://fossil-scm.org/home/help?cmd=diff-command
705 [dst]: https://invisible-island.net/diffstat/diffstat.html
706
707
708 <a id="btnames"></a>
709 ## Branch And Tag Names
710
711 Fossil has no special restrictions on the names of tags and branches,
712 though you might want to keep [Git's tag and branch name restrictions][gcrf]
713 in mind if you plan on [mirroring your Fossil repository to GitHub][mirgh].
 
 
714
715 Fossil does not require tag and branch names to be unique. It is
716 common, for example, to put a "`release`" tag on every release for a
717 Fossil-hosted project. This does not create a conflict in Fossil, since
718 Fossil resolves the ambiguity in a predictable way: the newest match
719 wins. Therefore, “`fossil up release`” always gets you the current
720 release in a project that uses this tagging convention.
721
722 [The `fossil git export` command][fge] squashes repeated tags down to a
723 single instance to avoid confusing Git, exporting only the newest tag,
724 emulating Fossil’s own ambiguity resolution rule as best it can within
725 Git’s limitations.
726
727 [fge]: /help?cmd=git
728 [gcrf]: https://git-scm.com/docs/git-check-ref-format
729
730
731
732
733 <a id="cpickrev"></a>
734 ## Cherry-Picking And Reverting Commits
735
736 Git’s separate "`git cherry-pick`" and “`git revert`” commands are
737 options to the [`fossil merge` command][merge]: `--cherrypick` and
738 `--backout`, respectively.
739
@@ -390,35 +752,175 @@
752 default: they do not actually rename or delete the files in your
753 check-out.
754
755 If you don’t like that default, you can change it globally:
756
757 fossil setting --global mv-rm-files 1
758
759 Now these commands behave like in Git in any Fossil repository where
760 this setting hasn’t been overridden locally.
761
762 If you want to keep Fossil’s soft `mv/rm` behavior most of the time, you
763 can cast it away on a per-command basis:
764
765 fossil mv --hard old-name new-name
766
767 [mv]: /help?cmd=mv
768 [rm]: /help?cmd=rm
769
770
771 ----
772
773
774 ## <a id="cvdate" name="cs1"></a> Case Study 1: Checking Out A Version By Date
775
776 Let’s get into something a bit more complicated: a case study showing
777 how the concepts lined out above cause Fossil to materially differ in
778 day-to-day operation from Git.
779
780 Why would you want to check out a version of a project by date? Perhaps
781 because your customer gave you a vague bug report referencing only a
782 date rather than a version. Or, you may be poking semi-randomly through
783 history to find a “good” version to anchor the start point of a
784 [`bisect`][bis] operation.
785
786 My search engine’s first result for “git checkout by date” is [this
787 highly-upvoted accepted Stack Overflow answer][gcod]. The first command
788 it gives is based on Git’s [`rev-parse` feature][grp]:
789
790 git checkout master@{2020-03-17}
791
792 There are a number of weaknesses in this command. From least to most
793 critical:
794
795 1. It’s a bit cryptic. Leave off the refname or punctuation, and it
796 means something else. You cannot simplify the cryptic incantation in
797 the typical use case.
798
799 2. A date string in Git without a time will be interpreted as
800 “[at localtime on that date][gapxd],” so the command means something
801 different from one second to the next! If there are multiple commits
802 on that date, that command can give different results depending on
803 the time of day you run it.
804
805 3. It gives misleading output if there is no close match for the date
806 in target commit in the local [reflog]. On a fresh clone, the reflog
807 is empty, and even on a well-established clone, Git [automatically
808 prunes][gle] the reflog to 90 days of history by default. This means
809 the command above can give different results from one machine to the
810 next, or even from one day to the next on the same clone.
811
812 The command won’t fail outright if the reflog can’t resolve the
813 given date: it simply gives the closest commit it can come up with,
814 even if it’s months or years out from your target! Sometimes it
815 gives a warning about the reflog not going back far enough to give a
816 useful result, and sometimes it doesn’t. If you’re on a fresh clone,
817 you are likely to get the “tip” commit’s revision ID no matter what
818 date value you give.
819
820 Git tries its best, but because it’s working from a purgeable and
821 possibly-stale local cache, you cannot trust its results.
822
823 We cannot recommend this command at all. It’s unreliable even in the
824 best case.
825
826 That same Stack Overflow answer therefore goes on to recommend an
827 entirely different command:
828
829 git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)
830
831 We believe you get such answers to Git help requests in part
832 because of its lack of an always-up-to-date [index into its log](#log) and in
833 part because of its “small tools loosely joined” design philosophy. This
834 sort of command is therefore composed piece by piece:
835
836 <center>◆  ◆  ◆</center>
837
838 “Oh, I know, I’ll search the rev-list, which outputs commit IDs by
839 parsing the log backwards from `HEAD`! Easy!”
840
841 git rev-list --before=2020-03-17
842
843 “Blast! Forgot the commit ID!”
844
845 git rev-list --before=2020-03-17 master
846
847 “Double blast! It just spammed my terminal with revision IDs! I need to
848 limit it to the single closest match:
849
850 git rev-list -n 1 --before=2020-03-17 master
851
852 “Okay, it gives me a single revision ID now, but is it what I’m after?
853 Let’s take a look…”
854
855 git show $(git rev-list -n 1 --before=2020-03-17 master)
856
857 “Oops, that’s giving me a merge commit, not what I want.
858 Off to search the web… Okay, it says I need to give either the
859 `--first-parent` or `--no-merges` flag to show only regular commits,
860 not merge-commits. Let’s try the first one:”
861
862 git show $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
863
864 “Better. Let’s check it out:”
865
866 git checkout $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
867
868 “Success, I guess?”
869
870 <center>◆  ◆  ◆</center>
871
872 This vignette is meant to explain some of Git’s popularity: it rewards
873 the sort of people who enjoy puzzles, many of whom are software
874 developers and thus need a tool like Git. Too bad if you’re just a
875 normal user.
876
877 And too bad if you’re a Windows user who doesn’t want to use [Git
878 Bash][gbash], since neither of the stock OS command shells have a
879 command interpolation feature needed to run that horrid command.
880
881 This alternative command still has weakness #2 above: if you run the
882 second `git show` command above on [Git’s own repository][gitgh], your
883 results may vary because there were four non-merge commits to Git on the
884 17th of March, 2020.
885
886 You may be asking with an exasperated huff, “What is your *point*, man?”
887 The point is that the equivalent in Fossil is simply:
888
889 fossil up 2020-03-17
890
891 …which will *always* give the commit closest to midnight UTC on the 17th
892 of March, 2020, no matter whether you do it on a fresh clone or a stale
893 one. The answer won’t shift about from one clone to the next or from
894 one local time of day to the next. We owe this reliability and stability
895 to three Fossil design choices:
896
897 * Parse timestamps from all commits on clone into a local commit index,
898 then maintain that index through subsequent commits and syncs.
899
900 * Use an indexed SQL `ORDER BY` query to match timestamps to commit
901 IDs for a fast and consistent result.
902
903 * Round timestamp strings up using [rules][frud] consistent across
904 computers and local time of day.
905
906 [frud]: https://fossil-scm.org/home/file/src/name.c?ci=d2a59b03727bc3&ln=122-141
907 [gbash]: https://appuals.com/what-is-git-bash/
908 [gapxd]: https://github.com/git/git/blob/7f7ebe054a/date.c#L1298-L1300
909 [gcod]: https://stackoverflow.com/a/6990682/142454
910 [gdh]: https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit/
911 [gitgh]: https://github.com/git/git/
912 [gle]: https://git-scm.com/docs/git-reflog#_options_for_expire
913 [gmc]: https://github.com/git/git/commit/67b0a24910fbb23c8f5e7a2c61c339818bc68296
914 [grp]: https://git-scm.com/docs/git-rev-parse
915 [reflog]: https://git-scm.com/docs/git-reflog
916
917 ----
918
919 ## <a id="morigin" name="cs2"></a> Case Study 2: Multiple "origin" Servers
920
921 Now let us consider a common use case at the time of this writing — during the
922 COVID-19 pandemic — where you’re working from home a lot, going into the
923 office one part-day a week only to do things that have to be done
924 on-site at the office. Let us also say you have no remote
925 access back into the work LAN, such as because your site IT is paranoid
926 about security. You may still want off-machine backups of your commits
@@ -448,20 +950,20 @@
950
951 ssh my-nas.local 'git init --bare /SHARES/dayjob/repo.git'
952 git push --all ssh://my-nas.local//SHARES/dayjob/repo.git
953
954 Realize that this is carefully optimized down to these two long
955 commands. In practice, we’d expect a user typing these commands by hand from memory
956 to need to give four or more commands here instead.
957 Packing the “`git init`” call into the “`ssh`” call is something more
958 often done in scripts and documentation examples than done interactively,
959 which then necessitates a third command before the push, “`exit`”.
960 There’s also a good chance that you’ll forget the need for the `--bare`
961 option here to avoid a fatal complaint from Git that the laptop can’t
962 push into a non-empty repo. If you fall into this trap, among the many
963 that Git lays for newbies, you have to nuke the incorrectly initted
964 repo, search the web or Git man pages to find out about `--bare`, and try again.
965
966 Having navigated that little minefield,
967 we can tell Git that there is a second origin, a “home” repo in
968 addition to the named “work” repo we set up earlier:
969
@@ -469,11 +971,11 @@
971 git config master.remote home
972
973 We don’t have to push or pull because the remote repo is a complete
974 clone of the repo on the laptop at this point, so we can just get to
975 work now, committing along the way to get our work safely off-machine
976 and onto our home NAS, like so:
977
978 git add
979 git commit
980 git push
981
@@ -493,38 +995,38 @@
995 that when returning home, you’d have to manually reset the upstream
996 again.
997
998 This example also shows a consequence of that fact that
999 [Git doesn’t sync branch names](#syncall): you have to keep repeating
1000 yourself like an obsequious supplicant: “Master, master.” Didn’t we
1001 invent computers to serve humans, rather than the other way around?
1002
1003
1004 #### Fossil Method
1005
1006 Now we’re going to do the same thing using Fossil, with
1007 the commands arranged in blocks corresponding to those above for comparison.
1008
1009 We start the same way, cloning the work repo down to the laptop:
1010
1011 fossil clone https://dev-server.example.com/repo
1012 cd repo
 
1013 fossil remote add work https://dev-server.example.com/repo
1014
1015 We’ve chosen the new “`fossil clone URI`” syntax added in Fossil 2.14 rather than separate
1016 `clone` and `open` commands to make the parallel with Git clearer. [See
1017 above](#mwd) for more on that topic.
1018
1019 Our [`remote` command][rem] is longer than the Git equivalent because
1020 Fossil currently has no short command
1021 to rename an existing remote. Worse, unlike with Git, we can’t just keep
1022 using the default remote name because Fossil uses that slot in its
1023 configuration database to store the *current* remote name, so on
1024 switching from work to home, the home URL will overwrite the work URL if
1025 we don’t give it an explicit name first.
1026
1027 Although the Fossil commands are longer, so far, keep it in perspective:
1028 they’re one-time setup costs,
1029 easily amortized to insignificance by the shorter day-to-day commands
1030 below.
1031
1032 On first beginning to work from home, we reverse-clone the Fossil repo
1033
+4 -4
--- www/index.wiki
+++ www/index.wiki
@@ -84,16 +84,16 @@
8484
the repository are consistent prior to each commit.
8585
8686
8. <b>Free and Open-Source</b> - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license].
8787
8888
<hr>
89
-<h3>Latest Release: 2.12.1 ([/timeline?c=202008201327|2020-08-20])</h3>
89
+<h3>Latest Release: 2.13 ([/timeline?c=version-2.13|2020-11-01])</h3>
9090
9191
* [/uv/download.html|Download]
92
- * [./changes.wiki#v2_12|Change Summary]
93
- * [/timeline?p=version-2.12.1&bt=version-2.11&n=all|Check-ins in version 2.12.1]
94
- * [/timeline?d=version-2.12&n=all&nd|Check-ins derived from the 2.12 release]
92
+ * [./changes.wiki#v2_13|Change Summary]
93
+ * [/timeline?p=version-2.13&bt=version-2.12&n=all|Check-ins in version 2.13]
94
+ * [/timeline?d=version-2.13&n=all&nd|Check-ins derived from the 2.13 release]
9595
* [/timeline?t=release|Timeline of all past releases]
9696
9797
<hr>
9898
<h3>Quick Start</h3>
9999
100100
--- www/index.wiki
+++ www/index.wiki
@@ -84,16 +84,16 @@
84 the repository are consistent prior to each commit.
85
86 8. <b>Free and Open-Source</b> - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license].
87
88 <hr>
89 <h3>Latest Release: 2.12.1 ([/timeline?c=202008201327|2020-08-20])</h3>
90
91 * [/uv/download.html|Download]
92 * [./changes.wiki#v2_12|Change Summary]
93 * [/timeline?p=version-2.12.1&bt=version-2.11&n=all|Check-ins in version 2.12.1]
94 * [/timeline?d=version-2.12&n=all&nd|Check-ins derived from the 2.12 release]
95 * [/timeline?t=release|Timeline of all past releases]
96
97 <hr>
98 <h3>Quick Start</h3>
99
100
--- www/index.wiki
+++ www/index.wiki
@@ -84,16 +84,16 @@
84 the repository are consistent prior to each commit.
85
86 8. <b>Free and Open-Source</b> - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license].
87
88 <hr>
89 <h3>Latest Release: 2.13 ([/timeline?c=version-2.13|2020-11-01])</h3>
90
91 * [/uv/download.html|Download]
92 * [./changes.wiki#v2_13|Change Summary]
93 * [/timeline?p=version-2.13&bt=version-2.12&n=all|Check-ins in version 2.13]
94 * [/timeline?d=version-2.13&n=all&nd|Check-ins derived from the 2.13 release]
95 * [/timeline?t=release|Timeline of all past releases]
96
97 <hr>
98 <h3>Quick Start</h3>
99
100
--- www/mirrortogithub.md
+++ www/mirrortogithub.md
@@ -77,14 +77,23 @@
7777
<pre>$ fossil git status</pre>
7878
</blockquote>
7979
</ol>
8080
8181
## Notes:
82
+
83
+ * Unless you specify --force, the mirroring only happens if the Fossil
84
+ repo has changed, with Fossil reporting "no changes", because Fossil
85
+ does not care about the success or failure of the mirror run. If a mirror
86
+ run failed (for example, due to an incorrect password, or a transient
87
+ error at github.com), Fossil will not retry until there has been a repo
88
+ change or --force is supplied.
8289
8390
* The mirroring is one-way. If you check in changes on GitHub, those
8491
changes will not be reabsorbed by Fossil. There are technical problems
85
- that make a two-way mirror all but impossible.
92
+ that make a two-way mirror all but impossible. (This is not to be
93
+ confused with the ability to import a Fossil mirror from Github back
94
+ into a Fossil repository. That works, but it is not a mirror.)
8695
8796
This also means that you cannot accept pull requests on GitHub.
8897
8998
* The "`fossil git export`" command creates subprocesses that run "`git`"
9099
commands, so you must have Git installed on your machine for any
91100
--- www/mirrortogithub.md
+++ www/mirrortogithub.md
@@ -77,14 +77,23 @@
77 <pre>$ fossil git status</pre>
78 </blockquote>
79 </ol>
80
81 ## Notes:
 
 
 
 
 
 
 
82
83 * The mirroring is one-way. If you check in changes on GitHub, those
84 changes will not be reabsorbed by Fossil. There are technical problems
85 that make a two-way mirror all but impossible.
 
 
86
87 This also means that you cannot accept pull requests on GitHub.
88
89 * The "`fossil git export`" command creates subprocesses that run "`git`"
90 commands, so you must have Git installed on your machine for any
91
--- www/mirrortogithub.md
+++ www/mirrortogithub.md
@@ -77,14 +77,23 @@
77 <pre>$ fossil git status</pre>
78 </blockquote>
79 </ol>
80
81 ## Notes:
82
83 * Unless you specify --force, the mirroring only happens if the Fossil
84 repo has changed, with Fossil reporting "no changes", because Fossil
85 does not care about the success or failure of the mirror run. If a mirror
86 run failed (for example, due to an incorrect password, or a transient
87 error at github.com), Fossil will not retry until there has been a repo
88 change or --force is supplied.
89
90 * The mirroring is one-way. If you check in changes on GitHub, those
91 changes will not be reabsorbed by Fossil. There are technical problems
92 that make a two-way mirror all but impossible. (This is not to be
93 confused with the ability to import a Fossil mirror from Github back
94 into a Fossil repository. That works, but it is not a mirror.)
95
96 This also means that you cannot accept pull requests on GitHub.
97
98 * The "`fossil git export`" command creates subprocesses that run "`git`"
99 commands, so you must have Git installed on your machine for any
100
+2 -1
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -27,10 +27,11 @@
2727
cgi.wiki {CGI Script Configuration Options}
2828
changes.wiki {Fossil Changelog}
2929
checkin_names.wiki {Check-in And Version Names}
3030
checkin.wiki {Check-in Checklist}
3131
childprojects.wiki {Child Projects}
32
+ ckout-workflows.md {Check-Out Workflows}
3233
copyright-release.html {Contributor License Agreement}
3334
concepts.wiki {Fossil Core Concepts}
3435
contribute.wiki {Contributing Code or Documentation To The Fossil Project}
3536
css-tricks.md {Fossil CSS Tips and Tricks}
3637
customgraph.md {Theming: Customizing the Timeline Graph}
@@ -52,11 +53,11 @@
5253
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
5354
fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
5455
fossil_prompt.wiki {Fossilized Bash Prompt}
5556
fossil-v-git.wiki {Fossil Versus Git}
5657
globs.md {File Name Glob Patterns}
57
- gitusers.md {Hints For Users With Git Experience}
58
+ gitusers.md {Git to Fossil Translation Guide}
5859
grep.md {Fossil grep vs POSIX grep}
5960
hacker-howto.wiki {Hacker How-To}
6061
hacker-howto.wiki {Fossil Developers Guide}
6162
hashes.md {Hashes: Fossil Artifact Identification}
6263
hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256}
6364
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -27,10 +27,11 @@
27 cgi.wiki {CGI Script Configuration Options}
28 changes.wiki {Fossil Changelog}
29 checkin_names.wiki {Check-in And Version Names}
30 checkin.wiki {Check-in Checklist}
31 childprojects.wiki {Child Projects}
 
32 copyright-release.html {Contributor License Agreement}
33 concepts.wiki {Fossil Core Concepts}
34 contribute.wiki {Contributing Code or Documentation To The Fossil Project}
35 css-tricks.md {Fossil CSS Tips and Tricks}
36 customgraph.md {Theming: Customizing the Timeline Graph}
@@ -52,11 +53,11 @@
52 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
53 fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
54 fossil_prompt.wiki {Fossilized Bash Prompt}
55 fossil-v-git.wiki {Fossil Versus Git}
56 globs.md {File Name Glob Patterns}
57 gitusers.md {Hints For Users With Git Experience}
58 grep.md {Fossil grep vs POSIX grep}
59 hacker-howto.wiki {Hacker How-To}
60 hacker-howto.wiki {Fossil Developers Guide}
61 hashes.md {Hashes: Fossil Artifact Identification}
62 hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256}
63
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -27,10 +27,11 @@
27 cgi.wiki {CGI Script Configuration Options}
28 changes.wiki {Fossil Changelog}
29 checkin_names.wiki {Check-in And Version Names}
30 checkin.wiki {Check-in Checklist}
31 childprojects.wiki {Child Projects}
32 ckout-workflows.md {Check-Out Workflows}
33 copyright-release.html {Contributor License Agreement}
34 concepts.wiki {Fossil Core Concepts}
35 contribute.wiki {Contributing Code or Documentation To The Fossil Project}
36 css-tricks.md {Fossil CSS Tips and Tricks}
37 customgraph.md {Theming: Customizing the Timeline Graph}
@@ -52,11 +53,11 @@
53 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
54 fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
55 fossil_prompt.wiki {Fossilized Bash Prompt}
56 fossil-v-git.wiki {Fossil Versus Git}
57 globs.md {File Name Glob Patterns}
58 gitusers.md {Git to Fossil Translation Guide}
59 grep.md {Fossil grep vs POSIX grep}
60 hacker-howto.wiki {Hacker How-To}
61 hacker-howto.wiki {Fossil Developers Guide}
62 hashes.md {Hashes: Fossil Artifact Identification}
63 hashpolicy.wiki {Hash Policy: Choosing Between SHA1 and SHA3-256}
64
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -57,10 +57,11 @@
5757
<li><a href="serverext.wiki"><b>CGI Server Extensions</b></a></li>
5858
<li><a href="aboutcgi.wiki">CGI Works In Fossil &mdash; How</a></li>
5959
<li><a href="changes.wiki">Changelog &mdash; Fossil</a></li>
6060
<li><a href="checkin_names.wiki"><b>Check-in And Version Names</b></a></li>
6161
<li><a href="checkin.wiki"><b>Check-in Checklist</b></a></li>
62
+<li><a href="ckout-workflows.md"><b>Check-Out Workflows</b></a></li>
6263
<li><a href="checkin.wiki">Checklist &mdash; Check-in</a></li>
6364
<li><a href="../test/release-checklist.wiki">Checklist &mdash; Pre-Release Testing</a></li>
6465
<li><a href="foss-cklist.wiki"><b>Checklist For Successful Open-Source Projects</b></a></li>
6566
<li><a href="selfcheck.wiki">Checks &mdash; Fossil Repository Integrity Self</a></li>
6667
<li><a href="childprojects.wiki"><b>Child Projects</b></a></li>
@@ -108,11 +109,10 @@
108109
<li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
109110
<li><a href="encryptedrepos.wiki">Encrypted Repositories &mdash; How To Use</a></li>
110111
<li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li>
111112
<li><a href="event.wiki"><b>Events</b></a></li>
112113
<li><a href="webpage-ex.md">Examples &mdash; Webpage</a></li>
113
-<li><a href="gitusers.md">Experience &mdash; Hints For Users With Git</a></li>
114114
<li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
115115
<li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
116116
<li><a href="serverext.wiki">Extensions &mdash; CGI Server</a></li>
117117
<li><a href="serverext.wiki">Extensions To A Fossil Server Using CGI Scripts &mdash; Adding</a></li>
118118
<li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
@@ -147,29 +147,29 @@
147147
<li><a href="fossil_prompt.wiki"><b>Fossilized Bash Prompt</b></a></li>
148148
<li><a href="faq.wiki"><b>Frequently Asked Questions</b></a></li>
149149
<li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
150150
<li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
151151
<li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
152
-<li><a href="gitusers.md">Git Experience &mdash; Hints For Users With</a></li>
153152
<li><a href="mirrorlimitations.md">Git Mirrors &mdash; Limitations On</a></li>
153
+<li><a href="gitusers.md"><b>Git to Fossil Translation Guide</b></a></li>
154154
<li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
155155
<li><a href="mirrortogithub.md">GitHub &mdash; How To Mirror A Fossil Repository On</a></li>
156156
<li><a href="globs.md">Glob Patterns &mdash; File Name</a></li>
157157
<li><a href="env-opts.md">Global Options &mdash; Environment Variables and</a></li>
158158
<li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
159159
<li><a href="grep.md">grep &mdash; Fossil grep vs POSIX</a></li>
160160
<li><a href="grep.md">grep vs POSIX grep &mdash; Fossil</a></li>
161161
<li><a href="hacker-howto.wiki">Guide &mdash; Fossil Developers</a></li>
162162
<li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
163
+<li><a href="gitusers.md">Guide &mdash; Git to Fossil Translation</a></li>
163164
<li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
164165
<li><a href="hacker-howto.wiki"><b>Hacker How-To</b></a></li>
165166
<li><a href="adding_code.wiki"><b>Hacking Fossil</b></a></li>
166167
<li><a href="rebaseharm.md">Harmful &mdash; Rebase Considered</a></li>
167168
<li><a href="hashpolicy.wiki"><b>Hash Policy: Choosing Between SHA1 and SHA3-256</b></a></li>
168169
<li><a href="hashes.md"><b>Hashes: Fossil Artifact Identification</b></a></li>
169170
<li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
170
-<li><a href="gitusers.md"><b>Hints For Users With Git Experience</b></a></li>
171171
<li><a href="history.md">History Of Fossil &mdash; The Purpose And</a></li>
172172
<li><a href="index.wiki"><b>Home Page</b></a></li>
173173
<li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
174174
<li><a href="aboutcgi.wiki"><b>How CGI Works In Fossil</b></a></li>
175175
<li><a href="aboutdownload.wiki"><b>How The Download Page Works</b></a></li>
@@ -310,10 +310,11 @@
310310
<li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
311311
<li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>
312312
<li><a href="css-tricks.md">Tips and Tricks &mdash; Fossil CSS</a></li>
313313
<li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
314314
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
315
+<li><a href="gitusers.md">Translation Guide &mdash; Git to Fossil</a></li>
315316
<li><a href="css-tricks.md">Tricks &mdash; Fossil CSS Tips and</a></li>
316317
<li><a href="unvers.wiki"><b>Unversioned Files</b></a></li>
317318
<li><a href="backup.md">Up a Remote Fossil Repository &mdash; Backing</a></li>
318319
<li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li>
319320
<li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
@@ -320,11 +321,10 @@
320321
<li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li>
321322
<li><a href="fiveminutes.wiki">User &mdash; Up and Running in 5 Minutes as a Single</a></li>
322323
<li><a href="caps/">User Capabilities &mdash; Administering</a></li>
323324
<li><a href="caps/ref.html"><b>User Capability Reference</b></a></li>
324325
<li><a href="caps/admin-v-setup.md">Users &mdash; Differences Between Setup and Admin</a></li>
325
-<li><a href="gitusers.md">Users With Git Experience &mdash; Hints For</a></li>
326326
<li><a href="serverext.wiki">Using CGI Scripts &mdash; Adding Extensions To A Fossil Server</a></li>
327327
<li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
328328
<li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
329329
<li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
330330
<li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
@@ -338,9 +338,10 @@
338338
<li><a href="../../../help">Webpages &mdash; Lists of Commands and</a></li>
339339
<li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
340340
<li><a href="whyusefossil.wiki"><b>Why You Should Use Fossil</b></a></li>
341341
<li><a href="../../../wiki_rules"><b>Wiki Formatting Rules</b></a></li>
342342
<li><a href="wikitheory.wiki"><b>Wiki In Fossil</b></a></li>
343
+<li><a href="ckout-workflows.md">Workflows &mdash; Check-Out</a></li>
343344
<li><a href="aboutdownload.wiki">Works &mdash; How The Download Page</a></li>
344345
<li><a href="aboutcgi.wiki">Works In Fossil &mdash; How CGI</a></li>
345346
<li><a href="whyusefossil.wiki">You Should Use Fossil &mdash; Why</a></li>
346347
</ul></div>
347348
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -57,10 +57,11 @@
57 <li><a href="serverext.wiki"><b>CGI Server Extensions</b></a></li>
58 <li><a href="aboutcgi.wiki">CGI Works In Fossil &mdash; How</a></li>
59 <li><a href="changes.wiki">Changelog &mdash; Fossil</a></li>
60 <li><a href="checkin_names.wiki"><b>Check-in And Version Names</b></a></li>
61 <li><a href="checkin.wiki"><b>Check-in Checklist</b></a></li>
 
62 <li><a href="checkin.wiki">Checklist &mdash; Check-in</a></li>
63 <li><a href="../test/release-checklist.wiki">Checklist &mdash; Pre-Release Testing</a></li>
64 <li><a href="foss-cklist.wiki"><b>Checklist For Successful Open-Source Projects</b></a></li>
65 <li><a href="selfcheck.wiki">Checks &mdash; Fossil Repository Integrity Self</a></li>
66 <li><a href="childprojects.wiki"><b>Child Projects</b></a></li>
@@ -108,11 +109,10 @@
108 <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
109 <li><a href="encryptedrepos.wiki">Encrypted Repositories &mdash; How To Use</a></li>
110 <li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li>
111 <li><a href="event.wiki"><b>Events</b></a></li>
112 <li><a href="webpage-ex.md">Examples &mdash; Webpage</a></li>
113 <li><a href="gitusers.md">Experience &mdash; Hints For Users With Git</a></li>
114 <li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
115 <li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
116 <li><a href="serverext.wiki">Extensions &mdash; CGI Server</a></li>
117 <li><a href="serverext.wiki">Extensions To A Fossil Server Using CGI Scripts &mdash; Adding</a></li>
118 <li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
@@ -147,29 +147,29 @@
147 <li><a href="fossil_prompt.wiki"><b>Fossilized Bash Prompt</b></a></li>
148 <li><a href="faq.wiki"><b>Frequently Asked Questions</b></a></li>
149 <li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
150 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
151 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
152 <li><a href="gitusers.md">Git Experience &mdash; Hints For Users With</a></li>
153 <li><a href="mirrorlimitations.md">Git Mirrors &mdash; Limitations On</a></li>
 
154 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
155 <li><a href="mirrortogithub.md">GitHub &mdash; How To Mirror A Fossil Repository On</a></li>
156 <li><a href="globs.md">Glob Patterns &mdash; File Name</a></li>
157 <li><a href="env-opts.md">Global Options &mdash; Environment Variables and</a></li>
158 <li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
159 <li><a href="grep.md">grep &mdash; Fossil grep vs POSIX</a></li>
160 <li><a href="grep.md">grep vs POSIX grep &mdash; Fossil</a></li>
161 <li><a href="hacker-howto.wiki">Guide &mdash; Fossil Developers</a></li>
162 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
 
163 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
164 <li><a href="hacker-howto.wiki"><b>Hacker How-To</b></a></li>
165 <li><a href="adding_code.wiki"><b>Hacking Fossil</b></a></li>
166 <li><a href="rebaseharm.md">Harmful &mdash; Rebase Considered</a></li>
167 <li><a href="hashpolicy.wiki"><b>Hash Policy: Choosing Between SHA1 and SHA3-256</b></a></li>
168 <li><a href="hashes.md"><b>Hashes: Fossil Artifact Identification</b></a></li>
169 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
170 <li><a href="gitusers.md"><b>Hints For Users With Git Experience</b></a></li>
171 <li><a href="history.md">History Of Fossil &mdash; The Purpose And</a></li>
172 <li><a href="index.wiki"><b>Home Page</b></a></li>
173 <li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
174 <li><a href="aboutcgi.wiki"><b>How CGI Works In Fossil</b></a></li>
175 <li><a href="aboutdownload.wiki"><b>How The Download Page Works</b></a></li>
@@ -310,10 +310,11 @@
310 <li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
311 <li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>
312 <li><a href="css-tricks.md">Tips and Tricks &mdash; Fossil CSS</a></li>
313 <li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
314 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
 
315 <li><a href="css-tricks.md">Tricks &mdash; Fossil CSS Tips and</a></li>
316 <li><a href="unvers.wiki"><b>Unversioned Files</b></a></li>
317 <li><a href="backup.md">Up a Remote Fossil Repository &mdash; Backing</a></li>
318 <li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li>
319 <li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
@@ -320,11 +321,10 @@
320 <li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li>
321 <li><a href="fiveminutes.wiki">User &mdash; Up and Running in 5 Minutes as a Single</a></li>
322 <li><a href="caps/">User Capabilities &mdash; Administering</a></li>
323 <li><a href="caps/ref.html"><b>User Capability Reference</b></a></li>
324 <li><a href="caps/admin-v-setup.md">Users &mdash; Differences Between Setup and Admin</a></li>
325 <li><a href="gitusers.md">Users With Git Experience &mdash; Hints For</a></li>
326 <li><a href="serverext.wiki">Using CGI Scripts &mdash; Adding Extensions To A Fossil Server</a></li>
327 <li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
328 <li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
329 <li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
330 <li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
@@ -338,9 +338,10 @@
338 <li><a href="../../../help">Webpages &mdash; Lists of Commands and</a></li>
339 <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
340 <li><a href="whyusefossil.wiki"><b>Why You Should Use Fossil</b></a></li>
341 <li><a href="../../../wiki_rules"><b>Wiki Formatting Rules</b></a></li>
342 <li><a href="wikitheory.wiki"><b>Wiki In Fossil</b></a></li>
 
343 <li><a href="aboutdownload.wiki">Works &mdash; How The Download Page</a></li>
344 <li><a href="aboutcgi.wiki">Works In Fossil &mdash; How CGI</a></li>
345 <li><a href="whyusefossil.wiki">You Should Use Fossil &mdash; Why</a></li>
346 </ul></div>
347
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -57,10 +57,11 @@
57 <li><a href="serverext.wiki"><b>CGI Server Extensions</b></a></li>
58 <li><a href="aboutcgi.wiki">CGI Works In Fossil &mdash; How</a></li>
59 <li><a href="changes.wiki">Changelog &mdash; Fossil</a></li>
60 <li><a href="checkin_names.wiki"><b>Check-in And Version Names</b></a></li>
61 <li><a href="checkin.wiki"><b>Check-in Checklist</b></a></li>
62 <li><a href="ckout-workflows.md"><b>Check-Out Workflows</b></a></li>
63 <li><a href="checkin.wiki">Checklist &mdash; Check-in</a></li>
64 <li><a href="../test/release-checklist.wiki">Checklist &mdash; Pre-Release Testing</a></li>
65 <li><a href="foss-cklist.wiki"><b>Checklist For Successful Open-Source Projects</b></a></li>
66 <li><a href="selfcheck.wiki">Checks &mdash; Fossil Repository Integrity Self</a></li>
67 <li><a href="childprojects.wiki"><b>Child Projects</b></a></li>
@@ -108,11 +109,10 @@
109 <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &mdash; Fossil Delta</a></li>
110 <li><a href="encryptedrepos.wiki">Encrypted Repositories &mdash; How To Use</a></li>
111 <li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li>
112 <li><a href="event.wiki"><b>Events</b></a></li>
113 <li><a href="webpage-ex.md">Examples &mdash; Webpage</a></li>
 
114 <li><a href="inout.wiki">Export To And From Git &mdash; Import And</a></li>
115 <li><a href="fossil-from-msvc.wiki">Express 2010 IDE &mdash; Integrating Fossil in the Microsoft</a></li>
116 <li><a href="serverext.wiki">Extensions &mdash; CGI Server</a></li>
117 <li><a href="serverext.wiki">Extensions To A Fossil Server Using CGI Scripts &mdash; Adding</a></li>
118 <li><a href="adding_code.wiki">Features To Fossil &mdash; Adding New</a></li>
@@ -147,29 +147,29 @@
147 <li><a href="fossil_prompt.wiki"><b>Fossilized Bash Prompt</b></a></li>
148 <li><a href="faq.wiki"><b>Frequently Asked Questions</b></a></li>
149 <li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
150 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
151 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
 
152 <li><a href="mirrorlimitations.md">Git Mirrors &mdash; Limitations On</a></li>
153 <li><a href="gitusers.md"><b>Git to Fossil Translation Guide</b></a></li>
154 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
155 <li><a href="mirrortogithub.md">GitHub &mdash; How To Mirror A Fossil Repository On</a></li>
156 <li><a href="globs.md">Glob Patterns &mdash; File Name</a></li>
157 <li><a href="env-opts.md">Global Options &mdash; Environment Variables and</a></li>
158 <li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
159 <li><a href="grep.md">grep &mdash; Fossil grep vs POSIX</a></li>
160 <li><a href="grep.md">grep vs POSIX grep &mdash; Fossil</a></li>
161 <li><a href="hacker-howto.wiki">Guide &mdash; Fossil Developers</a></li>
162 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
163 <li><a href="gitusers.md">Guide &mdash; Git to Fossil Translation</a></li>
164 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
165 <li><a href="hacker-howto.wiki"><b>Hacker How-To</b></a></li>
166 <li><a href="adding_code.wiki"><b>Hacking Fossil</b></a></li>
167 <li><a href="rebaseharm.md">Harmful &mdash; Rebase Considered</a></li>
168 <li><a href="hashpolicy.wiki"><b>Hash Policy: Choosing Between SHA1 and SHA3-256</b></a></li>
169 <li><a href="hashes.md"><b>Hashes: Fossil Artifact Identification</b></a></li>
170 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
 
171 <li><a href="history.md">History Of Fossil &mdash; The Purpose And</a></li>
172 <li><a href="index.wiki"><b>Home Page</b></a></li>
173 <li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
174 <li><a href="aboutcgi.wiki"><b>How CGI Works In Fossil</b></a></li>
175 <li><a href="aboutdownload.wiki"><b>How The Download Page Works</b></a></li>
@@ -310,10 +310,11 @@
310 <li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
311 <li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>
312 <li><a href="css-tricks.md">Tips and Tricks &mdash; Fossil CSS</a></li>
313 <li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
314 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
315 <li><a href="gitusers.md">Translation Guide &mdash; Git to Fossil</a></li>
316 <li><a href="css-tricks.md">Tricks &mdash; Fossil CSS Tips and</a></li>
317 <li><a href="unvers.wiki"><b>Unversioned Files</b></a></li>
318 <li><a href="backup.md">Up a Remote Fossil Repository &mdash; Backing</a></li>
319 <li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li>
320 <li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
@@ -320,11 +321,10 @@
321 <li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li>
322 <li><a href="fiveminutes.wiki">User &mdash; Up and Running in 5 Minutes as a Single</a></li>
323 <li><a href="caps/">User Capabilities &mdash; Administering</a></li>
324 <li><a href="caps/ref.html"><b>User Capability Reference</b></a></li>
325 <li><a href="caps/admin-v-setup.md">Users &mdash; Differences Between Setup and Admin</a></li>
 
326 <li><a href="serverext.wiki">Using CGI Scripts &mdash; Adding Extensions To A Fossil Server</a></li>
327 <li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
328 <li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
329 <li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
330 <li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
@@ -338,9 +338,10 @@
338 <li><a href="../../../help">Webpages &mdash; Lists of Commands and</a></li>
339 <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
340 <li><a href="whyusefossil.wiki"><b>Why You Should Use Fossil</b></a></li>
341 <li><a href="../../../wiki_rules"><b>Wiki Formatting Rules</b></a></li>
342 <li><a href="wikitheory.wiki"><b>Wiki In Fossil</b></a></li>
343 <li><a href="ckout-workflows.md">Workflows &mdash; Check-Out</a></li>
344 <li><a href="aboutdownload.wiki">Works &mdash; How The Download Page</a></li>
345 <li><a href="aboutcgi.wiki">Works In Fossil &mdash; How CGI</a></li>
346 <li><a href="whyusefossil.wiki">You Should Use Fossil &mdash; Why</a></li>
347 </ul></div>
348
--- www/serverext.wiki
+++ www/serverext.wiki
@@ -274,11 +274,31 @@
274274
If a CGI program requires separate data files, it is safe to put those
275275
files in the same directory as the CGI program itself as long as the names
276276
of the data files contain special characters that cause them to be ignored
277277
by Fossil.
278278
279
-<h2>6.0 Trouble-Shooting Hints</h2>
279
+<h2>6.0 Access Permissions</h2>
280
+
281
+CGI extension files and programs are accessible to everyone.
282
+
283
+When CGI extensions have been enabled (using either "extroot:" in the
284
+CGI file or the --extroot option for other server methods) all files
285
+in the extension root directory hierarchy, except special filenames
286
+identified previously, are accessible to all users. Users do not
287
+have to have "Read" privilege, or any other privilege, in order to
288
+access the extensions.
289
+
290
+This is by design. The CGI extension mechanism is intended to operate
291
+in the same way as a traditional web-server.
292
+
293
+CGI programs that want to restrict access
294
+can examine the FOSSIL_CAPABILITIES and/or FOSSIL_USER environment variables.
295
+In other words, access control is the responsibility of the individual
296
+extension programs.
297
+
298
+
299
+<h2>7.0 Trouble-Shooting Hints</h2>
280300
281301
Remember that the /ext will return any file in the extroot directory
282302
hierarchy as static content if the file is readable but not executable.
283303
When initially setting up the /ext mechanism, it is sometimes helpful
284304
to verify that you are able to receive static content prior to starting
285305
--- www/serverext.wiki
+++ www/serverext.wiki
@@ -274,11 +274,31 @@
274 If a CGI program requires separate data files, it is safe to put those
275 files in the same directory as the CGI program itself as long as the names
276 of the data files contain special characters that cause them to be ignored
277 by Fossil.
278
279 <h2>6.0 Trouble-Shooting Hints</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
281 Remember that the /ext will return any file in the extroot directory
282 hierarchy as static content if the file is readable but not executable.
283 When initially setting up the /ext mechanism, it is sometimes helpful
284 to verify that you are able to receive static content prior to starting
285
--- www/serverext.wiki
+++ www/serverext.wiki
@@ -274,11 +274,31 @@
274 If a CGI program requires separate data files, it is safe to put those
275 files in the same directory as the CGI program itself as long as the names
276 of the data files contain special characters that cause them to be ignored
277 by Fossil.
278
279 <h2>6.0 Access Permissions</h2>
280
281 CGI extension files and programs are accessible to everyone.
282
283 When CGI extensions have been enabled (using either "extroot:" in the
284 CGI file or the --extroot option for other server methods) all files
285 in the extension root directory hierarchy, except special filenames
286 identified previously, are accessible to all users. Users do not
287 have to have "Read" privilege, or any other privilege, in order to
288 access the extensions.
289
290 This is by design. The CGI extension mechanism is intended to operate
291 in the same way as a traditional web-server.
292
293 CGI programs that want to restrict access
294 can examine the FOSSIL_CAPABILITIES and/or FOSSIL_USER environment variables.
295 In other words, access control is the responsibility of the individual
296 extension programs.
297
298
299 <h2>7.0 Trouble-Shooting Hints</h2>
300
301 Remember that the /ext will return any file in the extroot directory
302 hierarchy as static content if the file is readable but not executable.
303 When initially setting up the /ext mechanism, it is sometimes helpful
304 to verify that you are able to receive static content prior to starting
305
--- www/shunning.wiki
+++ www/shunning.wiki
@@ -19,10 +19,17 @@
1919
copyright was accidentally committed and needs to be backed out.
2020
2121
* A malformed control artifact was inserted and is disrupting the
2222
operation of Fossil.
2323
24
+ * A legitimate legal request was received requiring content to
25
+ be removed. This would most likely be related to the accidental
26
+ intellectual property error or spam cases listed above. Some countries
27
+ recognise software patents, and so allow legal claims targetting code
28
+ commits. Some countries can require publicly-available encryption
29
+ software to be taken down if it is committed to the DAG without
30
+ the correct government authorisation.
2431
2532
<h2>Alternatives</h2>
2633
2734
All of these are rare cases: Fossil is [./antibot.wiki | designed to
2835
foil spammers up front], legally problematic check-ins should range from
@@ -81,10 +88,20 @@
8188
repository. Again, nothing is actually deleted; you're just adding
8289
more information to the repository which corrects a prior
8390
check-in.</p></li>
8491
</ul>
8592
93
+<h2>Exception: Non-versioned Content</h2>
94
+
95
+It is normal and expected to delete data which is not versioned, such as
96
+usernames and passwords in the user table. The [/help/scrub|fossil scrub]
97
+command will remove all sensitive non-versioned data from a respository.
98
+
99
+The scrub command will remove user 'bertina', along with their password,
100
+any supplied IP address, any concealed email address etc. However, in the
101
+DAG, commits by 'bertina' will continue to be visible unchanged even though
102
+there is no longer any such user in Fossil.
86103
87104
<h2>Shunning</h2>
88105
89106
Fossil provides a mechanism called "shunning" for removing content from
90107
a repository.
91108
--- www/shunning.wiki
+++ www/shunning.wiki
@@ -19,10 +19,17 @@
19 copyright was accidentally committed and needs to be backed out.
20
21 * A malformed control artifact was inserted and is disrupting the
22 operation of Fossil.
23
 
 
 
 
 
 
 
24
25 <h2>Alternatives</h2>
26
27 All of these are rare cases: Fossil is [./antibot.wiki | designed to
28 foil spammers up front], legally problematic check-ins should range from
@@ -81,10 +88,20 @@
81 repository. Again, nothing is actually deleted; you're just adding
82 more information to the repository which corrects a prior
83 check-in.</p></li>
84 </ul>
85
 
 
 
 
 
 
 
 
 
 
86
87 <h2>Shunning</h2>
88
89 Fossil provides a mechanism called "shunning" for removing content from
90 a repository.
91
--- www/shunning.wiki
+++ www/shunning.wiki
@@ -19,10 +19,17 @@
19 copyright was accidentally committed and needs to be backed out.
20
21 * A malformed control artifact was inserted and is disrupting the
22 operation of Fossil.
23
24 * A legitimate legal request was received requiring content to
25 be removed. This would most likely be related to the accidental
26 intellectual property error or spam cases listed above. Some countries
27 recognise software patents, and so allow legal claims targetting code
28 commits. Some countries can require publicly-available encryption
29 software to be taken down if it is committed to the DAG without
30 the correct government authorisation.
31
32 <h2>Alternatives</h2>
33
34 All of these are rare cases: Fossil is [./antibot.wiki | designed to
35 foil spammers up front], legally problematic check-ins should range from
@@ -81,10 +88,20 @@
88 repository. Again, nothing is actually deleted; you're just adding
89 more information to the repository which corrects a prior
90 check-in.</p></li>
91 </ul>
92
93 <h2>Exception: Non-versioned Content</h2>
94
95 It is normal and expected to delete data which is not versioned, such as
96 usernames and passwords in the user table. The [/help/scrub|fossil scrub]
97 command will remove all sensitive non-versioned data from a respository.
98
99 The scrub command will remove user 'bertina', along with their password,
100 any supplied IP address, any concealed email address etc. However, in the
101 DAG, commits by 'bertina' will continue to be visible unchanged even though
102 there is no longer any such user in Fossil.
103
104 <h2>Shunning</h2>
105
106 Fossil provides a mechanism called "shunning" for removing content from
107 a repository.
108

Keyboard Shortcuts

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