Fossil SCM

Continuing UX improvements on the /file, /artifact, and /whatis pages. More needs to be done.

drh 2020-05-11 18:12 trunk
Commit 1b5d0b0e18d6372afa5e848a053c79cc78601a63cf4b49ec38bf3111e54ba3db
1 file changed +117 -120
+117 -120
--- src/info.c
+++ src/info.c
@@ -1661,12 +1661,12 @@
16611661
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
16621662
cookie_link_parameter("diff","diff","2");
16631663
diffType = atoi(PD("diff","2"));
16641664
cookie_render();
16651665
if( P("from") && P("to") ){
1666
- v1 = artifact_from_ci_and_filename(0, "from");
1667
- v2 = artifact_from_ci_and_filename(0, "to");
1666
+ v1 = artifact_from_ci_and_filename("from");
1667
+ v2 = artifact_from_ci_and_filename("to");
16681668
}else{
16691669
Stmt q;
16701670
v1 = name_to_rid_www("v1");
16711671
v2 = name_to_rid_www("v2");
16721672
@@ -1763,12 +1763,12 @@
17631763
*/
17641764
void rawartifact_page(void){
17651765
int rid = 0;
17661766
char *zUuid;
17671767
1768
- if( P("ci") && P("filename") ){
1769
- rid = artifact_from_ci_and_filename(0, 0);
1768
+ if( P("ci") ){
1769
+ rid = artifact_from_ci_and_filename(0);
17701770
}
17711771
if( rid==0 ){
17721772
rid = name_to_rid_www("name");
17731773
}
17741774
login_check_credentials();
@@ -1942,59 +1942,53 @@
19421942
19431943
/*
19441944
** Look for "ci" and "filename" query parameters. If found, try to
19451945
** use them to extract the record ID of an artifact for the file.
19461946
**
1947
-** Also look for "fn" as an alias for "filename". If either "filename"
1948
-** or "fn" is present but "ci" is missing, use "tip" as a default value
1949
-** for "ci".
1950
-**
1951
-** If zNameParam is not NULL, this use that parameter as the filename
1952
-** rather than "fn" or "filename".
1953
-**
1954
-** If pUrl is not NULL, then record the "ci" and "filename" values in
1955
-** pUrl.
1956
-**
1957
-** At least one of pUrl or zNameParam must be NULL.
1947
+** Also look for "fn" and "name" as an aliases for "filename". If any
1948
+** "filename" or "fn" or "name" are present but "ci" is missing, then
1949
+** use "tip" as the default value for "ci".
1950
+**
1951
+** If zNameParam is not NULL, then use that parameter as the filename
1952
+** rather than "fn" or "filename" or "name". the zNameParam is used
1953
+** for the from= and to= query parameters of /fdiff.
19581954
*/
1959
-int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){
1955
+int artifact_from_ci_and_filename(const char *zNameParam){
19601956
const char *zFilename;
19611957
const char *zCI;
19621958
int cirid;
19631959
Manifest *pManifest;
19641960
ManifestFile *pFile;
1961
+ int rid = 0;
19651962
19661963
if( zNameParam ){
19671964
zFilename = P(zNameParam);
19681965
}else{
19691966
zFilename = P("filename");
19701967
if( zFilename==0 ){
19711968
zFilename = P("fn");
19721969
}
1970
+ if( zFilename==0 ){
1971
+ zFilename = P("name");
1972
+ }
19731973
}
19741974
if( zFilename==0 ) return 0;
19751975
1976
- zCI = P("ci");
1977
- cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci");
1976
+ zCI = PD("ci", "tip");
1977
+ cirid = name_to_typed_rid(zCI, "ci");
19781978
if( cirid<=0 ) return 0;
19791979
pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
19801980
if( pManifest==0 ) return 0;
19811981
manifest_file_rewind(pManifest);
19821982
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
19831983
if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1984
- int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1985
- manifest_destroy(pManifest);
1986
- if( pUrl ){
1987
- assert( zNameParam==0 );
1988
- url_add_parameter(pUrl, "fn", zFilename);
1989
- if( zCI ) url_add_parameter(pUrl, "ci", zCI);
1990
- }
1991
- return rid;
1984
+ rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1985
+ break;
19921986
}
19931987
}
19941988
manifest_destroy(pManifest);
1995
- return 0;
1989
+ return rid;
19961990
}
19971991
19981992
/*
19991993
** The "z" argument is a string that contains the text of a source code
20001994
** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2096,21 +2090,31 @@
20962090
** ln=N - highlight line number N
20972091
** ln=M-N - highlight lines M through N inclusive
20982092
** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
20992093
** verbose - show more detail in the description
21002094
** download - redirect to the download (artifact page only)
2101
-** name=NAME - Provide filename or hash as a query parameter
2095
+** name=NAME - filename or hash as a query parameter
21022096
** filename=NAME - alternative spelling for "name="
21032097
** fn=NAME - alternative spelling for "name="
2104
-** ci=VERSION - The specific check-in to use for "filename=".
2098
+** ci=VERSION - The specific check-in to use with "name=" to
2099
+** identify the file.
21052100
**
21062101
** The /artifact page show the complete content of a file
2107
-** identified by HASH as preformatted text. The
2108
-** /whatis page shows only a description of the file. The /file
2109
-** page shows the most recent version of the file or directory
2110
-** called NAME, or a list of the top-level directory if NAME is
2111
-** omitted.
2102
+** identified by HASH. The /whatis page shows only a description
2103
+** of how the artifact is used. The /file page shows the most recent
2104
+** version of the file or directory called NAME, or a list of the
2105
+** top-level directory if NAME is omitted.
2106
+**
2107
+** The name= query parameter can refer to either the name of a file,
2108
+** or an artifact hash. If the ci= query parameter is also present,
2109
+** then name= must refer to a file name. If ci= is omitted, either
2110
+** interpretation may be used. When name= is a filename and ci=
2111
+** is omitted, a default value of "tip" is used for ci=.
2112
+**
2113
+** If name= is ambiguous in that it might be either a filename or
2114
+** a hash, then the hash interpretation is preferred for /artifact
2115
+** and /whatis and the filename interpretation is preferred for /file.
21122116
*/
21132117
void artifact_page(void){
21142118
int rid = 0;
21152119
Blob content;
21162120
const char *zMime;
@@ -2125,101 +2129,88 @@
21252129
int isFile = fossil_strcmp(g.zPath,"file")==0;
21262130
const char *zLn = P("ln");
21272131
const char *zName = P("name");
21282132
const char *zCI = P("ci");
21292133
HQuery url;
2130
- Blob dirname;
21312134
char *zCIUuid = 0;
21322135
int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2136
+ int isBranchCI = 0; /* ci= refers to a branch name */
21332137
char *zHeader = 0;
21342138
21352139
login_check_credentials();
21362140
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2137
- url_initialize(&url, g.zPath);
2141
+
2142
+ /* Capture and normalize the name= and ci= query parameters */
21382143
if( zName==0 ){
21392144
zName = P("filename");
2140
- if( zName==0 ) zName = P("fn");
2145
+ if( zName==0 ){
2146
+ zName = P("fn");
2147
+ }
21412148
}
21422149
if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2143
- if( zCI && zName ){
2144
- blob_zero(&dirname);
2145
- hyperlinked_path(zName, &dirname, zCI, "dir", "");
2146
- blob_reset(&dirname);
2147
-
2148
- if( name_to_uuid2(zCI, "ci", &zCIUuid) ){
2149
- isSymbolicCI = (sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI)) != 0);
2150
- }
2151
- }
2152
- if( isFile && zName ) {
2153
- rid = artifact_from_ci_and_filename(0, "name");
2154
- }else{
2155
- rid = artifact_from_ci_and_filename(&url, 0);
2156
- }
2157
- if( rid==0 ){
2158
- url_add_parameter(&url, "name", zName);
2159
- if( isFile ){
2160
- int isUnknownAtCI = 0;
2161
-
2162
- /* Do a top-level directory listing in /file mode if no argument
2163
- ** specified */
2164
- if( zName==0 || zName[0]==0 ){
2165
- if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2166
- page_tree();
2167
- return;
2168
- }
2169
- /* Look for a single file with the given name */
2170
- rid = db_int(0,
2171
- "SELECT fid FROM filename, mlink, event"
2172
- " WHERE name=%Q"
2173
- " AND mlink.fnid=filename.fnid"
2174
- " AND event.objid=mlink.mid"
2175
- " ORDER BY event.mtime DESC LIMIT 1",
2176
- zName
2177
- );
2178
- /* If found only by the name, then the file is unknown in the check-in.
2179
- ** Possibly, the file was renamed/deleted.
2180
- */
2181
- if( rid && zCIUuid ){
2182
- rid = 0;
2183
- isUnknownAtCI = 1;
2184
- }
2185
- /* If no file called NAME exists, instead look for a directory
2186
- ** with that name, and do a directory listing */
2187
- if( rid==0 ){
2188
- int nName = (int)strlen(zName);
2189
- if( nName && zName[nName-1]=='/' ) nName--;
2190
- if( db_exists(
2191
- "SELECT 1 FROM filename"
2192
- " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2193
- nName, zName, nName+1, nName, zName
2194
- ) ){
2195
- if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2196
- page_tree();
2197
- return;
2198
- }
2199
- }
2200
- /* If no file or directory called NAME: issue an error */
2201
- if( rid==0 ){
2202
- if( isUnknownAtCI ){
2203
- if( isSymbolicCI ){
2204
- zHeader = mprintf("No such file at %s", zCI);
2205
- }else{
2206
- zHeader = mprintf("No such file at [%S]", zCIUuid);
2207
- }
2208
- style_header("%s", zHeader);
2209
- fossil_free(zHeader);
2210
- @ File %z(href("%R/finfo?name=%T",zName))%h(zName)</a> is not known
2211
- @ at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>].
2212
- }else{
2213
- style_header("No such file");
2214
- @ File '%h(zName)' is not known in this repository.
2215
- }
2216
- style_footer();
2217
- return;
2218
- }
2219
- }else{
2220
- rid = name_to_rid_www("name");
2150
+ if( zCI
2151
+ && name_to_uuid2(zCI, "ci", &zCIUuid)
2152
+ && sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI))!=0
2153
+ ){
2154
+ isSymbolicCI = 1;
2155
+ isBranchCI = db_exists(
2156
+ "SELECT 1 FROM tagxref, blob"
2157
+ " WHERE blob.uuid=%Q AND tagxref.rid=blob.rid"
2158
+ " AND tagxref.value=%Q AND tagxref.tagtype>0"
2159
+ " AND tagxref.tagid=%d",
2160
+ zCIUuid, zCI, TAG_BRANCH
2161
+ );
2162
+ }
2163
+
2164
+ /* The name= query parameter (or at least one of its alternative
2165
+ ** spellings) is required. Except for /file, show a top-level
2166
+ ** directory listing if name= is omitted.
2167
+ */
2168
+ if( zName==0 ){
2169
+ if( isFile ){
2170
+ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2171
+ page_tree();
2172
+ return;
2173
+ }
2174
+ style_header("Missing name= query parameter");
2175
+ @ The name= query parameter is missing
2176
+ style_footer();
2177
+ return;
2178
+ }
2179
+
2180
+ url_initialize(&url, g.zPath);
2181
+ url_add_parameter(&url, "name", zName);
2182
+ url_add_parameter(&url, "ci", zCI);
2183
+
2184
+ if( zCI==0 && !isFile ){
2185
+ /* If there is no ci= query parameter, then prefer to interpret
2186
+ ** name= as a hash for /artifact and /whatis. But for not for /file.
2187
+ ** For /file, a name= without a ci= while prefer to use the default
2188
+ ** "tip" value for ci=. */
2189
+ rid = name_to_rid(zName);
2190
+ }
2191
+ if( rid==0 ){
2192
+ rid = artifact_from_ci_and_filename(0);
2193
+ }
2194
+ if( rid==0 && zCI==0 && isFile ){
2195
+ /* For /file, only try to interpret name= as a hash if it did not
2196
+ ** match any known filename. */
2197
+ rid = name_to_rid(zName);
2198
+ }
2199
+ if( rid==0 && isFile ){
2200
+ /* If no file called NAME exists, instead look for a directory
2201
+ ** with that name, and do a directory listing */
2202
+ int nName = (int)strlen(zName);
2203
+ if( nName && zName[nName-1]=='/' ) nName--;
2204
+ if( db_exists(
2205
+ "SELECT 1 FROM filename"
2206
+ " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2207
+ nName, zName, nName+1, nName, zName
2208
+ ) ){
2209
+ if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2210
+ page_tree();
2211
+ return;
22212212
}
22222213
}
22232214
22242215
if( rid==0 ){
22252216
style_header("No such artifact");
@@ -2232,21 +2223,27 @@
22322223
objdescFlags |= OBJDESC_DETAIL;
22332224
}
22342225
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
22352226
22362227
if( isFile ){
2237
- if( zCI ){
2228
+ if( zCI==0 ){
2229
+ @ <h2>Latest version of file '%h(zName)':</h2>
2230
+ }else{
22382231
const char *zPath;
22392232
Blob path;
22402233
blob_zero(&path);
22412234
hyperlinked_path(zName, &path, zCI, "dir", "");
22422235
zPath = blob_str(&path);
2243
- @ <h2>File %s(zPath) at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]
2244
- @ </h2>
2236
+ @ <h2>File %s(zPath) \
2237
+ if( isBranchCI ){
2238
+ @ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
2239
+ }else if( isSymbolicCI ){
2240
+ @ as of check-in %z(href("/info/%!S",zCIUuid))%s(zCI)</a></h2>
2241
+ }else{
2242
+ @ as of check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
2243
+ }
22452244
blob_reset(&path);
2246
- }else{
2247
- @ <h2>Latest version of file '%h(zName)':</h2>
22482245
}
22492246
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
22502247
}else{
22512248
@ <h2>Artifact
22522249
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
22532250
--- src/info.c
+++ src/info.c
@@ -1661,12 +1661,12 @@
1661 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1662 cookie_link_parameter("diff","diff","2");
1663 diffType = atoi(PD("diff","2"));
1664 cookie_render();
1665 if( P("from") && P("to") ){
1666 v1 = artifact_from_ci_and_filename(0, "from");
1667 v2 = artifact_from_ci_and_filename(0, "to");
1668 }else{
1669 Stmt q;
1670 v1 = name_to_rid_www("v1");
1671 v2 = name_to_rid_www("v2");
1672
@@ -1763,12 +1763,12 @@
1763 */
1764 void rawartifact_page(void){
1765 int rid = 0;
1766 char *zUuid;
1767
1768 if( P("ci") && P("filename") ){
1769 rid = artifact_from_ci_and_filename(0, 0);
1770 }
1771 if( rid==0 ){
1772 rid = name_to_rid_www("name");
1773 }
1774 login_check_credentials();
@@ -1942,59 +1942,53 @@
1942
1943 /*
1944 ** Look for "ci" and "filename" query parameters. If found, try to
1945 ** use them to extract the record ID of an artifact for the file.
1946 **
1947 ** Also look for "fn" as an alias for "filename". If either "filename"
1948 ** or "fn" is present but "ci" is missing, use "tip" as a default value
1949 ** for "ci".
1950 **
1951 ** If zNameParam is not NULL, this use that parameter as the filename
1952 ** rather than "fn" or "filename".
1953 **
1954 ** If pUrl is not NULL, then record the "ci" and "filename" values in
1955 ** pUrl.
1956 **
1957 ** At least one of pUrl or zNameParam must be NULL.
1958 */
1959 int artifact_from_ci_and_filename(HQuery *pUrl, const char *zNameParam){
1960 const char *zFilename;
1961 const char *zCI;
1962 int cirid;
1963 Manifest *pManifest;
1964 ManifestFile *pFile;
 
1965
1966 if( zNameParam ){
1967 zFilename = P(zNameParam);
1968 }else{
1969 zFilename = P("filename");
1970 if( zFilename==0 ){
1971 zFilename = P("fn");
1972 }
 
 
 
1973 }
1974 if( zFilename==0 ) return 0;
1975
1976 zCI = P("ci");
1977 cirid = name_to_typed_rid(zCI ? zCI : "tip", "ci");
1978 if( cirid<=0 ) return 0;
1979 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1980 if( pManifest==0 ) return 0;
1981 manifest_file_rewind(pManifest);
1982 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1983 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1984 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1985 manifest_destroy(pManifest);
1986 if( pUrl ){
1987 assert( zNameParam==0 );
1988 url_add_parameter(pUrl, "fn", zFilename);
1989 if( zCI ) url_add_parameter(pUrl, "ci", zCI);
1990 }
1991 return rid;
1992 }
1993 }
1994 manifest_destroy(pManifest);
1995 return 0;
1996 }
1997
1998 /*
1999 ** The "z" argument is a string that contains the text of a source code
2000 ** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2096,21 +2090,31 @@
2096 ** ln=N - highlight line number N
2097 ** ln=M-N - highlight lines M through N inclusive
2098 ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
2099 ** verbose - show more detail in the description
2100 ** download - redirect to the download (artifact page only)
2101 ** name=NAME - Provide filename or hash as a query parameter
2102 ** filename=NAME - alternative spelling for "name="
2103 ** fn=NAME - alternative spelling for "name="
2104 ** ci=VERSION - The specific check-in to use for "filename=".
 
2105 **
2106 ** The /artifact page show the complete content of a file
2107 ** identified by HASH as preformatted text. The
2108 ** /whatis page shows only a description of the file. The /file
2109 ** page shows the most recent version of the file or directory
2110 ** called NAME, or a list of the top-level directory if NAME is
2111 ** omitted.
 
 
 
 
 
 
 
 
 
2112 */
2113 void artifact_page(void){
2114 int rid = 0;
2115 Blob content;
2116 const char *zMime;
@@ -2125,101 +2129,88 @@
2125 int isFile = fossil_strcmp(g.zPath,"file")==0;
2126 const char *zLn = P("ln");
2127 const char *zName = P("name");
2128 const char *zCI = P("ci");
2129 HQuery url;
2130 Blob dirname;
2131 char *zCIUuid = 0;
2132 int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
 
2133 char *zHeader = 0;
2134
2135 login_check_credentials();
2136 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2137 url_initialize(&url, g.zPath);
 
2138 if( zName==0 ){
2139 zName = P("filename");
2140 if( zName==0 ) zName = P("fn");
 
 
2141 }
2142 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2143 if( zCI && zName ){
2144 blob_zero(&dirname);
2145 hyperlinked_path(zName, &dirname, zCI, "dir", "");
2146 blob_reset(&dirname);
2147
2148 if( name_to_uuid2(zCI, "ci", &zCIUuid) ){
2149 isSymbolicCI = (sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI)) != 0);
2150 }
2151 }
2152 if( isFile && zName ) {
2153 rid = artifact_from_ci_and_filename(0, "name");
2154 }else{
2155 rid = artifact_from_ci_and_filename(&url, 0);
2156 }
2157 if( rid==0 ){
2158 url_add_parameter(&url, "name", zName);
2159 if( isFile ){
2160 int isUnknownAtCI = 0;
2161
2162 /* Do a top-level directory listing in /file mode if no argument
2163 ** specified */
2164 if( zName==0 || zName[0]==0 ){
2165 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2166 page_tree();
2167 return;
2168 }
2169 /* Look for a single file with the given name */
2170 rid = db_int(0,
2171 "SELECT fid FROM filename, mlink, event"
2172 " WHERE name=%Q"
2173 " AND mlink.fnid=filename.fnid"
2174 " AND event.objid=mlink.mid"
2175 " ORDER BY event.mtime DESC LIMIT 1",
2176 zName
2177 );
2178 /* If found only by the name, then the file is unknown in the check-in.
2179 ** Possibly, the file was renamed/deleted.
2180 */
2181 if( rid && zCIUuid ){
2182 rid = 0;
2183 isUnknownAtCI = 1;
2184 }
2185 /* If no file called NAME exists, instead look for a directory
2186 ** with that name, and do a directory listing */
2187 if( rid==0 ){
2188 int nName = (int)strlen(zName);
2189 if( nName && zName[nName-1]=='/' ) nName--;
2190 if( db_exists(
2191 "SELECT 1 FROM filename"
2192 " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2193 nName, zName, nName+1, nName, zName
2194 ) ){
2195 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2196 page_tree();
2197 return;
2198 }
2199 }
2200 /* If no file or directory called NAME: issue an error */
2201 if( rid==0 ){
2202 if( isUnknownAtCI ){
2203 if( isSymbolicCI ){
2204 zHeader = mprintf("No such file at %s", zCI);
2205 }else{
2206 zHeader = mprintf("No such file at [%S]", zCIUuid);
2207 }
2208 style_header("%s", zHeader);
2209 fossil_free(zHeader);
2210 @ File %z(href("%R/finfo?name=%T",zName))%h(zName)</a> is not known
2211 @ at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>].
2212 }else{
2213 style_header("No such file");
2214 @ File '%h(zName)' is not known in this repository.
2215 }
2216 style_footer();
2217 return;
2218 }
2219 }else{
2220 rid = name_to_rid_www("name");
2221 }
2222 }
2223
2224 if( rid==0 ){
2225 style_header("No such artifact");
@@ -2232,21 +2223,27 @@
2232 objdescFlags |= OBJDESC_DETAIL;
2233 }
2234 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2235
2236 if( isFile ){
2237 if( zCI ){
 
 
2238 const char *zPath;
2239 Blob path;
2240 blob_zero(&path);
2241 hyperlinked_path(zName, &path, zCI, "dir", "");
2242 zPath = blob_str(&path);
2243 @ <h2>File %s(zPath) at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]
2244 @ </h2>
 
 
 
 
 
 
2245 blob_reset(&path);
2246 }else{
2247 @ <h2>Latest version of file '%h(zName)':</h2>
2248 }
2249 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2250 }else{
2251 @ <h2>Artifact
2252 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2253
--- src/info.c
+++ src/info.c
@@ -1661,12 +1661,12 @@
1661 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1662 cookie_link_parameter("diff","diff","2");
1663 diffType = atoi(PD("diff","2"));
1664 cookie_render();
1665 if( P("from") && P("to") ){
1666 v1 = artifact_from_ci_and_filename("from");
1667 v2 = artifact_from_ci_and_filename("to");
1668 }else{
1669 Stmt q;
1670 v1 = name_to_rid_www("v1");
1671 v2 = name_to_rid_www("v2");
1672
@@ -1763,12 +1763,12 @@
1763 */
1764 void rawartifact_page(void){
1765 int rid = 0;
1766 char *zUuid;
1767
1768 if( P("ci") ){
1769 rid = artifact_from_ci_and_filename(0);
1770 }
1771 if( rid==0 ){
1772 rid = name_to_rid_www("name");
1773 }
1774 login_check_credentials();
@@ -1942,59 +1942,53 @@
1942
1943 /*
1944 ** Look for "ci" and "filename" query parameters. If found, try to
1945 ** use them to extract the record ID of an artifact for the file.
1946 **
1947 ** Also look for "fn" and "name" as an aliases for "filename". If any
1948 ** "filename" or "fn" or "name" are present but "ci" is missing, then
1949 ** use "tip" as the default value for "ci".
1950 **
1951 ** If zNameParam is not NULL, then use that parameter as the filename
1952 ** rather than "fn" or "filename" or "name". the zNameParam is used
1953 ** for the from= and to= query parameters of /fdiff.
 
 
 
 
1954 */
1955 int artifact_from_ci_and_filename(const char *zNameParam){
1956 const char *zFilename;
1957 const char *zCI;
1958 int cirid;
1959 Manifest *pManifest;
1960 ManifestFile *pFile;
1961 int rid = 0;
1962
1963 if( zNameParam ){
1964 zFilename = P(zNameParam);
1965 }else{
1966 zFilename = P("filename");
1967 if( zFilename==0 ){
1968 zFilename = P("fn");
1969 }
1970 if( zFilename==0 ){
1971 zFilename = P("name");
1972 }
1973 }
1974 if( zFilename==0 ) return 0;
1975
1976 zCI = PD("ci", "tip");
1977 cirid = name_to_typed_rid(zCI, "ci");
1978 if( cirid<=0 ) return 0;
1979 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1980 if( pManifest==0 ) return 0;
1981 manifest_file_rewind(pManifest);
1982 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1983 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1984 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
1985 break;
 
 
 
 
 
 
1986 }
1987 }
1988 manifest_destroy(pManifest);
1989 return rid;
1990 }
1991
1992 /*
1993 ** The "z" argument is a string that contains the text of a source code
1994 ** file. This routine appends that text to the HTTP reply with line numbering.
@@ -2096,21 +2090,31 @@
2090 ** ln=N - highlight line number N
2091 ** ln=M-N - highlight lines M through N inclusive
2092 ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
2093 ** verbose - show more detail in the description
2094 ** download - redirect to the download (artifact page only)
2095 ** name=NAME - filename or hash as a query parameter
2096 ** filename=NAME - alternative spelling for "name="
2097 ** fn=NAME - alternative spelling for "name="
2098 ** ci=VERSION - The specific check-in to use with "name=" to
2099 ** identify the file.
2100 **
2101 ** The /artifact page show the complete content of a file
2102 ** identified by HASH. The /whatis page shows only a description
2103 ** of how the artifact is used. The /file page shows the most recent
2104 ** version of the file or directory called NAME, or a list of the
2105 ** top-level directory if NAME is omitted.
2106 **
2107 ** The name= query parameter can refer to either the name of a file,
2108 ** or an artifact hash. If the ci= query parameter is also present,
2109 ** then name= must refer to a file name. If ci= is omitted, either
2110 ** interpretation may be used. When name= is a filename and ci=
2111 ** is omitted, a default value of "tip" is used for ci=.
2112 **
2113 ** If name= is ambiguous in that it might be either a filename or
2114 ** a hash, then the hash interpretation is preferred for /artifact
2115 ** and /whatis and the filename interpretation is preferred for /file.
2116 */
2117 void artifact_page(void){
2118 int rid = 0;
2119 Blob content;
2120 const char *zMime;
@@ -2125,101 +2129,88 @@
2129 int isFile = fossil_strcmp(g.zPath,"file")==0;
2130 const char *zLn = P("ln");
2131 const char *zName = P("name");
2132 const char *zCI = P("ci");
2133 HQuery url;
 
2134 char *zCIUuid = 0;
2135 int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2136 int isBranchCI = 0; /* ci= refers to a branch name */
2137 char *zHeader = 0;
2138
2139 login_check_credentials();
2140 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2141
2142 /* Capture and normalize the name= and ci= query parameters */
2143 if( zName==0 ){
2144 zName = P("filename");
2145 if( zName==0 ){
2146 zName = P("fn");
2147 }
2148 }
2149 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2150 if( zCI
2151 && name_to_uuid2(zCI, "ci", &zCIUuid)
2152 && sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI))!=0
2153 ){
2154 isSymbolicCI = 1;
2155 isBranchCI = db_exists(
2156 "SELECT 1 FROM tagxref, blob"
2157 " WHERE blob.uuid=%Q AND tagxref.rid=blob.rid"
2158 " AND tagxref.value=%Q AND tagxref.tagtype>0"
2159 " AND tagxref.tagid=%d",
2160 zCIUuid, zCI, TAG_BRANCH
2161 );
2162 }
2163
2164 /* The name= query parameter (or at least one of its alternative
2165 ** spellings) is required. Except for /file, show a top-level
2166 ** directory listing if name= is omitted.
2167 */
2168 if( zName==0 ){
2169 if( isFile ){
2170 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2171 page_tree();
2172 return;
2173 }
2174 style_header("Missing name= query parameter");
2175 @ The name= query parameter is missing
2176 style_footer();
2177 return;
2178 }
2179
2180 url_initialize(&url, g.zPath);
2181 url_add_parameter(&url, "name", zName);
2182 url_add_parameter(&url, "ci", zCI);
2183
2184 if( zCI==0 && !isFile ){
2185 /* If there is no ci= query parameter, then prefer to interpret
2186 ** name= as a hash for /artifact and /whatis. But for not for /file.
2187 ** For /file, a name= without a ci= while prefer to use the default
2188 ** "tip" value for ci=. */
2189 rid = name_to_rid(zName);
2190 }
2191 if( rid==0 ){
2192 rid = artifact_from_ci_and_filename(0);
2193 }
2194 if( rid==0 && zCI==0 && isFile ){
2195 /* For /file, only try to interpret name= as a hash if it did not
2196 ** match any known filename. */
2197 rid = name_to_rid(zName);
2198 }
2199 if( rid==0 && isFile ){
2200 /* If no file called NAME exists, instead look for a directory
2201 ** with that name, and do a directory listing */
2202 int nName = (int)strlen(zName);
2203 if( nName && zName[nName-1]=='/' ) nName--;
2204 if( db_exists(
2205 "SELECT 1 FROM filename"
2206 " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
2207 nName, zName, nName+1, nName, zName
2208 ) ){
2209 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2210 page_tree();
2211 return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2212 }
2213 }
2214
2215 if( rid==0 ){
2216 style_header("No such artifact");
@@ -2232,21 +2223,27 @@
2223 objdescFlags |= OBJDESC_DETAIL;
2224 }
2225 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2226
2227 if( isFile ){
2228 if( zCI==0 ){
2229 @ <h2>Latest version of file '%h(zName)':</h2>
2230 }else{
2231 const char *zPath;
2232 Blob path;
2233 blob_zero(&path);
2234 hyperlinked_path(zName, &path, zCI, "dir", "");
2235 zPath = blob_str(&path);
2236 @ <h2>File %s(zPath) \
2237 if( isBranchCI ){
2238 @ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
2239 }else if( isSymbolicCI ){
2240 @ as of check-in %z(href("/info/%!S",zCIUuid))%s(zCI)</a></h2>
2241 }else{
2242 @ as of check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
2243 }
2244 blob_reset(&path);
 
 
2245 }
2246 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2247 }else{
2248 @ <h2>Artifact
2249 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2250

Keyboard Shortcuts

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