From a5fd311b84821f8cfa9ce89725501385070e744d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 8 Jun 2009 11:06:17 +0200 Subject: [PATCH] Add support for annotated tags --- src/main.cpp | 6 ++++- src/repository.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/repository.h | 15 +++++++++++ src/ruleparser.cpp | 4 +++ src/ruleparser.h | 3 ++- src/svn.cpp | 28 +++++++++++++++++---- 6 files changed, 121 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8308eb6..abe9c28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,7 +85,11 @@ int main(int argc, char **argv) if (!svn.exportRevision(i)) break; - qDeleteAll(repositories); + foreach (Repository *repo, repositories) { + repo->finalizeTags(); + delete repo; + } + // success return 0; } diff --git a/src/repository.cpp b/src/repository.cpp index cfe4db9..182309c 100644 --- a/src/repository.cpp +++ b/src/repository.cpp @@ -142,7 +142,8 @@ void Repository::createBranch(const QString &branch, int revnum, } fastImport.write("reset " + branchRef + "\nfrom " + branchFromRef + "\n\n" - "progress Branch " + branchRef + " created from " + branchFromRef + "\n\n"); + "progress Branch " + branchRef + " created from " + + branchFromRef + " r" + QByteArray::number(revnum) + "\n\n"); } Repository::Transaction *Repository::newTransaction(const QString &branch, const QString &svnprefix, @@ -169,6 +170,76 @@ Repository::Transaction *Repository::newTransaction(const QString &branch, const return txn; } +void Repository::createAnnotatedTag(const QString &ref, const QString &svnprefix, + int revnum, + const QByteArray &author, uint dt, + const QByteArray &log) +{ + QString tagName = ref; + if (tagName.startsWith("refs/tags/")) + tagName.remove(0, 10); + + if (!annotatedTags.contains(tagName)) + printf("Creating annotated tag %s (%s)\n", qPrintable(tagName), qPrintable(ref)); + else + printf("Re-creating annotated tag %s\n", qPrintable(tagName)); + + AnnotatedTag &tag = annotatedTags[tagName]; + tag.supportingRef = ref; + tag.svnprefix = svnprefix.toUtf8(); + tag.revnum = revnum; + tag.author = author; + tag.log = log; + tag.dt = dt; +} + +void Repository::finalizeTags() +{ + if (annotatedTags.isEmpty()) + return; + + printf("Finalising tags for %s...", qPrintable(name)); + startFastImport(); + + QHash::ConstIterator it = annotatedTags.constBegin(); + for ( ; it != annotatedTags.constEnd(); ++it) { + const QString &tagName = it.key(); + const AnnotatedTag &tag = it.value(); + + QByteArray message = tag.log; + if (!message.endsWith('\n')) + message += '\n'; + if (Options::globalOptions->switches.value("metadata", true)) + message += "\nsvn path=" + tag.svnprefix + "; revision=" + QByteArray::number(tag.revnum) + "\n"; + + { + QByteArray branchRef = tag.supportingRef.toUtf8(); + if (!branchRef.startsWith("refs/")) + branchRef.prepend("refs/heads/"); + + QTextStream s(&fastImport); + s << "progress Creating annotated tag " << tagName << " from ref " << branchRef << endl + << "tag " << tagName << endl + << "from " << branchRef << endl + << "tagger " << QString::fromUtf8(tag.author) << ' ' << tag.dt << " -0000" << endl + << "data " << message.length() << endl; + } + + fastImport.write(message); + fastImport.putChar('\n'); + if (!fastImport.waitForBytesWritten(-1)) + qFatal("Failed to write to process: %s", qPrintable(fastImport.errorString())); + + printf(" %s", qPrintable(tagName)); + fflush(stdout); + } + + while (fastImport.bytesToWrite()) + if (!fastImport.waitForBytesWritten(-1)) + qFatal("Failed to write to process: %s", qPrintable(fastImport.errorString())); + printf("\n"); +} + void Repository::startFastImport() { if (fastImport.state() == QProcess::NotRunning) { diff --git a/src/repository.h b/src/repository.h index c5e70fe..ad23559 100644 --- a/src/repository.h +++ b/src/repository.h @@ -62,13 +62,28 @@ public: const QString &branchFrom, int revFrom); Transaction *newTransaction(const QString &branch, const QString &svnprefix, int revnum); + void createAnnotatedTag(const QString &name, const QString &svnprefix, int revnum, + const QByteArray &author, uint dt, + const QByteArray &log); + void finalizeTags(); + private: struct Branch { int created; }; + struct AnnotatedTag + { + QString supportingRef; + QByteArray svnprefix; + QByteArray author; + QByteArray log; + uint dt; + int revnum; + }; QHash branches; + QHash annotatedTags; QString name; QProcess fastImport; int commitCount; diff --git a/src/ruleparser.cpp b/src/ruleparser.cpp index 0f675dd..6e799c4 100644 --- a/src/ruleparser.cpp +++ b/src/ruleparser.cpp @@ -55,6 +55,7 @@ void Rules::load() QRegExp matchRepoLine("repository\\s+(\\S+)", Qt::CaseInsensitive); QRegExp matchBranchLine("branch\\s+(\\S+)", Qt::CaseInsensitive); QRegExp matchRevLine("(min|max) revision (\\d+)", Qt::CaseInsensitive); + QRegExp matchAnnotateLine("annotated\\s+(\\S+)", Qt::CaseInsensitive); QTextStream s(&file); enum { ReadingNone, ReadingRepository, ReadingMatch } state = ReadingNone; @@ -109,6 +110,9 @@ void Rules::load() else qFatal("Invalid action \"%s\" on line %d", qPrintable(action), lineNumber); continue; + } else if (matchAnnotateLine.exactMatch(line)) { + match.annotate = matchAnnotateLine.cap(1) == "true"; + continue; } else if (line == "end match") { if (!match.repository.isEmpty()) match.action = Match::Export; diff --git a/src/ruleparser.h b/src/ruleparser.h index 9525f14..2e0904e 100644 --- a/src/ruleparser.h +++ b/src/ruleparser.h @@ -47,6 +47,7 @@ public: int minRevision; int maxRevision; int lineNumber; + bool annotate; enum Action { Ignore, @@ -54,7 +55,7 @@ public: Recurse } action; - Match() : minRevision(-1), maxRevision(-1), lineNumber(0), action(Ignore) { } + Match() : minRevision(-1), maxRevision(-1), lineNumber(0), annotate(false), action(Ignore) { } }; Rules(const QString &filename); diff --git a/src/svn.cpp b/src/svn.cpp index 4bf4e9e..aff7191 100644 --- a/src/svn.cpp +++ b/src/svn.cpp @@ -365,6 +365,11 @@ public: svn_fs_root_t *fs_root; int revnum; + // must call fetchRevProps first: + QByteArray authorident; + QByteArray log; + uint epoch; + SvnRevision(int revision, svn_fs_t *f, apr_pool_t *parent_pool) : pool(parent_pool), fs(f), fs_root(0), revnum(revision) { @@ -377,6 +382,7 @@ public: } int prepareTransactions(); + int fetchRevProps(); int commit(); int exportEntry(const char *path, const svn_fs_path_change_t *change, apr_hash_t *changes); @@ -440,18 +446,17 @@ int SvnRevision::prepareTransactions() return EXIT_SUCCESS; } -int SvnRevision::commit() +int SvnRevision::fetchRevProps() { - // now create the commit apr_hash_t *revprops; SVN_ERR(svn_fs_revision_proplist(&revprops, fs, revnum, pool)); svn_string_t *svnauthor = (svn_string_t*)apr_hash_get(revprops, "svn:author", APR_HASH_KEY_STRING); svn_string_t *svndate = (svn_string_t*)apr_hash_get(revprops, "svn:date", APR_HASH_KEY_STRING); svn_string_t *svnlog = (svn_string_t*)apr_hash_get(revprops, "svn:log", APR_HASH_KEY_STRING); - QByteArray log = (char *)svnlog->data; - QByteArray authorident = svnauthor ? identities.value((char *)svnauthor->data) : QByteArray(); - time_t epoch = get_epoch((char*)svndate->data); + log = (char *)svnlog->data; + authorident = svnauthor ? identities.value((char *)svnauthor->data) : QByteArray(); + epoch = get_epoch((char*)svndate->data); if (authorident.isEmpty()) { if (!svnauthor || svn_string_isempty(svnauthor)) authorident = "nobody "; @@ -459,7 +464,14 @@ int SvnRevision::commit() authorident = svnauthor->data + QByteArray(" <") + svnauthor->data + QByteArray("@localhost>"); } + return EXIT_SUCCESS; +} +int SvnRevision::commit() +{ + // now create the commit + if (fetchRevProps() != EXIT_SUCCESS) + return EXIT_FAILURE; foreach (Repository::Transaction *txn, transactions) { txn->setAuthor(authorident); txn->setDateTime(epoch); @@ -596,6 +608,12 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change_t *cha } repo->createBranch(branch, revnum, prevbranch, rev_from); + if (rule.annotate) { + // create an annotated tag + fetchRevProps(); + repo->createAnnotatedTag(branch, svnprefix, revnum, authorident, + epoch, log); + } return EXIT_SUCCESS; } } -- 2.11.4.GIT