| | @@ -1340,33 +1340,22 @@ |
| 1340 | 1340 | |
| 1341 | 1341 | /* |
| 1342 | 1342 | ** Possible flags for the second parameter to |
| 1343 | 1343 | ** object_description() |
| 1344 | 1344 | */ |
| 1345 | | -#define OBJDESC_DETAIL 0x0001 /* more detail */ |
| 1345 | +#define OBJDESC_DETAIL 0x0001 /* Show more detail */ |
| 1346 | 1346 | #define OBJDESC_BASE 0x0002 /* Set <base> using this object */ |
| 1347 | 1347 | #endif |
| 1348 | 1348 | |
| 1349 | 1349 | /* |
| 1350 | 1350 | ** Write a description of an object to the www reply. |
| 1351 | | -** |
| 1352 | | -** If the object is a file then mention: |
| 1353 | | -** |
| 1354 | | -** * It's artifact ID |
| 1355 | | -** * All its filenames |
| 1356 | | -** * The check-in it was part of, with times and users |
| 1357 | | -** |
| 1358 | | -** If the object is a manifest, then mention: |
| 1359 | | -** |
| 1360 | | -** * It's artifact ID |
| 1361 | | -** * date of check-in |
| 1362 | | -** * Comment & user |
| 1363 | 1351 | */ |
| 1364 | 1352 | int object_description( |
| 1365 | | - int rid, /* The artifact ID */ |
| 1353 | + int rid, /* The artifact ID for the object to describe */ |
| 1366 | 1354 | u32 objdescFlags, /* Flags to control display */ |
| 1367 | | - Blob *pDownloadName /* Fill with an appropriate download name */ |
| 1355 | + const char *zFileName, /* For file objects, use this name. Can be NULL */ |
| 1356 | + Blob *pDownloadName /* Fill with a good download name. Can be NULL */ |
| 1368 | 1357 | ){ |
| 1369 | 1358 | Stmt q; |
| 1370 | 1359 | int cnt = 0; |
| 1371 | 1360 | int nWiki = 0; |
| 1372 | 1361 | int objType = 0; |
| | @@ -1401,10 +1390,11 @@ |
| 1401 | 1390 | const char *zVers = db_column_text(&q, 4); |
| 1402 | 1391 | int mPerm = db_column_int(&q, 5); |
| 1403 | 1392 | const char *zBr = db_column_text(&q, 6); |
| 1404 | 1393 | int szFile = db_column_int(&q,7); |
| 1405 | 1394 | int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0; |
| 1395 | + if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue; |
| 1406 | 1396 | if( sameFilename && !showDetail ){ |
| 1407 | 1397 | if( cnt==1 ){ |
| 1408 | 1398 | @ %z(href("%R/whatis/%!S",zUuid))[more...]</a> |
| 1409 | 1399 | } |
| 1410 | 1400 | cnt++; |
| | @@ -1747,13 +1737,13 @@ |
| 1747 | 1737 | @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To |
| 1748 | 1738 | @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2> |
| 1749 | 1739 | }else{ |
| 1750 | 1740 | @ <h2>Differences From |
| 1751 | 1741 | @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2> |
| 1752 | | - object_description(v1, objdescFlags, 0); |
| 1742 | + object_description(v1, objdescFlags,0, 0); |
| 1753 | 1743 | @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2> |
| 1754 | | - object_description(v2, objdescFlags, 0); |
| 1744 | + object_description(v2, objdescFlags,0, 0); |
| 1755 | 1745 | } |
| 1756 | 1746 | if( pRe ){ |
| 1757 | 1747 | @ <b>Only differences that match regular expression "%h(zRe)" |
| 1758 | 1748 | @ are shown.</b> |
| 1759 | 1749 | } |
| | @@ -1937,11 +1927,11 @@ |
| 1937 | 1927 | }else{ |
| 1938 | 1928 | @ :</h2> |
| 1939 | 1929 | } |
| 1940 | 1930 | blob_zero(&downloadName); |
| 1941 | 1931 | if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL; |
| 1942 | | - object_description(rid, objdescFlags, &downloadName); |
| 1932 | + object_description(rid, objdescFlags, 0, &downloadName); |
| 1943 | 1933 | style_submenu_element("Download", "%s/raw/%T?name=%s", |
| 1944 | 1934 | g.zTop, blob_str(&downloadName), zUuid); |
| 1945 | 1935 | @ <hr /> |
| 1946 | 1936 | content_get(rid, &content); |
| 1947 | 1937 | @ <blockquote><pre> |
| | @@ -2127,20 +2117,41 @@ |
| 2127 | 2117 | Blob downloadName; |
| 2128 | 2118 | int renderAsWiki = 0; |
| 2129 | 2119 | int renderAsHtml = 0; |
| 2130 | 2120 | int objType; |
| 2131 | 2121 | int asText; |
| 2132 | | - const char *zUuid; |
| 2122 | + const char *zUuid = 0; |
| 2133 | 2123 | u32 objdescFlags = OBJDESC_BASE; |
| 2134 | 2124 | int descOnly = fossil_strcmp(g.zPath,"whatis")==0; |
| 2135 | 2125 | int isFile = fossil_strcmp(g.zPath,"file")==0; |
| 2136 | 2126 | const char *zLn = P("ln"); |
| 2137 | 2127 | const char *zName = P("name"); |
| 2128 | + const char *zCI = P("ci"); |
| 2138 | 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; |
| 2139 | 2134 | |
| 2135 | + login_check_credentials(); |
| 2136 | + if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2140 | 2137 | url_initialize(&url, g.zPath); |
| 2141 | | - rid = artifact_from_ci_and_filename(&url, 0); |
| 2138 | + if( zCI && strlen(zCI)==0 ){ zCI = 0; } |
| 2139 | + if( zCI ){ |
| 2140 | + blob_zero(&dirname); |
| 2141 | + hyperlinked_path(zName, &dirname, zCI, "dir", ""); |
| 2142 | + blob_reset(&dirname); |
| 2143 | + |
| 2144 | + if( name_to_uuid2(zCI, "ci", &zCIUuid) ){ |
| 2145 | + isSymbolicCI = (strncmp(zCIUuid, zCI, strlen(zCI)) != 0); |
| 2146 | + } |
| 2147 | + } |
| 2148 | + if( isFile && zName ) { |
| 2149 | + rid = artifact_from_ci_and_filename(0, "name"); |
| 2150 | + }else{ |
| 2151 | + rid = artifact_from_ci_and_filename(&url, 0); |
| 2152 | + } |
| 2142 | 2153 | if( rid==0 ){ |
| 2143 | 2154 | url_add_parameter(&url, "name", zName); |
| 2144 | 2155 | if( isFile ){ |
| 2145 | 2156 | /* Do a top-level directory listing in /file mode if no argument |
| 2146 | 2157 | ** specified */ |
| | @@ -2183,12 +2194,10 @@ |
| 2183 | 2194 | }else{ |
| 2184 | 2195 | rid = name_to_rid_www("name"); |
| 2185 | 2196 | } |
| 2186 | 2197 | } |
| 2187 | 2198 | |
| 2188 | | - login_check_credentials(); |
| 2189 | | - if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2190 | 2199 | if( rid==0 ){ |
| 2191 | 2200 | style_header("No such artifact"); |
| 2192 | 2201 | @ Artifact '%h(zName)' does not exist in this repository. |
| 2193 | 2202 | style_footer(); |
| 2194 | 2203 | return; |
| | @@ -2196,12 +2205,24 @@ |
| 2196 | 2205 | if( descOnly || P("verbose")!=0 ){ |
| 2197 | 2206 | url_add_parameter(&url, "verbose", "1"); |
| 2198 | 2207 | objdescFlags |= OBJDESC_DETAIL; |
| 2199 | 2208 | } |
| 2200 | 2209 | zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 2210 | + |
| 2201 | 2211 | if( isFile ){ |
| 2202 | | - @ <h2>Latest version of file '%h(zName)':</h2> |
| 2212 | + if( zCI ){ |
| 2213 | + const char *zPath; |
| 2214 | + Blob path; |
| 2215 | + blob_zero(&path); |
| 2216 | + hyperlinked_path(zName, &path, zCI, "dir", ""); |
| 2217 | + zPath = blob_str(&path); |
| 2218 | + @ <h2>File %s(zPath) of check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>] |
| 2219 | + @ </h2> |
| 2220 | + blob_reset(&path); |
| 2221 | + }else{ |
| 2222 | + @ <h2>Latest version of file '%h(zName)':</h2> |
| 2223 | + } |
| 2203 | 2224 | style_submenu_element("Artifact", "%R/artifact/%S", zUuid); |
| 2204 | 2225 | }else{ |
| 2205 | 2226 | @ <h2>Artifact |
| 2206 | 2227 | style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid); |
| 2207 | 2228 | if( g.perm.Setup ){ |
| | @@ -2211,11 +2232,11 @@ |
| 2211 | 2232 | } |
| 2212 | 2233 | } |
| 2213 | 2234 | blob_zero(&downloadName); |
| 2214 | 2235 | asText = P("txt")!=0; |
| 2215 | 2236 | if( asText ) objdescFlags &= ~OBJDESC_BASE; |
| 2216 | | - objType = object_description(rid, objdescFlags, &downloadName); |
| 2237 | + objType = object_description(rid, objdescFlags, (isFile ? zName : 0),&downloadName); |
| 2217 | 2238 | if( !descOnly && P("download")!=0 ){ |
| 2218 | 2239 | cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName), |
| 2219 | 2240 | db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid)); |
| 2220 | 2241 | /*NOTREACHED*/ |
| 2221 | 2242 | } |
| | @@ -2226,12 +2247,27 @@ |
| 2226 | 2247 | g.zTop, zUuid); |
| 2227 | 2248 | }else{ |
| 2228 | 2249 | style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); |
| 2229 | 2250 | } |
| 2230 | 2251 | } |
| 2231 | | - style_header("%s", isFile ? "File Content" : |
| 2232 | | - descOnly ? "Artifact Description" : "Artifact Content"); |
| 2252 | + |
| 2253 | + if( isFile ){ |
| 2254 | + if( isSymbolicCI ){ |
| 2255 | + zHeader = mprintf("%s at %s", file_tail(zName), zCI); |
| 2256 | + }else if( zCI ){ |
| 2257 | + zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid); |
| 2258 | + }else{ |
| 2259 | + zHeader = mprintf("%s", file_tail(zName)); |
| 2260 | + } |
| 2261 | + }else if( descOnly ){ |
| 2262 | + zHeader = mprintf("Artifact Description [%S]", zUuid); |
| 2263 | + }else{ |
| 2264 | + zHeader = mprintf("Artifact [%S]", zUuid); |
| 2265 | + } |
| 2266 | + style_header("%s", zHeader); |
| 2267 | + fossil_free(zCIUuid); |
| 2268 | + fossil_free(zHeader); |
| 2233 | 2269 | if( g.perm.Admin ){ |
| 2234 | 2270 | Stmt q; |
| 2235 | 2271 | db_prepare(&q, |
| 2236 | 2272 | "SELECT coalesce(user.login,rcvfrom.uid)," |
| 2237 | 2273 | " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr" |
| 2238 | 2274 | |