/* ** Output the differences between two check-ins. */ static void diff_all_two_versions( const char *zFrom, const char *zTo, const char *zDiffCmd, int ignoreEolWs ){ Manifest mFrom, mTo; int iFrom, iTo; manifest_from_name(zFrom, &mFrom); manifest_from_name(zTo, &mTo); iFrom = iTo = 0; while( iFrom<mFrom.nFile && iTo<mTo.nFile ){ int cmp; if( iFrom>=mFrom.nFile ){ cmp = +1; }else if( iTo>=mTo.nFile ){ cmp = -1; }else{ cmp = strcmp(mFrom.aFile[iFrom].zName, mTo.aFile[iTo].zName); } if( cmp<0 ){ printf("DELETED %s\n", mFrom.aFile[iFrom].zName); iFrom++; }else if( cmp>0 ){ printf("ADDED %s\n", mTo.aFile[iTo].zName); iTo++; }else if( strcmp(mFrom.aFile[iFrom].zUuid, mTo.aFile[iTo].zUuid)==0 ){ /* No changes */ iFrom++; iTo++; }else{ Blob f1, f2; int rid; printf("CHANGED %s\n", mFrom.aFile[iFrom].zName); printf("Index: %s\n=======================================" "============================\n", mFrom.aFile[iFrom].zName ); rid = uuid_to_rid(mFrom.aFile[iFrom].zUuid, 0); content_get(rid, &f1); rid = uuid_to_rid(mTo.aFile[iTo].zUuid, 0); content_get(rid, &f2); diff_file_mem(&f1, &f2, mFrom.aFile[iFrom].zName, zDiffCmd, ignoreEolWs); blob_reset(&f1); blob_reset(&f2); iFrom++; iTo++; } } manifest_clear(&mFrom); manifest_clear(&mTo); }
/* ** Get the contents of a file within the check-in "revision". If ** revision==NULL then get the file content for the current checkout. */ int historical_version_of_file( const char *revision, /* The check-in containing the file */ const char *file, /* Full treename of the file */ Blob *content, /* Put the content here */ int *pIsLink, /* Set to true if file is link. */ int *pIsExe, /* Set to true if file is executable */ int *pIsBin, /* Set to true if file is binary */ int errCode /* Error code if file not found. Panic if <= 0. */ ) { Manifest *pManifest; ManifestFile *pFile; int rid=0; if( revision ) { rid = name_to_typed_rid(revision,"ci"); } else if( !g.localOpen ) { rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci"); } else { rid = db_lget_int("checkout", 0); } if( !is_a_version(rid) ) { if( errCode>0 ) return errCode; fossil_fatal("no such check-in: %s", revision); } pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0); if( pManifest ) { pFile = manifest_file_find(pManifest, file); if( pFile ) { int rc; rid = uuid_to_rid(pFile->zUuid, 0); if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE ); if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK ); manifest_destroy(pManifest); rc = content_get(rid, content); if( rc && pIsBin ) { *pIsBin = looks_like_binary(content); } return rc; } manifest_destroy(pManifest); if( errCode<=0 ) { fossil_fatal("file %s does not exist in check-in: %s", file, revision); } } else if( errCode<=0 ) { if( revision==0 ) { revision = db_text("current", "SELECT uuid FROM blob WHERE rid=%d", rid); } fossil_fatal("could not parse manifest for check-in: %s", revision); } return errCode; }
/* ** Compute an aggregate MD5 checksum over the repository image of every ** file in manifest vid. The file names are part of the checksum. The ** resulting checksum is suitable for use as the R-card of a manifest. ** ** Return the resulting checksum in blob pOut. ** ** If pManOut is not NULL then fill it with the checksum found in the ** "R" card near the end of the manifest. ** ** In a well-formed manifest, the two checksums computed here, pOut and ** pManOut, should be identical. */ void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){ int fid; Blob file; Blob err; Manifest *pManifest; ManifestFile *pFile; char zBuf[100]; blob_zero(pOut); blob_zero(&err); if( pManOut ){ blob_zero(pManOut); } db_must_be_within_tree(); pManifest = manifest_get(vid, CFTYPE_MANIFEST, &err); if( pManifest==0 ){ fossil_fatal("manifest file (%d) is malformed:\n%s\n", vid, blob_str(&err)); } manifest_file_rewind(pManifest); while( (pFile = manifest_file_next(pManifest,0))!=0 ){ if( pFile->zUuid==0 ) continue; fid = uuid_to_rid(pFile->zUuid, 0); md5sum_step_text(pFile->zName, -1); content_get(fid, &file); sqlite3_snprintf(sizeof(zBuf), zBuf, " %d\n", blob_size(&file)); md5sum_step_text(zBuf, -1); md5sum_step_blob(&file); blob_reset(&file); } if( pManOut ){ if( pManifest->zRepoCksum ){ blob_append(pManOut, pManifest->zRepoCksum, -1); }else{ blob_zero(pManOut); } } manifest_destroy(pManifest); md5sum_finish(pOut); }
/* ** Given the RID for a checkin, construct a tarball containing ** all files in that checkin ** ** If RID is for an object that is not a real manifest, then the ** resulting tarball contains a single file which is the RID ** object. ** ** If the RID object does not exist in the repository, then ** pTar is zeroed. ** ** zDir is a "synthetic" subdirectory which all files get ** added to as part of the tarball. It may be 0 or an empty string, in ** which case it is ignored. The intention is to create a tarball which ** politely expands into a subdir instead of filling your current dir ** with source files. For example, pass a UUID or "ProjectName". ** */ void tarball_of_checkin(int rid, Blob *pTar, const char *zDir){ Blob mfile, hash, file; Manifest *pManifest; ManifestFile *pFile; Blob filename; int nPrefix; char *zName; unsigned int mTime; content_get(rid, &mfile); if( blob_size(&mfile)==0 ){ blob_zero(pTar); return; } blob_zero(&hash); blob_zero(&filename); if( zDir && zDir[0] ){ blob_appendf(&filename, "%s/", zDir); } nPrefix = blob_size(&filename); pManifest = manifest_get(rid, CFTYPE_MANIFEST); if( pManifest ){ mTime = (pManifest->rDate - 2440587.5)*86400.0; tar_begin(mTime); if( db_get_boolean("manifest", 0) ){ blob_append(&filename, "manifest", -1); zName = blob_str(&filename); tar_add_file(zName, &mfile, 0, mTime); sha1sum_blob(&mfile, &hash); blob_reset(&mfile); blob_append(&hash, "\n", 1); blob_resize(&filename, nPrefix); blob_append(&filename, "manifest.uuid", -1); zName = blob_str(&filename); tar_add_file(zName, &hash, 0, mTime); blob_reset(&hash); } manifest_file_rewind(pManifest); while( (pFile = manifest_file_next(pManifest,0))!=0 ){ int fid = uuid_to_rid(pFile->zUuid, 0); if( fid ){ content_get(fid, &file); blob_resize(&filename, nPrefix); blob_append(&filename, pFile->zName, -1); zName = blob_str(&filename); tar_add_file(zName, &file, manifest_file_mperm(pFile), mTime); blob_reset(&file); } } }else{ sha1sum_blob(&mfile, &hash); blob_append(&filename, blob_str(&hash), 16); zName = blob_str(&filename); mTime = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0;"); tar_begin(mTime); tar_add_file(zName, &mfile, 0, mTime); } manifest_destroy(pManifest); blob_reset(&mfile); blob_reset(&filename); tar_finish(pTar); }