aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.cpp6
-rw-r--r--src/repository.cpp73
-rw-r--r--src/repository.h15
-rw-r--r--src/ruleparser.cpp4
-rw-r--r--src/ruleparser.h3
-rw-r--r--src/svn.cpp28
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<QString, AnnotatedTag>::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<QString, Branch> branches;
+ QHash<QString, AnnotatedTag> 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 <nobody@localhost>";
@@ -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;
}
}