Fossil SCM
Add the origin= query parameter to /annotate and the --origin option to the annotation command, to enable reverse annotations.
Commit
c91b810620ad1a804a963ab4b2ba81348a609552f40445d9754f87669bce7c92
Parent
517b9a5652649c9…
1 file changed
+44
-5
+44
-5
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -2200,16 +2200,18 @@ | ||
| 2200 | 2200 | static void annotate_file( |
| 2201 | 2201 | Annotator *p, /* The annotator */ |
| 2202 | 2202 | const char *zFilename, /* The name of the file to be annotated */ |
| 2203 | 2203 | const char *zRevision, /* Use the version of the file in this check-in */ |
| 2204 | 2204 | const char *zLimit, /* Limit the number of versions analyzed */ |
| 2205 | + const char *zOrigin, /* The origin check-in, or NULL for root-of-tree */ | |
| 2205 | 2206 | u64 annFlags /* Flags to alter the annotation */ |
| 2206 | 2207 | ){ |
| 2207 | 2208 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 2208 | 2209 | Blob step; /* Text of previous revision */ |
| 2209 | 2210 | Blob treename; /* FILENAME translated to canonical form */ |
| 2210 | 2211 | int cid; /* Selected check-in ID */ |
| 2212 | + int origid = 0; /* The origin ID or zero */ | |
| 2211 | 2213 | int rid; /* Artifact ID of the file being annotated */ |
| 2212 | 2214 | int fnid; /* Filename ID */ |
| 2213 | 2215 | Stmt q; /* Query returning all ancestor versions */ |
| 2214 | 2216 | int cnt = 0; /* Number of versions analyzed */ |
| 2215 | 2217 | int iLimit; /* Maximum number of versions to analyze */ |
| @@ -2239,14 +2241,39 @@ | ||
| 2239 | 2241 | cid = name_to_typed_rid(zRevision, "ci"); |
| 2240 | 2242 | }else{ |
| 2241 | 2243 | db_must_be_within_tree(); |
| 2242 | 2244 | cid = db_lget_int("checkout", 0); |
| 2243 | 2245 | } |
| 2246 | + origid = zOrigin ? name_to_typed_rid(zOrigin, "ci") : 0; | |
| 2244 | 2247 | |
| 2245 | 2248 | /* Compute all direct ancestors of the check-in being analyzed into |
| 2246 | 2249 | ** the "ancestor" table. */ |
| 2247 | - compute_direct_ancestors(cid); | |
| 2250 | + if( origid ){ | |
| 2251 | + PathNode *p; | |
| 2252 | + Blob sql; | |
| 2253 | + int gen = 0; | |
| 2254 | + char *zSep = "VALUES"; | |
| 2255 | + p = path_shortest(cid, origid, 1, 0); | |
| 2256 | + db_multi_exec( | |
| 2257 | + "CREATE TEMP TABLE IF NOT EXISTS ancestor(" | |
| 2258 | + " rid INT UNIQUE," | |
| 2259 | + " generation INTEGER PRIMARY KEY" | |
| 2260 | + ");" | |
| 2261 | + "DELETE FROM ancestor;" | |
| 2262 | + ); | |
| 2263 | + blob_init(&sql, "INSERT INTO ancestor(rid, generation)", -1); | |
| 2264 | + while( p ){ | |
| 2265 | + blob_append_sql(&sql, "%s(%d,%d)", zSep/*safe-for-%s*/, p->rid, ++gen); | |
| 2266 | + zSep = ","; | |
| 2267 | + p = p->u.pTo; | |
| 2268 | + } | |
| 2269 | + path_reset(); | |
| 2270 | + db_multi_exec("%s", blob_sql_text(&sql)); | |
| 2271 | + blob_reset(&sql); | |
| 2272 | + }else{ | |
| 2273 | + compute_direct_ancestors(cid); | |
| 2274 | + } | |
| 2248 | 2275 | |
| 2249 | 2276 | /* Get filename ID */ |
| 2250 | 2277 | file_tree_name(zFilename, &treename, 0, 1); |
| 2251 | 2278 | zFilename = blob_str(&treename); |
| 2252 | 2279 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| @@ -2281,11 +2308,11 @@ | ||
| 2281 | 2308 | if( !content_get(rid, &toAnnotate) ){ |
| 2282 | 2309 | fossil_fatal("unable to retrieve content of artifact #%d", rid); |
| 2283 | 2310 | } |
| 2284 | 2311 | blob_to_utf8_no_bom(&toAnnotate, 0); |
| 2285 | 2312 | annotation_start(p, &toAnnotate, annFlags); |
| 2286 | - p->bMoreToDo = 0; | |
| 2313 | + p->bMoreToDo = origid!=0; | |
| 2287 | 2314 | } |
| 2288 | 2315 | p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0])); |
| 2289 | 2316 | p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0)); |
| 2290 | 2317 | p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1)); |
| 2291 | 2318 | p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2)); |
| @@ -2336,18 +2363,22 @@ | ||
| 2336 | 2363 | ** the date of the changes and the check-in hash (with a link to the |
| 2337 | 2364 | ** check-in). /blame and /praise also show the user who made the check-in. |
| 2338 | 2365 | ** |
| 2339 | 2366 | ** Query parameters: |
| 2340 | 2367 | ** |
| 2341 | -** checkin=ID The manifest ID at which to start the annotation | |
| 2368 | +** checkin=ID The check-in at which to start the annotation | |
| 2342 | 2369 | ** filename=FILENAME The filename. |
| 2343 | 2370 | ** filevers=BOOLEAN Show file versions rather than check-in versions |
| 2344 | 2371 | ** limit=LIMIT Limit the amount of analysis: |
| 2345 | 2372 | ** "none" No limit |
| 2346 | 2373 | ** "Xs" As much as can be computed in X seconds |
| 2347 | 2374 | ** "N" N versions |
| 2348 | 2375 | ** log=BOOLEAN Show a log of versions analyzed |
| 2376 | +** origin=ID The origin checkin. If unspecified, the root | |
| 2377 | +** check-in over the entire repository is used. | |
| 2378 | +** Specify "origin=trunk" or similar for a reverse | |
| 2379 | +** annotation | |
| 2349 | 2380 | ** w=BOOLEAN Ignore whitespace |
| 2350 | 2381 | ** |
| 2351 | 2382 | */ |
| 2352 | 2383 | void annotation_page(void){ |
| 2353 | 2384 | int i; |
| @@ -2357,10 +2388,11 @@ | ||
| 2357 | 2388 | int fileVers; /* Show file version instead of check-in versions */ |
| 2358 | 2389 | int ignoreWs; /* Ignore whitespace */ |
| 2359 | 2390 | const char *zFilename; /* Name of file to annotate */ |
| 2360 | 2391 | const char *zRevision; /* Name of check-in from which to start annotation */ |
| 2361 | 2392 | const char *zCI; /* The check-in containing zFilename */ |
| 2393 | + const char *zOrigin; /* The origin of the analysis */ | |
| 2362 | 2394 | int szHash; /* Number of characters in %S display */ |
| 2363 | 2395 | char *zLink; |
| 2364 | 2396 | Annotator ann; |
| 2365 | 2397 | HQuery url; |
| 2366 | 2398 | struct AnnVers *p; |
| @@ -2372,18 +2404,19 @@ | ||
| 2372 | 2404 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2373 | 2405 | if( exclude_spiders() ) return; |
| 2374 | 2406 | load_control(); |
| 2375 | 2407 | zFilename = P("filename"); |
| 2376 | 2408 | zRevision = PD("checkin",0); |
| 2409 | + zOrigin = P("origin"); | |
| 2377 | 2410 | zLimit = P("limit"); |
| 2378 | 2411 | showLog = PB("log"); |
| 2379 | 2412 | fileVers = PB("filevers"); |
| 2380 | 2413 | ignoreWs = PB("w"); |
| 2381 | 2414 | if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; |
| 2382 | 2415 | |
| 2383 | 2416 | /* compute the annotation */ |
| 2384 | - annotate_file(&ann, zFilename, zRevision, zLimit, annFlags); | |
| 2417 | + annotate_file(&ann, zFilename, zRevision, zLimit, zOrigin, annFlags); | |
| 2385 | 2418 | zCI = ann.aVers[0].zMUuid; |
| 2386 | 2419 | |
| 2387 | 2420 | /* generate the web page */ |
| 2388 | 2421 | style_header("Annotation For %h", zFilename); |
| 2389 | 2422 | if( bBlame ){ |
| @@ -2512,10 +2545,14 @@ | ||
| 2512 | 2545 | ** -l|--log List all versions analyzed |
| 2513 | 2546 | ** -n|--limit LIMIT Limit the amount of analysis: |
| 2514 | 2547 | ** N Up to N versions |
| 2515 | 2548 | ** Xs As much as possible in X seconds |
| 2516 | 2549 | ** none No limit |
| 2550 | +** -o|--origin VERSION The origin check-in. By default this is the | |
| 2551 | +** root of the repository which is normally | |
| 2552 | +** what you want. Set to "trunk" or similar for | |
| 2553 | +** a reverse annotation. | |
| 2517 | 2554 | ** -w|--ignore-all-space Ignore white space when comparing lines |
| 2518 | 2555 | ** -Z|--ignore-trailing-space Ignore whitespace at line end |
| 2519 | 2556 | ** |
| 2520 | 2557 | ** See also: info, finfo, timeline |
| 2521 | 2558 | */ |
| @@ -2522,19 +2559,21 @@ | ||
| 2522 | 2559 | void annotate_cmd(void){ |
| 2523 | 2560 | const char *zRevision; /* Revision name, or NULL for current check-in */ |
| 2524 | 2561 | Annotator ann; /* The annotation of the file */ |
| 2525 | 2562 | int i; /* Loop counter */ |
| 2526 | 2563 | const char *zLimit; /* The value to the -n|--limit option */ |
| 2564 | + const char *zOrig; /* The value for -o|--origin */ | |
| 2527 | 2565 | int showLog; /* True to show the log */ |
| 2528 | 2566 | int fileVers; /* Show file version instead of check-in versions */ |
| 2529 | 2567 | u64 annFlags = 0; /* Flags to control annotation properties */ |
| 2530 | 2568 | int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ |
| 2531 | 2569 | int szHash; /* Display size of a version hash */ |
| 2532 | 2570 | |
| 2533 | 2571 | bBlame = g.argv[1][0]!='a'; |
| 2534 | 2572 | zRevision = find_option("r","revision",1); |
| 2535 | 2573 | zLimit = find_option("limit","n",1); |
| 2574 | + zOrig = find_option("origin","o",1); | |
| 2536 | 2575 | showLog = find_option("log","l",0)!=0; |
| 2537 | 2576 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2538 | 2577 | annFlags = DIFF_IGNORE_EOLWS; |
| 2539 | 2578 | } |
| 2540 | 2579 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| @@ -2549,11 +2588,11 @@ | ||
| 2549 | 2588 | if( g.argc<3 ) { |
| 2550 | 2589 | usage("FILENAME"); |
| 2551 | 2590 | } |
| 2552 | 2591 | |
| 2553 | 2592 | annFlags |= DIFF_STRIP_EOLCR; |
| 2554 | - annotate_file(&ann, g.argv[2], zRevision, zLimit, annFlags); | |
| 2593 | + annotate_file(&ann, g.argv[2], zRevision, zLimit, zOrig, annFlags); | |
| 2555 | 2594 | if( showLog ){ |
| 2556 | 2595 | struct AnnVers *p; |
| 2557 | 2596 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ |
| 2558 | 2597 | fossil_print("version %3d: %s %S file %S\n", |
| 2559 | 2598 | i+1, p->zDate, p->zMUuid, p->zFUuid); |
| 2560 | 2599 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -2200,16 +2200,18 @@ | |
| 2200 | static void annotate_file( |
| 2201 | Annotator *p, /* The annotator */ |
| 2202 | const char *zFilename, /* The name of the file to be annotated */ |
| 2203 | const char *zRevision, /* Use the version of the file in this check-in */ |
| 2204 | const char *zLimit, /* Limit the number of versions analyzed */ |
| 2205 | u64 annFlags /* Flags to alter the annotation */ |
| 2206 | ){ |
| 2207 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 2208 | Blob step; /* Text of previous revision */ |
| 2209 | Blob treename; /* FILENAME translated to canonical form */ |
| 2210 | int cid; /* Selected check-in ID */ |
| 2211 | int rid; /* Artifact ID of the file being annotated */ |
| 2212 | int fnid; /* Filename ID */ |
| 2213 | Stmt q; /* Query returning all ancestor versions */ |
| 2214 | int cnt = 0; /* Number of versions analyzed */ |
| 2215 | int iLimit; /* Maximum number of versions to analyze */ |
| @@ -2239,14 +2241,39 @@ | |
| 2239 | cid = name_to_typed_rid(zRevision, "ci"); |
| 2240 | }else{ |
| 2241 | db_must_be_within_tree(); |
| 2242 | cid = db_lget_int("checkout", 0); |
| 2243 | } |
| 2244 | |
| 2245 | /* Compute all direct ancestors of the check-in being analyzed into |
| 2246 | ** the "ancestor" table. */ |
| 2247 | compute_direct_ancestors(cid); |
| 2248 | |
| 2249 | /* Get filename ID */ |
| 2250 | file_tree_name(zFilename, &treename, 0, 1); |
| 2251 | zFilename = blob_str(&treename); |
| 2252 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| @@ -2281,11 +2308,11 @@ | |
| 2281 | if( !content_get(rid, &toAnnotate) ){ |
| 2282 | fossil_fatal("unable to retrieve content of artifact #%d", rid); |
| 2283 | } |
| 2284 | blob_to_utf8_no_bom(&toAnnotate, 0); |
| 2285 | annotation_start(p, &toAnnotate, annFlags); |
| 2286 | p->bMoreToDo = 0; |
| 2287 | } |
| 2288 | p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0])); |
| 2289 | p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0)); |
| 2290 | p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1)); |
| 2291 | p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2)); |
| @@ -2336,18 +2363,22 @@ | |
| 2336 | ** the date of the changes and the check-in hash (with a link to the |
| 2337 | ** check-in). /blame and /praise also show the user who made the check-in. |
| 2338 | ** |
| 2339 | ** Query parameters: |
| 2340 | ** |
| 2341 | ** checkin=ID The manifest ID at which to start the annotation |
| 2342 | ** filename=FILENAME The filename. |
| 2343 | ** filevers=BOOLEAN Show file versions rather than check-in versions |
| 2344 | ** limit=LIMIT Limit the amount of analysis: |
| 2345 | ** "none" No limit |
| 2346 | ** "Xs" As much as can be computed in X seconds |
| 2347 | ** "N" N versions |
| 2348 | ** log=BOOLEAN Show a log of versions analyzed |
| 2349 | ** w=BOOLEAN Ignore whitespace |
| 2350 | ** |
| 2351 | */ |
| 2352 | void annotation_page(void){ |
| 2353 | int i; |
| @@ -2357,10 +2388,11 @@ | |
| 2357 | int fileVers; /* Show file version instead of check-in versions */ |
| 2358 | int ignoreWs; /* Ignore whitespace */ |
| 2359 | const char *zFilename; /* Name of file to annotate */ |
| 2360 | const char *zRevision; /* Name of check-in from which to start annotation */ |
| 2361 | const char *zCI; /* The check-in containing zFilename */ |
| 2362 | int szHash; /* Number of characters in %S display */ |
| 2363 | char *zLink; |
| 2364 | Annotator ann; |
| 2365 | HQuery url; |
| 2366 | struct AnnVers *p; |
| @@ -2372,18 +2404,19 @@ | |
| 2372 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2373 | if( exclude_spiders() ) return; |
| 2374 | load_control(); |
| 2375 | zFilename = P("filename"); |
| 2376 | zRevision = PD("checkin",0); |
| 2377 | zLimit = P("limit"); |
| 2378 | showLog = PB("log"); |
| 2379 | fileVers = PB("filevers"); |
| 2380 | ignoreWs = PB("w"); |
| 2381 | if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; |
| 2382 | |
| 2383 | /* compute the annotation */ |
| 2384 | annotate_file(&ann, zFilename, zRevision, zLimit, annFlags); |
| 2385 | zCI = ann.aVers[0].zMUuid; |
| 2386 | |
| 2387 | /* generate the web page */ |
| 2388 | style_header("Annotation For %h", zFilename); |
| 2389 | if( bBlame ){ |
| @@ -2512,10 +2545,14 @@ | |
| 2512 | ** -l|--log List all versions analyzed |
| 2513 | ** -n|--limit LIMIT Limit the amount of analysis: |
| 2514 | ** N Up to N versions |
| 2515 | ** Xs As much as possible in X seconds |
| 2516 | ** none No limit |
| 2517 | ** -w|--ignore-all-space Ignore white space when comparing lines |
| 2518 | ** -Z|--ignore-trailing-space Ignore whitespace at line end |
| 2519 | ** |
| 2520 | ** See also: info, finfo, timeline |
| 2521 | */ |
| @@ -2522,19 +2559,21 @@ | |
| 2522 | void annotate_cmd(void){ |
| 2523 | const char *zRevision; /* Revision name, or NULL for current check-in */ |
| 2524 | Annotator ann; /* The annotation of the file */ |
| 2525 | int i; /* Loop counter */ |
| 2526 | const char *zLimit; /* The value to the -n|--limit option */ |
| 2527 | int showLog; /* True to show the log */ |
| 2528 | int fileVers; /* Show file version instead of check-in versions */ |
| 2529 | u64 annFlags = 0; /* Flags to control annotation properties */ |
| 2530 | int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ |
| 2531 | int szHash; /* Display size of a version hash */ |
| 2532 | |
| 2533 | bBlame = g.argv[1][0]!='a'; |
| 2534 | zRevision = find_option("r","revision",1); |
| 2535 | zLimit = find_option("limit","n",1); |
| 2536 | showLog = find_option("log","l",0)!=0; |
| 2537 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2538 | annFlags = DIFF_IGNORE_EOLWS; |
| 2539 | } |
| 2540 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| @@ -2549,11 +2588,11 @@ | |
| 2549 | if( g.argc<3 ) { |
| 2550 | usage("FILENAME"); |
| 2551 | } |
| 2552 | |
| 2553 | annFlags |= DIFF_STRIP_EOLCR; |
| 2554 | annotate_file(&ann, g.argv[2], zRevision, zLimit, annFlags); |
| 2555 | if( showLog ){ |
| 2556 | struct AnnVers *p; |
| 2557 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ |
| 2558 | fossil_print("version %3d: %s %S file %S\n", |
| 2559 | i+1, p->zDate, p->zMUuid, p->zFUuid); |
| 2560 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -2200,16 +2200,18 @@ | |
| 2200 | static void annotate_file( |
| 2201 | Annotator *p, /* The annotator */ |
| 2202 | const char *zFilename, /* The name of the file to be annotated */ |
| 2203 | const char *zRevision, /* Use the version of the file in this check-in */ |
| 2204 | const char *zLimit, /* Limit the number of versions analyzed */ |
| 2205 | const char *zOrigin, /* The origin check-in, or NULL for root-of-tree */ |
| 2206 | u64 annFlags /* Flags to alter the annotation */ |
| 2207 | ){ |
| 2208 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 2209 | Blob step; /* Text of previous revision */ |
| 2210 | Blob treename; /* FILENAME translated to canonical form */ |
| 2211 | int cid; /* Selected check-in ID */ |
| 2212 | int origid = 0; /* The origin ID or zero */ |
| 2213 | int rid; /* Artifact ID of the file being annotated */ |
| 2214 | int fnid; /* Filename ID */ |
| 2215 | Stmt q; /* Query returning all ancestor versions */ |
| 2216 | int cnt = 0; /* Number of versions analyzed */ |
| 2217 | int iLimit; /* Maximum number of versions to analyze */ |
| @@ -2239,14 +2241,39 @@ | |
| 2241 | cid = name_to_typed_rid(zRevision, "ci"); |
| 2242 | }else{ |
| 2243 | db_must_be_within_tree(); |
| 2244 | cid = db_lget_int("checkout", 0); |
| 2245 | } |
| 2246 | origid = zOrigin ? name_to_typed_rid(zOrigin, "ci") : 0; |
| 2247 | |
| 2248 | /* Compute all direct ancestors of the check-in being analyzed into |
| 2249 | ** the "ancestor" table. */ |
| 2250 | if( origid ){ |
| 2251 | PathNode *p; |
| 2252 | Blob sql; |
| 2253 | int gen = 0; |
| 2254 | char *zSep = "VALUES"; |
| 2255 | p = path_shortest(cid, origid, 1, 0); |
| 2256 | db_multi_exec( |
| 2257 | "CREATE TEMP TABLE IF NOT EXISTS ancestor(" |
| 2258 | " rid INT UNIQUE," |
| 2259 | " generation INTEGER PRIMARY KEY" |
| 2260 | ");" |
| 2261 | "DELETE FROM ancestor;" |
| 2262 | ); |
| 2263 | blob_init(&sql, "INSERT INTO ancestor(rid, generation)", -1); |
| 2264 | while( p ){ |
| 2265 | blob_append_sql(&sql, "%s(%d,%d)", zSep/*safe-for-%s*/, p->rid, ++gen); |
| 2266 | zSep = ","; |
| 2267 | p = p->u.pTo; |
| 2268 | } |
| 2269 | path_reset(); |
| 2270 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2271 | blob_reset(&sql); |
| 2272 | }else{ |
| 2273 | compute_direct_ancestors(cid); |
| 2274 | } |
| 2275 | |
| 2276 | /* Get filename ID */ |
| 2277 | file_tree_name(zFilename, &treename, 0, 1); |
| 2278 | zFilename = blob_str(&treename); |
| 2279 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| @@ -2281,11 +2308,11 @@ | |
| 2308 | if( !content_get(rid, &toAnnotate) ){ |
| 2309 | fossil_fatal("unable to retrieve content of artifact #%d", rid); |
| 2310 | } |
| 2311 | blob_to_utf8_no_bom(&toAnnotate, 0); |
| 2312 | annotation_start(p, &toAnnotate, annFlags); |
| 2313 | p->bMoreToDo = origid!=0; |
| 2314 | } |
| 2315 | p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0])); |
| 2316 | p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0)); |
| 2317 | p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1)); |
| 2318 | p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2)); |
| @@ -2336,18 +2363,22 @@ | |
| 2363 | ** the date of the changes and the check-in hash (with a link to the |
| 2364 | ** check-in). /blame and /praise also show the user who made the check-in. |
| 2365 | ** |
| 2366 | ** Query parameters: |
| 2367 | ** |
| 2368 | ** checkin=ID The check-in at which to start the annotation |
| 2369 | ** filename=FILENAME The filename. |
| 2370 | ** filevers=BOOLEAN Show file versions rather than check-in versions |
| 2371 | ** limit=LIMIT Limit the amount of analysis: |
| 2372 | ** "none" No limit |
| 2373 | ** "Xs" As much as can be computed in X seconds |
| 2374 | ** "N" N versions |
| 2375 | ** log=BOOLEAN Show a log of versions analyzed |
| 2376 | ** origin=ID The origin checkin. If unspecified, the root |
| 2377 | ** check-in over the entire repository is used. |
| 2378 | ** Specify "origin=trunk" or similar for a reverse |
| 2379 | ** annotation |
| 2380 | ** w=BOOLEAN Ignore whitespace |
| 2381 | ** |
| 2382 | */ |
| 2383 | void annotation_page(void){ |
| 2384 | int i; |
| @@ -2357,10 +2388,11 @@ | |
| 2388 | int fileVers; /* Show file version instead of check-in versions */ |
| 2389 | int ignoreWs; /* Ignore whitespace */ |
| 2390 | const char *zFilename; /* Name of file to annotate */ |
| 2391 | const char *zRevision; /* Name of check-in from which to start annotation */ |
| 2392 | const char *zCI; /* The check-in containing zFilename */ |
| 2393 | const char *zOrigin; /* The origin of the analysis */ |
| 2394 | int szHash; /* Number of characters in %S display */ |
| 2395 | char *zLink; |
| 2396 | Annotator ann; |
| 2397 | HQuery url; |
| 2398 | struct AnnVers *p; |
| @@ -2372,18 +2404,19 @@ | |
| 2404 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2405 | if( exclude_spiders() ) return; |
| 2406 | load_control(); |
| 2407 | zFilename = P("filename"); |
| 2408 | zRevision = PD("checkin",0); |
| 2409 | zOrigin = P("origin"); |
| 2410 | zLimit = P("limit"); |
| 2411 | showLog = PB("log"); |
| 2412 | fileVers = PB("filevers"); |
| 2413 | ignoreWs = PB("w"); |
| 2414 | if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS; |
| 2415 | |
| 2416 | /* compute the annotation */ |
| 2417 | annotate_file(&ann, zFilename, zRevision, zLimit, zOrigin, annFlags); |
| 2418 | zCI = ann.aVers[0].zMUuid; |
| 2419 | |
| 2420 | /* generate the web page */ |
| 2421 | style_header("Annotation For %h", zFilename); |
| 2422 | if( bBlame ){ |
| @@ -2512,10 +2545,14 @@ | |
| 2545 | ** -l|--log List all versions analyzed |
| 2546 | ** -n|--limit LIMIT Limit the amount of analysis: |
| 2547 | ** N Up to N versions |
| 2548 | ** Xs As much as possible in X seconds |
| 2549 | ** none No limit |
| 2550 | ** -o|--origin VERSION The origin check-in. By default this is the |
| 2551 | ** root of the repository which is normally |
| 2552 | ** what you want. Set to "trunk" or similar for |
| 2553 | ** a reverse annotation. |
| 2554 | ** -w|--ignore-all-space Ignore white space when comparing lines |
| 2555 | ** -Z|--ignore-trailing-space Ignore whitespace at line end |
| 2556 | ** |
| 2557 | ** See also: info, finfo, timeline |
| 2558 | */ |
| @@ -2522,19 +2559,21 @@ | |
| 2559 | void annotate_cmd(void){ |
| 2560 | const char *zRevision; /* Revision name, or NULL for current check-in */ |
| 2561 | Annotator ann; /* The annotation of the file */ |
| 2562 | int i; /* Loop counter */ |
| 2563 | const char *zLimit; /* The value to the -n|--limit option */ |
| 2564 | const char *zOrig; /* The value for -o|--origin */ |
| 2565 | int showLog; /* True to show the log */ |
| 2566 | int fileVers; /* Show file version instead of check-in versions */ |
| 2567 | u64 annFlags = 0; /* Flags to control annotation properties */ |
| 2568 | int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */ |
| 2569 | int szHash; /* Display size of a version hash */ |
| 2570 | |
| 2571 | bBlame = g.argv[1][0]!='a'; |
| 2572 | zRevision = find_option("r","revision",1); |
| 2573 | zLimit = find_option("limit","n",1); |
| 2574 | zOrig = find_option("origin","o",1); |
| 2575 | showLog = find_option("log","l",0)!=0; |
| 2576 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2577 | annFlags = DIFF_IGNORE_EOLWS; |
| 2578 | } |
| 2579 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| @@ -2549,11 +2588,11 @@ | |
| 2588 | if( g.argc<3 ) { |
| 2589 | usage("FILENAME"); |
| 2590 | } |
| 2591 | |
| 2592 | annFlags |= DIFF_STRIP_EOLCR; |
| 2593 | annotate_file(&ann, g.argv[2], zRevision, zLimit, zOrig, annFlags); |
| 2594 | if( showLog ){ |
| 2595 | struct AnnVers *p; |
| 2596 | for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){ |
| 2597 | fossil_print("version %3d: %s %S file %S\n", |
| 2598 | i+1, p->zDate, p->zMUuid, p->zFUuid); |
| 2599 |