Overview
SHA1 Hash: | e146d800ac37390cfec72c43ddbb88f583970c89 |
---|---|
Date: | 2008-11-09 19:22:06 |
User: | drh |
Comment: | Add the "mv" and "rename" commands (aliases for the same thing). |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/add.c from [8c54ff6ce9] to [905321226f].
@@ -96,11 +96,16 @@ ** COMMAND: rm ** COMMAND: del ** ** Usage: %fossil rm FILE... ** or: %fossil del FILE... +** ** Remove one or more files from the tree. +** +** This command does not remove the files from disk. It just marks the +** files as no longer being part of the project. In other words, future +** changes to the named files will not be versioned. */ void del_cmd(void){ int i; int vid; @@ -126,7 +131,108 @@ } blob_reset(&pathname); free(zName); } db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0"); + db_end_transaction(0); +} + +/* +** Rename a single file. +** +** The original name of the file is zOrig. The new filename is zNew. +*/ +static void mv_one_file(int vid, const char *zOrig, const char *zNew){ + printf("RENAME %s %s\n", zOrig, zNew); + db_multi_exec( + "UPDATE vfile SET pathname='%s' WHERE pathname='%s' AND vid=%d", + zNew, zOrig, vid + ); +} + +/* +** COMMAND: mv +** COMMAND: rename +** +** Usage: %fossil mv|rename OLDNAME NEWNAME +** or: %fossil mv|rename OLDNAME... DIR +** +** Move or rename one or more files within the tree +** +** This command does rename the files on disk. All this command does is +** record the fact that filenames have changed so that appropriate notations +** can be made at the next commit/checkin. +*/ +void mv_cmd(void){ + int i; + int vid; + char *zDest; + Blob dest; + Stmt q; + + db_must_be_within_tree(); + vid = db_lget_int("checkout", 0); + if( vid==0 ){ + fossil_panic("no checkout rename files in"); + } + if( g.argc<4 ){ + usage("OLDNAME NEWNAME"); + } + zDest = g.argv[g.argc-1]; + db_begin_transaction(); + file_tree_name(zDest, &dest, 1); + db_multi_exec( + "UPDATE vfile SET origname=pathname WHERE origname IS NULL;" + ); + db_multi_exec( + "CREATE TEMP TABLE mv(f TEXT UNIQUE ON CONFLICT IGNORE, t TEXT);" + ); + if( file_isdir(zDest)!=1 ){ + Blob orig; + if( g.argc!=4 ){ + usage("OLDNAME NEWNAME"); + } + file_tree_name(g.argv[2], &orig, 1); + db_multi_exec( + "INSERT INTO mv VALUES(%B,%B)", &orig, &dest + ); + }else{ + for(i=2; i<g.argc-1; i++){ + Blob orig; + char *zOrig; + int nOrig; + file_tree_name(g.argv[i], &orig, 1); + zOrig = blob_str(&orig); + nOrig = blob_size(&orig); + db_prepare(&q, + "SELECT pathname FROM vfile" + " WHERE vid=%d" + " AND (pathname='%s' OR pathname GLOB '%s/*')" + " ORDER BY 1", + vid, zOrig, zOrig + ); + while( db_step(&q)==SQLITE_ROW ){ + const char *zPath = db_column_text(&q, 0); + int nPath = db_column_bytes(&q, 0); + const char *zTail; + if( nPath==nOrig ){ + zTail = file_tail(zPath); + }else{ + zTail = &zPath[nOrig+1]; + } + db_multi_exec( + "INSERT INTO mv VALUES('%s','%s/%s')", + zPath, blob_str(&dest), zTail + ); + } + db_finalize(&q); + } + } + db_prepare(&q, "SELECT f, t FROM mv ORDER BY f"); + while( db_step(&q)==SQLITE_ROW ){ + const char *zFrom = db_column_text(&q, 0); + const char *zTo = db_column_text(&q, 1); + mv_one_file(vid, zFrom, zTo); + } + db_finalize(&q); db_end_transaction(0); }
Modified src/checkin.c from [ad8e78b43e] to [0b6152b93c].
@@ -36,18 +36,21 @@ */ static void status_report(Blob *report, const char *zPrefix){ Stmt q; int nPrefix = strlen(zPrefix); db_prepare(&q, - "SELECT pathname, deleted, chnged, rid FROM vfile " - "WHERE file_is_selected(id) AND (chnged OR deleted OR rid=0) ORDER BY 1" + "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)" + " FROM vfile " + " WHERE file_is_selected(id)" + " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1" ); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); int isDeleted = db_column_int(&q, 1); int isChnged = db_column_int(&q,2); int isNew = db_column_int(&q,3)==0; + int isRenamed = db_column_int(&q,4); char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname); blob_append(report, zPrefix, nPrefix); if( isDeleted ){ blob_appendf(report, "DELETED %s\n", zPathname); }else if( access(zFullName, 0) ){ @@ -58,12 +61,14 @@ blob_appendf(report, "DELETED %s\n", zPathname); }else if( isChnged==2 ){ blob_appendf(report, "UPDATED_BY_MERGE %s\n", zPathname); }else if( isChnged==3 ){ blob_appendf(report, "ADDED_BY_MERGE %s\n", zPathname); - }else{ + }else if( isChnged==1 ){ blob_appendf(report, "EDITED %s\n", zPathname); + }else if( isRenamed ){ + blob_appendf(report, "RENAMED %s\n", zPathname); } free(zFullName); } db_finalize(&q); db_prepare(&q, "SELECT uuid FROM vmerge JOIN blob ON merge=rid" @@ -127,26 +132,32 @@ Stmt q; db_must_be_within_tree(); vid = db_lget_int("checkout", 0); vfile_check_signature(vid); - db_prepare(&q, "SELECT pathname, deleted, rid, chnged FROM vfile" - " ORDER BY 1"); + db_prepare(&q, + "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" + " FROM vfile" + " ORDER BY 1" + ); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); int isDeleted = db_column_int(&q, 1); int isNew = db_column_int(&q,2)==0; int chnged = db_column_int(&q,3); + int renamed = db_column_int(&q,4); char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname); if( isNew ){ printf("ADDED %s\n", zPathname); }else if( access(zFullName, 0) ){ printf("MISSING %s\n", zPathname); }else if( isDeleted ){ printf("DELETED %s\n", zPathname); }else if( chnged ){ printf("EDITED %s\n", zPathname); + }else if( renamed ){ + printf("RENAMED %s\n", zPathname); }else{ printf("UNCHANGED %s\n", zPathname); } free(zFullName); } @@ -480,28 +491,35 @@ blob_appendf(&manifest, "C %F\n", blob_str(&comment)); zDate = db_text(0, "SELECT datetime('now')"); zDate[10] = 'T'; blob_appendf(&manifest, "D %s\n", zDate); db_prepare(&q, - "SELECT pathname, uuid FROM vfile JOIN blob ON vfile.mrid=blob.rid" + "SELECT pathname, uuid, origname" + " FROM vfile JOIN blob ON vfile.mrid=blob.rid" " WHERE NOT deleted AND vfile.vid=%d" " ORDER BY 1", vid); blob_zero(&filename); blob_appendf(&filename, "%s/", g.zLocalRoot); nBasename = blob_size(&filename); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zUuid = db_column_text(&q, 1); + const char *zOrig = db_column_text(&q, 2); const char *zPerm; blob_append(&filename, zName, -1); if( file_isexe(blob_str(&filename)) ){ zPerm = " x"; }else{ zPerm = ""; } blob_resize(&filename, nBasename); - blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm); + if( zOrig==0 || strcmp(zOrig,zName)==0 ){ + blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm); + }else{ + if( zPerm[0]==0 ){ zPerm = " w"; } + blob_appendf(&manifest, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig); + } } blob_reset(&filename); db_finalize(&q); zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); blob_appendf(&manifest, "P %s", zUuid); @@ -557,11 +575,12 @@ /* Update the vfile and vmerge tables */ db_multi_exec( "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND file_is_selected(id);" "DELETE FROM vmerge WHERE file_is_selected(id) OR id=0;" "UPDATE vfile SET vid=%d;" - "UPDATE vfile SET rid=mrid, chnged=0, deleted=0 WHERE file_is_selected(id);" + "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL" + " WHERE file_is_selected(id);" , vid, nvid ); db_lset_int("checkout", nvid); /* Verify that the repository checksum matches the expected checksum @@ -791,11 +810,11 @@ ** least one. */ blob_appendf(&manifest, "P"); for (i=0;i<zParentCount;i++) { - char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents [i]); + char* zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", zParents[i]); blob_appendf(&manifest, " %s", zUuid); free(zUuid); } blob_appendf(&manifest, "\n");
Modified src/checkout.c from [b372b89d4e] to [01a97dfc51].
@@ -40,11 +40,12 @@ int vid; db_must_be_within_tree(); vid = db_lget_int("checkout",0); if( vid==0 ) return 2; vfile_check_signature(vid); - return db_exists("SELECT 1 FROM vfile WHERE chnged"); + return db_exists("SELECT 1 FROM vfile WHERE chnged" + " OR coalesce(origname!=pathname,0)"); } /* ** Undo the current check-out. Unlink all files from the disk. ** Clear the VFILE table.
Modified src/db.c from [47e57e78e7] to [d8256506fc].
@@ -674,17 +674,28 @@ ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. */ static int isValidLocalDb(const char *zDbName){ i64 lsize; + int rc; + sqlite3_stmt *pStmt; + if( access(zDbName, F_OK) ) return 0; lsize = file_size(zDbName); if( lsize%1024!=0 || lsize<4096 ) return 0; db_open_or_attach(zDbName, "localdb"); g.localOpen = 1; db_open_config(); db_open_repository(0); + + /* If the "origname" column is missing from the vfile table, then + ** add it now. */ + rc = sqlite3_prepare(g.db, "SELECT origname FROM vfile", -1, &pStmt, 0); + if( rc==SQLITE_ERROR ){ + sqlite3_exec(g.db, "ALTER TABLE vfile ADD COLUMN origname TEXT", 0, 0, 0); + } + return 1; } /* ** Locate the root directory of the local repository tree. The root
Modified src/file.c from [d20fa8930e] to [3bd9bc50a5].
@@ -50,10 +50,23 @@ struct stat buf; if( stat(zFilename, &buf)!=0 ){ return -1; } return buf.st_mtime; +} + +/* +** Return the tail of a file pathname. The tail is the last component +** of the path. For example, the tail of "/a/b/c.d" is "c.d". +*/ +const char *file_tail(const char *z){ + const char *zTail = z; + while( z[0] ){ + if( z[0]=='/' ) zTail = &z[1]; + z++; + } + return zTail; } /* ** Copy the content of a file from one place to another. */
Modified src/schema.c from [cf525ce8ed] to [353a2ed8b8].
@@ -337,12 +337,12 @@ @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry @ value CLOB, -- Content of the named parameter @ CHECK( typeof(name)='text' AND length(name)>=1 ) @ ); @ -@ -- Each entry in the vfile table represents a single file or folder -@ -- that is part of a version. +@ -- Each entry in the vfile table represents a single file in the +@ -- current checkout. @ -- @ -- The file.rid field is 0 for files or folders that have been @ -- added but not yet committed. @ -- @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have @@ -359,11 +359,12 @@ @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge -@ pathname TEXT, -- Full pathname +@ pathname TEXT, -- Full pathname relative to root +@ origname TEXT -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); @ @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another