Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | The "fossil undo" and "fossil redo" commands remember file mtimes and restore them appropriately. When upgrading through this version, you may need to run "fossil undo --reset" to clear your old undo stack. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
0c37874941c89728f6cc0063a2a44b8b |
| User & Date: | drh 2012-10-10 16:06:37.834 |
References
|
2012-10-11
| ||
| 19:45 | Cherrypick changes [0c37874941c8972], [9ba8a393fcc569b], and [ae092ec605eed11] in order to backport the --setmtime option of "fossil update" and the --age and -t options of "fossil ls" to version 1.19. check-in: 773c6c5f2c user: drh tags: branch-1.19 | |
| 18:33 | Back out the undo/redo logic changes of [0c37874941c89] that caused the mtime to be restored on files. Playing games with mtimes is bad policy. Consider a scenario: "fossil merge; make; fossil undo; make". If the mtimes are reset by undo, then the second "make" above will not work correctly. This is not a complete backout of [0c37874941c89] as the underlying infrastructure used to compute the age of files is retained. check-in: 5c0843a8f1 user: drh tags: trunk | |
Context
|
2012-10-10
| ||
| 20:03 | Add the internal checkin_mtime() function. Use it to implement the --age and -t options to the "fossil ls" command. check-in: 9ba8a393fc user: drh tags: trunk | |
| 16:06 | The "fossil undo" and "fossil redo" commands remember file mtimes and restore them appropriately. When upgrading through this version, you may need to run "fossil undo --reset" to clear your old undo stack. check-in: 0c37874941 user: drh tags: trunk | |
|
2012-10-09
| ||
| 13:30 | Making the raw page download guess the mime type based on filename also for attachments, not only repository files. check-in: 5f3916ac5b user: viriketo tags: trunk | |
Changes
Changes to src/db.c.
| ︙ | ︙ | |||
720 721 722 723 724 725 726 | } /* ** zDbName is the name of a database file. If no other database ** file is open, then open this one. If another database file is ** already open, then attach zDbName using the name zLabel. */ | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
}
/*
** zDbName is the name of a database file. If no other database
** file is open, then open this one. If another database file is
** already open, then attach zDbName using the name zLabel.
*/
void db_open_or_attach(const char *zDbName, const char *zLabel){
if( !g.db ){
g.db = openDatabase(zDbName);
g.zMainDbType = zLabel;
db_connection_init();
}else{
db_attach(zDbName, zLabel);
}
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /* ** On Windows, include the Platform SDK header file. */ #ifdef _WIN32 # include <direct.h> # include <windows.h> #endif /* ** The file status information from the most recent stat() call. ** ** Use _stati64 rather than stat on windows, in order to handle files ** larger than 2GB. | > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /* ** On Windows, include the Platform SDK header file. */ #ifdef _WIN32 # include <direct.h> # include <windows.h> # include <sys/utime.h> #endif /* ** The file status information from the most recent stat() call. ** ** Use _stati64 rather than stat on windows, in order to handle files ** larger than 2GB. |
| ︙ | ︙ | |||
387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
chmod(zFilename, buf.st_mode & ~0111);
rc = 1;
}
}
#endif /* _WIN32 */
return rc;
}
/*
** Delete a file.
*/
void file_delete(const char *zFilename){
#ifdef _WIN32
wchar_t *z = fossil_utf8_to_unicode(zFilename);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
chmod(zFilename, buf.st_mode & ~0111);
rc = 1;
}
}
#endif /* _WIN32 */
return rc;
}
/*
** Set the mtime for a file.
*/
void file_set_mtime(const char *zFilename, i64 newMTime){
#if !defined(_WIN32)
struct timeval tv[2];
memset(tv, 0, sizeof(tv[0])*2);
tv[0].tv_sec = newMTime;
tv[1].tv_sec = newMTime;
utimes(zFilename, tv);
#else
struct utimbuf tb;
wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
tb.actime = newMTime;
tb.modtime = newMTime;
_wutime(zMbcs, &tb);
fossil_mbcs_free(zMbcs);
#endif
}
/*
** COMMAND: test-set-mtime
**
** Usage: %fossil test-set-mtime FILENAME DATE/TIME
**
** Sets the mtime of the named file to the date/time shown.
*/
void test_set_mtime(void){
const char *zFile;
char *zDate;
i64 iMTime;
if( g.argc!=4 ){
usage("test-set-mtime FILENAME DATE/TIME");
}
db_open_or_attach(":memory:", "mem");
iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
zFile = g.argv[2];
file_set_mtime(zFile, iMTime);
iMTime = file_wd_mtime(zFile);
zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
}
/*
** Delete a file.
*/
void file_delete(const char *zFilename){
#ifdef _WIN32
wchar_t *z = fossil_utf8_to_unicode(zFilename);
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
i += 2;
while( i<g.argc ) newArgv[j++] = g.argv[i++];
newArgv[j] = 0;
g.argc = j;
g.argv = newArgv;
}
/*
** Make a deep copy of the provided argument array and return it.
*/
static char **copy_args(int argc, char **argv){
char **zNewArgv;
int i;
zNewArgv = fossil_malloc( sizeof(char*)*(argc+1) );
memset(zNewArgv, 0, sizeof(char*)*(argc+1));
for(i=0; i<argc; i++){
zNewArgv[i] = fossil_strdup(argv[i]);
}
return zNewArgv;
}
/*
** This procedure runs first.
*/
int main(int argc, char **argv)
{
const char *zCmdName = "unknown";
| > > | 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 |
i += 2;
while( i<g.argc ) newArgv[j++] = g.argv[i++];
newArgv[j] = 0;
g.argc = j;
g.argv = newArgv;
}
#ifdef FOSSIL_ENABLE_TCL
/*
** Make a deep copy of the provided argument array and return it.
*/
static char **copy_args(int argc, char **argv){
char **zNewArgv;
int i;
zNewArgv = fossil_malloc( sizeof(char*)*(argc+1) );
memset(zNewArgv, 0, sizeof(char*)*(argc+1));
for(i=0; i<argc; i++){
zNewArgv[i] = fossil_strdup(argv[i]);
}
return zNewArgv;
}
#endif
/*
** This procedure runs first.
*/
int main(int argc, char **argv)
{
const char *zCmdName = "unknown";
|
| ︙ | ︙ |
Changes to src/undo.c.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
** true the redo a change. If there is nothing to undo (or redo) then
** this routine is a noop.
*/
static void undo_one(const char *zPathname, int redoFlag){
Stmt q;
char *zFullname;
db_prepare(&q,
| | > > > > > | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
** true the redo a change. If there is nothing to undo (or redo) then
** this routine is a noop.
*/
static void undo_one(const char *zPathname, int redoFlag){
Stmt q;
char *zFullname;
db_prepare(&q,
"SELECT content, existsflag, isExe, isLink, mtime FROM undo"
" WHERE pathname=%Q AND redoflag=%d",
zPathname, redoFlag
);
if( db_step(&q)==SQLITE_ROW ){
int old_exists;
int new_exists;
int old_exe;
int new_exe;
int new_link;
int old_link;
i64 old_mtime, new_mtime;
Blob current;
Blob new;
zFullname = mprintf("%s/%s", g.zLocalRoot, zPathname);
old_link = db_column_int(&q, 3);
new_link = file_wd_islink(zFullname);
new_exists = file_wd_size(zFullname)>=0;
if( new_exists ){
if( new_link ){
blob_read_link(¤t, zFullname);
}else{
blob_read_from_file(¤t, zFullname);
}
new_exe = file_wd_isexe(zFullname);
new_mtime = file_wd_mtime(zFullname);
}else{
blob_zero(¤t);
new_exe = 0;
new_mtime = 0;
}
blob_zero(&new);
old_exists = db_column_int(&q, 1);
old_exe = db_column_int(&q, 2);
old_mtime = db_column_int64(&q, 4);
if( old_exists ){
db_ephemeral_blob(&q, 0, &new);
}
if( old_exists ){
if( new_exists ){
fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname);
}else{
fossil_print("NEW %s\n", zPathname);
}
if( new_exists && (new_link || old_link) ){
file_delete(zFullname);
}
if( old_link ){
symlink_create(blob_str(&new), zFullname);
}else{
blob_write_to_file(&new, zFullname);
}
file_wd_setexe(zFullname, old_exe);
file_set_mtime(zFullname, old_mtime);
}else{
fossil_print("DELETE %s\n", zPathname);
file_delete(zFullname);
}
blob_reset(&new);
free(zFullname);
db_finalize(&q);
db_prepare(&q,
"UPDATE undo SET content=:c, existsflag=%d, isExe=%d, isLink=%d,"
" mtime=%lld, redoflag=NOT redoflag"
" WHERE pathname=%Q",
new_exists, new_exe, new_link, new_mtime, zPathname
);
if( new_exists ){
db_bind_blob(&q, ":c", ¤t);
}
db_step(&q);
blob_reset(¤t);
}
|
| ︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
static const char zSql[] =
@ CREATE TABLE %s.undo(
@ pathname TEXT UNIQUE, -- Name of the file
@ redoflag BOOLEAN, -- 0 for undoable. 1 for redoable
@ existsflag BOOLEAN, -- True if the file exists
@ isExe BOOLEAN, -- True if the file is executable
@ isLink BOOLEAN, -- True if the file is symlink
@ content BLOB -- Saved content
@ );
@ CREATE TABLE %s.undo_vfile AS SELECT * FROM vfile;
@ CREATE TABLE %s.undo_vmerge AS SELECT * FROM vmerge;
;
if( undoDisable ) return;
undo_reset();
| > | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
static const char zSql[] =
@ CREATE TABLE %s.undo(
@ pathname TEXT UNIQUE, -- Name of the file
@ redoflag BOOLEAN, -- 0 for undoable. 1 for redoable
@ existsflag BOOLEAN, -- True if the file exists
@ isExe BOOLEAN, -- True if the file is executable
@ isLink BOOLEAN, -- True if the file is symlink
@ mtime DATETIME, -- File modification time
@ content BLOB -- Saved content
@ );
@ CREATE TABLE %s.undo_vfile AS SELECT * FROM vfile;
@ CREATE TABLE %s.undo_vmerge AS SELECT * FROM vmerge;
;
if( undoDisable ) return;
undo_reset();
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 |
if( !undoActive ) return;
zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
existsFlag = file_wd_size(zFullname)>=0;
isLink = file_wd_islink(zFullname);
db_prepare(&q,
"INSERT OR IGNORE INTO"
| | | | > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
if( !undoActive ) return;
zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
existsFlag = file_wd_size(zFullname)>=0;
isLink = file_wd_islink(zFullname);
db_prepare(&q,
"INSERT OR IGNORE INTO"
" undo(pathname,redoflag,existsflag,isExe,isLink,mtime,content)"
" VALUES(%Q,0,%d,%d,%d,%lld,:c)",
zPathname, existsFlag, file_wd_isexe(zFullname), isLink,
file_wd_mtime(zFullname)
);
if( existsFlag ){
if( isLink ){
blob_read_link(&content, zFullname);
}else{
blob_read_from_file(&content, zFullname);
}
|
| ︙ | ︙ | |||
381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
*/
void undo_cmd(void){
int isRedo = g.argv[1][0]=='r';
int undo_available;
int explainFlag = find_option("explain", 0, 0)!=0;
const char *zCmd = isRedo ? "redo" : "undo";
db_must_be_within_tree();
verify_all_options();
db_begin_transaction();
undo_available = db_lget_int("undo_available", 0);
if( explainFlag ){
if( undo_available==0 ){
fossil_print("No undo or redo is available\n");
}else{
| > | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
*/
void undo_cmd(void){
int isRedo = g.argv[1][0]=='r';
int undo_available;
int explainFlag = find_option("explain", 0, 0)!=0;
const char *zCmd = isRedo ? "redo" : "undo";
db_must_be_within_tree();
if( find_option("reset", 0, 0)!=0 ){ undo_reset(); return; }
verify_all_options();
db_begin_transaction();
undo_available = db_lget_int("undo_available", 0);
if( explainFlag ){
if( undo_available==0 ){
fossil_print("No undo or redo is available\n");
}else{
|
| ︙ | ︙ |