Fossil SCM
Consolidated annotation file and manifest lookup code. This changes the error handling for the annotation web page to report an error rather than redirect to home. It also enables omitting the checkin query parameter when used with a server running within a checkout.
Commit
41f35ca4ec6178912c06f46abc9ac01d0769639b2745211b9072d044766e9e4c
Parent
d9ef474a1a31921…
1 file changed
+65
-80
+65
-80
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -2181,32 +2181,82 @@ | ||
| 2181 | 2181 | return 0; |
| 2182 | 2182 | } |
| 2183 | 2183 | |
| 2184 | 2184 | |
| 2185 | 2185 | /* |
| 2186 | -** Compute a complete annotation on a file. The file is identified | |
| 2187 | -** by its filename number (filename.fnid) and check-in (mlink.mid). | |
| 2186 | +** Compute a complete annotation on a file. The file is identified by its | |
| 2187 | +** filename and check-in name (NULL for current check-in). | |
| 2188 | 2188 | */ |
| 2189 | 2189 | static void annotate_file( |
| 2190 | 2190 | Annotator *p, /* The annotator */ |
| 2191 | - int fnid, /* The name of the file to be annotated */ | |
| 2192 | - int mid, /* Use the version of the file in this check-in */ | |
| 2191 | + const char *zFilename,/* The name of the file to be annotated */ | |
| 2192 | + const char *zRevision,/* Use the version of the file in this check-in */ | |
| 2193 | 2193 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 2194 | 2194 | u64 annFlags /* Flags to alter the annotation */ |
| 2195 | 2195 | ){ |
| 2196 | 2196 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 2197 | 2197 | Blob step; /* Text of previous revision */ |
| 2198 | + Blob treename; /* FILENAME translated to canonical form */ | |
| 2199 | + Manifest *pManifest; /* Manifest structure */ | |
| 2200 | + ManifestFile *pFile; /* Manifest file pointer */ | |
| 2201 | + int cid; /* Selected check-in ID */ | |
| 2202 | + int mid; /* Manifest where file was most recently changed */ | |
| 2198 | 2203 | int rid; /* Artifact ID of the file being annotated */ |
| 2204 | + int fnid; /* Filename ID */ | |
| 2199 | 2205 | Stmt q; /* Query returning all ancestor versions */ |
| 2200 | 2206 | Stmt ins; /* Inserts into the temporary VSEEN table */ |
| 2201 | 2207 | int cnt = 0; /* Number of versions examined */ |
| 2202 | 2208 | |
| 2203 | - /* Initialize the annotation */ | |
| 2204 | - rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); | |
| 2205 | - if( rid==0 ){ | |
| 2206 | - fossil_fatal("file #%d is unchanged in manifest #%d", fnid, mid); | |
| 2209 | + /* Get artifact IDs of selected check-in and file */ | |
| 2210 | + if( zRevision ){ | |
| 2211 | + /* Get artifact ID of selected check-in manifest */ | |
| 2212 | + cid = name_to_typed_rid(zRevision, "ci"); | |
| 2213 | + | |
| 2214 | + /* Get manifest structure for selected check-in */ | |
| 2215 | + pManifest = manifest_get(cid, CFTYPE_MANIFEST, 0); | |
| 2216 | + if( !pManifest ){ | |
| 2217 | + fossil_fatal("could not parse manifest for check-in: %s", zRevision); | |
| 2218 | + } | |
| 2219 | + | |
| 2220 | + /* Get selected file in manifest */ | |
| 2221 | + pFile = manifest_file_find(pManifest, zFilename); | |
| 2222 | + if( !pFile ){ | |
| 2223 | + fossil_fatal("file %s does not exist in check-in %s", zFilename, | |
| 2224 | + zRevision); | |
| 2225 | + } | |
| 2226 | + manifest_destroy(pManifest); | |
| 2227 | + | |
| 2228 | + /* Get file artifact ID from manifest file record */ | |
| 2229 | + rid = fast_uuid_to_rid(pFile->zUuid); | |
| 2230 | + }else{ | |
| 2231 | + /* Get artifact ID of current checkout manifest */ | |
| 2232 | + db_must_be_within_tree(); | |
| 2233 | + cid = db_lget_int("checkout", 0); | |
| 2234 | + | |
| 2235 | + /* Get file artifact ID from current checkout file table */ | |
| 2236 | + rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); | |
| 2237 | + if( rid==0 ){ | |
| 2238 | + fossil_fatal("file %s does not exist in current checkout", zFilename); | |
| 2239 | + } | |
| 2240 | + } | |
| 2241 | + | |
| 2242 | + /* Get filename ID */ | |
| 2243 | + file_tree_name(zFilename, &treename, 0, 1); | |
| 2244 | + zFilename = blob_str(&treename); | |
| 2245 | + fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); | |
| 2246 | + | |
| 2247 | + /* Get ID of most recent manifest containing a change to the selected file */ | |
| 2248 | + compute_direct_ancestors(cid); | |
| 2249 | + mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " | |
| 2250 | + " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" | |
| 2251 | + " ORDER BY ancestor.generation ASC LIMIT 1", | |
| 2252 | + rid, fnid); | |
| 2253 | + if( mid==0 ){ | |
| 2254 | + fossil_fatal("unable to find manifest"); | |
| 2207 | 2255 | } |
| 2256 | + | |
| 2257 | + /* Initialize the annotation */ | |
| 2208 | 2258 | if( !content_get(rid, &toAnnotate) ){ |
| 2209 | 2259 | fossil_fatal("unable to retrieve content of artifact #%d", rid); |
| 2210 | 2260 | } |
| 2211 | 2261 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2212 | 2262 | blob_to_utf8_no_bom(&toAnnotate, 0); |
| @@ -2304,18 +2354,17 @@ | ||
| 2304 | 2354 | ** log=BOOLEAN Show a log of versions analyzed |
| 2305 | 2355 | ** w Ignore whitespace |
| 2306 | 2356 | ** |
| 2307 | 2357 | */ |
| 2308 | 2358 | void annotation_page(void){ |
| 2309 | - int mid; | |
| 2310 | - int fnid; | |
| 2311 | 2359 | int i; |
| 2312 | 2360 | int iLimit; /* Depth limit */ |
| 2313 | 2361 | u64 annFlags = DIFF_STRIP_EOLCR; |
| 2314 | 2362 | int showLog = 0; /* True to display the log */ |
| 2315 | 2363 | int ignoreWs = 0; /* Ignore whitespace */ |
| 2316 | 2364 | const char *zFilename; /* Name of file to annotate */ |
| 2365 | + const char *zRevision; /* Name of check-in from which to start annotation */ | |
| 2317 | 2366 | const char *zCI; /* The check-in containing zFilename */ |
| 2318 | 2367 | Annotator ann; |
| 2319 | 2368 | HQuery url; |
| 2320 | 2369 | struct AnnVers *p; |
| 2321 | 2370 | unsigned clr1, clr2, clr; |
| @@ -2325,25 +2374,19 @@ | ||
| 2325 | 2374 | showLog = atoi(PD("log","1")); |
| 2326 | 2375 | login_check_credentials(); |
| 2327 | 2376 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2328 | 2377 | if( exclude_spiders() ) return; |
| 2329 | 2378 | load_control(); |
| 2330 | - mid = name_to_typed_rid(PD("checkin","0"),"ci"); | |
| 2331 | 2379 | zFilename = P("filename"); |
| 2332 | - fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); | |
| 2333 | - if( mid==0 || fnid==0 ){ fossil_redirect_home(); } | |
| 2380 | + zRevision = PD("checkin",0); | |
| 2334 | 2381 | iLimit = atoi(PD("limit","20")); |
| 2335 | 2382 | if( P("filevers") ) annFlags |= ANN_FILE_VERS; |
| 2336 | 2383 | ignoreWs = P("w")!=0; |
| 2337 | 2384 | if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; |
| 2338 | - if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ | |
| 2339 | - fossil_redirect_home(); | |
| 2340 | - } | |
| 2341 | 2385 | |
| 2342 | 2386 | /* compute the annotation */ |
| 2343 | - compute_direct_ancestors(mid); | |
| 2344 | - annotate_file(&ann, fnid, mid, iLimit, annFlags); | |
| 2387 | + annotate_file(&ann, zFilename, zRevision, iLimit, annFlags); | |
| 2345 | 2388 | zCI = ann.aVers[0].zMUuid; |
| 2346 | 2389 | |
| 2347 | 2390 | /* generate the web page */ |
| 2348 | 2391 | style_header("Annotation For %h", zFilename); |
| 2349 | 2392 | if( bBlame ){ |
| @@ -2495,17 +2538,11 @@ | ||
| 2495 | 2538 | ** -Z|--ignore-trailing-space Ignore whitespace at line end |
| 2496 | 2539 | ** |
| 2497 | 2540 | ** See also: info, finfo, timeline |
| 2498 | 2541 | */ |
| 2499 | 2542 | void annotate_cmd(void){ |
| 2500 | - int fnid; /* Filename ID */ | |
| 2501 | - int fid; /* File instance ID */ | |
| 2502 | - int mid; /* Manifest where file was checked in */ | |
| 2503 | - int cid; /* Checkout or selected check-in ID */ | |
| 2504 | - Blob treename; /* FILENAME translated to canonical form */ | |
| 2505 | - const char *zRev; /* Revision name, or NULL for current check-in */ | |
| 2506 | - char *zFilename; /* Canonical filename */ | |
| 2543 | + const char *zRevision; /* Revision name, or NULL for current check-in */ | |
| 2507 | 2544 | Annotator ann; /* The annotation of the file */ |
| 2508 | 2545 | int i; /* Loop counter */ |
| 2509 | 2546 | const char *zLimit; /* The value to the -n|--limit option */ |
| 2510 | 2547 | int iLimit; /* How far back in time to look */ |
| 2511 | 2548 | int showLog; /* True to show the log */ |
| @@ -2514,14 +2551,15 @@ | ||
| 2514 | 2551 | int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ |
| 2515 | 2552 | Manifest *pManifest; /* Manifest structure */ |
| 2516 | 2553 | ManifestFile *pFile; /* Manifest file pointer */ |
| 2517 | 2554 | |
| 2518 | 2555 | bBlame = g.argv[1][0]!='a'; |
| 2519 | - zRev = find_option("r","revision",1); | |
| 2556 | + zRevision = find_option("r","revision",1); | |
| 2520 | 2557 | zLimit = find_option("limit","n",1); |
| 2521 | 2558 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 2522 | 2559 | iLimit = atoi(zLimit); |
| 2560 | + if( iLimit<=0 ) iLimit = 1000000000; | |
| 2523 | 2561 | showLog = find_option("log","l",0)!=0; |
| 2524 | 2562 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2525 | 2563 | annFlags = DIFF_IGNORE_EOLWS; |
| 2526 | 2564 | } |
| 2527 | 2565 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| @@ -2535,65 +2573,12 @@ | ||
| 2535 | 2573 | |
| 2536 | 2574 | if( g.argc<3 ) { |
| 2537 | 2575 | usage("FILENAME"); |
| 2538 | 2576 | } |
| 2539 | 2577 | |
| 2540 | - /* Get filename ID */ | |
| 2541 | - file_tree_name(g.argv[2], &treename, 0, 1); | |
| 2542 | - zFilename = blob_str(&treename); | |
| 2543 | - fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); | |
| 2544 | - if( fnid==0 ){ | |
| 2545 | - fossil_fatal("no such file: %s", zFilename); | |
| 2546 | - } | |
| 2547 | - | |
| 2548 | - /* Get artifact IDs of selected check-in and file */ | |
| 2549 | - if( zRev ){ | |
| 2550 | - /* Get artifact ID of selected check-in manifest */ | |
| 2551 | - cid = name_to_typed_rid(zRev, "ci"); | |
| 2552 | - | |
| 2553 | - /* Get manifest structure for selected check-in */ | |
| 2554 | - pManifest = manifest_get(cid, CFTYPE_MANIFEST, 0); | |
| 2555 | - if( !pManifest ){ | |
| 2556 | - fossil_fatal("could not parse manifest for check-in: %s", zRev); | |
| 2557 | - } | |
| 2558 | - | |
| 2559 | - /* Get selected file in manifest */ | |
| 2560 | - pFile = manifest_file_find(pManifest, zFilename); | |
| 2561 | - if( !pFile ){ | |
| 2562 | - fossil_fatal("file %s does not exist in check-in %s", zFilename, zRev); | |
| 2563 | - } | |
| 2564 | - manifest_destroy(pManifest); | |
| 2565 | - | |
| 2566 | - /* Get file instance ID from manifest file record */ | |
| 2567 | - fid = fast_uuid_to_rid(pFile->zUuid); | |
| 2568 | - }else{ | |
| 2569 | - /* Get artifact ID of current checkout manifest */ | |
| 2570 | - cid = db_lget_int("checkout", 0); | |
| 2571 | - if( cid == 0 ){ | |
| 2572 | - fossil_fatal("not in a checkout"); | |
| 2573 | - } | |
| 2574 | - | |
| 2575 | - /* Get file instance ID from current checkout file table */ | |
| 2576 | - fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); | |
| 2577 | - if( fid==0 ){ | |
| 2578 | - fossil_fatal("not part of current checkout: %s", zFilename); | |
| 2579 | - } | |
| 2580 | - } | |
| 2581 | - | |
| 2582 | - /* Get ID of most recent manifest containing a change to the selected file */ | |
| 2583 | - compute_direct_ancestors(cid); | |
| 2584 | - mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " | |
| 2585 | - " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" | |
| 2586 | - " ORDER BY ancestor.generation ASC LIMIT 1", | |
| 2587 | - fid, fnid); | |
| 2588 | - if( mid==0 ){ | |
| 2589 | - fossil_fatal("unable to find manifest"); | |
| 2590 | - } | |
| 2591 | - | |
| 2592 | - if( iLimit<=0 ) iLimit = 1000000000; | |
| 2593 | 2578 | annFlags |= DIFF_STRIP_EOLCR; |
| 2594 | - annotate_file(&ann, fnid, mid, iLimit, annFlags); | |
| 2579 | + annotate_file(&ann, g.argv[2], zRevision, iLimit, annFlags); | |
| 2595 | 2580 | if( showLog ){ |
| 2596 | 2581 | struct AnnVers *p; |
| 2597 | 2582 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ |
| 2598 | 2583 | fossil_print("version %3d: %s %S file %S\n", |
| 2599 | 2584 | i+1, p->zDate, p->zMUuid, p->zFUuid); |
| 2600 | 2585 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -2181,32 +2181,82 @@ | |
| 2181 | return 0; |
| 2182 | } |
| 2183 | |
| 2184 | |
| 2185 | /* |
| 2186 | ** Compute a complete annotation on a file. The file is identified |
| 2187 | ** by its filename number (filename.fnid) and check-in (mlink.mid). |
| 2188 | */ |
| 2189 | static void annotate_file( |
| 2190 | Annotator *p, /* The annotator */ |
| 2191 | int fnid, /* The name of the file to be annotated */ |
| 2192 | int mid, /* Use the version of the file in this check-in */ |
| 2193 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 2194 | u64 annFlags /* Flags to alter the annotation */ |
| 2195 | ){ |
| 2196 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 2197 | Blob step; /* Text of previous revision */ |
| 2198 | int rid; /* Artifact ID of the file being annotated */ |
| 2199 | Stmt q; /* Query returning all ancestor versions */ |
| 2200 | Stmt ins; /* Inserts into the temporary VSEEN table */ |
| 2201 | int cnt = 0; /* Number of versions examined */ |
| 2202 | |
| 2203 | /* Initialize the annotation */ |
| 2204 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 2205 | if( rid==0 ){ |
| 2206 | fossil_fatal("file #%d is unchanged in manifest #%d", fnid, mid); |
| 2207 | } |
| 2208 | if( !content_get(rid, &toAnnotate) ){ |
| 2209 | fossil_fatal("unable to retrieve content of artifact #%d", rid); |
| 2210 | } |
| 2211 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2212 | blob_to_utf8_no_bom(&toAnnotate, 0); |
| @@ -2304,18 +2354,17 @@ | |
| 2304 | ** log=BOOLEAN Show a log of versions analyzed |
| 2305 | ** w Ignore whitespace |
| 2306 | ** |
| 2307 | */ |
| 2308 | void annotation_page(void){ |
| 2309 | int mid; |
| 2310 | int fnid; |
| 2311 | int i; |
| 2312 | int iLimit; /* Depth limit */ |
| 2313 | u64 annFlags = DIFF_STRIP_EOLCR; |
| 2314 | int showLog = 0; /* True to display the log */ |
| 2315 | int ignoreWs = 0; /* Ignore whitespace */ |
| 2316 | const char *zFilename; /* Name of file to annotate */ |
| 2317 | const char *zCI; /* The check-in containing zFilename */ |
| 2318 | Annotator ann; |
| 2319 | HQuery url; |
| 2320 | struct AnnVers *p; |
| 2321 | unsigned clr1, clr2, clr; |
| @@ -2325,25 +2374,19 @@ | |
| 2325 | showLog = atoi(PD("log","1")); |
| 2326 | login_check_credentials(); |
| 2327 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2328 | if( exclude_spiders() ) return; |
| 2329 | load_control(); |
| 2330 | mid = name_to_typed_rid(PD("checkin","0"),"ci"); |
| 2331 | zFilename = P("filename"); |
| 2332 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| 2333 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 2334 | iLimit = atoi(PD("limit","20")); |
| 2335 | if( P("filevers") ) annFlags |= ANN_FILE_VERS; |
| 2336 | ignoreWs = P("w")!=0; |
| 2337 | if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; |
| 2338 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 2339 | fossil_redirect_home(); |
| 2340 | } |
| 2341 | |
| 2342 | /* compute the annotation */ |
| 2343 | compute_direct_ancestors(mid); |
| 2344 | annotate_file(&ann, fnid, mid, iLimit, annFlags); |
| 2345 | zCI = ann.aVers[0].zMUuid; |
| 2346 | |
| 2347 | /* generate the web page */ |
| 2348 | style_header("Annotation For %h", zFilename); |
| 2349 | if( bBlame ){ |
| @@ -2495,17 +2538,11 @@ | |
| 2495 | ** -Z|--ignore-trailing-space Ignore whitespace at line end |
| 2496 | ** |
| 2497 | ** See also: info, finfo, timeline |
| 2498 | */ |
| 2499 | void annotate_cmd(void){ |
| 2500 | int fnid; /* Filename ID */ |
| 2501 | int fid; /* File instance ID */ |
| 2502 | int mid; /* Manifest where file was checked in */ |
| 2503 | int cid; /* Checkout or selected check-in ID */ |
| 2504 | Blob treename; /* FILENAME translated to canonical form */ |
| 2505 | const char *zRev; /* Revision name, or NULL for current check-in */ |
| 2506 | char *zFilename; /* Canonical filename */ |
| 2507 | Annotator ann; /* The annotation of the file */ |
| 2508 | int i; /* Loop counter */ |
| 2509 | const char *zLimit; /* The value to the -n|--limit option */ |
| 2510 | int iLimit; /* How far back in time to look */ |
| 2511 | int showLog; /* True to show the log */ |
| @@ -2514,14 +2551,15 @@ | |
| 2514 | int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ |
| 2515 | Manifest *pManifest; /* Manifest structure */ |
| 2516 | ManifestFile *pFile; /* Manifest file pointer */ |
| 2517 | |
| 2518 | bBlame = g.argv[1][0]!='a'; |
| 2519 | zRev = find_option("r","revision",1); |
| 2520 | zLimit = find_option("limit","n",1); |
| 2521 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 2522 | iLimit = atoi(zLimit); |
| 2523 | showLog = find_option("log","l",0)!=0; |
| 2524 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2525 | annFlags = DIFF_IGNORE_EOLWS; |
| 2526 | } |
| 2527 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| @@ -2535,65 +2573,12 @@ | |
| 2535 | |
| 2536 | if( g.argc<3 ) { |
| 2537 | usage("FILENAME"); |
| 2538 | } |
| 2539 | |
| 2540 | /* Get filename ID */ |
| 2541 | file_tree_name(g.argv[2], &treename, 0, 1); |
| 2542 | zFilename = blob_str(&treename); |
| 2543 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| 2544 | if( fnid==0 ){ |
| 2545 | fossil_fatal("no such file: %s", zFilename); |
| 2546 | } |
| 2547 | |
| 2548 | /* Get artifact IDs of selected check-in and file */ |
| 2549 | if( zRev ){ |
| 2550 | /* Get artifact ID of selected check-in manifest */ |
| 2551 | cid = name_to_typed_rid(zRev, "ci"); |
| 2552 | |
| 2553 | /* Get manifest structure for selected check-in */ |
| 2554 | pManifest = manifest_get(cid, CFTYPE_MANIFEST, 0); |
| 2555 | if( !pManifest ){ |
| 2556 | fossil_fatal("could not parse manifest for check-in: %s", zRev); |
| 2557 | } |
| 2558 | |
| 2559 | /* Get selected file in manifest */ |
| 2560 | pFile = manifest_file_find(pManifest, zFilename); |
| 2561 | if( !pFile ){ |
| 2562 | fossil_fatal("file %s does not exist in check-in %s", zFilename, zRev); |
| 2563 | } |
| 2564 | manifest_destroy(pManifest); |
| 2565 | |
| 2566 | /* Get file instance ID from manifest file record */ |
| 2567 | fid = fast_uuid_to_rid(pFile->zUuid); |
| 2568 | }else{ |
| 2569 | /* Get artifact ID of current checkout manifest */ |
| 2570 | cid = db_lget_int("checkout", 0); |
| 2571 | if( cid == 0 ){ |
| 2572 | fossil_fatal("not in a checkout"); |
| 2573 | } |
| 2574 | |
| 2575 | /* Get file instance ID from current checkout file table */ |
| 2576 | fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); |
| 2577 | if( fid==0 ){ |
| 2578 | fossil_fatal("not part of current checkout: %s", zFilename); |
| 2579 | } |
| 2580 | } |
| 2581 | |
| 2582 | /* Get ID of most recent manifest containing a change to the selected file */ |
| 2583 | compute_direct_ancestors(cid); |
| 2584 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| 2585 | " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" |
| 2586 | " ORDER BY ancestor.generation ASC LIMIT 1", |
| 2587 | fid, fnid); |
| 2588 | if( mid==0 ){ |
| 2589 | fossil_fatal("unable to find manifest"); |
| 2590 | } |
| 2591 | |
| 2592 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2593 | annFlags |= DIFF_STRIP_EOLCR; |
| 2594 | annotate_file(&ann, fnid, mid, iLimit, annFlags); |
| 2595 | if( showLog ){ |
| 2596 | struct AnnVers *p; |
| 2597 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ |
| 2598 | fossil_print("version %3d: %s %S file %S\n", |
| 2599 | i+1, p->zDate, p->zMUuid, p->zFUuid); |
| 2600 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -2181,32 +2181,82 @@ | |
| 2181 | return 0; |
| 2182 | } |
| 2183 | |
| 2184 | |
| 2185 | /* |
| 2186 | ** Compute a complete annotation on a file. The file is identified by its |
| 2187 | ** filename and check-in name (NULL for current check-in). |
| 2188 | */ |
| 2189 | static void annotate_file( |
| 2190 | Annotator *p, /* The annotator */ |
| 2191 | const char *zFilename,/* The name of the file to be annotated */ |
| 2192 | const char *zRevision,/* Use the version of the file in this check-in */ |
| 2193 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 2194 | u64 annFlags /* Flags to alter the annotation */ |
| 2195 | ){ |
| 2196 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 2197 | Blob step; /* Text of previous revision */ |
| 2198 | Blob treename; /* FILENAME translated to canonical form */ |
| 2199 | Manifest *pManifest; /* Manifest structure */ |
| 2200 | ManifestFile *pFile; /* Manifest file pointer */ |
| 2201 | int cid; /* Selected check-in ID */ |
| 2202 | int mid; /* Manifest where file was most recently changed */ |
| 2203 | int rid; /* Artifact ID of the file being annotated */ |
| 2204 | int fnid; /* Filename ID */ |
| 2205 | Stmt q; /* Query returning all ancestor versions */ |
| 2206 | Stmt ins; /* Inserts into the temporary VSEEN table */ |
| 2207 | int cnt = 0; /* Number of versions examined */ |
| 2208 | |
| 2209 | /* Get artifact IDs of selected check-in and file */ |
| 2210 | if( zRevision ){ |
| 2211 | /* Get artifact ID of selected check-in manifest */ |
| 2212 | cid = name_to_typed_rid(zRevision, "ci"); |
| 2213 | |
| 2214 | /* Get manifest structure for selected check-in */ |
| 2215 | pManifest = manifest_get(cid, CFTYPE_MANIFEST, 0); |
| 2216 | if( !pManifest ){ |
| 2217 | fossil_fatal("could not parse manifest for check-in: %s", zRevision); |
| 2218 | } |
| 2219 | |
| 2220 | /* Get selected file in manifest */ |
| 2221 | pFile = manifest_file_find(pManifest, zFilename); |
| 2222 | if( !pFile ){ |
| 2223 | fossil_fatal("file %s does not exist in check-in %s", zFilename, |
| 2224 | zRevision); |
| 2225 | } |
| 2226 | manifest_destroy(pManifest); |
| 2227 | |
| 2228 | /* Get file artifact ID from manifest file record */ |
| 2229 | rid = fast_uuid_to_rid(pFile->zUuid); |
| 2230 | }else{ |
| 2231 | /* Get artifact ID of current checkout manifest */ |
| 2232 | db_must_be_within_tree(); |
| 2233 | cid = db_lget_int("checkout", 0); |
| 2234 | |
| 2235 | /* Get file artifact ID from current checkout file table */ |
| 2236 | rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); |
| 2237 | if( rid==0 ){ |
| 2238 | fossil_fatal("file %s does not exist in current checkout", zFilename); |
| 2239 | } |
| 2240 | } |
| 2241 | |
| 2242 | /* Get filename ID */ |
| 2243 | file_tree_name(zFilename, &treename, 0, 1); |
| 2244 | zFilename = blob_str(&treename); |
| 2245 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| 2246 | |
| 2247 | /* Get ID of most recent manifest containing a change to the selected file */ |
| 2248 | compute_direct_ancestors(cid); |
| 2249 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| 2250 | " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" |
| 2251 | " ORDER BY ancestor.generation ASC LIMIT 1", |
| 2252 | rid, fnid); |
| 2253 | if( mid==0 ){ |
| 2254 | fossil_fatal("unable to find manifest"); |
| 2255 | } |
| 2256 | |
| 2257 | /* Initialize the annotation */ |
| 2258 | if( !content_get(rid, &toAnnotate) ){ |
| 2259 | fossil_fatal("unable to retrieve content of artifact #%d", rid); |
| 2260 | } |
| 2261 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2262 | blob_to_utf8_no_bom(&toAnnotate, 0); |
| @@ -2304,18 +2354,17 @@ | |
| 2354 | ** log=BOOLEAN Show a log of versions analyzed |
| 2355 | ** w Ignore whitespace |
| 2356 | ** |
| 2357 | */ |
| 2358 | void annotation_page(void){ |
| 2359 | int i; |
| 2360 | int iLimit; /* Depth limit */ |
| 2361 | u64 annFlags = DIFF_STRIP_EOLCR; |
| 2362 | int showLog = 0; /* True to display the log */ |
| 2363 | int ignoreWs = 0; /* Ignore whitespace */ |
| 2364 | const char *zFilename; /* Name of file to annotate */ |
| 2365 | const char *zRevision; /* Name of check-in from which to start annotation */ |
| 2366 | const char *zCI; /* The check-in containing zFilename */ |
| 2367 | Annotator ann; |
| 2368 | HQuery url; |
| 2369 | struct AnnVers *p; |
| 2370 | unsigned clr1, clr2, clr; |
| @@ -2325,25 +2374,19 @@ | |
| 2374 | showLog = atoi(PD("log","1")); |
| 2375 | login_check_credentials(); |
| 2376 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2377 | if( exclude_spiders() ) return; |
| 2378 | load_control(); |
| 2379 | zFilename = P("filename"); |
| 2380 | zRevision = PD("checkin",0); |
| 2381 | iLimit = atoi(PD("limit","20")); |
| 2382 | if( P("filevers") ) annFlags |= ANN_FILE_VERS; |
| 2383 | ignoreWs = P("w")!=0; |
| 2384 | if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; |
| 2385 | |
| 2386 | /* compute the annotation */ |
| 2387 | annotate_file(&ann, zFilename, zRevision, iLimit, annFlags); |
| 2388 | zCI = ann.aVers[0].zMUuid; |
| 2389 | |
| 2390 | /* generate the web page */ |
| 2391 | style_header("Annotation For %h", zFilename); |
| 2392 | if( bBlame ){ |
| @@ -2495,17 +2538,11 @@ | |
| 2538 | ** -Z|--ignore-trailing-space Ignore whitespace at line end |
| 2539 | ** |
| 2540 | ** See also: info, finfo, timeline |
| 2541 | */ |
| 2542 | void annotate_cmd(void){ |
| 2543 | const char *zRevision; /* Revision name, or NULL for current check-in */ |
| 2544 | Annotator ann; /* The annotation of the file */ |
| 2545 | int i; /* Loop counter */ |
| 2546 | const char *zLimit; /* The value to the -n|--limit option */ |
| 2547 | int iLimit; /* How far back in time to look */ |
| 2548 | int showLog; /* True to show the log */ |
| @@ -2514,14 +2551,15 @@ | |
| 2551 | int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ |
| 2552 | Manifest *pManifest; /* Manifest structure */ |
| 2553 | ManifestFile *pFile; /* Manifest file pointer */ |
| 2554 | |
| 2555 | bBlame = g.argv[1][0]!='a'; |
| 2556 | zRevision = find_option("r","revision",1); |
| 2557 | zLimit = find_option("limit","n",1); |
| 2558 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 2559 | iLimit = atoi(zLimit); |
| 2560 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2561 | showLog = find_option("log","l",0)!=0; |
| 2562 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2563 | annFlags = DIFF_IGNORE_EOLWS; |
| 2564 | } |
| 2565 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| @@ -2535,65 +2573,12 @@ | |
| 2573 | |
| 2574 | if( g.argc<3 ) { |
| 2575 | usage("FILENAME"); |
| 2576 | } |
| 2577 | |
| 2578 | annFlags |= DIFF_STRIP_EOLCR; |
| 2579 | annotate_file(&ann, g.argv[2], zRevision, iLimit, annFlags); |
| 2580 | if( showLog ){ |
| 2581 | struct AnnVers *p; |
| 2582 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ |
| 2583 | fossil_print("version %3d: %s %S file %S\n", |
| 2584 | i+1, p->zDate, p->zMUuid, p->zFUuid); |
| 2585 |