| | @@ -101,10 +101,48 @@ |
| 101 | 101 | rc = 0; |
| 102 | 102 | } |
| 103 | 103 | db_finalize(&q); |
| 104 | 104 | return rc; |
| 105 | 105 | } |
| 106 | + |
| 107 | +/* |
| 108 | +** Write unversioned content into the database. |
| 109 | +*/ |
| 110 | +static void unversioned_write( |
| 111 | + const char *zUVFile, /* Name of the unversioned file */ |
| 112 | + Blob *pContent, /* File content */ |
| 113 | + sqlite3_int64 mtime /* Modification time */ |
| 114 | +){ |
| 115 | + Stmt ins; |
| 116 | + Blob compressed; |
| 117 | + Blob hash; |
| 118 | + |
| 119 | + db_prepare(&ins, |
| 120 | + "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)" |
| 121 | + " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)" |
| 122 | + ); |
| 123 | + sha1sum_blob(pContent, &hash); |
| 124 | + blob_compress(pContent, &compressed); |
| 125 | + db_bind_text(&ins, ":name", zUVFile); |
| 126 | + db_bind_int(&ins, ":rcvid", g.rcvid); |
| 127 | + db_bind_int64(&ins, ":mtime", mtime); |
| 128 | + db_bind_text(&ins, ":hash", blob_str(&hash)); |
| 129 | + db_bind_int(&ins, ":sz", blob_size(pContent)); |
| 130 | + if( blob_size(&compressed) <= 0.8*blob_size(pContent) ){ |
| 131 | + db_bind_int(&ins, ":encoding", 1); |
| 132 | + db_bind_blob(&ins, ":content", &compressed); |
| 133 | + }else{ |
| 134 | + db_bind_int(&ins, ":encoding", 0); |
| 135 | + db_bind_blob(&ins, ":content", pContent); |
| 136 | + } |
| 137 | + db_step(&ins); |
| 138 | + blob_reset(&compressed); |
| 139 | + blob_reset(&hash); |
| 140 | + db_finalize(&ins); |
| 141 | + db_unset("uv-hash", 0); |
| 142 | +} |
| 143 | + |
| 106 | 144 | |
| 107 | 145 | /* |
| 108 | 146 | ** Check the status of unversioned file zName. Return an integer status |
| 109 | 147 | ** code as follows: |
| 110 | 148 | ** |
| | @@ -157,10 +195,12 @@ |
| 157 | 195 | ** Changes are not pushed to other repositories until |
| 158 | 196 | ** the next sync. |
| 159 | 197 | ** |
| 160 | 198 | ** cat FILE ... Concatenate the content of FILEs to stdout. |
| 161 | 199 | ** |
| 200 | +** edit FILE Bring up FILE in a text editor for modification. |
| 201 | +** |
| 162 | 202 | ** export FILE OUTPUT Write the content of FILE into OUTPUT on disk |
| 163 | 203 | ** |
| 164 | 204 | ** list | ls Show all unversioned files held in the local repository. |
| 165 | 205 | ** |
| 166 | 206 | ** revert ?URL? Restore the state of all unversioned files in the local |
| | @@ -198,55 +238,27 @@ |
| 198 | 238 | } |
| 199 | 239 | if( memcmp(zCmd, "add", nCmd)==0 ){ |
| 200 | 240 | const char *zIn; |
| 201 | 241 | const char *zAs; |
| 202 | 242 | Blob file; |
| 203 | | - Blob hash; |
| 204 | | - Blob compressed; |
| 205 | | - Stmt ins; |
| 206 | 243 | int i; |
| 207 | 244 | |
| 208 | 245 | zAs = find_option("as",0,1); |
| 209 | 246 | if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE"); |
| 210 | 247 | verify_all_options(); |
| 211 | 248 | db_begin_transaction(); |
| 212 | | - user_select(); |
| 213 | | - g.zIpAddr = "command-line"; |
| 214 | | - content_rcvid_init(); |
| 215 | | - db_prepare(&ins, |
| 216 | | - "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)" |
| 217 | | - " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)" |
| 218 | | - ); |
| 249 | + content_rcvid_init("#!fossil unversioned add"); |
| 219 | 250 | for(i=3; i<g.argc; i++){ |
| 220 | 251 | zIn = zAs ? zAs : g.argv[i]; |
| 221 | 252 | if( zIn[0]==0 || zIn[0]=='/' || !file_is_simple_pathname(zIn,1) ){ |
| 222 | 253 | fossil_fatal("'%Q' is not an acceptable filename", zIn); |
| 223 | 254 | } |
| 224 | 255 | blob_init(&file,0,0); |
| 225 | 256 | blob_read_from_file(&file, g.argv[i]); |
| 226 | | - sha1sum_blob(&file, &hash); |
| 227 | | - blob_compress(&file, &compressed); |
| 228 | | - db_bind_text(&ins, ":name", zIn); |
| 229 | | - db_bind_int(&ins, ":rcvid", g.rcvid); |
| 230 | | - db_bind_int64(&ins, ":mtime", mtime); |
| 231 | | - db_bind_text(&ins, ":hash", blob_str(&hash)); |
| 232 | | - db_bind_int(&ins, ":sz", blob_size(&file)); |
| 233 | | - if( blob_size(&compressed) <= 0.8*blob_size(&file) ){ |
| 234 | | - db_bind_int(&ins, ":encoding", 1); |
| 235 | | - db_bind_blob(&ins, ":content", &compressed); |
| 236 | | - }else{ |
| 237 | | - db_bind_int(&ins, ":encoding", 0); |
| 238 | | - db_bind_blob(&ins, ":content", &file); |
| 239 | | - } |
| 240 | | - db_step(&ins); |
| 241 | | - db_reset(&ins); |
| 242 | | - blob_reset(&compressed); |
| 243 | | - blob_reset(&hash); |
| 257 | + unversioned_write(zIn, &file, mtime); |
| 244 | 258 | blob_reset(&file); |
| 245 | 259 | } |
| 246 | | - db_finalize(&ins); |
| 247 | | - db_unset("uv-hash", 0); |
| 248 | 260 | db_end_transaction(0); |
| 249 | 261 | }else if( memcmp(zCmd, "cat", nCmd)==0 ){ |
| 250 | 262 | int i; |
| 251 | 263 | verify_all_options(); |
| 252 | 264 | db_begin_transaction(); |
| | @@ -256,18 +268,53 @@ |
| 256 | 268 | blob_write_to_file(&content, "-"); |
| 257 | 269 | } |
| 258 | 270 | blob_reset(&content); |
| 259 | 271 | } |
| 260 | 272 | db_end_transaction(0); |
| 273 | + }else if( memcmp(zCmd, "edit", nCmd)==0 ){ |
| 274 | + const char *zEditor; /* Name of the text-editor command */ |
| 275 | + const char *zTFile; /* Temporary file */ |
| 276 | + const char *zUVFile; /* Name of the unversioned file */ |
| 277 | + char *zCmd; /* Command to run the text editor */ |
| 278 | + Blob content; /* Content of the unversioned file */ |
| 279 | + |
| 280 | + verify_all_options(); |
| 281 | + if( g.argc!=4) usage("edit UVFILE"); |
| 282 | + zUVFile = g.argv[3]; |
| 283 | + zEditor = fossil_text_editor(); |
| 284 | + if( zEditor==0 ) fossil_fatal("no text editor - set the VISUAL env variable"); |
| 285 | + zTFile = fossil_temp_filename(); |
| 286 | + if( zTFile==0 ) fossil_fatal("cannot find a temporary filename"); |
| 287 | + db_begin_transaction(); |
| 288 | + content_rcvid_init("#!fossil unversioned edit"); |
| 289 | + if( unversioned_content(zUVFile, &content) ){ |
| 290 | + fossil_fatal("no such uv-file: %Q", zUVFile); |
| 291 | + } |
| 292 | + if( looks_like_binary(&content) ){ |
| 293 | + fossil_fatal("cannot edit binary content"); |
| 294 | + } |
| 295 | + blob_write_to_file(&content, zTFile); |
| 296 | + zCmd = mprintf("%s \"%s\"", zEditor, zTFile); |
| 297 | + if( fossil_system(zCmd) ){ |
| 298 | + fossil_fatal("editor aborted: %Q", zCmd); |
| 299 | + } |
| 300 | + fossil_free(zCmd); |
| 301 | + blob_reset(&content); |
| 302 | + blob_read_from_file(&content, zTFile); |
| 303 | + file_delete(zTFile); |
| 304 | + if( zMtime==0 ) mtime = time(0); |
| 305 | + unversioned_write(zUVFile, &content, mtime); |
| 306 | + db_end_transaction(0); |
| 307 | + blob_reset(&content); |
| 261 | 308 | }else if( memcmp(zCmd, "export", nCmd)==0 ){ |
| 262 | 309 | Blob content; |
| 263 | 310 | verify_all_options(); |
| 264 | 311 | if( g.argc!=5 ) usage("export UVFILE OUTPUT"); |
| 265 | 312 | if( unversioned_content(g.argv[3], &content) ){ |
| 266 | 313 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 267 | 314 | } |
| 268 | | - blob_write_to_file(&content, g.argv[4]); |
| 315 | + blob_write_to_file(&content, g.argv[4]); |
| 269 | 316 | blob_reset(&content); |
| 270 | 317 | }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ |
| 271 | 318 | /* Show the hash value used during uv sync */ |
| 272 | 319 | int debugFlag = find_option("debug",0,0)!=0; |
| 273 | 320 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| | @@ -344,11 +391,11 @@ |
| 344 | 391 | ); |
| 345 | 392 | } |
| 346 | 393 | db_unset("uv-hash", 0); |
| 347 | 394 | db_end_transaction(0); |
| 348 | 395 | }else{ |
| 349 | | - usage("add|cat|export|ls|revert|rm|sync|touch"); |
| 396 | + usage("add|cat|edit|export|ls|revert|rm|sync|touch"); |
| 350 | 397 | } |
| 351 | 398 | } |
| 352 | 399 | |
| 353 | 400 | /* |
| 354 | 401 | ** WEBPAGE: uvlist |
| 355 | 402 | |