Fossil SCM
Updating from trunk.
Commit
3cdf9480dd9f1889ad791fe731c5c073c5926d74
Parent
314a29432176685…
31 files changed
+7
-12
+152
+2
-2
+2
-2
+46
-19
+46
-19
+1
-1
+32
+21
-3
+21
-3
+39
-3
+1
-1
+1
-1
+44
+1
-1
+3
-2
+3
-2
+2
+1
-1
+1
-1
+9
-5
+9
-5
+21
-14
+1
-1
+1
-1
+2
-2
+2
-2
+6
+5
-2
+76
-15
+1
-1
~
src/add.c
~
src/browse.c
~
src/captcha.c
~
src/cgi.c
~
src/checkin.c
~
src/checkin.c
~
src/checkout.c
~
src/content.c
~
src/db.c
~
src/db.c
~
src/descendants.c
~
src/diffcmd.c
~
src/diffcmd.c
~
src/file.c
~
src/finfo.c
~
src/info.c
~
src/info.c
~
src/main.c
~
src/merge.c
~
src/merge.c
~
src/name.c
~
src/name.c
~
src/rebuild.c
~
src/report.c
~
src/stash.c
~
src/timeline.c
~
src/timeline.c
~
src/tkt.c
~
src/update.c
~
src/vfile.c
~
src/xfer.c
+7
-12
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -21,16 +21,10 @@ | ||
| 21 | 21 | #include "config.h" |
| 22 | 22 | #include "add.h" |
| 23 | 23 | #include <assert.h> |
| 24 | 24 | #include <dirent.h> |
| 25 | 25 | |
| 26 | -/* | |
| 27 | -** Set to true if files whose names begin with "." should be | |
| 28 | -** included when processing a recursive "add" command. | |
| 29 | -*/ | |
| 30 | -static int includeDotFiles = 0; | |
| 31 | - | |
| 32 | 26 | /* |
| 33 | 27 | ** This routine returns the names of files in a working checkout that |
| 34 | 28 | ** are created by Fossil itself, and hence should not be added, deleted, |
| 35 | 29 | ** or merge, and should be omitted from "clean" and "extra" lists. |
| 36 | 30 | ** |
| @@ -39,11 +33,11 @@ | ||
| 39 | 33 | */ |
| 40 | 34 | const char *fossil_reserved_name(int N){ |
| 41 | 35 | /* Possible names of the local per-checkout database file and |
| 42 | 36 | ** its associated journals |
| 43 | 37 | */ |
| 44 | - static const char *azName[] = { | |
| 38 | + static const char *const azName[] = { | |
| 45 | 39 | "_FOSSIL_", |
| 46 | 40 | "_FOSSIL_-journal", |
| 47 | 41 | "_FOSSIL_-wal", |
| 48 | 42 | "_FOSSIL_-shm", |
| 49 | 43 | ".fslckout", |
| @@ -61,11 +55,11 @@ | ||
| 61 | 55 | }; |
| 62 | 56 | |
| 63 | 57 | /* Names of auxiliary files generated by SQLite when the "manifest" |
| 64 | 58 | ** properity is enabled |
| 65 | 59 | */ |
| 66 | - static const char *azManifest[] = { | |
| 60 | + static const char *const azManifest[] = { | |
| 67 | 61 | "manifest", |
| 68 | 62 | "manifest.uuid", |
| 69 | 63 | }; |
| 70 | 64 | |
| 71 | 65 | /* Cached setting "manifest" */ |
| @@ -216,13 +210,14 @@ | ||
| 216 | 210 | int vid; /* Currently checked out version */ |
| 217 | 211 | int nRoot; /* Full path characters in g.zLocalRoot */ |
| 218 | 212 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 219 | 213 | Glob *pIgnore; /* Ignore everything matching this glob pattern */ |
| 220 | 214 | int caseSensitive; /* True if filenames are case sensitive */ |
| 215 | + unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ | |
| 221 | 216 | |
| 222 | 217 | zIgnoreFlag = find_option("ignore",0,1); |
| 223 | - includeDotFiles = find_option("dotfiles",0,0)!=0; | |
| 218 | + if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; | |
| 224 | 219 | capture_case_sensitive_option(); |
| 225 | 220 | db_must_be_within_tree(); |
| 226 | 221 | caseSensitive = filenames_are_case_sensitive(); |
| 227 | 222 | if( zIgnoreFlag==0 ){ |
| 228 | 223 | zIgnoreFlag = db_get("ignore-glob", 0); |
| @@ -250,11 +245,11 @@ | ||
| 250 | 245 | |
| 251 | 246 | file_canonical_name(g.argv[i], &fullName, 0); |
| 252 | 247 | zName = blob_str(&fullName); |
| 253 | 248 | isDir = file_wd_isdir(zName); |
| 254 | 249 | if( isDir==1 ){ |
| 255 | - vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore); | |
| 250 | + vfile_scan(&fullName, nRoot-1, scanFlags, pIgnore); | |
| 256 | 251 | }else if( isDir==0 ){ |
| 257 | 252 | fossil_warning("not found: %s", zName); |
| 258 | 253 | }else if( file_access(zName, R_OK) ){ |
| 259 | 254 | fossil_fatal("cannot open %s", zName); |
| 260 | 255 | }else{ |
| @@ -433,11 +428,11 @@ | ||
| 433 | 428 | ** See also: add, rm |
| 434 | 429 | */ |
| 435 | 430 | void addremove_cmd(void){ |
| 436 | 431 | Blob path; |
| 437 | 432 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 438 | - int allFlag = find_option("dotfiles",0,0)!=0; | |
| 433 | + unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; | |
| 439 | 434 | int isTest = find_option("test",0,0)!=0; |
| 440 | 435 | int caseSensitive; |
| 441 | 436 | int n; |
| 442 | 437 | Stmt q; |
| 443 | 438 | int vid; |
| @@ -466,11 +461,11 @@ | ||
| 466 | 461 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 467 | 462 | n = strlen(g.zLocalRoot); |
| 468 | 463 | blob_init(&path, g.zLocalRoot, n-1); |
| 469 | 464 | /* now we read the complete file structure into a temp table */ |
| 470 | 465 | pIgnore = glob_create(zIgnoreFlag); |
| 471 | - vfile_scan(&path, blob_size(&path), allFlag, pIgnore); | |
| 466 | + vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); | |
| 472 | 467 | glob_free(pIgnore); |
| 473 | 468 | nAdd = add_files_in_sfile(vid, caseSensitive); |
| 474 | 469 | |
| 475 | 470 | /* step 2: search for missing files */ |
| 476 | 471 | db_prepare(&q, |
| 477 | 472 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -21,16 +21,10 @@ | |
| 21 | #include "config.h" |
| 22 | #include "add.h" |
| 23 | #include <assert.h> |
| 24 | #include <dirent.h> |
| 25 | |
| 26 | /* |
| 27 | ** Set to true if files whose names begin with "." should be |
| 28 | ** included when processing a recursive "add" command. |
| 29 | */ |
| 30 | static int includeDotFiles = 0; |
| 31 | |
| 32 | /* |
| 33 | ** This routine returns the names of files in a working checkout that |
| 34 | ** are created by Fossil itself, and hence should not be added, deleted, |
| 35 | ** or merge, and should be omitted from "clean" and "extra" lists. |
| 36 | ** |
| @@ -39,11 +33,11 @@ | |
| 39 | */ |
| 40 | const char *fossil_reserved_name(int N){ |
| 41 | /* Possible names of the local per-checkout database file and |
| 42 | ** its associated journals |
| 43 | */ |
| 44 | static const char *azName[] = { |
| 45 | "_FOSSIL_", |
| 46 | "_FOSSIL_-journal", |
| 47 | "_FOSSIL_-wal", |
| 48 | "_FOSSIL_-shm", |
| 49 | ".fslckout", |
| @@ -61,11 +55,11 @@ | |
| 61 | }; |
| 62 | |
| 63 | /* Names of auxiliary files generated by SQLite when the "manifest" |
| 64 | ** properity is enabled |
| 65 | */ |
| 66 | static const char *azManifest[] = { |
| 67 | "manifest", |
| 68 | "manifest.uuid", |
| 69 | }; |
| 70 | |
| 71 | /* Cached setting "manifest" */ |
| @@ -216,13 +210,14 @@ | |
| 216 | int vid; /* Currently checked out version */ |
| 217 | int nRoot; /* Full path characters in g.zLocalRoot */ |
| 218 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 219 | Glob *pIgnore; /* Ignore everything matching this glob pattern */ |
| 220 | int caseSensitive; /* True if filenames are case sensitive */ |
| 221 | |
| 222 | zIgnoreFlag = find_option("ignore",0,1); |
| 223 | includeDotFiles = find_option("dotfiles",0,0)!=0; |
| 224 | capture_case_sensitive_option(); |
| 225 | db_must_be_within_tree(); |
| 226 | caseSensitive = filenames_are_case_sensitive(); |
| 227 | if( zIgnoreFlag==0 ){ |
| 228 | zIgnoreFlag = db_get("ignore-glob", 0); |
| @@ -250,11 +245,11 @@ | |
| 250 | |
| 251 | file_canonical_name(g.argv[i], &fullName, 0); |
| 252 | zName = blob_str(&fullName); |
| 253 | isDir = file_wd_isdir(zName); |
| 254 | if( isDir==1 ){ |
| 255 | vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore); |
| 256 | }else if( isDir==0 ){ |
| 257 | fossil_warning("not found: %s", zName); |
| 258 | }else if( file_access(zName, R_OK) ){ |
| 259 | fossil_fatal("cannot open %s", zName); |
| 260 | }else{ |
| @@ -433,11 +428,11 @@ | |
| 433 | ** See also: add, rm |
| 434 | */ |
| 435 | void addremove_cmd(void){ |
| 436 | Blob path; |
| 437 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 438 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 439 | int isTest = find_option("test",0,0)!=0; |
| 440 | int caseSensitive; |
| 441 | int n; |
| 442 | Stmt q; |
| 443 | int vid; |
| @@ -466,11 +461,11 @@ | |
| 466 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 467 | n = strlen(g.zLocalRoot); |
| 468 | blob_init(&path, g.zLocalRoot, n-1); |
| 469 | /* now we read the complete file structure into a temp table */ |
| 470 | pIgnore = glob_create(zIgnoreFlag); |
| 471 | vfile_scan(&path, blob_size(&path), allFlag, pIgnore); |
| 472 | glob_free(pIgnore); |
| 473 | nAdd = add_files_in_sfile(vid, caseSensitive); |
| 474 | |
| 475 | /* step 2: search for missing files */ |
| 476 | db_prepare(&q, |
| 477 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -21,16 +21,10 @@ | |
| 21 | #include "config.h" |
| 22 | #include "add.h" |
| 23 | #include <assert.h> |
| 24 | #include <dirent.h> |
| 25 | |
| 26 | /* |
| 27 | ** This routine returns the names of files in a working checkout that |
| 28 | ** are created by Fossil itself, and hence should not be added, deleted, |
| 29 | ** or merge, and should be omitted from "clean" and "extra" lists. |
| 30 | ** |
| @@ -39,11 +33,11 @@ | |
| 33 | */ |
| 34 | const char *fossil_reserved_name(int N){ |
| 35 | /* Possible names of the local per-checkout database file and |
| 36 | ** its associated journals |
| 37 | */ |
| 38 | static const char *const azName[] = { |
| 39 | "_FOSSIL_", |
| 40 | "_FOSSIL_-journal", |
| 41 | "_FOSSIL_-wal", |
| 42 | "_FOSSIL_-shm", |
| 43 | ".fslckout", |
| @@ -61,11 +55,11 @@ | |
| 55 | }; |
| 56 | |
| 57 | /* Names of auxiliary files generated by SQLite when the "manifest" |
| 58 | ** properity is enabled |
| 59 | */ |
| 60 | static const char *const azManifest[] = { |
| 61 | "manifest", |
| 62 | "manifest.uuid", |
| 63 | }; |
| 64 | |
| 65 | /* Cached setting "manifest" */ |
| @@ -216,13 +210,14 @@ | |
| 210 | int vid; /* Currently checked out version */ |
| 211 | int nRoot; /* Full path characters in g.zLocalRoot */ |
| 212 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 213 | Glob *pIgnore; /* Ignore everything matching this glob pattern */ |
| 214 | int caseSensitive; /* True if filenames are case sensitive */ |
| 215 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 216 | |
| 217 | zIgnoreFlag = find_option("ignore",0,1); |
| 218 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| 219 | capture_case_sensitive_option(); |
| 220 | db_must_be_within_tree(); |
| 221 | caseSensitive = filenames_are_case_sensitive(); |
| 222 | if( zIgnoreFlag==0 ){ |
| 223 | zIgnoreFlag = db_get("ignore-glob", 0); |
| @@ -250,11 +245,11 @@ | |
| 245 | |
| 246 | file_canonical_name(g.argv[i], &fullName, 0); |
| 247 | zName = blob_str(&fullName); |
| 248 | isDir = file_wd_isdir(zName); |
| 249 | if( isDir==1 ){ |
| 250 | vfile_scan(&fullName, nRoot-1, scanFlags, pIgnore); |
| 251 | }else if( isDir==0 ){ |
| 252 | fossil_warning("not found: %s", zName); |
| 253 | }else if( file_access(zName, R_OK) ){ |
| 254 | fossil_fatal("cannot open %s", zName); |
| 255 | }else{ |
| @@ -433,11 +428,11 @@ | |
| 428 | ** See also: add, rm |
| 429 | */ |
| 430 | void addremove_cmd(void){ |
| 431 | Blob path; |
| 432 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 433 | unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 434 | int isTest = find_option("test",0,0)!=0; |
| 435 | int caseSensitive; |
| 436 | int n; |
| 437 | Stmt q; |
| 438 | int vid; |
| @@ -466,11 +461,11 @@ | |
| 461 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 462 | n = strlen(g.zLocalRoot); |
| 463 | blob_init(&path, g.zLocalRoot, n-1); |
| 464 | /* now we read the complete file structure into a temp table */ |
| 465 | pIgnore = glob_create(zIgnoreFlag); |
| 466 | vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); |
| 467 | glob_free(pIgnore); |
| 468 | nAdd = add_files_in_sfile(vid, caseSensitive); |
| 469 | |
| 470 | /* step 2: search for missing files */ |
| 471 | db_prepare(&q, |
| 472 |
+152
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -165,10 +165,12 @@ | ||
| 165 | 165 | if( zD ){ |
| 166 | 166 | style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); |
| 167 | 167 | style_submenu_element("All", "All", "%R/dir?name=%t", zD); |
| 168 | 168 | }else{ |
| 169 | 169 | style_submenu_element("All", "All", "%R/dir"); |
| 170 | + style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", | |
| 171 | + zUuid); | |
| 170 | 172 | } |
| 171 | 173 | }else{ |
| 172 | 174 | int hasTrunk; |
| 173 | 175 | @ <h2>The union of all files from all check-ins |
| 174 | 176 | @ %s(blob_str(&dirname))</h2> |
| @@ -293,5 +295,155 @@ | ||
| 293 | 295 | db_finalize(&q); |
| 294 | 296 | manifest_destroy(pM); |
| 295 | 297 | @ </ul></td></tr></table> |
| 296 | 298 | style_footer(); |
| 297 | 299 | } |
| 300 | + | |
| 301 | +/* | |
| 302 | +** Look at all file containing in the version "vid". Construct a | |
| 303 | +** temporary table named "fileage" that contains the file-id for each | |
| 304 | +** files, the pathname, the check-in where the file was added, and the | |
| 305 | +** mtime on that checkin. | |
| 306 | +*/ | |
| 307 | +int compute_fileage(int vid){ | |
| 308 | + Manifest *pManifest; | |
| 309 | + ManifestFile *pFile; | |
| 310 | + int nFile = 0; | |
| 311 | + double vmtime; | |
| 312 | + Stmt ins; | |
| 313 | + Stmt q1, q2, q3; | |
| 314 | + Stmt upd; | |
| 315 | + db_multi_exec( | |
| 316 | + /*"DROP TABLE IF EXISTS temp.fileage;"*/ | |
| 317 | + "CREATE TEMP TABLE fileage(" | |
| 318 | + " fid INTEGER," | |
| 319 | + " mid INTEGER," | |
| 320 | + " mtime DATETIME," | |
| 321 | + " pathname TEXT" | |
| 322 | + ");" | |
| 323 | + "CREATE INDEX fileage_fid ON fileage(fid);" | |
| 324 | + ); | |
| 325 | + pManifest = manifest_get(vid, CFTYPE_MANIFEST); | |
| 326 | + if( pManifest==0 ) return 1; | |
| 327 | + manifest_file_rewind(pManifest); | |
| 328 | + db_prepare(&ins, | |
| 329 | + "INSERT INTO temp.fileage(fid, pathname)" | |
| 330 | + " SELECT rid, :path FROM blob WHERE uuid=:uuid" | |
| 331 | + ); | |
| 332 | + while( (pFile = manifest_file_next(pManifest, 0))!=0 ){ | |
| 333 | + db_bind_text(&ins, ":uuid", pFile->zUuid); | |
| 334 | + db_bind_text(&ins, ":path", pFile->zName); | |
| 335 | + db_step(&ins); | |
| 336 | + db_reset(&ins); | |
| 337 | + nFile++; | |
| 338 | + } | |
| 339 | + db_finalize(&ins); | |
| 340 | + manifest_destroy(pManifest); | |
| 341 | + db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid"); | |
| 342 | + db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime" | |
| 343 | + " WHERE fid=:fid AND mid IS NULL"); | |
| 344 | + db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim"); | |
| 345 | + db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid"); | |
| 346 | + while( nFile>0 && vid>0 ){ | |
| 347 | + db_bind_int(&q3, ":vid", vid); | |
| 348 | + if( db_step(&q3)==SQLITE_ROW ){ | |
| 349 | + vmtime = db_column_double(&q3, 0); | |
| 350 | + }else{ | |
| 351 | + break; | |
| 352 | + } | |
| 353 | + db_reset(&q3); | |
| 354 | + db_bind_int(&q1, ":mid", vid); | |
| 355 | + db_bind_int(&upd, ":mid", vid); | |
| 356 | + db_bind_double(&upd, ":vmtime", vmtime); | |
| 357 | + while( db_step(&q1)==SQLITE_ROW ){ | |
| 358 | + db_bind_int(&upd, ":fid", db_column_int(&q1, 0)); | |
| 359 | + db_step(&upd); | |
| 360 | + nFile -= db_changes(); | |
| 361 | + db_reset(&upd); | |
| 362 | + } | |
| 363 | + db_reset(&q1); | |
| 364 | + db_bind_int(&q2, ":vid", vid); | |
| 365 | + if( db_step(&q2)!=SQLITE_ROW ) break; | |
| 366 | + vid = db_column_int(&q2, 0); | |
| 367 | + db_reset(&q2); | |
| 368 | + } | |
| 369 | + db_finalize(&q1); | |
| 370 | + db_finalize(&upd); | |
| 371 | + db_finalize(&q2); | |
| 372 | + db_finalize(&q3); | |
| 373 | + return 0; | |
| 374 | +} | |
| 375 | + | |
| 376 | +/* | |
| 377 | +** WEBPAGE: fileage | |
| 378 | +** | |
| 379 | +** Parameters: | |
| 380 | +** name=VERSION | |
| 381 | +*/ | |
| 382 | +void fileage_page(void){ | |
| 383 | + int rid; | |
| 384 | + const char *zName; | |
| 385 | + char *zBaseTime; | |
| 386 | + Stmt q; | |
| 387 | + double baseTime; | |
| 388 | + int lastMid = -1; | |
| 389 | + | |
| 390 | + login_check_credentials(); | |
| 391 | + if( !g.perm.Read ){ login_needed(); return; } | |
| 392 | + zName = P("name"); | |
| 393 | + if( zName==0 ) zName = "tip"; | |
| 394 | + rid = symbolic_name_to_rid(zName, "ci"); | |
| 395 | + if( rid==0 ){ | |
| 396 | + fossil_fatal("not a valid check-in: %s", zName); | |
| 397 | + } | |
| 398 | + style_header("File Ages", zName); | |
| 399 | + compute_fileage(rid); | |
| 400 | + baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 401 | + zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime); | |
| 402 | + @ <h2>File Ages For Check-in | |
| 403 | + @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> | |
| 404 | + @ | |
| 405 | + @ <p>The times given are relative | |
| 406 | + @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the | |
| 407 | + @ check-in time for | |
| 408 | + @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p> | |
| 409 | + @ | |
| 410 | + @ <table border=0 cellspacing=0 cellpadding=0> | |
| 411 | + db_prepare(&q, | |
| 412 | + "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" | |
| 413 | + " FROM fileage" | |
| 414 | + " ORDER BY mtime DESC, mid, pathname" | |
| 415 | + ); | |
| 416 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 417 | + double age = baseTime - db_column_double(&q, 0); | |
| 418 | + int mid = db_column_int(&q, 2); | |
| 419 | + const char *zFUuid = db_column_text(&q, 1); | |
| 420 | + char zAge[200]; | |
| 421 | + if( lastMid!=mid ){ | |
| 422 | + @ <tr><td colspan=3><hr></tr> | |
| 423 | + lastMid = mid; | |
| 424 | + if( age*86400.0<120 ){ | |
| 425 | + sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0)); | |
| 426 | + }else if( age*1440.0<90 ){ | |
| 427 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0); | |
| 428 | + }else if( age*24.0<36 ){ | |
| 429 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0); | |
| 430 | + }else if( age<365.0 ){ | |
| 431 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age); | |
| 432 | + }else{ | |
| 433 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0); | |
| 434 | + } | |
| 435 | + }else{ | |
| 436 | + zAge[0] = 0; | |
| 437 | + } | |
| 438 | + @ <tr> | |
| 439 | + @ <td>%s(zAge) | |
| 440 | + @ <td width="25"> | |
| 441 | + @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a> | |
| 442 | + @ </tr> | |
| 443 | + @ | |
| 444 | + } | |
| 445 | + @ <tr><td colspan=3><hr></tr> | |
| 446 | + @ </table> | |
| 447 | + db_finalize(&q); | |
| 448 | + style_footer(); | |
| 449 | +} | |
| 298 | 450 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -165,10 +165,12 @@ | |
| 165 | if( zD ){ |
| 166 | style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); |
| 167 | style_submenu_element("All", "All", "%R/dir?name=%t", zD); |
| 168 | }else{ |
| 169 | style_submenu_element("All", "All", "%R/dir"); |
| 170 | } |
| 171 | }else{ |
| 172 | int hasTrunk; |
| 173 | @ <h2>The union of all files from all check-ins |
| 174 | @ %s(blob_str(&dirname))</h2> |
| @@ -293,5 +295,155 @@ | |
| 293 | db_finalize(&q); |
| 294 | manifest_destroy(pM); |
| 295 | @ </ul></td></tr></table> |
| 296 | style_footer(); |
| 297 | } |
| 298 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -165,10 +165,12 @@ | |
| 165 | if( zD ){ |
| 166 | style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); |
| 167 | style_submenu_element("All", "All", "%R/dir?name=%t", zD); |
| 168 | }else{ |
| 169 | style_submenu_element("All", "All", "%R/dir"); |
| 170 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 171 | zUuid); |
| 172 | } |
| 173 | }else{ |
| 174 | int hasTrunk; |
| 175 | @ <h2>The union of all files from all check-ins |
| 176 | @ %s(blob_str(&dirname))</h2> |
| @@ -293,5 +295,155 @@ | |
| 295 | db_finalize(&q); |
| 296 | manifest_destroy(pM); |
| 297 | @ </ul></td></tr></table> |
| 298 | style_footer(); |
| 299 | } |
| 300 | |
| 301 | /* |
| 302 | ** Look at all file containing in the version "vid". Construct a |
| 303 | ** temporary table named "fileage" that contains the file-id for each |
| 304 | ** files, the pathname, the check-in where the file was added, and the |
| 305 | ** mtime on that checkin. |
| 306 | */ |
| 307 | int compute_fileage(int vid){ |
| 308 | Manifest *pManifest; |
| 309 | ManifestFile *pFile; |
| 310 | int nFile = 0; |
| 311 | double vmtime; |
| 312 | Stmt ins; |
| 313 | Stmt q1, q2, q3; |
| 314 | Stmt upd; |
| 315 | db_multi_exec( |
| 316 | /*"DROP TABLE IF EXISTS temp.fileage;"*/ |
| 317 | "CREATE TEMP TABLE fileage(" |
| 318 | " fid INTEGER," |
| 319 | " mid INTEGER," |
| 320 | " mtime DATETIME," |
| 321 | " pathname TEXT" |
| 322 | ");" |
| 323 | "CREATE INDEX fileage_fid ON fileage(fid);" |
| 324 | ); |
| 325 | pManifest = manifest_get(vid, CFTYPE_MANIFEST); |
| 326 | if( pManifest==0 ) return 1; |
| 327 | manifest_file_rewind(pManifest); |
| 328 | db_prepare(&ins, |
| 329 | "INSERT INTO temp.fileage(fid, pathname)" |
| 330 | " SELECT rid, :path FROM blob WHERE uuid=:uuid" |
| 331 | ); |
| 332 | while( (pFile = manifest_file_next(pManifest, 0))!=0 ){ |
| 333 | db_bind_text(&ins, ":uuid", pFile->zUuid); |
| 334 | db_bind_text(&ins, ":path", pFile->zName); |
| 335 | db_step(&ins); |
| 336 | db_reset(&ins); |
| 337 | nFile++; |
| 338 | } |
| 339 | db_finalize(&ins); |
| 340 | manifest_destroy(pManifest); |
| 341 | db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid"); |
| 342 | db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime" |
| 343 | " WHERE fid=:fid AND mid IS NULL"); |
| 344 | db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim"); |
| 345 | db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid"); |
| 346 | while( nFile>0 && vid>0 ){ |
| 347 | db_bind_int(&q3, ":vid", vid); |
| 348 | if( db_step(&q3)==SQLITE_ROW ){ |
| 349 | vmtime = db_column_double(&q3, 0); |
| 350 | }else{ |
| 351 | break; |
| 352 | } |
| 353 | db_reset(&q3); |
| 354 | db_bind_int(&q1, ":mid", vid); |
| 355 | db_bind_int(&upd, ":mid", vid); |
| 356 | db_bind_double(&upd, ":vmtime", vmtime); |
| 357 | while( db_step(&q1)==SQLITE_ROW ){ |
| 358 | db_bind_int(&upd, ":fid", db_column_int(&q1, 0)); |
| 359 | db_step(&upd); |
| 360 | nFile -= db_changes(); |
| 361 | db_reset(&upd); |
| 362 | } |
| 363 | db_reset(&q1); |
| 364 | db_bind_int(&q2, ":vid", vid); |
| 365 | if( db_step(&q2)!=SQLITE_ROW ) break; |
| 366 | vid = db_column_int(&q2, 0); |
| 367 | db_reset(&q2); |
| 368 | } |
| 369 | db_finalize(&q1); |
| 370 | db_finalize(&upd); |
| 371 | db_finalize(&q2); |
| 372 | db_finalize(&q3); |
| 373 | return 0; |
| 374 | } |
| 375 | |
| 376 | /* |
| 377 | ** WEBPAGE: fileage |
| 378 | ** |
| 379 | ** Parameters: |
| 380 | ** name=VERSION |
| 381 | */ |
| 382 | void fileage_page(void){ |
| 383 | int rid; |
| 384 | const char *zName; |
| 385 | char *zBaseTime; |
| 386 | Stmt q; |
| 387 | double baseTime; |
| 388 | int lastMid = -1; |
| 389 | |
| 390 | login_check_credentials(); |
| 391 | if( !g.perm.Read ){ login_needed(); return; } |
| 392 | zName = P("name"); |
| 393 | if( zName==0 ) zName = "tip"; |
| 394 | rid = symbolic_name_to_rid(zName, "ci"); |
| 395 | if( rid==0 ){ |
| 396 | fossil_fatal("not a valid check-in: %s", zName); |
| 397 | } |
| 398 | style_header("File Ages", zName); |
| 399 | compute_fileage(rid); |
| 400 | baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 401 | zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime); |
| 402 | @ <h2>File Ages For Check-in |
| 403 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> |
| 404 | @ |
| 405 | @ <p>The times given are relative |
| 406 | @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the |
| 407 | @ check-in time for |
| 408 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p> |
| 409 | @ |
| 410 | @ <table border=0 cellspacing=0 cellpadding=0> |
| 411 | db_prepare(&q, |
| 412 | "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" |
| 413 | " FROM fileage" |
| 414 | " ORDER BY mtime DESC, mid, pathname" |
| 415 | ); |
| 416 | while( db_step(&q)==SQLITE_ROW ){ |
| 417 | double age = baseTime - db_column_double(&q, 0); |
| 418 | int mid = db_column_int(&q, 2); |
| 419 | const char *zFUuid = db_column_text(&q, 1); |
| 420 | char zAge[200]; |
| 421 | if( lastMid!=mid ){ |
| 422 | @ <tr><td colspan=3><hr></tr> |
| 423 | lastMid = mid; |
| 424 | if( age*86400.0<120 ){ |
| 425 | sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0)); |
| 426 | }else if( age*1440.0<90 ){ |
| 427 | sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0); |
| 428 | }else if( age*24.0<36 ){ |
| 429 | sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0); |
| 430 | }else if( age<365.0 ){ |
| 431 | sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age); |
| 432 | }else{ |
| 433 | sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0); |
| 434 | } |
| 435 | }else{ |
| 436 | zAge[0] = 0; |
| 437 | } |
| 438 | @ <tr> |
| 439 | @ <td>%s(zAge) |
| 440 | @ <td width="25"> |
| 441 | @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a> |
| 442 | @ </tr> |
| 443 | @ |
| 444 | } |
| 445 | @ <tr><td colspan=3><hr></tr> |
| 446 | @ </table> |
| 447 | db_finalize(&q); |
| 448 | style_footer(); |
| 449 | } |
| 450 |
+2
-2
| --- src/captcha.c | ||
| +++ src/captcha.c | ||
| @@ -98,11 +98,11 @@ | ||
| 98 | 98 | } |
| 99 | 99 | #endif /* CAPTCHA==1 */ |
| 100 | 100 | |
| 101 | 101 | |
| 102 | 102 | #if CAPTCHA==2 |
| 103 | -static const char *azFont2[] = { | |
| 103 | +static const char *const azFont2[] = { | |
| 104 | 104 | /* 0 */ |
| 105 | 105 | " __ ", |
| 106 | 106 | " / \\ ", |
| 107 | 107 | "| () |", |
| 108 | 108 | " \\__/ ", |
| @@ -223,11 +223,11 @@ | ||
| 223 | 223 | return z; |
| 224 | 224 | } |
| 225 | 225 | #endif /* CAPTCHA==2 */ |
| 226 | 226 | |
| 227 | 227 | #if CAPTCHA==3 |
| 228 | -static const char *azFont3[] = { | |
| 228 | +static const char *const azFont3[] = { | |
| 229 | 229 | /* 0 */ |
| 230 | 230 | " ___ ", |
| 231 | 231 | " / _ \\ ", |
| 232 | 232 | "| | | |", |
| 233 | 233 | "| | | |", |
| 234 | 234 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -98,11 +98,11 @@ | |
| 98 | } |
| 99 | #endif /* CAPTCHA==1 */ |
| 100 | |
| 101 | |
| 102 | #if CAPTCHA==2 |
| 103 | static const char *azFont2[] = { |
| 104 | /* 0 */ |
| 105 | " __ ", |
| 106 | " / \\ ", |
| 107 | "| () |", |
| 108 | " \\__/ ", |
| @@ -223,11 +223,11 @@ | |
| 223 | return z; |
| 224 | } |
| 225 | #endif /* CAPTCHA==2 */ |
| 226 | |
| 227 | #if CAPTCHA==3 |
| 228 | static const char *azFont3[] = { |
| 229 | /* 0 */ |
| 230 | " ___ ", |
| 231 | " / _ \\ ", |
| 232 | "| | | |", |
| 233 | "| | | |", |
| 234 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -98,11 +98,11 @@ | |
| 98 | } |
| 99 | #endif /* CAPTCHA==1 */ |
| 100 | |
| 101 | |
| 102 | #if CAPTCHA==2 |
| 103 | static const char *const azFont2[] = { |
| 104 | /* 0 */ |
| 105 | " __ ", |
| 106 | " / \\ ", |
| 107 | "| () |", |
| 108 | " \\__/ ", |
| @@ -223,11 +223,11 @@ | |
| 223 | return z; |
| 224 | } |
| 225 | #endif /* CAPTCHA==2 */ |
| 226 | |
| 227 | #if CAPTCHA==3 |
| 228 | static const char *const azFont3[] = { |
| 229 | /* 0 */ |
| 230 | " ___ ", |
| 231 | " / _ \\ ", |
| 232 | "| | | |", |
| 233 | "| | | |", |
| 234 |
+2
-2
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -1354,13 +1354,13 @@ | ||
| 1354 | 1354 | |
| 1355 | 1355 | |
| 1356 | 1356 | /* |
| 1357 | 1357 | ** Name of days and months. |
| 1358 | 1358 | */ |
| 1359 | -static const char *azDays[] = | |
| 1359 | +static const char *const azDays[] = | |
| 1360 | 1360 | {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0}; |
| 1361 | -static const char *azMonths[] = | |
| 1361 | +static const char *const azMonths[] = | |
| 1362 | 1362 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| 1363 | 1363 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; |
| 1364 | 1364 | |
| 1365 | 1365 | |
| 1366 | 1366 | /* |
| 1367 | 1367 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1354,13 +1354,13 @@ | |
| 1354 | |
| 1355 | |
| 1356 | /* |
| 1357 | ** Name of days and months. |
| 1358 | */ |
| 1359 | static const char *azDays[] = |
| 1360 | {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0}; |
| 1361 | static const char *azMonths[] = |
| 1362 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| 1363 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; |
| 1364 | |
| 1365 | |
| 1366 | /* |
| 1367 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1354,13 +1354,13 @@ | |
| 1354 | |
| 1355 | |
| 1356 | /* |
| 1357 | ** Name of days and months. |
| 1358 | */ |
| 1359 | static const char *const azDays[] = |
| 1360 | {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0}; |
| 1361 | static const char *const azMonths[] = |
| 1362 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| 1363 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; |
| 1364 | |
| 1365 | |
| 1366 | /* |
| 1367 |
+46
-19
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -163,11 +163,11 @@ | ||
| 163 | 163 | int cwdRelative = 0; |
| 164 | 164 | db_must_be_within_tree(); |
| 165 | 165 | cwdRelative = determine_cwd_relative_option(); |
| 166 | 166 | blob_zero(&report); |
| 167 | 167 | vid = db_lget_int("checkout", 0); |
| 168 | - vfile_check_signature(vid, 0, useSha1sum); | |
| 168 | + vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); | |
| 169 | 169 | status_report(&report, "", 0, cwdRelative); |
| 170 | 170 | if( verbose && blob_size(&report)==0 ){ |
| 171 | 171 | blob_append(&report, " (none)\n", -1); |
| 172 | 172 | } |
| 173 | 173 | if( showHdr && blob_size(&report)>0 ){ |
| @@ -208,46 +208,74 @@ | ||
| 208 | 208 | show_common_info(vid, "checkout:", 1, 1); |
| 209 | 209 | } |
| 210 | 210 | db_record_repository_filename(0); |
| 211 | 211 | changes_cmd(); |
| 212 | 212 | } |
| 213 | + | |
| 214 | +/* | |
| 215 | +** Implementation of the checkin_mtime SQL function | |
| 216 | +*/ | |
| 217 | + | |
| 213 | 218 | |
| 214 | 219 | /* |
| 215 | 220 | ** COMMAND: ls |
| 216 | 221 | ** |
| 217 | -** Usage: %fossil ls ?OPTIONS? | |
| 222 | +** Usage: %fossil ls ?OPTIONS? ?VERSION? | |
| 218 | 223 | ** |
| 219 | 224 | ** Show the names of all files in the current checkout. The -l provides |
| 220 | 225 | ** extra information about each file. |
| 221 | 226 | ** |
| 222 | 227 | ** Options: |
| 223 | -** -l Provide extra information about each file. | |
| 228 | +** -l Provide extra information about each file. | |
| 229 | +** --age Show when each file was committed | |
| 224 | 230 | ** |
| 225 | 231 | ** See also: changes, extra, status |
| 226 | 232 | */ |
| 227 | 233 | void ls_cmd(void){ |
| 228 | 234 | int vid; |
| 229 | 235 | Stmt q; |
| 230 | 236 | int isBrief; |
| 237 | + int showAge; | |
| 238 | + char *zOrderBy = "pathname"; | |
| 231 | 239 | |
| 232 | 240 | isBrief = find_option("l","l", 0)==0; |
| 241 | + showAge = find_option("age",0,0)!=0; | |
| 233 | 242 | db_must_be_within_tree(); |
| 234 | 243 | vid = db_lget_int("checkout", 0); |
| 235 | - vfile_check_signature(vid, 0, 0); | |
| 236 | - db_prepare(&q, | |
| 237 | - "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" | |
| 238 | - " FROM vfile" | |
| 239 | - " ORDER BY 1" | |
| 240 | - ); | |
| 244 | + if( find_option("t","t",0)!=0 ){ | |
| 245 | + if( showAge ){ | |
| 246 | + zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid); | |
| 247 | + }else{ | |
| 248 | + zOrderBy = "mtime DESC"; | |
| 249 | + } | |
| 250 | + } | |
| 251 | + verify_all_options(); | |
| 252 | + vfile_check_signature(vid, 0); | |
| 253 | + if( showAge ){ | |
| 254 | + db_prepare(&q, | |
| 255 | + "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," | |
| 256 | + " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" | |
| 257 | + " FROM vfile" | |
| 258 | + " ORDER BY %s", vid, zOrderBy | |
| 259 | + ); | |
| 260 | + }else{ | |
| 261 | + db_prepare(&q, | |
| 262 | + "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" | |
| 263 | + " FROM vfile" | |
| 264 | + " ORDER BY %s", zOrderBy | |
| 265 | + ); | |
| 266 | + } | |
| 241 | 267 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | 268 | const char *zPathname = db_column_text(&q,0); |
| 243 | 269 | int isDeleted = db_column_int(&q, 1); |
| 244 | 270 | int isNew = db_column_int(&q,2)==0; |
| 245 | 271 | int chnged = db_column_int(&q,3); |
| 246 | 272 | int renamed = db_column_int(&q,4); |
| 247 | 273 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 248 | - if( isBrief ){ | |
| 274 | + if( showAge ){ | |
| 275 | + fossil_print("%s %s\n", db_column_text(&q, 5), zPathname); | |
| 276 | + }else if( isBrief ){ | |
| 249 | 277 | fossil_print("%s\n", zPathname); |
| 250 | 278 | }else if( isNew ){ |
| 251 | 279 | fossil_print("ADDED %s\n", zPathname); |
| 252 | 280 | }else if( isDeleted ){ |
| 253 | 281 | fossil_print("DELETED %s\n", zPathname); |
| @@ -299,16 +327,17 @@ | ||
| 299 | 327 | Blob path; |
| 300 | 328 | Blob repo; |
| 301 | 329 | Stmt q; |
| 302 | 330 | int n; |
| 303 | 331 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 304 | - int allFlag = find_option("dotfiles",0,0)!=0; | |
| 332 | + unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; | |
| 305 | 333 | int cwdRelative = 0; |
| 306 | 334 | Glob *pIgnore; |
| 307 | 335 | Blob rewrittenPathname; |
| 308 | 336 | const char *zPathname, *zDisplayName; |
| 309 | 337 | |
| 338 | + if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; | |
| 310 | 339 | db_must_be_within_tree(); |
| 311 | 340 | cwdRelative = determine_cwd_relative_option(); |
| 312 | 341 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 313 | 342 | filename_collation()); |
| 314 | 343 | n = strlen(g.zLocalRoot); |
| @@ -315,11 +344,11 @@ | ||
| 315 | 344 | blob_init(&path, g.zLocalRoot, n-1); |
| 316 | 345 | if( zIgnoreFlag==0 ){ |
| 317 | 346 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 318 | 347 | } |
| 319 | 348 | pIgnore = glob_create(zIgnoreFlag); |
| 320 | - vfile_scan(&path, blob_size(&path), allFlag, pIgnore); | |
| 349 | + vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); | |
| 321 | 350 | glob_free(pIgnore); |
| 322 | 351 | db_prepare(&q, |
| 323 | 352 | "SELECT x FROM sfile" |
| 324 | 353 | " WHERE x NOT IN (%s)" |
| 325 | 354 | " ORDER BY 1", |
| @@ -370,34 +399,36 @@ | ||
| 370 | 399 | ** Options: |
| 371 | 400 | ** --dotfiles include files beginning with a dot (".") |
| 372 | 401 | ** --force Remove files without prompting |
| 373 | 402 | ** --ignore <CSG> ignore files matching patterns from the |
| 374 | 403 | ** comma separated list of glob patterns. |
| 404 | +** --temp Remove only Fossil-generated temporary files | |
| 375 | 405 | ** |
| 376 | 406 | ** See also: addremove, extra, status |
| 377 | 407 | */ |
| 378 | 408 | void clean_cmd(void){ |
| 379 | 409 | int allFlag; |
| 380 | - int dotfilesFlag; | |
| 410 | + unsigned scanFlags = 0; | |
| 381 | 411 | const char *zIgnoreFlag; |
| 382 | 412 | Blob path, repo; |
| 383 | 413 | Stmt q; |
| 384 | 414 | int n; |
| 385 | 415 | Glob *pIgnore; |
| 386 | 416 | |
| 387 | 417 | allFlag = find_option("force","f",0)!=0; |
| 388 | - dotfilesFlag = find_option("dotfiles",0,0)!=0; | |
| 418 | + if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; | |
| 419 | + if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; | |
| 389 | 420 | zIgnoreFlag = find_option("ignore",0,1); |
| 390 | 421 | db_must_be_within_tree(); |
| 391 | 422 | if( zIgnoreFlag==0 ){ |
| 392 | 423 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 393 | 424 | } |
| 394 | 425 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 395 | 426 | n = strlen(g.zLocalRoot); |
| 396 | 427 | blob_init(&path, g.zLocalRoot, n-1); |
| 397 | 428 | pIgnore = glob_create(zIgnoreFlag); |
| 398 | - vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); | |
| 429 | + vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); | |
| 399 | 430 | glob_free(pIgnore); |
| 400 | 431 | db_prepare(&q, |
| 401 | 432 | "SELECT %Q || x FROM sfile" |
| 402 | 433 | " WHERE x NOT IN (%s)" |
| 403 | 434 | " ORDER BY 1", |
| @@ -806,14 +837,10 @@ | ||
| 806 | 837 | } |
| 807 | 838 | if( zColor && zColor[0] ){ |
| 808 | 839 | /* One-time background color */ |
| 809 | 840 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 810 | 841 | } |
| 811 | - if( g.markPrivate ){ | |
| 812 | - /* If this manifest is private, mark it as such */ | |
| 813 | - blob_appendf(pOut, "T +private *\n"); | |
| 814 | - } | |
| 815 | 842 | if( azTag ){ |
| 816 | 843 | for(i=0; azTag[i]; i++){ |
| 817 | 844 | /* Add a symbolic tag to this check-in. The tag names have already |
| 818 | 845 | ** been sorted and converted using the %F format */ |
| 819 | 846 | blob_appendf(pOut, "T +sym-%s *\n", azTag[i]); |
| 820 | 847 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -163,11 +163,11 @@ | |
| 163 | int cwdRelative = 0; |
| 164 | db_must_be_within_tree(); |
| 165 | cwdRelative = determine_cwd_relative_option(); |
| 166 | blob_zero(&report); |
| 167 | vid = db_lget_int("checkout", 0); |
| 168 | vfile_check_signature(vid, 0, useSha1sum); |
| 169 | status_report(&report, "", 0, cwdRelative); |
| 170 | if( verbose && blob_size(&report)==0 ){ |
| 171 | blob_append(&report, " (none)\n", -1); |
| 172 | } |
| 173 | if( showHdr && blob_size(&report)>0 ){ |
| @@ -208,46 +208,74 @@ | |
| 208 | show_common_info(vid, "checkout:", 1, 1); |
| 209 | } |
| 210 | db_record_repository_filename(0); |
| 211 | changes_cmd(); |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | ** COMMAND: ls |
| 216 | ** |
| 217 | ** Usage: %fossil ls ?OPTIONS? |
| 218 | ** |
| 219 | ** Show the names of all files in the current checkout. The -l provides |
| 220 | ** extra information about each file. |
| 221 | ** |
| 222 | ** Options: |
| 223 | ** -l Provide extra information about each file. |
| 224 | ** |
| 225 | ** See also: changes, extra, status |
| 226 | */ |
| 227 | void ls_cmd(void){ |
| 228 | int vid; |
| 229 | Stmt q; |
| 230 | int isBrief; |
| 231 | |
| 232 | isBrief = find_option("l","l", 0)==0; |
| 233 | db_must_be_within_tree(); |
| 234 | vid = db_lget_int("checkout", 0); |
| 235 | vfile_check_signature(vid, 0, 0); |
| 236 | db_prepare(&q, |
| 237 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 238 | " FROM vfile" |
| 239 | " ORDER BY 1" |
| 240 | ); |
| 241 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | const char *zPathname = db_column_text(&q,0); |
| 243 | int isDeleted = db_column_int(&q, 1); |
| 244 | int isNew = db_column_int(&q,2)==0; |
| 245 | int chnged = db_column_int(&q,3); |
| 246 | int renamed = db_column_int(&q,4); |
| 247 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 248 | if( isBrief ){ |
| 249 | fossil_print("%s\n", zPathname); |
| 250 | }else if( isNew ){ |
| 251 | fossil_print("ADDED %s\n", zPathname); |
| 252 | }else if( isDeleted ){ |
| 253 | fossil_print("DELETED %s\n", zPathname); |
| @@ -299,16 +327,17 @@ | |
| 299 | Blob path; |
| 300 | Blob repo; |
| 301 | Stmt q; |
| 302 | int n; |
| 303 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 304 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 305 | int cwdRelative = 0; |
| 306 | Glob *pIgnore; |
| 307 | Blob rewrittenPathname; |
| 308 | const char *zPathname, *zDisplayName; |
| 309 | |
| 310 | db_must_be_within_tree(); |
| 311 | cwdRelative = determine_cwd_relative_option(); |
| 312 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 313 | filename_collation()); |
| 314 | n = strlen(g.zLocalRoot); |
| @@ -315,11 +344,11 @@ | |
| 315 | blob_init(&path, g.zLocalRoot, n-1); |
| 316 | if( zIgnoreFlag==0 ){ |
| 317 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 318 | } |
| 319 | pIgnore = glob_create(zIgnoreFlag); |
| 320 | vfile_scan(&path, blob_size(&path), allFlag, pIgnore); |
| 321 | glob_free(pIgnore); |
| 322 | db_prepare(&q, |
| 323 | "SELECT x FROM sfile" |
| 324 | " WHERE x NOT IN (%s)" |
| 325 | " ORDER BY 1", |
| @@ -370,34 +399,36 @@ | |
| 370 | ** Options: |
| 371 | ** --dotfiles include files beginning with a dot (".") |
| 372 | ** --force Remove files without prompting |
| 373 | ** --ignore <CSG> ignore files matching patterns from the |
| 374 | ** comma separated list of glob patterns. |
| 375 | ** |
| 376 | ** See also: addremove, extra, status |
| 377 | */ |
| 378 | void clean_cmd(void){ |
| 379 | int allFlag; |
| 380 | int dotfilesFlag; |
| 381 | const char *zIgnoreFlag; |
| 382 | Blob path, repo; |
| 383 | Stmt q; |
| 384 | int n; |
| 385 | Glob *pIgnore; |
| 386 | |
| 387 | allFlag = find_option("force","f",0)!=0; |
| 388 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 389 | zIgnoreFlag = find_option("ignore",0,1); |
| 390 | db_must_be_within_tree(); |
| 391 | if( zIgnoreFlag==0 ){ |
| 392 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 393 | } |
| 394 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 395 | n = strlen(g.zLocalRoot); |
| 396 | blob_init(&path, g.zLocalRoot, n-1); |
| 397 | pIgnore = glob_create(zIgnoreFlag); |
| 398 | vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); |
| 399 | glob_free(pIgnore); |
| 400 | db_prepare(&q, |
| 401 | "SELECT %Q || x FROM sfile" |
| 402 | " WHERE x NOT IN (%s)" |
| 403 | " ORDER BY 1", |
| @@ -806,14 +837,10 @@ | |
| 806 | } |
| 807 | if( zColor && zColor[0] ){ |
| 808 | /* One-time background color */ |
| 809 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 810 | } |
| 811 | if( g.markPrivate ){ |
| 812 | /* If this manifest is private, mark it as such */ |
| 813 | blob_appendf(pOut, "T +private *\n"); |
| 814 | } |
| 815 | if( azTag ){ |
| 816 | for(i=0; azTag[i]; i++){ |
| 817 | /* Add a symbolic tag to this check-in. The tag names have already |
| 818 | ** been sorted and converted using the %F format */ |
| 819 | blob_appendf(pOut, "T +sym-%s *\n", azTag[i]); |
| 820 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -163,11 +163,11 @@ | |
| 163 | int cwdRelative = 0; |
| 164 | db_must_be_within_tree(); |
| 165 | cwdRelative = determine_cwd_relative_option(); |
| 166 | blob_zero(&report); |
| 167 | vid = db_lget_int("checkout", 0); |
| 168 | vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); |
| 169 | status_report(&report, "", 0, cwdRelative); |
| 170 | if( verbose && blob_size(&report)==0 ){ |
| 171 | blob_append(&report, " (none)\n", -1); |
| 172 | } |
| 173 | if( showHdr && blob_size(&report)>0 ){ |
| @@ -208,46 +208,74 @@ | |
| 208 | show_common_info(vid, "checkout:", 1, 1); |
| 209 | } |
| 210 | db_record_repository_filename(0); |
| 211 | changes_cmd(); |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | ** Implementation of the checkin_mtime SQL function |
| 216 | */ |
| 217 | |
| 218 | |
| 219 | /* |
| 220 | ** COMMAND: ls |
| 221 | ** |
| 222 | ** Usage: %fossil ls ?OPTIONS? ?VERSION? |
| 223 | ** |
| 224 | ** Show the names of all files in the current checkout. The -l provides |
| 225 | ** extra information about each file. |
| 226 | ** |
| 227 | ** Options: |
| 228 | ** -l Provide extra information about each file. |
| 229 | ** --age Show when each file was committed |
| 230 | ** |
| 231 | ** See also: changes, extra, status |
| 232 | */ |
| 233 | void ls_cmd(void){ |
| 234 | int vid; |
| 235 | Stmt q; |
| 236 | int isBrief; |
| 237 | int showAge; |
| 238 | char *zOrderBy = "pathname"; |
| 239 | |
| 240 | isBrief = find_option("l","l", 0)==0; |
| 241 | showAge = find_option("age",0,0)!=0; |
| 242 | db_must_be_within_tree(); |
| 243 | vid = db_lget_int("checkout", 0); |
| 244 | if( find_option("t","t",0)!=0 ){ |
| 245 | if( showAge ){ |
| 246 | zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid); |
| 247 | }else{ |
| 248 | zOrderBy = "mtime DESC"; |
| 249 | } |
| 250 | } |
| 251 | verify_all_options(); |
| 252 | vfile_check_signature(vid, 0); |
| 253 | if( showAge ){ |
| 254 | db_prepare(&q, |
| 255 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," |
| 256 | " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" |
| 257 | " FROM vfile" |
| 258 | " ORDER BY %s", vid, zOrderBy |
| 259 | ); |
| 260 | }else{ |
| 261 | db_prepare(&q, |
| 262 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 263 | " FROM vfile" |
| 264 | " ORDER BY %s", zOrderBy |
| 265 | ); |
| 266 | } |
| 267 | while( db_step(&q)==SQLITE_ROW ){ |
| 268 | const char *zPathname = db_column_text(&q,0); |
| 269 | int isDeleted = db_column_int(&q, 1); |
| 270 | int isNew = db_column_int(&q,2)==0; |
| 271 | int chnged = db_column_int(&q,3); |
| 272 | int renamed = db_column_int(&q,4); |
| 273 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 274 | if( showAge ){ |
| 275 | fossil_print("%s %s\n", db_column_text(&q, 5), zPathname); |
| 276 | }else if( isBrief ){ |
| 277 | fossil_print("%s\n", zPathname); |
| 278 | }else if( isNew ){ |
| 279 | fossil_print("ADDED %s\n", zPathname); |
| 280 | }else if( isDeleted ){ |
| 281 | fossil_print("DELETED %s\n", zPathname); |
| @@ -299,16 +327,17 @@ | |
| 327 | Blob path; |
| 328 | Blob repo; |
| 329 | Stmt q; |
| 330 | int n; |
| 331 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 332 | unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 333 | int cwdRelative = 0; |
| 334 | Glob *pIgnore; |
| 335 | Blob rewrittenPathname; |
| 336 | const char *zPathname, *zDisplayName; |
| 337 | |
| 338 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 339 | db_must_be_within_tree(); |
| 340 | cwdRelative = determine_cwd_relative_option(); |
| 341 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 342 | filename_collation()); |
| 343 | n = strlen(g.zLocalRoot); |
| @@ -315,11 +344,11 @@ | |
| 344 | blob_init(&path, g.zLocalRoot, n-1); |
| 345 | if( zIgnoreFlag==0 ){ |
| 346 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 347 | } |
| 348 | pIgnore = glob_create(zIgnoreFlag); |
| 349 | vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); |
| 350 | glob_free(pIgnore); |
| 351 | db_prepare(&q, |
| 352 | "SELECT x FROM sfile" |
| 353 | " WHERE x NOT IN (%s)" |
| 354 | " ORDER BY 1", |
| @@ -370,34 +399,36 @@ | |
| 399 | ** Options: |
| 400 | ** --dotfiles include files beginning with a dot (".") |
| 401 | ** --force Remove files without prompting |
| 402 | ** --ignore <CSG> ignore files matching patterns from the |
| 403 | ** comma separated list of glob patterns. |
| 404 | ** --temp Remove only Fossil-generated temporary files |
| 405 | ** |
| 406 | ** See also: addremove, extra, status |
| 407 | */ |
| 408 | void clean_cmd(void){ |
| 409 | int allFlag; |
| 410 | unsigned scanFlags = 0; |
| 411 | const char *zIgnoreFlag; |
| 412 | Blob path, repo; |
| 413 | Stmt q; |
| 414 | int n; |
| 415 | Glob *pIgnore; |
| 416 | |
| 417 | allFlag = find_option("force","f",0)!=0; |
| 418 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| 419 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 420 | zIgnoreFlag = find_option("ignore",0,1); |
| 421 | db_must_be_within_tree(); |
| 422 | if( zIgnoreFlag==0 ){ |
| 423 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 424 | } |
| 425 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 426 | n = strlen(g.zLocalRoot); |
| 427 | blob_init(&path, g.zLocalRoot, n-1); |
| 428 | pIgnore = glob_create(zIgnoreFlag); |
| 429 | vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); |
| 430 | glob_free(pIgnore); |
| 431 | db_prepare(&q, |
| 432 | "SELECT %Q || x FROM sfile" |
| 433 | " WHERE x NOT IN (%s)" |
| 434 | " ORDER BY 1", |
| @@ -806,14 +837,10 @@ | |
| 837 | } |
| 838 | if( zColor && zColor[0] ){ |
| 839 | /* One-time background color */ |
| 840 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 841 | } |
| 842 | if( azTag ){ |
| 843 | for(i=0; azTag[i]; i++){ |
| 844 | /* Add a symbolic tag to this check-in. The tag names have already |
| 845 | ** been sorted and converted using the %F format */ |
| 846 | blob_appendf(pOut, "T +sym-%s *\n", azTag[i]); |
| 847 |
+46
-19
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -163,11 +163,11 @@ | ||
| 163 | 163 | int cwdRelative = 0; |
| 164 | 164 | db_must_be_within_tree(); |
| 165 | 165 | cwdRelative = determine_cwd_relative_option(); |
| 166 | 166 | blob_zero(&report); |
| 167 | 167 | vid = db_lget_int("checkout", 0); |
| 168 | - vfile_check_signature(vid, 0, useSha1sum); | |
| 168 | + vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); | |
| 169 | 169 | status_report(&report, "", 0, cwdRelative); |
| 170 | 170 | if( verbose && blob_size(&report)==0 ){ |
| 171 | 171 | blob_append(&report, " (none)\n", -1); |
| 172 | 172 | } |
| 173 | 173 | if( showHdr && blob_size(&report)>0 ){ |
| @@ -208,46 +208,74 @@ | ||
| 208 | 208 | show_common_info(vid, "checkout:", 1, 1); |
| 209 | 209 | } |
| 210 | 210 | db_record_repository_filename(0); |
| 211 | 211 | changes_cmd(); |
| 212 | 212 | } |
| 213 | + | |
| 214 | +/* | |
| 215 | +** Implementation of the checkin_mtime SQL function | |
| 216 | +*/ | |
| 217 | + | |
| 213 | 218 | |
| 214 | 219 | /* |
| 215 | 220 | ** COMMAND: ls |
| 216 | 221 | ** |
| 217 | -** Usage: %fossil ls ?OPTIONS? | |
| 222 | +** Usage: %fossil ls ?OPTIONS? ?VERSION? | |
| 218 | 223 | ** |
| 219 | 224 | ** Show the names of all files in the current checkout. The -l provides |
| 220 | 225 | ** extra information about each file. |
| 221 | 226 | ** |
| 222 | 227 | ** Options: |
| 223 | -** -l Provide extra information about each file. | |
| 228 | +** -l Provide extra information about each file. | |
| 229 | +** --age Show when each file was committed | |
| 224 | 230 | ** |
| 225 | 231 | ** See also: changes, extra, status |
| 226 | 232 | */ |
| 227 | 233 | void ls_cmd(void){ |
| 228 | 234 | int vid; |
| 229 | 235 | Stmt q; |
| 230 | 236 | int isBrief; |
| 237 | + int showAge; | |
| 238 | + char *zOrderBy = "pathname"; | |
| 231 | 239 | |
| 232 | 240 | isBrief = find_option("l","l", 0)==0; |
| 241 | + showAge = find_option("age",0,0)!=0; | |
| 233 | 242 | db_must_be_within_tree(); |
| 234 | 243 | vid = db_lget_int("checkout", 0); |
| 235 | - vfile_check_signature(vid, 0, 0); | |
| 236 | - db_prepare(&q, | |
| 237 | - "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" | |
| 238 | - " FROM vfile" | |
| 239 | - " ORDER BY 1" | |
| 240 | - ); | |
| 244 | + if( find_option("t","t",0)!=0 ){ | |
| 245 | + if( showAge ){ | |
| 246 | + zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid); | |
| 247 | + }else{ | |
| 248 | + zOrderBy = "mtime DESC"; | |
| 249 | + } | |
| 250 | + } | |
| 251 | + verify_all_options(); | |
| 252 | + vfile_check_signature(vid, 0); | |
| 253 | + if( showAge ){ | |
| 254 | + db_prepare(&q, | |
| 255 | + "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," | |
| 256 | + " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" | |
| 257 | + " FROM vfile" | |
| 258 | + " ORDER BY %s", vid, zOrderBy | |
| 259 | + ); | |
| 260 | + }else{ | |
| 261 | + db_prepare(&q, | |
| 262 | + "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" | |
| 263 | + " FROM vfile" | |
| 264 | + " ORDER BY %s", zOrderBy | |
| 265 | + ); | |
| 266 | + } | |
| 241 | 267 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | 268 | const char *zPathname = db_column_text(&q,0); |
| 243 | 269 | int isDeleted = db_column_int(&q, 1); |
| 244 | 270 | int isNew = db_column_int(&q,2)==0; |
| 245 | 271 | int chnged = db_column_int(&q,3); |
| 246 | 272 | int renamed = db_column_int(&q,4); |
| 247 | 273 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 248 | - if( isBrief ){ | |
| 274 | + if( showAge ){ | |
| 275 | + fossil_print("%s %s\n", db_column_text(&q, 5), zPathname); | |
| 276 | + }else if( isBrief ){ | |
| 249 | 277 | fossil_print("%s\n", zPathname); |
| 250 | 278 | }else if( isNew ){ |
| 251 | 279 | fossil_print("ADDED %s\n", zPathname); |
| 252 | 280 | }else if( isDeleted ){ |
| 253 | 281 | fossil_print("DELETED %s\n", zPathname); |
| @@ -299,16 +327,17 @@ | ||
| 299 | 327 | Blob path; |
| 300 | 328 | Blob repo; |
| 301 | 329 | Stmt q; |
| 302 | 330 | int n; |
| 303 | 331 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 304 | - int allFlag = find_option("dotfiles",0,0)!=0; | |
| 332 | + unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; | |
| 305 | 333 | int cwdRelative = 0; |
| 306 | 334 | Glob *pIgnore; |
| 307 | 335 | Blob rewrittenPathname; |
| 308 | 336 | const char *zPathname, *zDisplayName; |
| 309 | 337 | |
| 338 | + if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; | |
| 310 | 339 | db_must_be_within_tree(); |
| 311 | 340 | cwdRelative = determine_cwd_relative_option(); |
| 312 | 341 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 313 | 342 | filename_collation()); |
| 314 | 343 | n = strlen(g.zLocalRoot); |
| @@ -315,11 +344,11 @@ | ||
| 315 | 344 | blob_init(&path, g.zLocalRoot, n-1); |
| 316 | 345 | if( zIgnoreFlag==0 ){ |
| 317 | 346 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 318 | 347 | } |
| 319 | 348 | pIgnore = glob_create(zIgnoreFlag); |
| 320 | - vfile_scan(&path, blob_size(&path), allFlag, pIgnore); | |
| 349 | + vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); | |
| 321 | 350 | glob_free(pIgnore); |
| 322 | 351 | db_prepare(&q, |
| 323 | 352 | "SELECT x FROM sfile" |
| 324 | 353 | " WHERE x NOT IN (%s)" |
| 325 | 354 | " ORDER BY 1", |
| @@ -370,34 +399,36 @@ | ||
| 370 | 399 | ** Options: |
| 371 | 400 | ** --dotfiles include files beginning with a dot (".") |
| 372 | 401 | ** --force Remove files without prompting |
| 373 | 402 | ** --ignore <CSG> ignore files matching patterns from the |
| 374 | 403 | ** comma separated list of glob patterns. |
| 404 | +** --temp Remove only Fossil-generated temporary files | |
| 375 | 405 | ** |
| 376 | 406 | ** See also: addremove, extra, status |
| 377 | 407 | */ |
| 378 | 408 | void clean_cmd(void){ |
| 379 | 409 | int allFlag; |
| 380 | - int dotfilesFlag; | |
| 410 | + unsigned scanFlags = 0; | |
| 381 | 411 | const char *zIgnoreFlag; |
| 382 | 412 | Blob path, repo; |
| 383 | 413 | Stmt q; |
| 384 | 414 | int n; |
| 385 | 415 | Glob *pIgnore; |
| 386 | 416 | |
| 387 | 417 | allFlag = find_option("force","f",0)!=0; |
| 388 | - dotfilesFlag = find_option("dotfiles",0,0)!=0; | |
| 418 | + if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; | |
| 419 | + if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; | |
| 389 | 420 | zIgnoreFlag = find_option("ignore",0,1); |
| 390 | 421 | db_must_be_within_tree(); |
| 391 | 422 | if( zIgnoreFlag==0 ){ |
| 392 | 423 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 393 | 424 | } |
| 394 | 425 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 395 | 426 | n = strlen(g.zLocalRoot); |
| 396 | 427 | blob_init(&path, g.zLocalRoot, n-1); |
| 397 | 428 | pIgnore = glob_create(zIgnoreFlag); |
| 398 | - vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); | |
| 429 | + vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); | |
| 399 | 430 | glob_free(pIgnore); |
| 400 | 431 | db_prepare(&q, |
| 401 | 432 | "SELECT %Q || x FROM sfile" |
| 402 | 433 | " WHERE x NOT IN (%s)" |
| 403 | 434 | " ORDER BY 1", |
| @@ -806,14 +837,10 @@ | ||
| 806 | 837 | } |
| 807 | 838 | if( zColor && zColor[0] ){ |
| 808 | 839 | /* One-time background color */ |
| 809 | 840 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 810 | 841 | } |
| 811 | - if( g.markPrivate ){ | |
| 812 | - /* If this manifest is private, mark it as such */ | |
| 813 | - blob_appendf(pOut, "T +private *\n"); | |
| 814 | - } | |
| 815 | 842 | if( azTag ){ |
| 816 | 843 | for(i=0; azTag[i]; i++){ |
| 817 | 844 | /* Add a symbolic tag to this check-in. The tag names have already |
| 818 | 845 | ** been sorted and converted using the %F format */ |
| 819 | 846 | blob_appendf(pOut, "T +sym-%s *\n", azTag[i]); |
| 820 | 847 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -163,11 +163,11 @@ | |
| 163 | int cwdRelative = 0; |
| 164 | db_must_be_within_tree(); |
| 165 | cwdRelative = determine_cwd_relative_option(); |
| 166 | blob_zero(&report); |
| 167 | vid = db_lget_int("checkout", 0); |
| 168 | vfile_check_signature(vid, 0, useSha1sum); |
| 169 | status_report(&report, "", 0, cwdRelative); |
| 170 | if( verbose && blob_size(&report)==0 ){ |
| 171 | blob_append(&report, " (none)\n", -1); |
| 172 | } |
| 173 | if( showHdr && blob_size(&report)>0 ){ |
| @@ -208,46 +208,74 @@ | |
| 208 | show_common_info(vid, "checkout:", 1, 1); |
| 209 | } |
| 210 | db_record_repository_filename(0); |
| 211 | changes_cmd(); |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | ** COMMAND: ls |
| 216 | ** |
| 217 | ** Usage: %fossil ls ?OPTIONS? |
| 218 | ** |
| 219 | ** Show the names of all files in the current checkout. The -l provides |
| 220 | ** extra information about each file. |
| 221 | ** |
| 222 | ** Options: |
| 223 | ** -l Provide extra information about each file. |
| 224 | ** |
| 225 | ** See also: changes, extra, status |
| 226 | */ |
| 227 | void ls_cmd(void){ |
| 228 | int vid; |
| 229 | Stmt q; |
| 230 | int isBrief; |
| 231 | |
| 232 | isBrief = find_option("l","l", 0)==0; |
| 233 | db_must_be_within_tree(); |
| 234 | vid = db_lget_int("checkout", 0); |
| 235 | vfile_check_signature(vid, 0, 0); |
| 236 | db_prepare(&q, |
| 237 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 238 | " FROM vfile" |
| 239 | " ORDER BY 1" |
| 240 | ); |
| 241 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | const char *zPathname = db_column_text(&q,0); |
| 243 | int isDeleted = db_column_int(&q, 1); |
| 244 | int isNew = db_column_int(&q,2)==0; |
| 245 | int chnged = db_column_int(&q,3); |
| 246 | int renamed = db_column_int(&q,4); |
| 247 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 248 | if( isBrief ){ |
| 249 | fossil_print("%s\n", zPathname); |
| 250 | }else if( isNew ){ |
| 251 | fossil_print("ADDED %s\n", zPathname); |
| 252 | }else if( isDeleted ){ |
| 253 | fossil_print("DELETED %s\n", zPathname); |
| @@ -299,16 +327,17 @@ | |
| 299 | Blob path; |
| 300 | Blob repo; |
| 301 | Stmt q; |
| 302 | int n; |
| 303 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 304 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 305 | int cwdRelative = 0; |
| 306 | Glob *pIgnore; |
| 307 | Blob rewrittenPathname; |
| 308 | const char *zPathname, *zDisplayName; |
| 309 | |
| 310 | db_must_be_within_tree(); |
| 311 | cwdRelative = determine_cwd_relative_option(); |
| 312 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 313 | filename_collation()); |
| 314 | n = strlen(g.zLocalRoot); |
| @@ -315,11 +344,11 @@ | |
| 315 | blob_init(&path, g.zLocalRoot, n-1); |
| 316 | if( zIgnoreFlag==0 ){ |
| 317 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 318 | } |
| 319 | pIgnore = glob_create(zIgnoreFlag); |
| 320 | vfile_scan(&path, blob_size(&path), allFlag, pIgnore); |
| 321 | glob_free(pIgnore); |
| 322 | db_prepare(&q, |
| 323 | "SELECT x FROM sfile" |
| 324 | " WHERE x NOT IN (%s)" |
| 325 | " ORDER BY 1", |
| @@ -370,34 +399,36 @@ | |
| 370 | ** Options: |
| 371 | ** --dotfiles include files beginning with a dot (".") |
| 372 | ** --force Remove files without prompting |
| 373 | ** --ignore <CSG> ignore files matching patterns from the |
| 374 | ** comma separated list of glob patterns. |
| 375 | ** |
| 376 | ** See also: addremove, extra, status |
| 377 | */ |
| 378 | void clean_cmd(void){ |
| 379 | int allFlag; |
| 380 | int dotfilesFlag; |
| 381 | const char *zIgnoreFlag; |
| 382 | Blob path, repo; |
| 383 | Stmt q; |
| 384 | int n; |
| 385 | Glob *pIgnore; |
| 386 | |
| 387 | allFlag = find_option("force","f",0)!=0; |
| 388 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 389 | zIgnoreFlag = find_option("ignore",0,1); |
| 390 | db_must_be_within_tree(); |
| 391 | if( zIgnoreFlag==0 ){ |
| 392 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 393 | } |
| 394 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 395 | n = strlen(g.zLocalRoot); |
| 396 | blob_init(&path, g.zLocalRoot, n-1); |
| 397 | pIgnore = glob_create(zIgnoreFlag); |
| 398 | vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); |
| 399 | glob_free(pIgnore); |
| 400 | db_prepare(&q, |
| 401 | "SELECT %Q || x FROM sfile" |
| 402 | " WHERE x NOT IN (%s)" |
| 403 | " ORDER BY 1", |
| @@ -806,14 +837,10 @@ | |
| 806 | } |
| 807 | if( zColor && zColor[0] ){ |
| 808 | /* One-time background color */ |
| 809 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 810 | } |
| 811 | if( g.markPrivate ){ |
| 812 | /* If this manifest is private, mark it as such */ |
| 813 | blob_appendf(pOut, "T +private *\n"); |
| 814 | } |
| 815 | if( azTag ){ |
| 816 | for(i=0; azTag[i]; i++){ |
| 817 | /* Add a symbolic tag to this check-in. The tag names have already |
| 818 | ** been sorted and converted using the %F format */ |
| 819 | blob_appendf(pOut, "T +sym-%s *\n", azTag[i]); |
| 820 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -163,11 +163,11 @@ | |
| 163 | int cwdRelative = 0; |
| 164 | db_must_be_within_tree(); |
| 165 | cwdRelative = determine_cwd_relative_option(); |
| 166 | blob_zero(&report); |
| 167 | vid = db_lget_int("checkout", 0); |
| 168 | vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0); |
| 169 | status_report(&report, "", 0, cwdRelative); |
| 170 | if( verbose && blob_size(&report)==0 ){ |
| 171 | blob_append(&report, " (none)\n", -1); |
| 172 | } |
| 173 | if( showHdr && blob_size(&report)>0 ){ |
| @@ -208,46 +208,74 @@ | |
| 208 | show_common_info(vid, "checkout:", 1, 1); |
| 209 | } |
| 210 | db_record_repository_filename(0); |
| 211 | changes_cmd(); |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | ** Implementation of the checkin_mtime SQL function |
| 216 | */ |
| 217 | |
| 218 | |
| 219 | /* |
| 220 | ** COMMAND: ls |
| 221 | ** |
| 222 | ** Usage: %fossil ls ?OPTIONS? ?VERSION? |
| 223 | ** |
| 224 | ** Show the names of all files in the current checkout. The -l provides |
| 225 | ** extra information about each file. |
| 226 | ** |
| 227 | ** Options: |
| 228 | ** -l Provide extra information about each file. |
| 229 | ** --age Show when each file was committed |
| 230 | ** |
| 231 | ** See also: changes, extra, status |
| 232 | */ |
| 233 | void ls_cmd(void){ |
| 234 | int vid; |
| 235 | Stmt q; |
| 236 | int isBrief; |
| 237 | int showAge; |
| 238 | char *zOrderBy = "pathname"; |
| 239 | |
| 240 | isBrief = find_option("l","l", 0)==0; |
| 241 | showAge = find_option("age",0,0)!=0; |
| 242 | db_must_be_within_tree(); |
| 243 | vid = db_lget_int("checkout", 0); |
| 244 | if( find_option("t","t",0)!=0 ){ |
| 245 | if( showAge ){ |
| 246 | zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid); |
| 247 | }else{ |
| 248 | zOrderBy = "mtime DESC"; |
| 249 | } |
| 250 | } |
| 251 | verify_all_options(); |
| 252 | vfile_check_signature(vid, 0); |
| 253 | if( showAge ){ |
| 254 | db_prepare(&q, |
| 255 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," |
| 256 | " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" |
| 257 | " FROM vfile" |
| 258 | " ORDER BY %s", vid, zOrderBy |
| 259 | ); |
| 260 | }else{ |
| 261 | db_prepare(&q, |
| 262 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 263 | " FROM vfile" |
| 264 | " ORDER BY %s", zOrderBy |
| 265 | ); |
| 266 | } |
| 267 | while( db_step(&q)==SQLITE_ROW ){ |
| 268 | const char *zPathname = db_column_text(&q,0); |
| 269 | int isDeleted = db_column_int(&q, 1); |
| 270 | int isNew = db_column_int(&q,2)==0; |
| 271 | int chnged = db_column_int(&q,3); |
| 272 | int renamed = db_column_int(&q,4); |
| 273 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 274 | if( showAge ){ |
| 275 | fossil_print("%s %s\n", db_column_text(&q, 5), zPathname); |
| 276 | }else if( isBrief ){ |
| 277 | fossil_print("%s\n", zPathname); |
| 278 | }else if( isNew ){ |
| 279 | fossil_print("ADDED %s\n", zPathname); |
| 280 | }else if( isDeleted ){ |
| 281 | fossil_print("DELETED %s\n", zPathname); |
| @@ -299,16 +327,17 @@ | |
| 327 | Blob path; |
| 328 | Blob repo; |
| 329 | Stmt q; |
| 330 | int n; |
| 331 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 332 | unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 333 | int cwdRelative = 0; |
| 334 | Glob *pIgnore; |
| 335 | Blob rewrittenPathname; |
| 336 | const char *zPathname, *zDisplayName; |
| 337 | |
| 338 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 339 | db_must_be_within_tree(); |
| 340 | cwdRelative = determine_cwd_relative_option(); |
| 341 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 342 | filename_collation()); |
| 343 | n = strlen(g.zLocalRoot); |
| @@ -315,11 +344,11 @@ | |
| 344 | blob_init(&path, g.zLocalRoot, n-1); |
| 345 | if( zIgnoreFlag==0 ){ |
| 346 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 347 | } |
| 348 | pIgnore = glob_create(zIgnoreFlag); |
| 349 | vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); |
| 350 | glob_free(pIgnore); |
| 351 | db_prepare(&q, |
| 352 | "SELECT x FROM sfile" |
| 353 | " WHERE x NOT IN (%s)" |
| 354 | " ORDER BY 1", |
| @@ -370,34 +399,36 @@ | |
| 399 | ** Options: |
| 400 | ** --dotfiles include files beginning with a dot (".") |
| 401 | ** --force Remove files without prompting |
| 402 | ** --ignore <CSG> ignore files matching patterns from the |
| 403 | ** comma separated list of glob patterns. |
| 404 | ** --temp Remove only Fossil-generated temporary files |
| 405 | ** |
| 406 | ** See also: addremove, extra, status |
| 407 | */ |
| 408 | void clean_cmd(void){ |
| 409 | int allFlag; |
| 410 | unsigned scanFlags = 0; |
| 411 | const char *zIgnoreFlag; |
| 412 | Blob path, repo; |
| 413 | Stmt q; |
| 414 | int n; |
| 415 | Glob *pIgnore; |
| 416 | |
| 417 | allFlag = find_option("force","f",0)!=0; |
| 418 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| 419 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 420 | zIgnoreFlag = find_option("ignore",0,1); |
| 421 | db_must_be_within_tree(); |
| 422 | if( zIgnoreFlag==0 ){ |
| 423 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 424 | } |
| 425 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 426 | n = strlen(g.zLocalRoot); |
| 427 | blob_init(&path, g.zLocalRoot, n-1); |
| 428 | pIgnore = glob_create(zIgnoreFlag); |
| 429 | vfile_scan(&path, blob_size(&path), scanFlags, pIgnore); |
| 430 | glob_free(pIgnore); |
| 431 | db_prepare(&q, |
| 432 | "SELECT %Q || x FROM sfile" |
| 433 | " WHERE x NOT IN (%s)" |
| 434 | " ORDER BY 1", |
| @@ -806,14 +837,10 @@ | |
| 837 | } |
| 838 | if( zColor && zColor[0] ){ |
| 839 | /* One-time background color */ |
| 840 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 841 | } |
| 842 | if( azTag ){ |
| 843 | for(i=0; azTag[i]; i++){ |
| 844 | /* Add a symbolic tag to this check-in. The tag names have already |
| 845 | ** been sorted and converted using the %F format */ |
| 846 | blob_appendf(pOut, "T +sym-%s *\n", azTag[i]); |
| 847 |
+1
-1
| --- src/checkout.c | ||
| +++ src/checkout.c | ||
| @@ -33,11 +33,11 @@ | ||
| 33 | 33 | int unsaved_changes(void){ |
| 34 | 34 | int vid; |
| 35 | 35 | db_must_be_within_tree(); |
| 36 | 36 | vid = db_lget_int("checkout",0); |
| 37 | 37 | if( vid==0 ) return 2; |
| 38 | - vfile_check_signature(vid, 1, 0); | |
| 38 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 39 | 39 | return db_exists("SELECT 1 FROM vfile WHERE chnged" |
| 40 | 40 | " OR coalesce(origname!=pathname,0)"); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | /* |
| 44 | 44 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -33,11 +33,11 @@ | |
| 33 | int unsaved_changes(void){ |
| 34 | int vid; |
| 35 | db_must_be_within_tree(); |
| 36 | vid = db_lget_int("checkout",0); |
| 37 | if( vid==0 ) return 2; |
| 38 | vfile_check_signature(vid, 1, 0); |
| 39 | return db_exists("SELECT 1 FROM vfile WHERE chnged" |
| 40 | " OR coalesce(origname!=pathname,0)"); |
| 41 | } |
| 42 | |
| 43 | /* |
| 44 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -33,11 +33,11 @@ | |
| 33 | int unsaved_changes(void){ |
| 34 | int vid; |
| 35 | db_must_be_within_tree(); |
| 36 | vid = db_lget_int("checkout",0); |
| 37 | if( vid==0 ) return 2; |
| 38 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 39 | return db_exists("SELECT 1 FROM vfile WHERE chnged" |
| 40 | " OR coalesce(origname!=pathname,0)"); |
| 41 | } |
| 42 | |
| 43 | /* |
| 44 |
+32
| --- src/content.c | ||
| +++ src/content.c | ||
| @@ -894,5 +894,37 @@ | ||
| 894 | 894 | } |
| 895 | 895 | db_finalize(&q); |
| 896 | 896 | fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n", |
| 897 | 897 | n2, n1, nErr); |
| 898 | 898 | } |
| 899 | + | |
| 900 | +/* | |
| 901 | +** COMMAND: test-orphans | |
| 902 | +** | |
| 903 | +** Search the repository for orphaned artifacts | |
| 904 | +*/ | |
| 905 | +void test_orphans(void){ | |
| 906 | + Stmt q; | |
| 907 | + int cnt = 0; | |
| 908 | + | |
| 909 | + db_find_and_open_repository(0, 0); | |
| 910 | + db_multi_exec( | |
| 911 | + "CREATE TEMP TABLE used(id INTEGER PRIMARY KEY ON CONFLICT IGNORE);" | |
| 912 | + "INSERT INTO used SELECT mid FROM mlink;" /* Manifests */ | |
| 913 | + "INSERT INTO used SELECT fid FROM mlink;" /* Files */ | |
| 914 | + "INSERT INTO used SELECT srcid FROM tagxref WHERE srcid>0;" /* Tags */ | |
| 915 | + "INSERT INTO used SELECT rid FROM tagxref;" /* Wiki & tickets */ | |
| 916 | + "INSERT INTO used SELECT rid FROM attachment JOIN blob ON src=uuid;" | |
| 917 | + "INSERT INTO used SELECT attachid FROM attachment;" | |
| 918 | + "INSERT INTO used SELECT objid FROM event;" | |
| 919 | + ); | |
| 920 | + db_prepare(&q, "SELECT rid, uuid, size FROM blob WHERE rid NOT IN used"); | |
| 921 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 922 | + fossil_print("%7d %s size: %d\n", | |
| 923 | + db_column_int(&q, 0), | |
| 924 | + db_column_text(&q, 1), | |
| 925 | + db_column_int(&q,2)); | |
| 926 | + cnt++; | |
| 927 | + } | |
| 928 | + db_finalize(&q); | |
| 929 | + fossil_print("%d orphans\n", cnt); | |
| 930 | +} | |
| 899 | 931 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -894,5 +894,37 @@ | |
| 894 | } |
| 895 | db_finalize(&q); |
| 896 | fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n", |
| 897 | n2, n1, nErr); |
| 898 | } |
| 899 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -894,5 +894,37 @@ | |
| 894 | } |
| 895 | db_finalize(&q); |
| 896 | fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n", |
| 897 | n2, n1, nErr); |
| 898 | } |
| 899 | |
| 900 | /* |
| 901 | ** COMMAND: test-orphans |
| 902 | ** |
| 903 | ** Search the repository for orphaned artifacts |
| 904 | */ |
| 905 | void test_orphans(void){ |
| 906 | Stmt q; |
| 907 | int cnt = 0; |
| 908 | |
| 909 | db_find_and_open_repository(0, 0); |
| 910 | db_multi_exec( |
| 911 | "CREATE TEMP TABLE used(id INTEGER PRIMARY KEY ON CONFLICT IGNORE);" |
| 912 | "INSERT INTO used SELECT mid FROM mlink;" /* Manifests */ |
| 913 | "INSERT INTO used SELECT fid FROM mlink;" /* Files */ |
| 914 | "INSERT INTO used SELECT srcid FROM tagxref WHERE srcid>0;" /* Tags */ |
| 915 | "INSERT INTO used SELECT rid FROM tagxref;" /* Wiki & tickets */ |
| 916 | "INSERT INTO used SELECT rid FROM attachment JOIN blob ON src=uuid;" |
| 917 | "INSERT INTO used SELECT attachid FROM attachment;" |
| 918 | "INSERT INTO used SELECT objid FROM event;" |
| 919 | ); |
| 920 | db_prepare(&q, "SELECT rid, uuid, size FROM blob WHERE rid NOT IN used"); |
| 921 | while( db_step(&q)==SQLITE_ROW ){ |
| 922 | fossil_print("%7d %s size: %d\n", |
| 923 | db_column_int(&q, 0), |
| 924 | db_column_text(&q, 1), |
| 925 | db_column_int(&q,2)); |
| 926 | cnt++; |
| 927 | } |
| 928 | db_finalize(&q); |
| 929 | fossil_print("%d orphans\n", cnt); |
| 930 | } |
| 931 |
M
src/db.c
+21
-3
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -676,10 +676,26 @@ | ||
| 676 | 676 | sqlite3_value **argv |
| 677 | 677 | ){ |
| 678 | 678 | sqlite3_result_int64(context, time(0)); |
| 679 | 679 | } |
| 680 | 680 | |
| 681 | +/* | |
| 682 | +** Function to return the check-in time for a file. | |
| 683 | +*/ | |
| 684 | +void db_checkin_mtime_function( | |
| 685 | + sqlite3_context *context, | |
| 686 | + int argc, | |
| 687 | + sqlite3_value **argv | |
| 688 | +){ | |
| 689 | + i64 mtime; | |
| 690 | + int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]), | |
| 691 | + sqlite3_value_int(argv[1]), &mtime); | |
| 692 | + if( rc==0 ){ | |
| 693 | + sqlite3_result_int64(context, mtime); | |
| 694 | + } | |
| 695 | +} | |
| 696 | + | |
| 681 | 697 | |
| 682 | 698 | /* |
| 683 | 699 | ** Open a database file. Return a pointer to the new database |
| 684 | 700 | ** connection. An error results in process abort. |
| 685 | 701 | */ |
| @@ -698,10 +714,12 @@ | ||
| 698 | 714 | db_err(sqlite3_errmsg(db)); |
| 699 | 715 | } |
| 700 | 716 | sqlite3_busy_timeout(db, 5000); |
| 701 | 717 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 702 | 718 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 719 | + sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0, | |
| 720 | + db_checkin_mtime_function, 0, 0); | |
| 703 | 721 | return db; |
| 704 | 722 | } |
| 705 | 723 | |
| 706 | 724 | |
| 707 | 725 | /* |
| @@ -722,11 +740,11 @@ | ||
| 722 | 740 | /* |
| 723 | 741 | ** zDbName is the name of a database file. If no other database |
| 724 | 742 | ** file is open, then open this one. If another database file is |
| 725 | 743 | ** already open, then attach zDbName using the name zLabel. |
| 726 | 744 | */ |
| 727 | -static void db_open_or_attach(const char *zDbName, const char *zLabel){ | |
| 745 | +void db_open_or_attach(const char *zDbName, const char *zLabel){ | |
| 728 | 746 | if( !g.db ){ |
| 729 | 747 | g.db = openDatabase(zDbName); |
| 730 | 748 | g.zMainDbType = zLabel; |
| 731 | 749 | db_connection_init(); |
| 732 | 750 | }else{ |
| @@ -1591,19 +1609,19 @@ | ||
| 1591 | 1609 | |
| 1592 | 1610 | /* |
| 1593 | 1611 | ** Return true if the string zVal represents "true" (or "false"). |
| 1594 | 1612 | */ |
| 1595 | 1613 | int is_truth(const char *zVal){ |
| 1596 | - static const char *azOn[] = { "on", "yes", "true", "1" }; | |
| 1614 | + static const char *const azOn[] = { "on", "yes", "true", "1" }; | |
| 1597 | 1615 | int i; |
| 1598 | 1616 | for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ |
| 1599 | 1617 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1600 | 1618 | } |
| 1601 | 1619 | return 0; |
| 1602 | 1620 | } |
| 1603 | 1621 | int is_false(const char *zVal){ |
| 1604 | - static const char *azOff[] = { "off", "no", "false", "0" }; | |
| 1622 | + static const char *const azOff[] = { "off", "no", "false", "0" }; | |
| 1605 | 1623 | int i; |
| 1606 | 1624 | for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ |
| 1607 | 1625 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1608 | 1626 | } |
| 1609 | 1627 | return 0; |
| 1610 | 1628 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -676,10 +676,26 @@ | |
| 676 | sqlite3_value **argv |
| 677 | ){ |
| 678 | sqlite3_result_int64(context, time(0)); |
| 679 | } |
| 680 | |
| 681 | |
| 682 | /* |
| 683 | ** Open a database file. Return a pointer to the new database |
| 684 | ** connection. An error results in process abort. |
| 685 | */ |
| @@ -698,10 +714,12 @@ | |
| 698 | db_err(sqlite3_errmsg(db)); |
| 699 | } |
| 700 | sqlite3_busy_timeout(db, 5000); |
| 701 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 702 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 703 | return db; |
| 704 | } |
| 705 | |
| 706 | |
| 707 | /* |
| @@ -722,11 +740,11 @@ | |
| 722 | /* |
| 723 | ** zDbName is the name of a database file. If no other database |
| 724 | ** file is open, then open this one. If another database file is |
| 725 | ** already open, then attach zDbName using the name zLabel. |
| 726 | */ |
| 727 | static void db_open_or_attach(const char *zDbName, const char *zLabel){ |
| 728 | if( !g.db ){ |
| 729 | g.db = openDatabase(zDbName); |
| 730 | g.zMainDbType = zLabel; |
| 731 | db_connection_init(); |
| 732 | }else{ |
| @@ -1591,19 +1609,19 @@ | |
| 1591 | |
| 1592 | /* |
| 1593 | ** Return true if the string zVal represents "true" (or "false"). |
| 1594 | */ |
| 1595 | int is_truth(const char *zVal){ |
| 1596 | static const char *azOn[] = { "on", "yes", "true", "1" }; |
| 1597 | int i; |
| 1598 | for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ |
| 1599 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1600 | } |
| 1601 | return 0; |
| 1602 | } |
| 1603 | int is_false(const char *zVal){ |
| 1604 | static const char *azOff[] = { "off", "no", "false", "0" }; |
| 1605 | int i; |
| 1606 | for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ |
| 1607 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1608 | } |
| 1609 | return 0; |
| 1610 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -676,10 +676,26 @@ | |
| 676 | sqlite3_value **argv |
| 677 | ){ |
| 678 | sqlite3_result_int64(context, time(0)); |
| 679 | } |
| 680 | |
| 681 | /* |
| 682 | ** Function to return the check-in time for a file. |
| 683 | */ |
| 684 | void db_checkin_mtime_function( |
| 685 | sqlite3_context *context, |
| 686 | int argc, |
| 687 | sqlite3_value **argv |
| 688 | ){ |
| 689 | i64 mtime; |
| 690 | int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]), |
| 691 | sqlite3_value_int(argv[1]), &mtime); |
| 692 | if( rc==0 ){ |
| 693 | sqlite3_result_int64(context, mtime); |
| 694 | } |
| 695 | } |
| 696 | |
| 697 | |
| 698 | /* |
| 699 | ** Open a database file. Return a pointer to the new database |
| 700 | ** connection. An error results in process abort. |
| 701 | */ |
| @@ -698,10 +714,12 @@ | |
| 714 | db_err(sqlite3_errmsg(db)); |
| 715 | } |
| 716 | sqlite3_busy_timeout(db, 5000); |
| 717 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 718 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 719 | sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0, |
| 720 | db_checkin_mtime_function, 0, 0); |
| 721 | return db; |
| 722 | } |
| 723 | |
| 724 | |
| 725 | /* |
| @@ -722,11 +740,11 @@ | |
| 740 | /* |
| 741 | ** zDbName is the name of a database file. If no other database |
| 742 | ** file is open, then open this one. If another database file is |
| 743 | ** already open, then attach zDbName using the name zLabel. |
| 744 | */ |
| 745 | void db_open_or_attach(const char *zDbName, const char *zLabel){ |
| 746 | if( !g.db ){ |
| 747 | g.db = openDatabase(zDbName); |
| 748 | g.zMainDbType = zLabel; |
| 749 | db_connection_init(); |
| 750 | }else{ |
| @@ -1591,19 +1609,19 @@ | |
| 1609 | |
| 1610 | /* |
| 1611 | ** Return true if the string zVal represents "true" (or "false"). |
| 1612 | */ |
| 1613 | int is_truth(const char *zVal){ |
| 1614 | static const char *const azOn[] = { "on", "yes", "true", "1" }; |
| 1615 | int i; |
| 1616 | for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ |
| 1617 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1618 | } |
| 1619 | return 0; |
| 1620 | } |
| 1621 | int is_false(const char *zVal){ |
| 1622 | static const char *const azOff[] = { "off", "no", "false", "0" }; |
| 1623 | int i; |
| 1624 | for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ |
| 1625 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1626 | } |
| 1627 | return 0; |
| 1628 |
M
src/db.c
+21
-3
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -676,10 +676,26 @@ | ||
| 676 | 676 | sqlite3_value **argv |
| 677 | 677 | ){ |
| 678 | 678 | sqlite3_result_int64(context, time(0)); |
| 679 | 679 | } |
| 680 | 680 | |
| 681 | +/* | |
| 682 | +** Function to return the check-in time for a file. | |
| 683 | +*/ | |
| 684 | +void db_checkin_mtime_function( | |
| 685 | + sqlite3_context *context, | |
| 686 | + int argc, | |
| 687 | + sqlite3_value **argv | |
| 688 | +){ | |
| 689 | + i64 mtime; | |
| 690 | + int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]), | |
| 691 | + sqlite3_value_int(argv[1]), &mtime); | |
| 692 | + if( rc==0 ){ | |
| 693 | + sqlite3_result_int64(context, mtime); | |
| 694 | + } | |
| 695 | +} | |
| 696 | + | |
| 681 | 697 | |
| 682 | 698 | /* |
| 683 | 699 | ** Open a database file. Return a pointer to the new database |
| 684 | 700 | ** connection. An error results in process abort. |
| 685 | 701 | */ |
| @@ -698,10 +714,12 @@ | ||
| 698 | 714 | db_err(sqlite3_errmsg(db)); |
| 699 | 715 | } |
| 700 | 716 | sqlite3_busy_timeout(db, 5000); |
| 701 | 717 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 702 | 718 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 719 | + sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0, | |
| 720 | + db_checkin_mtime_function, 0, 0); | |
| 703 | 721 | return db; |
| 704 | 722 | } |
| 705 | 723 | |
| 706 | 724 | |
| 707 | 725 | /* |
| @@ -722,11 +740,11 @@ | ||
| 722 | 740 | /* |
| 723 | 741 | ** zDbName is the name of a database file. If no other database |
| 724 | 742 | ** file is open, then open this one. If another database file is |
| 725 | 743 | ** already open, then attach zDbName using the name zLabel. |
| 726 | 744 | */ |
| 727 | -static void db_open_or_attach(const char *zDbName, const char *zLabel){ | |
| 745 | +void db_open_or_attach(const char *zDbName, const char *zLabel){ | |
| 728 | 746 | if( !g.db ){ |
| 729 | 747 | g.db = openDatabase(zDbName); |
| 730 | 748 | g.zMainDbType = zLabel; |
| 731 | 749 | db_connection_init(); |
| 732 | 750 | }else{ |
| @@ -1591,19 +1609,19 @@ | ||
| 1591 | 1609 | |
| 1592 | 1610 | /* |
| 1593 | 1611 | ** Return true if the string zVal represents "true" (or "false"). |
| 1594 | 1612 | */ |
| 1595 | 1613 | int is_truth(const char *zVal){ |
| 1596 | - static const char *azOn[] = { "on", "yes", "true", "1" }; | |
| 1614 | + static const char *const azOn[] = { "on", "yes", "true", "1" }; | |
| 1597 | 1615 | int i; |
| 1598 | 1616 | for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ |
| 1599 | 1617 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1600 | 1618 | } |
| 1601 | 1619 | return 0; |
| 1602 | 1620 | } |
| 1603 | 1621 | int is_false(const char *zVal){ |
| 1604 | - static const char *azOff[] = { "off", "no", "false", "0" }; | |
| 1622 | + static const char *const azOff[] = { "off", "no", "false", "0" }; | |
| 1605 | 1623 | int i; |
| 1606 | 1624 | for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ |
| 1607 | 1625 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1608 | 1626 | } |
| 1609 | 1627 | return 0; |
| 1610 | 1628 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -676,10 +676,26 @@ | |
| 676 | sqlite3_value **argv |
| 677 | ){ |
| 678 | sqlite3_result_int64(context, time(0)); |
| 679 | } |
| 680 | |
| 681 | |
| 682 | /* |
| 683 | ** Open a database file. Return a pointer to the new database |
| 684 | ** connection. An error results in process abort. |
| 685 | */ |
| @@ -698,10 +714,12 @@ | |
| 698 | db_err(sqlite3_errmsg(db)); |
| 699 | } |
| 700 | sqlite3_busy_timeout(db, 5000); |
| 701 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 702 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 703 | return db; |
| 704 | } |
| 705 | |
| 706 | |
| 707 | /* |
| @@ -722,11 +740,11 @@ | |
| 722 | /* |
| 723 | ** zDbName is the name of a database file. If no other database |
| 724 | ** file is open, then open this one. If another database file is |
| 725 | ** already open, then attach zDbName using the name zLabel. |
| 726 | */ |
| 727 | static void db_open_or_attach(const char *zDbName, const char *zLabel){ |
| 728 | if( !g.db ){ |
| 729 | g.db = openDatabase(zDbName); |
| 730 | g.zMainDbType = zLabel; |
| 731 | db_connection_init(); |
| 732 | }else{ |
| @@ -1591,19 +1609,19 @@ | |
| 1591 | |
| 1592 | /* |
| 1593 | ** Return true if the string zVal represents "true" (or "false"). |
| 1594 | */ |
| 1595 | int is_truth(const char *zVal){ |
| 1596 | static const char *azOn[] = { "on", "yes", "true", "1" }; |
| 1597 | int i; |
| 1598 | for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ |
| 1599 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1600 | } |
| 1601 | return 0; |
| 1602 | } |
| 1603 | int is_false(const char *zVal){ |
| 1604 | static const char *azOff[] = { "off", "no", "false", "0" }; |
| 1605 | int i; |
| 1606 | for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ |
| 1607 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1608 | } |
| 1609 | return 0; |
| 1610 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -676,10 +676,26 @@ | |
| 676 | sqlite3_value **argv |
| 677 | ){ |
| 678 | sqlite3_result_int64(context, time(0)); |
| 679 | } |
| 680 | |
| 681 | /* |
| 682 | ** Function to return the check-in time for a file. |
| 683 | */ |
| 684 | void db_checkin_mtime_function( |
| 685 | sqlite3_context *context, |
| 686 | int argc, |
| 687 | sqlite3_value **argv |
| 688 | ){ |
| 689 | i64 mtime; |
| 690 | int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]), |
| 691 | sqlite3_value_int(argv[1]), &mtime); |
| 692 | if( rc==0 ){ |
| 693 | sqlite3_result_int64(context, mtime); |
| 694 | } |
| 695 | } |
| 696 | |
| 697 | |
| 698 | /* |
| 699 | ** Open a database file. Return a pointer to the new database |
| 700 | ** connection. An error results in process abort. |
| 701 | */ |
| @@ -698,10 +714,12 @@ | |
| 714 | db_err(sqlite3_errmsg(db)); |
| 715 | } |
| 716 | sqlite3_busy_timeout(db, 5000); |
| 717 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 718 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 719 | sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0, |
| 720 | db_checkin_mtime_function, 0, 0); |
| 721 | return db; |
| 722 | } |
| 723 | |
| 724 | |
| 725 | /* |
| @@ -722,11 +740,11 @@ | |
| 740 | /* |
| 741 | ** zDbName is the name of a database file. If no other database |
| 742 | ** file is open, then open this one. If another database file is |
| 743 | ** already open, then attach zDbName using the name zLabel. |
| 744 | */ |
| 745 | void db_open_or_attach(const char *zDbName, const char *zLabel){ |
| 746 | if( !g.db ){ |
| 747 | g.db = openDatabase(zDbName); |
| 748 | g.zMainDbType = zLabel; |
| 749 | db_connection_init(); |
| 750 | }else{ |
| @@ -1591,19 +1609,19 @@ | |
| 1609 | |
| 1610 | /* |
| 1611 | ** Return true if the string zVal represents "true" (or "false"). |
| 1612 | */ |
| 1613 | int is_truth(const char *zVal){ |
| 1614 | static const char *const azOn[] = { "on", "yes", "true", "1" }; |
| 1615 | int i; |
| 1616 | for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){ |
| 1617 | if( fossil_stricmp(zVal,azOn[i])==0 ) return 1; |
| 1618 | } |
| 1619 | return 0; |
| 1620 | } |
| 1621 | int is_false(const char *zVal){ |
| 1622 | static const char *const azOff[] = { "off", "no", "false", "0" }; |
| 1623 | int i; |
| 1624 | for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){ |
| 1625 | if( fossil_stricmp(zVal,azOff[i])==0 ) return 1; |
| 1626 | } |
| 1627 | return 0; |
| 1628 |
+39
-3
| --- src/descendants.c | ||
| +++ src/descendants.c | ||
| @@ -156,11 +156,11 @@ | ||
| 156 | 156 | |
| 157 | 157 | /* |
| 158 | 158 | ** Load the record ID rid and up to N-1 closest ancestors into |
| 159 | 159 | ** the "ok" table. |
| 160 | 160 | */ |
| 161 | -void compute_ancestors(int rid, int N){ | |
| 161 | +void compute_ancestors(int rid, int N, int directOnly){ | |
| 162 | 162 | Bag seen; |
| 163 | 163 | PQueue queue; |
| 164 | 164 | Stmt ins; |
| 165 | 165 | Stmt q; |
| 166 | 166 | bag_init(&seen); |
| @@ -168,11 +168,12 @@ | ||
| 168 | 168 | bag_insert(&seen, rid); |
| 169 | 169 | pqueuex_insert(&queue, rid, 0.0, 0); |
| 170 | 170 | db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); |
| 171 | 171 | db_prepare(&q, |
| 172 | 172 | "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" |
| 173 | - " WHERE a.cid=:rid" | |
| 173 | + " WHERE a.cid=:rid %s", | |
| 174 | + directOnly ? " AND a.isprim" : "" | |
| 174 | 175 | ); |
| 175 | 176 | while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){ |
| 176 | 177 | db_bind_int(&ins, ":rid", rid); |
| 177 | 178 | db_step(&ins); |
| 178 | 179 | db_reset(&ins); |
| @@ -202,11 +203,12 @@ | ||
| 202 | 203 | void compute_direct_ancestors(int rid, int N){ |
| 203 | 204 | Stmt ins; |
| 204 | 205 | Stmt q; |
| 205 | 206 | int gen = 0; |
| 206 | 207 | db_multi_exec( |
| 207 | - "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);" | |
| 208 | + "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER," | |
| 209 | + " generation INTEGER PRIMARY KEY);" | |
| 208 | 210 | "DELETE FROM ancestor;" |
| 209 | 211 | "INSERT INTO ancestor VALUES(%d, 0);", rid |
| 210 | 212 | ); |
| 211 | 213 | db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)"); |
| 212 | 214 | db_prepare(&q, |
| @@ -225,10 +227,44 @@ | ||
| 225 | 227 | db_reset(&ins); |
| 226 | 228 | } |
| 227 | 229 | db_finalize(&ins); |
| 228 | 230 | db_finalize(&q); |
| 229 | 231 | } |
| 232 | + | |
| 233 | +/* | |
| 234 | +** Compute the "mtime" of the file given whose blob.rid is "fid" that | |
| 235 | +** is part of check-in "vid". The mtime will be the mtime on vid or | |
| 236 | +** some ancestor of vid where fid first appears. | |
| 237 | +*/ | |
| 238 | +int mtime_of_manifest_file( | |
| 239 | + int vid, /* The check-in that contains fid */ | |
| 240 | + int fid, /* The id of the file whose check-in time is sought */ | |
| 241 | + i64 *pMTime /* Write result here */ | |
| 242 | +){ | |
| 243 | + static int prevVid = -1; | |
| 244 | + static Stmt q; | |
| 245 | + | |
| 246 | + if( prevVid!=vid ){ | |
| 247 | + prevVid = vid; | |
| 248 | + db_multi_exec("DROP TABLE IF EXISTS temp.ok;" | |
| 249 | + "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);"); | |
| 250 | + compute_ancestors(vid, 100000000, 1); | |
| 251 | + } | |
| 252 | + db_static_prepare(&q, | |
| 253 | + "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event" | |
| 254 | + " WHERE mlink.mid=event.objid" | |
| 255 | + " AND +mlink.mid IN ok" | |
| 256 | + " AND mlink.fid=:fid"); | |
| 257 | + db_bind_int(&q, ":fid", fid); | |
| 258 | + if( db_step(&q)!=SQLITE_ROW ){ | |
| 259 | + db_reset(&q); | |
| 260 | + return 1; | |
| 261 | + } | |
| 262 | + *pMTime = db_column_int64(&q, 0); | |
| 263 | + db_reset(&q); | |
| 264 | + return 0; | |
| 265 | +} | |
| 230 | 266 | |
| 231 | 267 | /* |
| 232 | 268 | ** Load the record ID rid and up to N-1 closest descendants into |
| 233 | 269 | ** the "ok" table. |
| 234 | 270 | */ |
| 235 | 271 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -156,11 +156,11 @@ | |
| 156 | |
| 157 | /* |
| 158 | ** Load the record ID rid and up to N-1 closest ancestors into |
| 159 | ** the "ok" table. |
| 160 | */ |
| 161 | void compute_ancestors(int rid, int N){ |
| 162 | Bag seen; |
| 163 | PQueue queue; |
| 164 | Stmt ins; |
| 165 | Stmt q; |
| 166 | bag_init(&seen); |
| @@ -168,11 +168,12 @@ | |
| 168 | bag_insert(&seen, rid); |
| 169 | pqueuex_insert(&queue, rid, 0.0, 0); |
| 170 | db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); |
| 171 | db_prepare(&q, |
| 172 | "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" |
| 173 | " WHERE a.cid=:rid" |
| 174 | ); |
| 175 | while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){ |
| 176 | db_bind_int(&ins, ":rid", rid); |
| 177 | db_step(&ins); |
| 178 | db_reset(&ins); |
| @@ -202,11 +203,12 @@ | |
| 202 | void compute_direct_ancestors(int rid, int N){ |
| 203 | Stmt ins; |
| 204 | Stmt q; |
| 205 | int gen = 0; |
| 206 | db_multi_exec( |
| 207 | "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);" |
| 208 | "DELETE FROM ancestor;" |
| 209 | "INSERT INTO ancestor VALUES(%d, 0);", rid |
| 210 | ); |
| 211 | db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)"); |
| 212 | db_prepare(&q, |
| @@ -225,10 +227,44 @@ | |
| 225 | db_reset(&ins); |
| 226 | } |
| 227 | db_finalize(&ins); |
| 228 | db_finalize(&q); |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | ** Load the record ID rid and up to N-1 closest descendants into |
| 233 | ** the "ok" table. |
| 234 | */ |
| 235 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -156,11 +156,11 @@ | |
| 156 | |
| 157 | /* |
| 158 | ** Load the record ID rid and up to N-1 closest ancestors into |
| 159 | ** the "ok" table. |
| 160 | */ |
| 161 | void compute_ancestors(int rid, int N, int directOnly){ |
| 162 | Bag seen; |
| 163 | PQueue queue; |
| 164 | Stmt ins; |
| 165 | Stmt q; |
| 166 | bag_init(&seen); |
| @@ -168,11 +168,12 @@ | |
| 168 | bag_insert(&seen, rid); |
| 169 | pqueuex_insert(&queue, rid, 0.0, 0); |
| 170 | db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); |
| 171 | db_prepare(&q, |
| 172 | "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" |
| 173 | " WHERE a.cid=:rid %s", |
| 174 | directOnly ? " AND a.isprim" : "" |
| 175 | ); |
| 176 | while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){ |
| 177 | db_bind_int(&ins, ":rid", rid); |
| 178 | db_step(&ins); |
| 179 | db_reset(&ins); |
| @@ -202,11 +203,12 @@ | |
| 203 | void compute_direct_ancestors(int rid, int N){ |
| 204 | Stmt ins; |
| 205 | Stmt q; |
| 206 | int gen = 0; |
| 207 | db_multi_exec( |
| 208 | "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER," |
| 209 | " generation INTEGER PRIMARY KEY);" |
| 210 | "DELETE FROM ancestor;" |
| 211 | "INSERT INTO ancestor VALUES(%d, 0);", rid |
| 212 | ); |
| 213 | db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)"); |
| 214 | db_prepare(&q, |
| @@ -225,10 +227,44 @@ | |
| 227 | db_reset(&ins); |
| 228 | } |
| 229 | db_finalize(&ins); |
| 230 | db_finalize(&q); |
| 231 | } |
| 232 | |
| 233 | /* |
| 234 | ** Compute the "mtime" of the file given whose blob.rid is "fid" that |
| 235 | ** is part of check-in "vid". The mtime will be the mtime on vid or |
| 236 | ** some ancestor of vid where fid first appears. |
| 237 | */ |
| 238 | int mtime_of_manifest_file( |
| 239 | int vid, /* The check-in that contains fid */ |
| 240 | int fid, /* The id of the file whose check-in time is sought */ |
| 241 | i64 *pMTime /* Write result here */ |
| 242 | ){ |
| 243 | static int prevVid = -1; |
| 244 | static Stmt q; |
| 245 | |
| 246 | if( prevVid!=vid ){ |
| 247 | prevVid = vid; |
| 248 | db_multi_exec("DROP TABLE IF EXISTS temp.ok;" |
| 249 | "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);"); |
| 250 | compute_ancestors(vid, 100000000, 1); |
| 251 | } |
| 252 | db_static_prepare(&q, |
| 253 | "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event" |
| 254 | " WHERE mlink.mid=event.objid" |
| 255 | " AND +mlink.mid IN ok" |
| 256 | " AND mlink.fid=:fid"); |
| 257 | db_bind_int(&q, ":fid", fid); |
| 258 | if( db_step(&q)!=SQLITE_ROW ){ |
| 259 | db_reset(&q); |
| 260 | return 1; |
| 261 | } |
| 262 | *pMTime = db_column_int64(&q, 0); |
| 263 | db_reset(&q); |
| 264 | return 0; |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | ** Load the record ID rid and up to N-1 closest descendants into |
| 269 | ** the "ok" table. |
| 270 | */ |
| 271 |
+1
-1
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -329,11 +329,11 @@ | ||
| 329 | 329 | Stmt q; |
| 330 | 330 | int asNewFile; /* Treat non-existant files as empty files */ |
| 331 | 331 | |
| 332 | 332 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 333 | 333 | vid = db_lget_int("checkout", 0); |
| 334 | - vfile_check_signature(vid, 1, 0); | |
| 334 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 335 | 335 | blob_zero(&sql); |
| 336 | 336 | db_begin_transaction(); |
| 337 | 337 | if( zFrom ){ |
| 338 | 338 | int rid = name_to_typed_rid(zFrom, "ci"); |
| 339 | 339 | if( !is_a_version(rid) ){ |
| 340 | 340 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -329,11 +329,11 @@ | |
| 329 | Stmt q; |
| 330 | int asNewFile; /* Treat non-existant files as empty files */ |
| 331 | |
| 332 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 333 | vid = db_lget_int("checkout", 0); |
| 334 | vfile_check_signature(vid, 1, 0); |
| 335 | blob_zero(&sql); |
| 336 | db_begin_transaction(); |
| 337 | if( zFrom ){ |
| 338 | int rid = name_to_typed_rid(zFrom, "ci"); |
| 339 | if( !is_a_version(rid) ){ |
| 340 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -329,11 +329,11 @@ | |
| 329 | Stmt q; |
| 330 | int asNewFile; /* Treat non-existant files as empty files */ |
| 331 | |
| 332 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 333 | vid = db_lget_int("checkout", 0); |
| 334 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 335 | blob_zero(&sql); |
| 336 | db_begin_transaction(); |
| 337 | if( zFrom ){ |
| 338 | int rid = name_to_typed_rid(zFrom, "ci"); |
| 339 | if( !is_a_version(rid) ){ |
| 340 |
+1
-1
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -329,11 +329,11 @@ | ||
| 329 | 329 | Stmt q; |
| 330 | 330 | int asNewFile; /* Treat non-existant files as empty files */ |
| 331 | 331 | |
| 332 | 332 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 333 | 333 | vid = db_lget_int("checkout", 0); |
| 334 | - vfile_check_signature(vid, 1, 0); | |
| 334 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 335 | 335 | blob_zero(&sql); |
| 336 | 336 | db_begin_transaction(); |
| 337 | 337 | if( zFrom ){ |
| 338 | 338 | int rid = name_to_typed_rid(zFrom, "ci"); |
| 339 | 339 | if( !is_a_version(rid) ){ |
| 340 | 340 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -329,11 +329,11 @@ | |
| 329 | Stmt q; |
| 330 | int asNewFile; /* Treat non-existant files as empty files */ |
| 331 | |
| 332 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 333 | vid = db_lget_int("checkout", 0); |
| 334 | vfile_check_signature(vid, 1, 0); |
| 335 | blob_zero(&sql); |
| 336 | db_begin_transaction(); |
| 337 | if( zFrom ){ |
| 338 | int rid = name_to_typed_rid(zFrom, "ci"); |
| 339 | if( !is_a_version(rid) ){ |
| 340 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -329,11 +329,11 @@ | |
| 329 | Stmt q; |
| 330 | int asNewFile; /* Treat non-existant files as empty files */ |
| 331 | |
| 332 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 333 | vid = db_lget_int("checkout", 0); |
| 334 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 335 | blob_zero(&sql); |
| 336 | db_begin_transaction(); |
| 337 | if( zFrom ){ |
| 338 | int rid = name_to_typed_rid(zFrom, "ci"); |
| 339 | if( !is_a_version(rid) ){ |
| 340 |
+44
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -34,10 +34,11 @@ | ||
| 34 | 34 | ** On Windows, include the Platform SDK header file. |
| 35 | 35 | */ |
| 36 | 36 | #ifdef _WIN32 |
| 37 | 37 | # include <direct.h> |
| 38 | 38 | # include <windows.h> |
| 39 | +# include <sys/utime.h> | |
| 39 | 40 | #endif |
| 40 | 41 | |
| 41 | 42 | /* |
| 42 | 43 | ** The file status information from the most recent stat() call. |
| 43 | 44 | ** |
| @@ -389,10 +390,53 @@ | ||
| 389 | 390 | } |
| 390 | 391 | } |
| 391 | 392 | #endif /* _WIN32 */ |
| 392 | 393 | return rc; |
| 393 | 394 | } |
| 395 | + | |
| 396 | +/* | |
| 397 | +** Set the mtime for a file. | |
| 398 | +*/ | |
| 399 | +void file_set_mtime(const char *zFilename, i64 newMTime){ | |
| 400 | +#if !defined(_WIN32) | |
| 401 | + struct timeval tv[2]; | |
| 402 | + memset(tv, 0, sizeof(tv[0])*2); | |
| 403 | + tv[0].tv_sec = newMTime; | |
| 404 | + tv[1].tv_sec = newMTime; | |
| 405 | + utimes(zFilename, tv); | |
| 406 | +#else | |
| 407 | + struct _utimbuf tb; | |
| 408 | + wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename); | |
| 409 | + tb.actime = newMTime; | |
| 410 | + tb.modtime = newMTime; | |
| 411 | + _wutime(zMbcs, &tb); | |
| 412 | + fossil_mbcs_free(zMbcs); | |
| 413 | +#endif | |
| 414 | +} | |
| 415 | + | |
| 416 | +/* | |
| 417 | +** COMMAND: test-set-mtime | |
| 418 | +** | |
| 419 | +** Usage: %fossil test-set-mtime FILENAME DATE/TIME | |
| 420 | +** | |
| 421 | +** Sets the mtime of the named file to the date/time shown. | |
| 422 | +*/ | |
| 423 | +void test_set_mtime(void){ | |
| 424 | + const char *zFile; | |
| 425 | + char *zDate; | |
| 426 | + i64 iMTime; | |
| 427 | + if( g.argc!=4 ){ | |
| 428 | + usage("test-set-mtime FILENAME DATE/TIME"); | |
| 429 | + } | |
| 430 | + db_open_or_attach(":memory:", "mem"); | |
| 431 | + iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]); | |
| 432 | + zFile = g.argv[2]; | |
| 433 | + file_set_mtime(zFile, iMTime); | |
| 434 | + iMTime = file_wd_mtime(zFile); | |
| 435 | + zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime); | |
| 436 | + fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime); | |
| 437 | +} | |
| 394 | 438 | |
| 395 | 439 | /* |
| 396 | 440 | ** Delete a file. |
| 397 | 441 | */ |
| 398 | 442 | void file_delete(const char *zFilename){ |
| 399 | 443 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -34,10 +34,11 @@ | |
| 34 | ** On Windows, include the Platform SDK header file. |
| 35 | */ |
| 36 | #ifdef _WIN32 |
| 37 | # include <direct.h> |
| 38 | # include <windows.h> |
| 39 | #endif |
| 40 | |
| 41 | /* |
| 42 | ** The file status information from the most recent stat() call. |
| 43 | ** |
| @@ -389,10 +390,53 @@ | |
| 389 | } |
| 390 | } |
| 391 | #endif /* _WIN32 */ |
| 392 | return rc; |
| 393 | } |
| 394 | |
| 395 | /* |
| 396 | ** Delete a file. |
| 397 | */ |
| 398 | void file_delete(const char *zFilename){ |
| 399 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -34,10 +34,11 @@ | |
| 34 | ** On Windows, include the Platform SDK header file. |
| 35 | */ |
| 36 | #ifdef _WIN32 |
| 37 | # include <direct.h> |
| 38 | # include <windows.h> |
| 39 | # include <sys/utime.h> |
| 40 | #endif |
| 41 | |
| 42 | /* |
| 43 | ** The file status information from the most recent stat() call. |
| 44 | ** |
| @@ -389,10 +390,53 @@ | |
| 390 | } |
| 391 | } |
| 392 | #endif /* _WIN32 */ |
| 393 | return rc; |
| 394 | } |
| 395 | |
| 396 | /* |
| 397 | ** Set the mtime for a file. |
| 398 | */ |
| 399 | void file_set_mtime(const char *zFilename, i64 newMTime){ |
| 400 | #if !defined(_WIN32) |
| 401 | struct timeval tv[2]; |
| 402 | memset(tv, 0, sizeof(tv[0])*2); |
| 403 | tv[0].tv_sec = newMTime; |
| 404 | tv[1].tv_sec = newMTime; |
| 405 | utimes(zFilename, tv); |
| 406 | #else |
| 407 | struct _utimbuf tb; |
| 408 | wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename); |
| 409 | tb.actime = newMTime; |
| 410 | tb.modtime = newMTime; |
| 411 | _wutime(zMbcs, &tb); |
| 412 | fossil_mbcs_free(zMbcs); |
| 413 | #endif |
| 414 | } |
| 415 | |
| 416 | /* |
| 417 | ** COMMAND: test-set-mtime |
| 418 | ** |
| 419 | ** Usage: %fossil test-set-mtime FILENAME DATE/TIME |
| 420 | ** |
| 421 | ** Sets the mtime of the named file to the date/time shown. |
| 422 | */ |
| 423 | void test_set_mtime(void){ |
| 424 | const char *zFile; |
| 425 | char *zDate; |
| 426 | i64 iMTime; |
| 427 | if( g.argc!=4 ){ |
| 428 | usage("test-set-mtime FILENAME DATE/TIME"); |
| 429 | } |
| 430 | db_open_or_attach(":memory:", "mem"); |
| 431 | iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]); |
| 432 | zFile = g.argv[2]; |
| 433 | file_set_mtime(zFile, iMTime); |
| 434 | iMTime = file_wd_mtime(zFile); |
| 435 | zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime); |
| 436 | fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime); |
| 437 | } |
| 438 | |
| 439 | /* |
| 440 | ** Delete a file. |
| 441 | */ |
| 442 | void file_delete(const char *zFilename){ |
| 443 |
+1
-1
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -66,11 +66,11 @@ | ||
| 66 | 66 | if( g.argc!=3 ) usage("-s|--status FILENAME"); |
| 67 | 67 | vid = db_lget_int("checkout", 0); |
| 68 | 68 | if( vid==0 ){ |
| 69 | 69 | fossil_panic("no checkout to finfo files in"); |
| 70 | 70 | } |
| 71 | - vfile_check_signature(vid, 1, 0); | |
| 71 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 72 | 72 | file_tree_name(g.argv[2], &fname, 1); |
| 73 | 73 | db_prepare(&q, |
| 74 | 74 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 75 | 75 | " FROM vfile WHERE vfile.pathname=%B %s", |
| 76 | 76 | &fname, filename_collation()); |
| 77 | 77 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -66,11 +66,11 @@ | |
| 66 | if( g.argc!=3 ) usage("-s|--status FILENAME"); |
| 67 | vid = db_lget_int("checkout", 0); |
| 68 | if( vid==0 ){ |
| 69 | fossil_panic("no checkout to finfo files in"); |
| 70 | } |
| 71 | vfile_check_signature(vid, 1, 0); |
| 72 | file_tree_name(g.argv[2], &fname, 1); |
| 73 | db_prepare(&q, |
| 74 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 75 | " FROM vfile WHERE vfile.pathname=%B %s", |
| 76 | &fname, filename_collation()); |
| 77 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -66,11 +66,11 @@ | |
| 66 | if( g.argc!=3 ) usage("-s|--status FILENAME"); |
| 67 | vid = db_lget_int("checkout", 0); |
| 68 | if( vid==0 ){ |
| 69 | fossil_panic("no checkout to finfo files in"); |
| 70 | } |
| 71 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 72 | file_tree_name(g.argv[2], &fname, 1); |
| 73 | db_prepare(&q, |
| 74 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 75 | " FROM vfile WHERE vfile.pathname=%B %s", |
| 76 | &fname, filename_collation()); |
| 77 |
+3
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -631,10 +631,11 @@ | ||
| 631 | 631 | } |
| 632 | 632 | @ </td></tr> |
| 633 | 633 | @ <tr><th>Other Links:</th> |
| 634 | 634 | @ <td> |
| 635 | 635 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 636 | + @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> | |
| 636 | 637 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | 638 | @ | <a href="%s(g.zTop)/vdiff?from=pbranch:%S(zUuid)&to=%S(zUuid)"> |
| 638 | 639 | @ vdiff to parent branch</a> |
| 639 | 640 | if( g.perm.Write ){ |
| 640 | 641 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| @@ -983,15 +984,15 @@ | ||
| 983 | 984 | }else{ |
| 984 | 985 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 985 | 986 | } |
| 986 | 987 | if( cmp<0 ){ |
| 987 | 988 | append_file_change_line(pFileFrom->zName, |
| 988 | - pFileFrom->zUuid, 0, 0, 0, 0); | |
| 989 | + pFileFrom->zUuid, 0, 0, diffFlags, 0); | |
| 989 | 990 | pFileFrom = manifest_file_next(pFrom, 0); |
| 990 | 991 | }else if( cmp>0 ){ |
| 991 | 992 | append_file_change_line(pFileTo->zName, |
| 992 | - 0, pFileTo->zUuid, 0, 0, | |
| 993 | + 0, pFileTo->zUuid, 0, diffFlags, | |
| 993 | 994 | manifest_file_mperm(pFileTo)); |
| 994 | 995 | pFileTo = manifest_file_next(pTo, 0); |
| 995 | 996 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 996 | 997 | /* No changes */ |
| 997 | 998 | pFileFrom = manifest_file_next(pFrom, 0); |
| 998 | 999 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -631,10 +631,11 @@ | |
| 631 | } |
| 632 | @ </td></tr> |
| 633 | @ <tr><th>Other Links:</th> |
| 634 | @ <td> |
| 635 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 636 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | @ | <a href="%s(g.zTop)/vdiff?from=pbranch:%S(zUuid)&to=%S(zUuid)"> |
| 638 | @ vdiff to parent branch</a> |
| 639 | if( g.perm.Write ){ |
| 640 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| @@ -983,15 +984,15 @@ | |
| 983 | }else{ |
| 984 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 985 | } |
| 986 | if( cmp<0 ){ |
| 987 | append_file_change_line(pFileFrom->zName, |
| 988 | pFileFrom->zUuid, 0, 0, 0, 0); |
| 989 | pFileFrom = manifest_file_next(pFrom, 0); |
| 990 | }else if( cmp>0 ){ |
| 991 | append_file_change_line(pFileTo->zName, |
| 992 | 0, pFileTo->zUuid, 0, 0, |
| 993 | manifest_file_mperm(pFileTo)); |
| 994 | pFileTo = manifest_file_next(pTo, 0); |
| 995 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 996 | /* No changes */ |
| 997 | pFileFrom = manifest_file_next(pFrom, 0); |
| 998 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -631,10 +631,11 @@ | |
| 631 | } |
| 632 | @ </td></tr> |
| 633 | @ <tr><th>Other Links:</th> |
| 634 | @ <td> |
| 635 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 636 | @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> |
| 637 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 638 | @ | <a href="%s(g.zTop)/vdiff?from=pbranch:%S(zUuid)&to=%S(zUuid)"> |
| 639 | @ vdiff to parent branch</a> |
| 640 | if( g.perm.Write ){ |
| 641 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| @@ -983,15 +984,15 @@ | |
| 984 | }else{ |
| 985 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 986 | } |
| 987 | if( cmp<0 ){ |
| 988 | append_file_change_line(pFileFrom->zName, |
| 989 | pFileFrom->zUuid, 0, 0, diffFlags, 0); |
| 990 | pFileFrom = manifest_file_next(pFrom, 0); |
| 991 | }else if( cmp>0 ){ |
| 992 | append_file_change_line(pFileTo->zName, |
| 993 | 0, pFileTo->zUuid, 0, diffFlags, |
| 994 | manifest_file_mperm(pFileTo)); |
| 995 | pFileTo = manifest_file_next(pTo, 0); |
| 996 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 997 | /* No changes */ |
| 998 | pFileFrom = manifest_file_next(pFrom, 0); |
| 999 |
+3
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -631,10 +631,11 @@ | ||
| 631 | 631 | } |
| 632 | 632 | @ </td></tr> |
| 633 | 633 | @ <tr><th>Other Links:</th> |
| 634 | 634 | @ <td> |
| 635 | 635 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 636 | + @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> | |
| 636 | 637 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | 638 | @ | <a href="%s(g.zTop)/vdiff?from=pbranch:%S(zUuid)&to=%S(zUuid)"> |
| 638 | 639 | @ vdiff to parent branch</a> |
| 639 | 640 | if( g.perm.Write ){ |
| 640 | 641 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| @@ -983,15 +984,15 @@ | ||
| 983 | 984 | }else{ |
| 984 | 985 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 985 | 986 | } |
| 986 | 987 | if( cmp<0 ){ |
| 987 | 988 | append_file_change_line(pFileFrom->zName, |
| 988 | - pFileFrom->zUuid, 0, 0, 0, 0); | |
| 989 | + pFileFrom->zUuid, 0, 0, diffFlags, 0); | |
| 989 | 990 | pFileFrom = manifest_file_next(pFrom, 0); |
| 990 | 991 | }else if( cmp>0 ){ |
| 991 | 992 | append_file_change_line(pFileTo->zName, |
| 992 | - 0, pFileTo->zUuid, 0, 0, | |
| 993 | + 0, pFileTo->zUuid, 0, diffFlags, | |
| 993 | 994 | manifest_file_mperm(pFileTo)); |
| 994 | 995 | pFileTo = manifest_file_next(pTo, 0); |
| 995 | 996 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 996 | 997 | /* No changes */ |
| 997 | 998 | pFileFrom = manifest_file_next(pFrom, 0); |
| 998 | 999 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -631,10 +631,11 @@ | |
| 631 | } |
| 632 | @ </td></tr> |
| 633 | @ <tr><th>Other Links:</th> |
| 634 | @ <td> |
| 635 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 636 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | @ | <a href="%s(g.zTop)/vdiff?from=pbranch:%S(zUuid)&to=%S(zUuid)"> |
| 638 | @ vdiff to parent branch</a> |
| 639 | if( g.perm.Write ){ |
| 640 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| @@ -983,15 +984,15 @@ | |
| 983 | }else{ |
| 984 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 985 | } |
| 986 | if( cmp<0 ){ |
| 987 | append_file_change_line(pFileFrom->zName, |
| 988 | pFileFrom->zUuid, 0, 0, 0, 0); |
| 989 | pFileFrom = manifest_file_next(pFrom, 0); |
| 990 | }else if( cmp>0 ){ |
| 991 | append_file_change_line(pFileTo->zName, |
| 992 | 0, pFileTo->zUuid, 0, 0, |
| 993 | manifest_file_mperm(pFileTo)); |
| 994 | pFileTo = manifest_file_next(pTo, 0); |
| 995 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 996 | /* No changes */ |
| 997 | pFileFrom = manifest_file_next(pFrom, 0); |
| 998 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -631,10 +631,11 @@ | |
| 631 | } |
| 632 | @ </td></tr> |
| 633 | @ <tr><th>Other Links:</th> |
| 634 | @ <td> |
| 635 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 636 | @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> |
| 637 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 638 | @ | <a href="%s(g.zTop)/vdiff?from=pbranch:%S(zUuid)&to=%S(zUuid)"> |
| 639 | @ vdiff to parent branch</a> |
| 640 | if( g.perm.Write ){ |
| 641 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| @@ -983,15 +984,15 @@ | |
| 984 | }else{ |
| 985 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 986 | } |
| 987 | if( cmp<0 ){ |
| 988 | append_file_change_line(pFileFrom->zName, |
| 989 | pFileFrom->zUuid, 0, 0, diffFlags, 0); |
| 990 | pFileFrom = manifest_file_next(pFrom, 0); |
| 991 | }else if( cmp>0 ){ |
| 992 | append_file_change_line(pFileTo->zName, |
| 993 | 0, pFileTo->zUuid, 0, diffFlags, |
| 994 | manifest_file_mperm(pFileTo)); |
| 995 | pFileTo = manifest_file_next(pTo, 0); |
| 996 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 997 | /* No changes */ |
| 998 | pFileFrom = manifest_file_next(pFrom, 0); |
| 999 |
+2
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -555,10 +555,11 @@ | ||
| 555 | 555 | newArgv[j] = 0; |
| 556 | 556 | g.argc = j; |
| 557 | 557 | g.argv = newArgv; |
| 558 | 558 | } |
| 559 | 559 | |
| 560 | +#ifdef FOSSIL_ENABLE_TCL | |
| 560 | 561 | /* |
| 561 | 562 | ** Make a deep copy of the provided argument array and return it. |
| 562 | 563 | */ |
| 563 | 564 | static char **copy_args(int argc, char **argv){ |
| 564 | 565 | char **zNewArgv; |
| @@ -568,10 +569,11 @@ | ||
| 568 | 569 | for(i=0; i<argc; i++){ |
| 569 | 570 | zNewArgv[i] = fossil_strdup(argv[i]); |
| 570 | 571 | } |
| 571 | 572 | return zNewArgv; |
| 572 | 573 | } |
| 574 | +#endif | |
| 573 | 575 | |
| 574 | 576 | /* |
| 575 | 577 | ** This procedure runs first. |
| 576 | 578 | */ |
| 577 | 579 | int main(int argc, char **argv) |
| 578 | 580 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -555,10 +555,11 @@ | |
| 555 | newArgv[j] = 0; |
| 556 | g.argc = j; |
| 557 | g.argv = newArgv; |
| 558 | } |
| 559 | |
| 560 | /* |
| 561 | ** Make a deep copy of the provided argument array and return it. |
| 562 | */ |
| 563 | static char **copy_args(int argc, char **argv){ |
| 564 | char **zNewArgv; |
| @@ -568,10 +569,11 @@ | |
| 568 | for(i=0; i<argc; i++){ |
| 569 | zNewArgv[i] = fossil_strdup(argv[i]); |
| 570 | } |
| 571 | return zNewArgv; |
| 572 | } |
| 573 | |
| 574 | /* |
| 575 | ** This procedure runs first. |
| 576 | */ |
| 577 | int main(int argc, char **argv) |
| 578 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -555,10 +555,11 @@ | |
| 555 | newArgv[j] = 0; |
| 556 | g.argc = j; |
| 557 | g.argv = newArgv; |
| 558 | } |
| 559 | |
| 560 | #ifdef FOSSIL_ENABLE_TCL |
| 561 | /* |
| 562 | ** Make a deep copy of the provided argument array and return it. |
| 563 | */ |
| 564 | static char **copy_args(int argc, char **argv){ |
| 565 | char **zNewArgv; |
| @@ -568,10 +569,11 @@ | |
| 569 | for(i=0; i<argc; i++){ |
| 570 | zNewArgv[i] = fossil_strdup(argv[i]); |
| 571 | } |
| 572 | return zNewArgv; |
| 573 | } |
| 574 | #endif |
| 575 | |
| 576 | /* |
| 577 | ** This procedure runs first. |
| 578 | */ |
| 579 | int main(int argc, char **argv) |
| 580 |
+1
-1
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -189,11 +189,11 @@ | ||
| 189 | 189 | } |
| 190 | 190 | if( detailFlag ){ |
| 191 | 191 | print_checkin_description(mid, 12, "merge-from:"); |
| 192 | 192 | print_checkin_description(pid, 12, "baseline:"); |
| 193 | 193 | } |
| 194 | - vfile_check_signature(vid, 1, 0); | |
| 194 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 195 | 195 | db_begin_transaction(); |
| 196 | 196 | if( !nochangeFlag ) undo_begin(); |
| 197 | 197 | load_vfile_from_rid(mid); |
| 198 | 198 | load_vfile_from_rid(pid); |
| 199 | 199 | if( debugFlag ){ |
| 200 | 200 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -189,11 +189,11 @@ | |
| 189 | } |
| 190 | if( detailFlag ){ |
| 191 | print_checkin_description(mid, 12, "merge-from:"); |
| 192 | print_checkin_description(pid, 12, "baseline:"); |
| 193 | } |
| 194 | vfile_check_signature(vid, 1, 0); |
| 195 | db_begin_transaction(); |
| 196 | if( !nochangeFlag ) undo_begin(); |
| 197 | load_vfile_from_rid(mid); |
| 198 | load_vfile_from_rid(pid); |
| 199 | if( debugFlag ){ |
| 200 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -189,11 +189,11 @@ | |
| 189 | } |
| 190 | if( detailFlag ){ |
| 191 | print_checkin_description(mid, 12, "merge-from:"); |
| 192 | print_checkin_description(pid, 12, "baseline:"); |
| 193 | } |
| 194 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 195 | db_begin_transaction(); |
| 196 | if( !nochangeFlag ) undo_begin(); |
| 197 | load_vfile_from_rid(mid); |
| 198 | load_vfile_from_rid(pid); |
| 199 | if( debugFlag ){ |
| 200 |
+1
-1
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -189,11 +189,11 @@ | ||
| 189 | 189 | } |
| 190 | 190 | if( detailFlag ){ |
| 191 | 191 | print_checkin_description(mid, 12, "merge-from:"); |
| 192 | 192 | print_checkin_description(pid, 12, "baseline:"); |
| 193 | 193 | } |
| 194 | - vfile_check_signature(vid, 1, 0); | |
| 194 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 195 | 195 | db_begin_transaction(); |
| 196 | 196 | if( !nochangeFlag ) undo_begin(); |
| 197 | 197 | load_vfile_from_rid(mid); |
| 198 | 198 | load_vfile_from_rid(pid); |
| 199 | 199 | if( debugFlag ){ |
| 200 | 200 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -189,11 +189,11 @@ | |
| 189 | } |
| 190 | if( detailFlag ){ |
| 191 | print_checkin_description(mid, 12, "merge-from:"); |
| 192 | print_checkin_description(pid, 12, "baseline:"); |
| 193 | } |
| 194 | vfile_check_signature(vid, 1, 0); |
| 195 | db_begin_transaction(); |
| 196 | if( !nochangeFlag ) undo_begin(); |
| 197 | load_vfile_from_rid(mid); |
| 198 | load_vfile_from_rid(pid); |
| 199 | if( debugFlag ){ |
| 200 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -189,11 +189,11 @@ | |
| 189 | } |
| 190 | if( detailFlag ){ |
| 191 | print_checkin_description(mid, 12, "merge-from:"); |
| 192 | print_checkin_description(pid, 12, "baseline:"); |
| 193 | } |
| 194 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 195 | db_begin_transaction(); |
| 196 | if( !nochangeFlag ) undo_begin(); |
| 197 | load_vfile_from_rid(mid); |
| 198 | load_vfile_from_rid(pid); |
| 199 | if( debugFlag ){ |
| 200 |
+9
-5
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -261,15 +261,19 @@ | ||
| 261 | 261 | if( rid>0 ) return rid; |
| 262 | 262 | |
| 263 | 263 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 264 | 264 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| 265 | 265 | if( zTag[i]==0 ){ |
| 266 | - rid = db_int(0, | |
| 267 | - "SELECT event.objid" | |
| 268 | - " FROM event" | |
| 269 | - " WHERE event.objid=%s" | |
| 270 | - " AND event.type GLOB '%q'", zTag, zType); | |
| 266 | + if( strcmp(zType,"*")==0 ){ | |
| 267 | + rid = atoi(zTag); | |
| 268 | + }else{ | |
| 269 | + rid = db_int(0, | |
| 270 | + "SELECT event.objid" | |
| 271 | + " FROM event" | |
| 272 | + " WHERE event.objid=%s" | |
| 273 | + " AND event.type GLOB '%q'", zTag, zType); | |
| 274 | + } | |
| 271 | 275 | } |
| 272 | 276 | return rid; |
| 273 | 277 | } |
| 274 | 278 | |
| 275 | 279 | |
| 276 | 280 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -261,15 +261,19 @@ | |
| 261 | if( rid>0 ) return rid; |
| 262 | |
| 263 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 264 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| 265 | if( zTag[i]==0 ){ |
| 266 | rid = db_int(0, |
| 267 | "SELECT event.objid" |
| 268 | " FROM event" |
| 269 | " WHERE event.objid=%s" |
| 270 | " AND event.type GLOB '%q'", zTag, zType); |
| 271 | } |
| 272 | return rid; |
| 273 | } |
| 274 | |
| 275 | |
| 276 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -261,15 +261,19 @@ | |
| 261 | if( rid>0 ) return rid; |
| 262 | |
| 263 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 264 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| 265 | if( zTag[i]==0 ){ |
| 266 | if( strcmp(zType,"*")==0 ){ |
| 267 | rid = atoi(zTag); |
| 268 | }else{ |
| 269 | rid = db_int(0, |
| 270 | "SELECT event.objid" |
| 271 | " FROM event" |
| 272 | " WHERE event.objid=%s" |
| 273 | " AND event.type GLOB '%q'", zTag, zType); |
| 274 | } |
| 275 | } |
| 276 | return rid; |
| 277 | } |
| 278 | |
| 279 | |
| 280 |
+9
-5
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -261,15 +261,19 @@ | ||
| 261 | 261 | if( rid>0 ) return rid; |
| 262 | 262 | |
| 263 | 263 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 264 | 264 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| 265 | 265 | if( zTag[i]==0 ){ |
| 266 | - rid = db_int(0, | |
| 267 | - "SELECT event.objid" | |
| 268 | - " FROM event" | |
| 269 | - " WHERE event.objid=%s" | |
| 270 | - " AND event.type GLOB '%q'", zTag, zType); | |
| 266 | + if( strcmp(zType,"*")==0 ){ | |
| 267 | + rid = atoi(zTag); | |
| 268 | + }else{ | |
| 269 | + rid = db_int(0, | |
| 270 | + "SELECT event.objid" | |
| 271 | + " FROM event" | |
| 272 | + " WHERE event.objid=%s" | |
| 273 | + " AND event.type GLOB '%q'", zTag, zType); | |
| 274 | + } | |
| 271 | 275 | } |
| 272 | 276 | return rid; |
| 273 | 277 | } |
| 274 | 278 | |
| 275 | 279 | |
| 276 | 280 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -261,15 +261,19 @@ | |
| 261 | if( rid>0 ) return rid; |
| 262 | |
| 263 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 264 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| 265 | if( zTag[i]==0 ){ |
| 266 | rid = db_int(0, |
| 267 | "SELECT event.objid" |
| 268 | " FROM event" |
| 269 | " WHERE event.objid=%s" |
| 270 | " AND event.type GLOB '%q'", zTag, zType); |
| 271 | } |
| 272 | return rid; |
| 273 | } |
| 274 | |
| 275 | |
| 276 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -261,15 +261,19 @@ | |
| 261 | if( rid>0 ) return rid; |
| 262 | |
| 263 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 264 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| 265 | if( zTag[i]==0 ){ |
| 266 | if( strcmp(zType,"*")==0 ){ |
| 267 | rid = atoi(zTag); |
| 268 | }else{ |
| 269 | rid = db_int(0, |
| 270 | "SELECT event.objid" |
| 271 | " FROM event" |
| 272 | " WHERE event.objid=%s" |
| 273 | " AND event.type GLOB '%q'", zTag, zType); |
| 274 | } |
| 275 | } |
| 276 | return rid; |
| 277 | } |
| 278 | |
| 279 | |
| 280 |
+21
-14
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -925,27 +925,20 @@ | ||
| 925 | 925 | ** |
| 926 | 926 | ** Options: |
| 927 | 927 | ** -R|--repository REPOSITORY deconstruct given REPOSITORY |
| 928 | 928 | ** -L|--prefixlength N set the length of the names of the DESTINATION |
| 929 | 929 | ** subdirectories to N |
| 930 | +** --private Include private artifacts. | |
| 930 | 931 | ** |
| 931 | 932 | ** See also: rebuild, reconstruct |
| 932 | 933 | */ |
| 933 | 934 | void deconstruct_cmd(void){ |
| 934 | 935 | const char *zDestDir; |
| 935 | 936 | const char *zPrefixOpt; |
| 936 | 937 | Stmt s; |
| 937 | - | |
| 938 | - /* check number of arguments */ | |
| 939 | - if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){ | |
| 940 | - usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION"); | |
| 941 | - } | |
| 942 | - /* get and check argument destination directory */ | |
| 943 | - zDestDir = g.argv[g.argc-1]; | |
| 944 | - if( !*zDestDir || !file_isdir(zDestDir)) { | |
| 945 | - fossil_panic("DESTINATION(%s) is not a directory!",zDestDir); | |
| 946 | - } | |
| 938 | + int privateFlag; | |
| 939 | + | |
| 947 | 940 | /* get and check prefix length argument and build format string */ |
| 948 | 941 | zPrefixOpt=find_option("prefixlength","L",1); |
| 949 | 942 | if( !zPrefixOpt ){ |
| 950 | 943 | prefixLength = 2; |
| 951 | 944 | }else{ |
| @@ -953,10 +946,23 @@ | ||
| 953 | 946 | prefixLength = (int)(*zPrefixOpt-'0'); |
| 954 | 947 | }else{ |
| 955 | 948 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 956 | 949 | } |
| 957 | 950 | } |
| 951 | + /* open repository and open query for all artifacts */ | |
| 952 | + db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); | |
| 953 | + privateFlag = find_option("private",0,0)!=0; | |
| 954 | + verify_all_options(); | |
| 955 | + /* check number of arguments */ | |
| 956 | + if( g.argc!=3 ){ | |
| 957 | + usage ("?OPTIONS? DESTINATION"); | |
| 958 | + } | |
| 959 | + /* get and check argument destination directory */ | |
| 960 | + zDestDir = g.argv[g.argc-1]; | |
| 961 | + if( !*zDestDir || !file_isdir(zDestDir)) { | |
| 962 | + fossil_fatal("DESTINATION(%s) is not a directory!",zDestDir); | |
| 963 | + } | |
| 958 | 964 | #ifndef _WIN32 |
| 959 | 965 | if( file_access(zDestDir, W_OK) ){ |
| 960 | 966 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 961 | 967 | } |
| 962 | 968 | #else |
| @@ -967,12 +973,11 @@ | ||
| 967 | 973 | if( prefixLength ){ |
| 968 | 974 | zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); |
| 969 | 975 | }else{ |
| 970 | 976 | zFNameFormat = mprintf("%s/%%s",zDestDir); |
| 971 | 977 | } |
| 972 | - /* open repository and open query for all artifacts */ | |
| 973 | - db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); | |
| 978 | + | |
| 974 | 979 | bag_init(&bagDone); |
| 975 | 980 | ttyOutput = 1; |
| 976 | 981 | processCnt = 0; |
| 977 | 982 | if (!g.fQuiet) { |
| 978 | 983 | fossil_print("0 (0%%)...\r"); |
| @@ -980,11 +985,12 @@ | ||
| 980 | 985 | } |
| 981 | 986 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 982 | 987 | db_prepare(&s, |
| 983 | 988 | "SELECT rid, size FROM blob /*scan*/" |
| 984 | 989 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" |
| 985 | - " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)" | |
| 990 | + " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid) %s", | |
| 991 | + privateFlag==0 ? "AND rid NOT IN private" : "" | |
| 986 | 992 | ); |
| 987 | 993 | while( db_step(&s)==SQLITE_ROW ){ |
| 988 | 994 | int rid = db_column_int(&s, 0); |
| 989 | 995 | int size = db_column_int(&s, 1); |
| 990 | 996 | if( size>=0 ){ |
| @@ -994,11 +1000,12 @@ | ||
| 994 | 1000 | } |
| 995 | 1001 | } |
| 996 | 1002 | db_finalize(&s); |
| 997 | 1003 | db_prepare(&s, |
| 998 | 1004 | "SELECT rid, size FROM blob" |
| 999 | - " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" | |
| 1005 | + " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s", | |
| 1006 | + privateFlag==0 ? "AND rid NOT IN private" : "" | |
| 1000 | 1007 | ); |
| 1001 | 1008 | while( db_step(&s)==SQLITE_ROW ){ |
| 1002 | 1009 | int rid = db_column_int(&s, 0); |
| 1003 | 1010 | int size = db_column_int(&s, 1); |
| 1004 | 1011 | if( size>=0 ){ |
| 1005 | 1012 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -925,27 +925,20 @@ | |
| 925 | ** |
| 926 | ** Options: |
| 927 | ** -R|--repository REPOSITORY deconstruct given REPOSITORY |
| 928 | ** -L|--prefixlength N set the length of the names of the DESTINATION |
| 929 | ** subdirectories to N |
| 930 | ** |
| 931 | ** See also: rebuild, reconstruct |
| 932 | */ |
| 933 | void deconstruct_cmd(void){ |
| 934 | const char *zDestDir; |
| 935 | const char *zPrefixOpt; |
| 936 | Stmt s; |
| 937 | |
| 938 | /* check number of arguments */ |
| 939 | if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){ |
| 940 | usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION"); |
| 941 | } |
| 942 | /* get and check argument destination directory */ |
| 943 | zDestDir = g.argv[g.argc-1]; |
| 944 | if( !*zDestDir || !file_isdir(zDestDir)) { |
| 945 | fossil_panic("DESTINATION(%s) is not a directory!",zDestDir); |
| 946 | } |
| 947 | /* get and check prefix length argument and build format string */ |
| 948 | zPrefixOpt=find_option("prefixlength","L",1); |
| 949 | if( !zPrefixOpt ){ |
| 950 | prefixLength = 2; |
| 951 | }else{ |
| @@ -953,10 +946,23 @@ | |
| 953 | prefixLength = (int)(*zPrefixOpt-'0'); |
| 954 | }else{ |
| 955 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 956 | } |
| 957 | } |
| 958 | #ifndef _WIN32 |
| 959 | if( file_access(zDestDir, W_OK) ){ |
| 960 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 961 | } |
| 962 | #else |
| @@ -967,12 +973,11 @@ | |
| 967 | if( prefixLength ){ |
| 968 | zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); |
| 969 | }else{ |
| 970 | zFNameFormat = mprintf("%s/%%s",zDestDir); |
| 971 | } |
| 972 | /* open repository and open query for all artifacts */ |
| 973 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 974 | bag_init(&bagDone); |
| 975 | ttyOutput = 1; |
| 976 | processCnt = 0; |
| 977 | if (!g.fQuiet) { |
| 978 | fossil_print("0 (0%%)...\r"); |
| @@ -980,11 +985,12 @@ | |
| 980 | } |
| 981 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 982 | db_prepare(&s, |
| 983 | "SELECT rid, size FROM blob /*scan*/" |
| 984 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" |
| 985 | " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)" |
| 986 | ); |
| 987 | while( db_step(&s)==SQLITE_ROW ){ |
| 988 | int rid = db_column_int(&s, 0); |
| 989 | int size = db_column_int(&s, 1); |
| 990 | if( size>=0 ){ |
| @@ -994,11 +1000,12 @@ | |
| 994 | } |
| 995 | } |
| 996 | db_finalize(&s); |
| 997 | db_prepare(&s, |
| 998 | "SELECT rid, size FROM blob" |
| 999 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" |
| 1000 | ); |
| 1001 | while( db_step(&s)==SQLITE_ROW ){ |
| 1002 | int rid = db_column_int(&s, 0); |
| 1003 | int size = db_column_int(&s, 1); |
| 1004 | if( size>=0 ){ |
| 1005 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -925,27 +925,20 @@ | |
| 925 | ** |
| 926 | ** Options: |
| 927 | ** -R|--repository REPOSITORY deconstruct given REPOSITORY |
| 928 | ** -L|--prefixlength N set the length of the names of the DESTINATION |
| 929 | ** subdirectories to N |
| 930 | ** --private Include private artifacts. |
| 931 | ** |
| 932 | ** See also: rebuild, reconstruct |
| 933 | */ |
| 934 | void deconstruct_cmd(void){ |
| 935 | const char *zDestDir; |
| 936 | const char *zPrefixOpt; |
| 937 | Stmt s; |
| 938 | int privateFlag; |
| 939 | |
| 940 | /* get and check prefix length argument and build format string */ |
| 941 | zPrefixOpt=find_option("prefixlength","L",1); |
| 942 | if( !zPrefixOpt ){ |
| 943 | prefixLength = 2; |
| 944 | }else{ |
| @@ -953,10 +946,23 @@ | |
| 946 | prefixLength = (int)(*zPrefixOpt-'0'); |
| 947 | }else{ |
| 948 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 949 | } |
| 950 | } |
| 951 | /* open repository and open query for all artifacts */ |
| 952 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 953 | privateFlag = find_option("private",0,0)!=0; |
| 954 | verify_all_options(); |
| 955 | /* check number of arguments */ |
| 956 | if( g.argc!=3 ){ |
| 957 | usage ("?OPTIONS? DESTINATION"); |
| 958 | } |
| 959 | /* get and check argument destination directory */ |
| 960 | zDestDir = g.argv[g.argc-1]; |
| 961 | if( !*zDestDir || !file_isdir(zDestDir)) { |
| 962 | fossil_fatal("DESTINATION(%s) is not a directory!",zDestDir); |
| 963 | } |
| 964 | #ifndef _WIN32 |
| 965 | if( file_access(zDestDir, W_OK) ){ |
| 966 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 967 | } |
| 968 | #else |
| @@ -967,12 +973,11 @@ | |
| 973 | if( prefixLength ){ |
| 974 | zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); |
| 975 | }else{ |
| 976 | zFNameFormat = mprintf("%s/%%s",zDestDir); |
| 977 | } |
| 978 | |
| 979 | bag_init(&bagDone); |
| 980 | ttyOutput = 1; |
| 981 | processCnt = 0; |
| 982 | if (!g.fQuiet) { |
| 983 | fossil_print("0 (0%%)...\r"); |
| @@ -980,11 +985,12 @@ | |
| 985 | } |
| 986 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 987 | db_prepare(&s, |
| 988 | "SELECT rid, size FROM blob /*scan*/" |
| 989 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" |
| 990 | " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid) %s", |
| 991 | privateFlag==0 ? "AND rid NOT IN private" : "" |
| 992 | ); |
| 993 | while( db_step(&s)==SQLITE_ROW ){ |
| 994 | int rid = db_column_int(&s, 0); |
| 995 | int size = db_column_int(&s, 1); |
| 996 | if( size>=0 ){ |
| @@ -994,11 +1000,12 @@ | |
| 1000 | } |
| 1001 | } |
| 1002 | db_finalize(&s); |
| 1003 | db_prepare(&s, |
| 1004 | "SELECT rid, size FROM blob" |
| 1005 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s", |
| 1006 | privateFlag==0 ? "AND rid NOT IN private" : "" |
| 1007 | ); |
| 1008 | while( db_step(&s)==SQLITE_ROW ){ |
| 1009 | int rid = db_column_int(&s, 0); |
| 1010 | int size = db_column_int(&s, 1); |
| 1011 | if( size>=0 ){ |
| 1012 |
+1
-1
| --- src/report.c | ||
| +++ src/report.c | ||
| @@ -170,11 +170,11 @@ | ||
| 170 | 170 | case SQLITE_SELECT: |
| 171 | 171 | case SQLITE_FUNCTION: { |
| 172 | 172 | break; |
| 173 | 173 | } |
| 174 | 174 | case SQLITE_READ: { |
| 175 | - static const char *azAllowed[] = { | |
| 175 | + static const char *const azAllowed[] = { | |
| 176 | 176 | "ticket", |
| 177 | 177 | "blob", |
| 178 | 178 | "filename", |
| 179 | 179 | "mlink", |
| 180 | 180 | "plink", |
| 181 | 181 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -170,11 +170,11 @@ | |
| 170 | case SQLITE_SELECT: |
| 171 | case SQLITE_FUNCTION: { |
| 172 | break; |
| 173 | } |
| 174 | case SQLITE_READ: { |
| 175 | static const char *azAllowed[] = { |
| 176 | "ticket", |
| 177 | "blob", |
| 178 | "filename", |
| 179 | "mlink", |
| 180 | "plink", |
| 181 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -170,11 +170,11 @@ | |
| 170 | case SQLITE_SELECT: |
| 171 | case SQLITE_FUNCTION: { |
| 172 | break; |
| 173 | } |
| 174 | case SQLITE_READ: { |
| 175 | static const char *const azAllowed[] = { |
| 176 | "ticket", |
| 177 | "blob", |
| 178 | "filename", |
| 179 | "mlink", |
| 180 | "plink", |
| 181 |
+1
-1
| --- src/stash.c | ||
| +++ src/stash.c | ||
| @@ -172,11 +172,11 @@ | ||
| 172 | 172 | zComment = blob_str(&comment); |
| 173 | 173 | } |
| 174 | 174 | stashid = db_lget_int("stash-next", 1); |
| 175 | 175 | db_lset_int("stash-next", stashid+1); |
| 176 | 176 | vid = db_lget_int("checkout", 0); |
| 177 | - vfile_check_signature(vid, 0, 0); | |
| 177 | + vfile_check_signature(vid, 0); | |
| 178 | 178 | db_multi_exec( |
| 179 | 179 | "INSERT INTO stash(stashid,vid,comment,ctime)" |
| 180 | 180 | "VALUES(%d,%d,%Q,julianday('now'))", |
| 181 | 181 | stashid, vid, zComment |
| 182 | 182 | ); |
| 183 | 183 |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -172,11 +172,11 @@ | |
| 172 | zComment = blob_str(&comment); |
| 173 | } |
| 174 | stashid = db_lget_int("stash-next", 1); |
| 175 | db_lset_int("stash-next", stashid+1); |
| 176 | vid = db_lget_int("checkout", 0); |
| 177 | vfile_check_signature(vid, 0, 0); |
| 178 | db_multi_exec( |
| 179 | "INSERT INTO stash(stashid,vid,comment,ctime)" |
| 180 | "VALUES(%d,%d,%Q,julianday('now'))", |
| 181 | stashid, vid, zComment |
| 182 | ); |
| 183 |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -172,11 +172,11 @@ | |
| 172 | zComment = blob_str(&comment); |
| 173 | } |
| 174 | stashid = db_lget_int("stash-next", 1); |
| 175 | db_lset_int("stash-next", stashid+1); |
| 176 | vid = db_lget_int("checkout", 0); |
| 177 | vfile_check_signature(vid, 0); |
| 178 | db_multi_exec( |
| 179 | "INSERT INTO stash(stashid,vid,comment,ctime)" |
| 180 | "VALUES(%d,%d,%Q,julianday('now'))", |
| 181 | stashid, vid, zComment |
| 182 | ); |
| 183 |
+2
-2
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1022,11 +1022,11 @@ | ||
| 1022 | 1022 | if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 1023 | 1023 | if( useDividers ) timeline_add_dividers(0, d_rid); |
| 1024 | 1024 | db_multi_exec("DELETE FROM ok"); |
| 1025 | 1025 | } |
| 1026 | 1026 | if( p_rid ){ |
| 1027 | - compute_ancestors(p_rid, nEntry+1); | |
| 1027 | + compute_ancestors(p_rid, nEntry+1, 0); | |
| 1028 | 1028 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 1029 | 1029 | if( np>0 ){ |
| 1030 | 1030 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 1031 | 1031 | blob_appendf(&desc, "%d ancestors", np); |
| 1032 | 1032 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -1537,11 +1537,11 @@ | ||
| 1537 | 1537 | if( mode==3 || mode==4 ){ |
| 1538 | 1538 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1539 | 1539 | if( mode==3 ){ |
| 1540 | 1540 | compute_descendants(objid, n); |
| 1541 | 1541 | }else{ |
| 1542 | - compute_ancestors(objid, n); | |
| 1542 | + compute_ancestors(objid, n, 0); | |
| 1543 | 1543 | } |
| 1544 | 1544 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1545 | 1545 | } |
| 1546 | 1546 | if( zType && (zType[0]!='a') ){ |
| 1547 | 1547 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1548 | 1548 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 1023 | if( useDividers ) timeline_add_dividers(0, d_rid); |
| 1024 | db_multi_exec("DELETE FROM ok"); |
| 1025 | } |
| 1026 | if( p_rid ){ |
| 1027 | compute_ancestors(p_rid, nEntry+1); |
| 1028 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 1029 | if( np>0 ){ |
| 1030 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 1031 | blob_appendf(&desc, "%d ancestors", np); |
| 1032 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -1537,11 +1537,11 @@ | |
| 1537 | if( mode==3 || mode==4 ){ |
| 1538 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1539 | if( mode==3 ){ |
| 1540 | compute_descendants(objid, n); |
| 1541 | }else{ |
| 1542 | compute_ancestors(objid, n); |
| 1543 | } |
| 1544 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1545 | } |
| 1546 | if( zType && (zType[0]!='a') ){ |
| 1547 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1548 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 1023 | if( useDividers ) timeline_add_dividers(0, d_rid); |
| 1024 | db_multi_exec("DELETE FROM ok"); |
| 1025 | } |
| 1026 | if( p_rid ){ |
| 1027 | compute_ancestors(p_rid, nEntry+1, 0); |
| 1028 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 1029 | if( np>0 ){ |
| 1030 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 1031 | blob_appendf(&desc, "%d ancestors", np); |
| 1032 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -1537,11 +1537,11 @@ | |
| 1537 | if( mode==3 || mode==4 ){ |
| 1538 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1539 | if( mode==3 ){ |
| 1540 | compute_descendants(objid, n); |
| 1541 | }else{ |
| 1542 | compute_ancestors(objid, n, 0); |
| 1543 | } |
| 1544 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1545 | } |
| 1546 | if( zType && (zType[0]!='a') ){ |
| 1547 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1548 |
+2
-2
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1022,11 +1022,11 @@ | ||
| 1022 | 1022 | if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 1023 | 1023 | if( useDividers ) timeline_add_dividers(0, d_rid); |
| 1024 | 1024 | db_multi_exec("DELETE FROM ok"); |
| 1025 | 1025 | } |
| 1026 | 1026 | if( p_rid ){ |
| 1027 | - compute_ancestors(p_rid, nEntry+1); | |
| 1027 | + compute_ancestors(p_rid, nEntry+1, 0); | |
| 1028 | 1028 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 1029 | 1029 | if( np>0 ){ |
| 1030 | 1030 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 1031 | 1031 | blob_appendf(&desc, "%d ancestors", np); |
| 1032 | 1032 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -1537,11 +1537,11 @@ | ||
| 1537 | 1537 | if( mode==3 || mode==4 ){ |
| 1538 | 1538 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1539 | 1539 | if( mode==3 ){ |
| 1540 | 1540 | compute_descendants(objid, n); |
| 1541 | 1541 | }else{ |
| 1542 | - compute_ancestors(objid, n); | |
| 1542 | + compute_ancestors(objid, n, 0); | |
| 1543 | 1543 | } |
| 1544 | 1544 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1545 | 1545 | } |
| 1546 | 1546 | if( zType && (zType[0]!='a') ){ |
| 1547 | 1547 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1548 | 1548 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 1023 | if( useDividers ) timeline_add_dividers(0, d_rid); |
| 1024 | db_multi_exec("DELETE FROM ok"); |
| 1025 | } |
| 1026 | if( p_rid ){ |
| 1027 | compute_ancestors(p_rid, nEntry+1); |
| 1028 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 1029 | if( np>0 ){ |
| 1030 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 1031 | blob_appendf(&desc, "%d ancestors", np); |
| 1032 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -1537,11 +1537,11 @@ | |
| 1537 | if( mode==3 || mode==4 ){ |
| 1538 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1539 | if( mode==3 ){ |
| 1540 | compute_descendants(objid, n); |
| 1541 | }else{ |
| 1542 | compute_ancestors(objid, n); |
| 1543 | } |
| 1544 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1545 | } |
| 1546 | if( zType && (zType[0]!='a') ){ |
| 1547 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1548 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 1023 | if( useDividers ) timeline_add_dividers(0, d_rid); |
| 1024 | db_multi_exec("DELETE FROM ok"); |
| 1025 | } |
| 1026 | if( p_rid ){ |
| 1027 | compute_ancestors(p_rid, nEntry+1, 0); |
| 1028 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 1029 | if( np>0 ){ |
| 1030 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 1031 | blob_appendf(&desc, "%d ancestors", np); |
| 1032 | db_multi_exec("%s", blob_str(&sql)); |
| @@ -1537,11 +1537,11 @@ | |
| 1537 | if( mode==3 || mode==4 ){ |
| 1538 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1539 | if( mode==3 ){ |
| 1540 | compute_descendants(objid, n); |
| 1541 | }else{ |
| 1542 | compute_ancestors(objid, n, 0); |
| 1543 | } |
| 1544 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1545 | } |
| 1546 | if( zType && (zType[0]!='a') ){ |
| 1547 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1548 |
+6
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -433,10 +433,11 @@ | ||
| 433 | 433 | ){ |
| 434 | 434 | char *zDate; |
| 435 | 435 | const char *zUuid; |
| 436 | 436 | int i; |
| 437 | 437 | int rid; |
| 438 | + int nJ = 0; | |
| 438 | 439 | Blob tktchng, cksum; |
| 439 | 440 | |
| 440 | 441 | login_verify_csrf_secret(); |
| 441 | 442 | zUuid = (const char *)pUuid; |
| 442 | 443 | blob_zero(&tktchng); |
| @@ -461,10 +462,11 @@ | ||
| 461 | 462 | zValue = db_conceal(zValue, nValue); |
| 462 | 463 | blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue); |
| 463 | 464 | }else{ |
| 464 | 465 | blob_appendf(&tktchng, "J %s %#F\n", azField[i], nValue, zValue); |
| 465 | 466 | } |
| 467 | + nJ++; | |
| 466 | 468 | } |
| 467 | 469 | } |
| 468 | 470 | } |
| 469 | 471 | if( *(char**)pUuid ){ |
| 470 | 472 | zUuid = db_text(0, |
| @@ -476,10 +478,14 @@ | ||
| 476 | 478 | *(const char**)pUuid = zUuid; |
| 477 | 479 | blob_appendf(&tktchng, "K %s\n", zUuid); |
| 478 | 480 | blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : ""); |
| 479 | 481 | md5sum_blob(&tktchng, &cksum); |
| 480 | 482 | blob_appendf(&tktchng, "Z %b\n", &cksum); |
| 483 | + if( nJ==0 ){ | |
| 484 | + blob_reset(&tktchng); | |
| 485 | + return TH_OK; | |
| 486 | + } | |
| 481 | 487 | if( g.zPath[0]=='d' ){ |
| 482 | 488 | /* If called from /debug_tktnew or /debug_tktedit... */ |
| 483 | 489 | @ <font color="blue"> |
| 484 | 490 | @ <p>Ticket artifact that would have been submitted:</p> |
| 485 | 491 | @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote> |
| 486 | 492 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -433,10 +433,11 @@ | |
| 433 | ){ |
| 434 | char *zDate; |
| 435 | const char *zUuid; |
| 436 | int i; |
| 437 | int rid; |
| 438 | Blob tktchng, cksum; |
| 439 | |
| 440 | login_verify_csrf_secret(); |
| 441 | zUuid = (const char *)pUuid; |
| 442 | blob_zero(&tktchng); |
| @@ -461,10 +462,11 @@ | |
| 461 | zValue = db_conceal(zValue, nValue); |
| 462 | blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue); |
| 463 | }else{ |
| 464 | blob_appendf(&tktchng, "J %s %#F\n", azField[i], nValue, zValue); |
| 465 | } |
| 466 | } |
| 467 | } |
| 468 | } |
| 469 | if( *(char**)pUuid ){ |
| 470 | zUuid = db_text(0, |
| @@ -476,10 +478,14 @@ | |
| 476 | *(const char**)pUuid = zUuid; |
| 477 | blob_appendf(&tktchng, "K %s\n", zUuid); |
| 478 | blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : ""); |
| 479 | md5sum_blob(&tktchng, &cksum); |
| 480 | blob_appendf(&tktchng, "Z %b\n", &cksum); |
| 481 | if( g.zPath[0]=='d' ){ |
| 482 | /* If called from /debug_tktnew or /debug_tktedit... */ |
| 483 | @ <font color="blue"> |
| 484 | @ <p>Ticket artifact that would have been submitted:</p> |
| 485 | @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote> |
| 486 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -433,10 +433,11 @@ | |
| 433 | ){ |
| 434 | char *zDate; |
| 435 | const char *zUuid; |
| 436 | int i; |
| 437 | int rid; |
| 438 | int nJ = 0; |
| 439 | Blob tktchng, cksum; |
| 440 | |
| 441 | login_verify_csrf_secret(); |
| 442 | zUuid = (const char *)pUuid; |
| 443 | blob_zero(&tktchng); |
| @@ -461,10 +462,11 @@ | |
| 462 | zValue = db_conceal(zValue, nValue); |
| 463 | blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue); |
| 464 | }else{ |
| 465 | blob_appendf(&tktchng, "J %s %#F\n", azField[i], nValue, zValue); |
| 466 | } |
| 467 | nJ++; |
| 468 | } |
| 469 | } |
| 470 | } |
| 471 | if( *(char**)pUuid ){ |
| 472 | zUuid = db_text(0, |
| @@ -476,10 +478,14 @@ | |
| 478 | *(const char**)pUuid = zUuid; |
| 479 | blob_appendf(&tktchng, "K %s\n", zUuid); |
| 480 | blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : ""); |
| 481 | md5sum_blob(&tktchng, &cksum); |
| 482 | blob_appendf(&tktchng, "Z %b\n", &cksum); |
| 483 | if( nJ==0 ){ |
| 484 | blob_reset(&tktchng); |
| 485 | return TH_OK; |
| 486 | } |
| 487 | if( g.zPath[0]=='d' ){ |
| 488 | /* If called from /debug_tktnew or /debug_tktedit... */ |
| 489 | @ <font color="blue"> |
| 490 | @ <p>Ticket artifact that would have been submitted:</p> |
| 491 | @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote> |
| 492 |
+5
-2
| --- src/update.c | ||
| +++ src/update.c | ||
| @@ -100,10 +100,11 @@ | ||
| 100 | 100 | Stmt q; |
| 101 | 101 | int latestFlag; /* --latest. Pick the latest version if true */ |
| 102 | 102 | int nochangeFlag; /* -n or --nochange. Do a dry run */ |
| 103 | 103 | int verboseFlag; /* -v or --verbose. Output extra information */ |
| 104 | 104 | int debugFlag; /* --debug option */ |
| 105 | + int setmtimeFlag; /* --setmtime. Set mtimes on files */ | |
| 105 | 106 | int nChng; /* Number of file renames */ |
| 106 | 107 | int *aChng; /* Array of file renames */ |
| 107 | 108 | int i; /* Loop counter */ |
| 108 | 109 | int nConflict = 0; /* Number of merge conflicts */ |
| 109 | 110 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
| @@ -116,10 +117,11 @@ | ||
| 116 | 117 | } |
| 117 | 118 | latestFlag = find_option("latest",0, 0)!=0; |
| 118 | 119 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 119 | 120 | verboseFlag = find_option("verbose","v",0)!=0; |
| 120 | 121 | debugFlag = find_option("debug",0,0)!=0; |
| 122 | + setmtimeFlag = find_option("setmtime",0,0)!=0; | |
| 121 | 123 | db_must_be_within_tree(); |
| 122 | 124 | vid = db_lget_int("checkout", 0); |
| 123 | 125 | if( vid==0 ){ |
| 124 | 126 | fossil_fatal("cannot find current version"); |
| 125 | 127 | } |
| @@ -194,11 +196,11 @@ | ||
| 194 | 196 | if( tid==0 ){ |
| 195 | 197 | fossil_panic("Internal Error: unable to find a version to update to."); |
| 196 | 198 | } |
| 197 | 199 | |
| 198 | 200 | db_begin_transaction(); |
| 199 | - vfile_check_signature(vid, 1, 0); | |
| 201 | + vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 200 | 202 | if( !nochangeFlag && !internalUpdate ) undo_begin(); |
| 201 | 203 | load_vfile_from_rid(tid); |
| 202 | 204 | |
| 203 | 205 | /* |
| 204 | 206 | ** The record.fn field is used to match files against each other. The |
| @@ -529,10 +531,11 @@ | ||
| 529 | 531 | /* A subset of files have been checked out. Keep the current |
| 530 | 532 | ** checkout unchanged. */ |
| 531 | 533 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 532 | 534 | } |
| 533 | 535 | if( !internalUpdate ) undo_finish(); |
| 536 | + if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME); | |
| 534 | 537 | db_end_transaction(0); |
| 535 | 538 | } |
| 536 | 539 | } |
| 537 | 540 | |
| 538 | 541 | /* |
| @@ -696,11 +699,11 @@ | ||
| 696 | 699 | blob_reset(&fname); |
| 697 | 700 | } |
| 698 | 701 | }else{ |
| 699 | 702 | int vid; |
| 700 | 703 | vid = db_lget_int("checkout", 0); |
| 701 | - vfile_check_signature(vid, 0, 0); | |
| 704 | + vfile_check_signature(vid, 0); | |
| 702 | 705 | db_multi_exec( |
| 703 | 706 | "DELETE FROM vmerge;" |
| 704 | 707 | "INSERT INTO torevert " |
| 705 | 708 | "SELECT pathname" |
| 706 | 709 | " FROM vfile " |
| 707 | 710 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -100,10 +100,11 @@ | |
| 100 | Stmt q; |
| 101 | int latestFlag; /* --latest. Pick the latest version if true */ |
| 102 | int nochangeFlag; /* -n or --nochange. Do a dry run */ |
| 103 | int verboseFlag; /* -v or --verbose. Output extra information */ |
| 104 | int debugFlag; /* --debug option */ |
| 105 | int nChng; /* Number of file renames */ |
| 106 | int *aChng; /* Array of file renames */ |
| 107 | int i; /* Loop counter */ |
| 108 | int nConflict = 0; /* Number of merge conflicts */ |
| 109 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
| @@ -116,10 +117,11 @@ | |
| 116 | } |
| 117 | latestFlag = find_option("latest",0, 0)!=0; |
| 118 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 119 | verboseFlag = find_option("verbose","v",0)!=0; |
| 120 | debugFlag = find_option("debug",0,0)!=0; |
| 121 | db_must_be_within_tree(); |
| 122 | vid = db_lget_int("checkout", 0); |
| 123 | if( vid==0 ){ |
| 124 | fossil_fatal("cannot find current version"); |
| 125 | } |
| @@ -194,11 +196,11 @@ | |
| 194 | if( tid==0 ){ |
| 195 | fossil_panic("Internal Error: unable to find a version to update to."); |
| 196 | } |
| 197 | |
| 198 | db_begin_transaction(); |
| 199 | vfile_check_signature(vid, 1, 0); |
| 200 | if( !nochangeFlag && !internalUpdate ) undo_begin(); |
| 201 | load_vfile_from_rid(tid); |
| 202 | |
| 203 | /* |
| 204 | ** The record.fn field is used to match files against each other. The |
| @@ -529,10 +531,11 @@ | |
| 529 | /* A subset of files have been checked out. Keep the current |
| 530 | ** checkout unchanged. */ |
| 531 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 532 | } |
| 533 | if( !internalUpdate ) undo_finish(); |
| 534 | db_end_transaction(0); |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | /* |
| @@ -696,11 +699,11 @@ | |
| 696 | blob_reset(&fname); |
| 697 | } |
| 698 | }else{ |
| 699 | int vid; |
| 700 | vid = db_lget_int("checkout", 0); |
| 701 | vfile_check_signature(vid, 0, 0); |
| 702 | db_multi_exec( |
| 703 | "DELETE FROM vmerge;" |
| 704 | "INSERT INTO torevert " |
| 705 | "SELECT pathname" |
| 706 | " FROM vfile " |
| 707 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -100,10 +100,11 @@ | |
| 100 | Stmt q; |
| 101 | int latestFlag; /* --latest. Pick the latest version if true */ |
| 102 | int nochangeFlag; /* -n or --nochange. Do a dry run */ |
| 103 | int verboseFlag; /* -v or --verbose. Output extra information */ |
| 104 | int debugFlag; /* --debug option */ |
| 105 | int setmtimeFlag; /* --setmtime. Set mtimes on files */ |
| 106 | int nChng; /* Number of file renames */ |
| 107 | int *aChng; /* Array of file renames */ |
| 108 | int i; /* Loop counter */ |
| 109 | int nConflict = 0; /* Number of merge conflicts */ |
| 110 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
| @@ -116,10 +117,11 @@ | |
| 117 | } |
| 118 | latestFlag = find_option("latest",0, 0)!=0; |
| 119 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 120 | verboseFlag = find_option("verbose","v",0)!=0; |
| 121 | debugFlag = find_option("debug",0,0)!=0; |
| 122 | setmtimeFlag = find_option("setmtime",0,0)!=0; |
| 123 | db_must_be_within_tree(); |
| 124 | vid = db_lget_int("checkout", 0); |
| 125 | if( vid==0 ){ |
| 126 | fossil_fatal("cannot find current version"); |
| 127 | } |
| @@ -194,11 +196,11 @@ | |
| 196 | if( tid==0 ){ |
| 197 | fossil_panic("Internal Error: unable to find a version to update to."); |
| 198 | } |
| 199 | |
| 200 | db_begin_transaction(); |
| 201 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 202 | if( !nochangeFlag && !internalUpdate ) undo_begin(); |
| 203 | load_vfile_from_rid(tid); |
| 204 | |
| 205 | /* |
| 206 | ** The record.fn field is used to match files against each other. The |
| @@ -529,10 +531,11 @@ | |
| 531 | /* A subset of files have been checked out. Keep the current |
| 532 | ** checkout unchanged. */ |
| 533 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 534 | } |
| 535 | if( !internalUpdate ) undo_finish(); |
| 536 | if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME); |
| 537 | db_end_transaction(0); |
| 538 | } |
| 539 | } |
| 540 | |
| 541 | /* |
| @@ -696,11 +699,11 @@ | |
| 699 | blob_reset(&fname); |
| 700 | } |
| 701 | }else{ |
| 702 | int vid; |
| 703 | vid = db_lget_int("checkout", 0); |
| 704 | vfile_check_signature(vid, 0); |
| 705 | db_multi_exec( |
| 706 | "DELETE FROM vmerge;" |
| 707 | "INSERT INTO torevert " |
| 708 | "SELECT pathname" |
| 709 | " FROM vfile " |
| 710 |
+76
-15
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -118,19 +118,30 @@ | ||
| 118 | 118 | db_finalize(&ins); |
| 119 | 119 | manifest_destroy(p); |
| 120 | 120 | db_end_transaction(0); |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | +#if INTERFACE | |
| 124 | +/* | |
| 125 | +** The cksigFlags parameter to vfile_check_signature() is an OR-ed | |
| 126 | +** combination of the following bits: | |
| 127 | +*/ | |
| 128 | +#define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */ | |
| 129 | +#define CKSIG_SHA1 0x002 /* Verify file content using sha1sum */ | |
| 130 | +#define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */ | |
| 131 | + | |
| 132 | +#endif /* INTERFACE */ | |
| 133 | + | |
| 123 | 134 | /* |
| 124 | -** Look at every VFILE entry with the given vid and set update | |
| 125 | -** VFILE.CHNGED field on every file according to whether or not | |
| 126 | -** the file has changes. 0 means no change. 1 means edited. 2 means | |
| 135 | +** Look at every VFILE entry with the given vid and update | |
| 136 | +** VFILE.CHNGED field according to whether or not | |
| 137 | +** the file has changed. 0 means no change. 1 means edited. 2 means | |
| 127 | 138 | ** the file has changed due to a merge. 3 means the file was added |
| 128 | 139 | ** by a merge. |
| 129 | 140 | ** |
| 130 | -** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was | |
| 131 | -** either removed from managemented via "fossil rm" or added via | |
| 141 | +** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either | |
| 142 | +** removed from configuration management via "fossil rm" or added via | |
| 132 | 143 | ** "fossil add", respectively, and in both cases we always know that |
| 133 | 144 | ** the file has changed without having the check the size, mtime, |
| 134 | 145 | ** or on-disk content. |
| 135 | 146 | ** |
| 136 | 147 | ** If the size of the file has changed, then we always know that the file |
| @@ -144,15 +155,16 @@ | ||
| 144 | 155 | ** |
| 145 | 156 | ** If the mtime is used, it is used only to determine if files are the same. |
| 146 | 157 | ** If the mtime of a file has changed, we still examine the on-disk content |
| 147 | 158 | ** to see whether or not the edit was a null-edit. |
| 148 | 159 | */ |
| 149 | -void vfile_check_signature(int vid, int notFileIsFatal, int useSha1sum){ | |
| 160 | +void vfile_check_signature(int vid, unsigned int cksigFlags){ | |
| 150 | 161 | int nErr = 0; |
| 151 | 162 | Stmt q; |
| 152 | 163 | Blob fileCksum, origCksum; |
| 153 | - int useMtime = useSha1sum==0 && db_get_boolean("mtime-changes", 1); | |
| 164 | + int useMtime = (cksigFlags & CKSIG_SHA1)==0 | |
| 165 | + && db_get_boolean("mtime-changes", 1); | |
| 154 | 166 | |
| 155 | 167 | db_begin_transaction(); |
| 156 | 168 | db_prepare(&q, "SELECT id, %Q || pathname," |
| 157 | 169 | " vfile.mrid, deleted, chnged, uuid, size, mtime" |
| 158 | 170 | " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" |
| @@ -178,11 +190,11 @@ | ||
| 178 | 190 | currentMtime = file_wd_mtime(0); |
| 179 | 191 | if( chnged==0 && (isDeleted || rid==0) ){ |
| 180 | 192 | /* "fossil rm" or "fossil add" always change the file */ |
| 181 | 193 | chnged = 1; |
| 182 | 194 | }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){ |
| 183 | - if( notFileIsFatal ){ | |
| 195 | + if( cksigFlags & CKSIG_ENOTFILE ){ | |
| 184 | 196 | fossil_warning("not an ordinary file: %s", zName); |
| 185 | 197 | nErr++; |
| 186 | 198 | } |
| 187 | 199 | chnged = 1; |
| 188 | 200 | } |
| @@ -217,10 +229,19 @@ | ||
| 217 | 229 | if( blob_compare(&fileCksum, &origCksum) ){ |
| 218 | 230 | chnged = 1; |
| 219 | 231 | } |
| 220 | 232 | blob_reset(&origCksum); |
| 221 | 233 | blob_reset(&fileCksum); |
| 234 | + } | |
| 235 | + if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2) ){ | |
| 236 | + i64 desiredMtime; | |
| 237 | + if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){ | |
| 238 | + if( currentMtime!=desiredMtime ){ | |
| 239 | + file_set_mtime(zName, desiredMtime); | |
| 240 | + currentMtime = file_wd_mtime(zName); | |
| 241 | + } | |
| 242 | + } | |
| 222 | 243 | } |
| 223 | 244 | if( currentMtime!=oldMtime || chnged!=oldChnged ){ |
| 224 | 245 | db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d", |
| 225 | 246 | currentMtime, chnged, id); |
| 226 | 247 | } |
| @@ -360,10 +381,48 @@ | ||
| 360 | 381 | fossil_free(zFile); |
| 361 | 382 | } |
| 362 | 383 | return fileFound; |
| 363 | 384 | } |
| 364 | 385 | |
| 386 | +/* | |
| 387 | +** Return TRUE if zFile is a temporary file. Return FALSE if not. | |
| 388 | +*/ | |
| 389 | +static int is_temporary_file(const char *zName){ | |
| 390 | + static const char *const azTemp[] = { | |
| 391 | + "baseline", | |
| 392 | + "merge", | |
| 393 | + "original", | |
| 394 | + "output", | |
| 395 | + }; | |
| 396 | + int i, j, n; | |
| 397 | + | |
| 398 | + if( strglob("ci-comment-????????????.txt", zName) ) return 1; | |
| 399 | + for(; zName[0]!=0; zName++){ | |
| 400 | + if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){ | |
| 401 | + return 1; | |
| 402 | + } | |
| 403 | + if( zName[0]!='-' ) continue; | |
| 404 | + for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){ | |
| 405 | + n = (int)strlen(azTemp[i]); | |
| 406 | + if( memcmp(azTemp[i], zName+1, n) ) continue; | |
| 407 | + if( zName[n+1]==0 ) return 1; | |
| 408 | + if( zName[n+1]=='-' ){ | |
| 409 | + for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){} | |
| 410 | + if( zName[j]==0 ) return 1; | |
| 411 | + } | |
| 412 | + } | |
| 413 | + } | |
| 414 | + return 0; | |
| 415 | +} | |
| 416 | + | |
| 417 | +#if INTERFACE | |
| 418 | +/* | |
| 419 | +** Values for the scanFlags parameter to vfile_scan(). | |
| 420 | +*/ | |
| 421 | +#define SCAN_ALL 0x001 /* Includes files that begin with "." */ | |
| 422 | +#define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */ | |
| 423 | +#endif /* INTERFACE */ | |
| 365 | 424 | |
| 366 | 425 | /* |
| 367 | 426 | ** Load into table SFILE the name of every ordinary file in |
| 368 | 427 | ** the directory pPath. Omit the first nPrefix characters of |
| 369 | 428 | ** of pPath when inserting into the SFILE table. |
| @@ -375,11 +434,11 @@ | ||
| 375 | 434 | ** |
| 376 | 435 | ** Any files or directories that match the glob pattern pIgnore are |
| 377 | 436 | ** excluded from the scan. Name matching occurs after the first |
| 378 | 437 | ** nPrefix characters are elided from the filename. |
| 379 | 438 | */ |
| 380 | -void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){ | |
| 439 | +void vfile_scan(Blob *pPath, int nPrefix, unsigned scanFlags, Glob *pIgnore){ | |
| 381 | 440 | DIR *d; |
| 382 | 441 | int origSize; |
| 383 | 442 | const char *zDir; |
| 384 | 443 | struct dirent *pEntry; |
| 385 | 444 | int skipAll = 0; |
| @@ -409,29 +468,31 @@ | ||
| 409 | 468 | if( d ){ |
| 410 | 469 | while( (pEntry=readdir(d))!=0 ){ |
| 411 | 470 | char *zPath; |
| 412 | 471 | char *zUtf8; |
| 413 | 472 | if( pEntry->d_name[0]=='.' ){ |
| 414 | - if( !allFlag ) continue; | |
| 473 | + if( (scanFlags & SCAN_ALL)==0 ) continue; | |
| 415 | 474 | if( pEntry->d_name[1]==0 ) continue; |
| 416 | 475 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 417 | 476 | } |
| 418 | 477 | zUtf8 = fossil_unicode_to_utf8(pEntry->d_name); |
| 419 | 478 | blob_appendf(pPath, "/%s", zUtf8); |
| 420 | - fossil_mbcs_free(zUtf8); | |
| 421 | 479 | zPath = blob_str(pPath); |
| 422 | 480 | if( glob_match(pIgnore, &zPath[nPrefix+1]) ){ |
| 423 | 481 | /* do nothing */ |
| 424 | 482 | }else if( file_wd_isdir(zPath)==1 ){ |
| 425 | 483 | if( !vfile_top_of_checkout(zPath) ){ |
| 426 | - vfile_scan(pPath, nPrefix, allFlag, pIgnore); | |
| 484 | + vfile_scan(pPath, nPrefix, scanFlags, pIgnore); | |
| 427 | 485 | } |
| 428 | 486 | }else if( file_wd_isfile_or_link(zPath) ){ |
| 429 | - db_bind_text(&ins, ":file", &zPath[nPrefix+1]); | |
| 430 | - db_step(&ins); | |
| 431 | - db_reset(&ins); | |
| 487 | + if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){ | |
| 488 | + db_bind_text(&ins, ":file", &zPath[nPrefix+1]); | |
| 489 | + db_step(&ins); | |
| 490 | + db_reset(&ins); | |
| 491 | + } | |
| 432 | 492 | } |
| 493 | + fossil_mbcs_free(zUtf8); | |
| 433 | 494 | blob_resize(pPath, origSize); |
| 434 | 495 | } |
| 435 | 496 | closedir(d); |
| 436 | 497 | } |
| 437 | 498 | fossil_mbcs_free(zMbcs); |
| 438 | 499 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -118,19 +118,30 @@ | |
| 118 | db_finalize(&ins); |
| 119 | manifest_destroy(p); |
| 120 | db_end_transaction(0); |
| 121 | } |
| 122 | |
| 123 | /* |
| 124 | ** Look at every VFILE entry with the given vid and set update |
| 125 | ** VFILE.CHNGED field on every file according to whether or not |
| 126 | ** the file has changes. 0 means no change. 1 means edited. 2 means |
| 127 | ** the file has changed due to a merge. 3 means the file was added |
| 128 | ** by a merge. |
| 129 | ** |
| 130 | ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was |
| 131 | ** either removed from managemented via "fossil rm" or added via |
| 132 | ** "fossil add", respectively, and in both cases we always know that |
| 133 | ** the file has changed without having the check the size, mtime, |
| 134 | ** or on-disk content. |
| 135 | ** |
| 136 | ** If the size of the file has changed, then we always know that the file |
| @@ -144,15 +155,16 @@ | |
| 144 | ** |
| 145 | ** If the mtime is used, it is used only to determine if files are the same. |
| 146 | ** If the mtime of a file has changed, we still examine the on-disk content |
| 147 | ** to see whether or not the edit was a null-edit. |
| 148 | */ |
| 149 | void vfile_check_signature(int vid, int notFileIsFatal, int useSha1sum){ |
| 150 | int nErr = 0; |
| 151 | Stmt q; |
| 152 | Blob fileCksum, origCksum; |
| 153 | int useMtime = useSha1sum==0 && db_get_boolean("mtime-changes", 1); |
| 154 | |
| 155 | db_begin_transaction(); |
| 156 | db_prepare(&q, "SELECT id, %Q || pathname," |
| 157 | " vfile.mrid, deleted, chnged, uuid, size, mtime" |
| 158 | " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" |
| @@ -178,11 +190,11 @@ | |
| 178 | currentMtime = file_wd_mtime(0); |
| 179 | if( chnged==0 && (isDeleted || rid==0) ){ |
| 180 | /* "fossil rm" or "fossil add" always change the file */ |
| 181 | chnged = 1; |
| 182 | }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){ |
| 183 | if( notFileIsFatal ){ |
| 184 | fossil_warning("not an ordinary file: %s", zName); |
| 185 | nErr++; |
| 186 | } |
| 187 | chnged = 1; |
| 188 | } |
| @@ -217,10 +229,19 @@ | |
| 217 | if( blob_compare(&fileCksum, &origCksum) ){ |
| 218 | chnged = 1; |
| 219 | } |
| 220 | blob_reset(&origCksum); |
| 221 | blob_reset(&fileCksum); |
| 222 | } |
| 223 | if( currentMtime!=oldMtime || chnged!=oldChnged ){ |
| 224 | db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d", |
| 225 | currentMtime, chnged, id); |
| 226 | } |
| @@ -360,10 +381,48 @@ | |
| 360 | fossil_free(zFile); |
| 361 | } |
| 362 | return fileFound; |
| 363 | } |
| 364 | |
| 365 | |
| 366 | /* |
| 367 | ** Load into table SFILE the name of every ordinary file in |
| 368 | ** the directory pPath. Omit the first nPrefix characters of |
| 369 | ** of pPath when inserting into the SFILE table. |
| @@ -375,11 +434,11 @@ | |
| 375 | ** |
| 376 | ** Any files or directories that match the glob pattern pIgnore are |
| 377 | ** excluded from the scan. Name matching occurs after the first |
| 378 | ** nPrefix characters are elided from the filename. |
| 379 | */ |
| 380 | void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){ |
| 381 | DIR *d; |
| 382 | int origSize; |
| 383 | const char *zDir; |
| 384 | struct dirent *pEntry; |
| 385 | int skipAll = 0; |
| @@ -409,29 +468,31 @@ | |
| 409 | if( d ){ |
| 410 | while( (pEntry=readdir(d))!=0 ){ |
| 411 | char *zPath; |
| 412 | char *zUtf8; |
| 413 | if( pEntry->d_name[0]=='.' ){ |
| 414 | if( !allFlag ) continue; |
| 415 | if( pEntry->d_name[1]==0 ) continue; |
| 416 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 417 | } |
| 418 | zUtf8 = fossil_unicode_to_utf8(pEntry->d_name); |
| 419 | blob_appendf(pPath, "/%s", zUtf8); |
| 420 | fossil_mbcs_free(zUtf8); |
| 421 | zPath = blob_str(pPath); |
| 422 | if( glob_match(pIgnore, &zPath[nPrefix+1]) ){ |
| 423 | /* do nothing */ |
| 424 | }else if( file_wd_isdir(zPath)==1 ){ |
| 425 | if( !vfile_top_of_checkout(zPath) ){ |
| 426 | vfile_scan(pPath, nPrefix, allFlag, pIgnore); |
| 427 | } |
| 428 | }else if( file_wd_isfile_or_link(zPath) ){ |
| 429 | db_bind_text(&ins, ":file", &zPath[nPrefix+1]); |
| 430 | db_step(&ins); |
| 431 | db_reset(&ins); |
| 432 | } |
| 433 | blob_resize(pPath, origSize); |
| 434 | } |
| 435 | closedir(d); |
| 436 | } |
| 437 | fossil_mbcs_free(zMbcs); |
| 438 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -118,19 +118,30 @@ | |
| 118 | db_finalize(&ins); |
| 119 | manifest_destroy(p); |
| 120 | db_end_transaction(0); |
| 121 | } |
| 122 | |
| 123 | #if INTERFACE |
| 124 | /* |
| 125 | ** The cksigFlags parameter to vfile_check_signature() is an OR-ed |
| 126 | ** combination of the following bits: |
| 127 | */ |
| 128 | #define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */ |
| 129 | #define CKSIG_SHA1 0x002 /* Verify file content using sha1sum */ |
| 130 | #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */ |
| 131 | |
| 132 | #endif /* INTERFACE */ |
| 133 | |
| 134 | /* |
| 135 | ** Look at every VFILE entry with the given vid and update |
| 136 | ** VFILE.CHNGED field according to whether or not |
| 137 | ** the file has changed. 0 means no change. 1 means edited. 2 means |
| 138 | ** the file has changed due to a merge. 3 means the file was added |
| 139 | ** by a merge. |
| 140 | ** |
| 141 | ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either |
| 142 | ** removed from configuration management via "fossil rm" or added via |
| 143 | ** "fossil add", respectively, and in both cases we always know that |
| 144 | ** the file has changed without having the check the size, mtime, |
| 145 | ** or on-disk content. |
| 146 | ** |
| 147 | ** If the size of the file has changed, then we always know that the file |
| @@ -144,15 +155,16 @@ | |
| 155 | ** |
| 156 | ** If the mtime is used, it is used only to determine if files are the same. |
| 157 | ** If the mtime of a file has changed, we still examine the on-disk content |
| 158 | ** to see whether or not the edit was a null-edit. |
| 159 | */ |
| 160 | void vfile_check_signature(int vid, unsigned int cksigFlags){ |
| 161 | int nErr = 0; |
| 162 | Stmt q; |
| 163 | Blob fileCksum, origCksum; |
| 164 | int useMtime = (cksigFlags & CKSIG_SHA1)==0 |
| 165 | && db_get_boolean("mtime-changes", 1); |
| 166 | |
| 167 | db_begin_transaction(); |
| 168 | db_prepare(&q, "SELECT id, %Q || pathname," |
| 169 | " vfile.mrid, deleted, chnged, uuid, size, mtime" |
| 170 | " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" |
| @@ -178,11 +190,11 @@ | |
| 190 | currentMtime = file_wd_mtime(0); |
| 191 | if( chnged==0 && (isDeleted || rid==0) ){ |
| 192 | /* "fossil rm" or "fossil add" always change the file */ |
| 193 | chnged = 1; |
| 194 | }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){ |
| 195 | if( cksigFlags & CKSIG_ENOTFILE ){ |
| 196 | fossil_warning("not an ordinary file: %s", zName); |
| 197 | nErr++; |
| 198 | } |
| 199 | chnged = 1; |
| 200 | } |
| @@ -217,10 +229,19 @@ | |
| 229 | if( blob_compare(&fileCksum, &origCksum) ){ |
| 230 | chnged = 1; |
| 231 | } |
| 232 | blob_reset(&origCksum); |
| 233 | blob_reset(&fileCksum); |
| 234 | } |
| 235 | if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2) ){ |
| 236 | i64 desiredMtime; |
| 237 | if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){ |
| 238 | if( currentMtime!=desiredMtime ){ |
| 239 | file_set_mtime(zName, desiredMtime); |
| 240 | currentMtime = file_wd_mtime(zName); |
| 241 | } |
| 242 | } |
| 243 | } |
| 244 | if( currentMtime!=oldMtime || chnged!=oldChnged ){ |
| 245 | db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d", |
| 246 | currentMtime, chnged, id); |
| 247 | } |
| @@ -360,10 +381,48 @@ | |
| 381 | fossil_free(zFile); |
| 382 | } |
| 383 | return fileFound; |
| 384 | } |
| 385 | |
| 386 | /* |
| 387 | ** Return TRUE if zFile is a temporary file. Return FALSE if not. |
| 388 | */ |
| 389 | static int is_temporary_file(const char *zName){ |
| 390 | static const char *const azTemp[] = { |
| 391 | "baseline", |
| 392 | "merge", |
| 393 | "original", |
| 394 | "output", |
| 395 | }; |
| 396 | int i, j, n; |
| 397 | |
| 398 | if( strglob("ci-comment-????????????.txt", zName) ) return 1; |
| 399 | for(; zName[0]!=0; zName++){ |
| 400 | if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){ |
| 401 | return 1; |
| 402 | } |
| 403 | if( zName[0]!='-' ) continue; |
| 404 | for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){ |
| 405 | n = (int)strlen(azTemp[i]); |
| 406 | if( memcmp(azTemp[i], zName+1, n) ) continue; |
| 407 | if( zName[n+1]==0 ) return 1; |
| 408 | if( zName[n+1]=='-' ){ |
| 409 | for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){} |
| 410 | if( zName[j]==0 ) return 1; |
| 411 | } |
| 412 | } |
| 413 | } |
| 414 | return 0; |
| 415 | } |
| 416 | |
| 417 | #if INTERFACE |
| 418 | /* |
| 419 | ** Values for the scanFlags parameter to vfile_scan(). |
| 420 | */ |
| 421 | #define SCAN_ALL 0x001 /* Includes files that begin with "." */ |
| 422 | #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */ |
| 423 | #endif /* INTERFACE */ |
| 424 | |
| 425 | /* |
| 426 | ** Load into table SFILE the name of every ordinary file in |
| 427 | ** the directory pPath. Omit the first nPrefix characters of |
| 428 | ** of pPath when inserting into the SFILE table. |
| @@ -375,11 +434,11 @@ | |
| 434 | ** |
| 435 | ** Any files or directories that match the glob pattern pIgnore are |
| 436 | ** excluded from the scan. Name matching occurs after the first |
| 437 | ** nPrefix characters are elided from the filename. |
| 438 | */ |
| 439 | void vfile_scan(Blob *pPath, int nPrefix, unsigned scanFlags, Glob *pIgnore){ |
| 440 | DIR *d; |
| 441 | int origSize; |
| 442 | const char *zDir; |
| 443 | struct dirent *pEntry; |
| 444 | int skipAll = 0; |
| @@ -409,29 +468,31 @@ | |
| 468 | if( d ){ |
| 469 | while( (pEntry=readdir(d))!=0 ){ |
| 470 | char *zPath; |
| 471 | char *zUtf8; |
| 472 | if( pEntry->d_name[0]=='.' ){ |
| 473 | if( (scanFlags & SCAN_ALL)==0 ) continue; |
| 474 | if( pEntry->d_name[1]==0 ) continue; |
| 475 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 476 | } |
| 477 | zUtf8 = fossil_unicode_to_utf8(pEntry->d_name); |
| 478 | blob_appendf(pPath, "/%s", zUtf8); |
| 479 | zPath = blob_str(pPath); |
| 480 | if( glob_match(pIgnore, &zPath[nPrefix+1]) ){ |
| 481 | /* do nothing */ |
| 482 | }else if( file_wd_isdir(zPath)==1 ){ |
| 483 | if( !vfile_top_of_checkout(zPath) ){ |
| 484 | vfile_scan(pPath, nPrefix, scanFlags, pIgnore); |
| 485 | } |
| 486 | }else if( file_wd_isfile_or_link(zPath) ){ |
| 487 | if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){ |
| 488 | db_bind_text(&ins, ":file", &zPath[nPrefix+1]); |
| 489 | db_step(&ins); |
| 490 | db_reset(&ins); |
| 491 | } |
| 492 | } |
| 493 | fossil_mbcs_free(zUtf8); |
| 494 | blob_resize(pPath, origSize); |
| 495 | } |
| 496 | closedir(d); |
| 497 | } |
| 498 | fossil_mbcs_free(zMbcs); |
| 499 |
+1
-1
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -270,11 +270,11 @@ | ||
| 270 | 270 | int rid, /* record id of the file to send */ |
| 271 | 271 | int isPrivate, /* True if rid is a private artifact */ |
| 272 | 272 | Blob *pContent, /* The content of the file to send */ |
| 273 | 273 | Blob *pUuid /* The UUID of the file to send */ |
| 274 | 274 | ){ |
| 275 | - static const char *azQuery[] = { | |
| 275 | + static const char *const azQuery[] = { | |
| 276 | 276 | "SELECT pid FROM plink x" |
| 277 | 277 | " WHERE cid=%d" |
| 278 | 278 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 279 | 279 | " AND NOT EXISTS(SELECT 1 FROM plink y" |
| 280 | 280 | " WHERE y.pid=x.cid AND y.cid=x.pid)", |
| 281 | 281 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -270,11 +270,11 @@ | |
| 270 | int rid, /* record id of the file to send */ |
| 271 | int isPrivate, /* True if rid is a private artifact */ |
| 272 | Blob *pContent, /* The content of the file to send */ |
| 273 | Blob *pUuid /* The UUID of the file to send */ |
| 274 | ){ |
| 275 | static const char *azQuery[] = { |
| 276 | "SELECT pid FROM plink x" |
| 277 | " WHERE cid=%d" |
| 278 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 279 | " AND NOT EXISTS(SELECT 1 FROM plink y" |
| 280 | " WHERE y.pid=x.cid AND y.cid=x.pid)", |
| 281 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -270,11 +270,11 @@ | |
| 270 | int rid, /* record id of the file to send */ |
| 271 | int isPrivate, /* True if rid is a private artifact */ |
| 272 | Blob *pContent, /* The content of the file to send */ |
| 273 | Blob *pUuid /* The UUID of the file to send */ |
| 274 | ){ |
| 275 | static const char *const azQuery[] = { |
| 276 | "SELECT pid FROM plink x" |
| 277 | " WHERE cid=%d" |
| 278 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 279 | " AND NOT EXISTS(SELECT 1 FROM plink y" |
| 280 | " WHERE y.pid=x.cid AND y.cid=x.pid)", |
| 281 |