| | @@ -264,38 +264,64 @@ |
| 264 | 264 | ** resulting ZIP archive contains a single file which is the RID |
| 265 | 265 | ** object. |
| 266 | 266 | ** |
| 267 | 267 | ** If the RID object does not exist in the repository, then |
| 268 | 268 | ** pZip is zeroed. |
| 269 | +** |
| 270 | +** zSynthDir is a "synthetic" subdirectory which all zipped files get |
| 271 | +** added to as part of the zip file. It may be 0 or an empty string, |
| 272 | +** in which case it is ignored. The intention is to create a zip which |
| 273 | +** politely expands into a subdir instead of filling your current dir |
| 274 | +** with source files. For example, pass a UUID or "ProjectName". |
| 275 | +** |
| 269 | 276 | */ |
| 270 | | -void zip_of_baseline(int rid, Blob *pZip){ |
| 277 | +void zip_of_baseline(int rid, Blob *pZip, char const * zSynthDir ){ |
| 271 | 278 | int i; |
| 272 | 279 | Blob mfile, file, hash; |
| 273 | 280 | Manifest m; |
| 274 | | - |
| 281 | + char const * zDir = (zSynthDir && zSynthDir[0]) ? zSynthDir : ""; |
| 275 | 282 | content_get(rid, &mfile); |
| 276 | 283 | if( blob_size(&mfile)==0 ){ |
| 277 | 284 | blob_zero(pZip); |
| 278 | 285 | return; |
| 279 | 286 | } |
| 280 | 287 | blob_zero(&file); |
| 281 | 288 | blob_zero(&hash); |
| 282 | 289 | blob_copy(&file, &mfile); |
| 283 | 290 | zip_open(); |
| 291 | + |
| 292 | + const int dirLen = strlen(zDir); |
| 293 | + char zPrefix[dirLen+2]; |
| 294 | + memset(zPrefix, 0, sizeof(zPrefix)); |
| 295 | + if( zDir[0] ){ |
| 296 | + snprintf( zPrefix, sizeof(zPrefix), "%s/", zDir ); |
| 297 | + } |
| 298 | + const int bufsize = 512; |
| 299 | + char aSBuf[bufsize]; |
| 300 | + int prxLen = strlen(zPrefix); |
| 301 | + memcpy(aSBuf, zPrefix, prxLen); |
| 302 | + char * zHead = aSBuf + prxLen; |
| 303 | + /* Rather than use a lot of mprintf()s here, we reuse aSBuf as a |
| 304 | + ** buffer for the prefix + current file name. zHead keeps track |
| 305 | + ** of where we should write file names to this buffer. |
| 306 | + */ |
| 284 | 307 | if( manifest_parse(&m, &mfile) ){ |
| 285 | 308 | zip_set_timedate(m.rDate); |
| 286 | | - zip_add_file("manifest", &file); |
| 309 | + snprintf( zHead, bufsize, "manifest" ); |
| 310 | + zip_add_file(aSBuf, &file); |
| 287 | 311 | sha1sum_blob(&file, &hash); |
| 288 | 312 | blob_reset(&file); |
| 289 | 313 | blob_append(&hash, "\n", 1); |
| 290 | | - zip_add_file("manifest.uuid", &hash); |
| 314 | + snprintf( zHead, bufsize, "manifest.uuid" ); |
| 315 | + zip_add_file(aSBuf, &hash); |
| 291 | 316 | blob_reset(&hash); |
| 292 | 317 | for(i=0; i<m.nFile; i++){ |
| 293 | 318 | int fid = uuid_to_rid(m.aFile[i].zUuid, 0); |
| 294 | 319 | if( fid ){ |
| 295 | 320 | content_get(fid, &file); |
| 296 | | - zip_add_file(m.aFile[i].zName, &file); |
| 321 | + snprintf( zHead, bufsize, "%s", m.aFile[i].zName ); |
| 322 | + zip_add_file( aSBuf, &file); |
| 297 | 323 | blob_reset(&file); |
| 298 | 324 | } |
| 299 | 325 | } |
| 300 | 326 | manifest_clear(&m); |
| 301 | 327 | }else{ |
| | @@ -316,11 +342,11 @@ |
| 316 | 342 | if( g.argc!=4 ){ |
| 317 | 343 | usage("UUID ZIPFILE"); |
| 318 | 344 | } |
| 319 | 345 | db_must_be_within_tree(); |
| 320 | 346 | rid = name_to_rid(g.argv[2]); |
| 321 | | - zip_of_baseline(rid, &zip); |
| 347 | + zip_of_baseline(rid, &zip, g.argv[2]); |
| 322 | 348 | blob_write_to_file(&zip, g.argv[3]); |
| 323 | 349 | } |
| 324 | 350 | |
| 325 | 351 | /* |
| 326 | 352 | ** WEBPAGE: zip |
| | @@ -348,10 +374,10 @@ |
| 348 | 374 | rid = name_to_rid(zName); |
| 349 | 375 | if( rid==0 ){ |
| 350 | 376 | @ Not found |
| 351 | 377 | return; |
| 352 | 378 | } |
| 353 | | - zip_of_baseline(rid, &zip); |
| 379 | + zip_of_baseline(rid, &zip, zName); |
| 354 | 380 | cgi_set_content(&zip); |
| 355 | 381 | cgi_set_content_type("application/zip"); |
| 356 | 382 | cgi_reply(); |
| 357 | 383 | } |
| 358 | 384 | |