Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 Dec 2012 13:00:41 +0000 (UTC)
From:      Ulrich Spoerlein <uqs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r243982 - in user/uqs/git_conv/svn2git: . src
Message-ID:  <201212071300.qB7D0f3I098809@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: uqs
Date: Fri Dec  7 13:00:41 2012
New Revision: 243982
URL: http://svnweb.freebsd.org/changeset/base/243982

Log:
  Add a copy of the svn2git converter from https://gitorious.org/svn2git/svn2git

Added:
  user/uqs/git_conv/svn2git/
  user/uqs/git_conv/svn2git/fast-export2.pro
  user/uqs/git_conv/svn2git/src/
  user/uqs/git_conv/svn2git/src/CommandLineParser.cpp   (contents, props changed)
  user/uqs/git_conv/svn2git/src/CommandLineParser.h   (contents, props changed)
  user/uqs/git_conv/svn2git/src/main.cpp   (contents, props changed)
  user/uqs/git_conv/svn2git/src/repository.cpp   (contents, props changed)
  user/uqs/git_conv/svn2git/src/repository.h   (contents, props changed)
  user/uqs/git_conv/svn2git/src/ruleparser.cpp   (contents, props changed)
  user/uqs/git_conv/svn2git/src/ruleparser.h   (contents, props changed)
  user/uqs/git_conv/svn2git/src/src.pro
  user/uqs/git_conv/svn2git/src/svn.cpp   (contents, props changed)
  user/uqs/git_conv/svn2git/src/svn.h   (contents, props changed)

Added: user/uqs/git_conv/svn2git/fast-export2.pro
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/uqs/git_conv/svn2git/fast-export2.pro	Fri Dec  7 13:00:41 2012	(r243982)
@@ -0,0 +1,8 @@
+######################################################################
+# Automatically generated by qmake (2.01a) dim. dec. 23 13:48:52 2007
+######################################################################
+
+TEMPLATE = subdirs
+
+# Directories
+SUBDIRS = src

Added: user/uqs/git_conv/svn2git/src/CommandLineParser.cpp
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/uqs/git_conv/svn2git/src/CommandLineParser.cpp	Fri Dec  7 13:00:41 2012	(r243982)
@@ -0,0 +1,403 @@
+/*
+ * This file is part of the vng project
+ * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "CommandLineParser.h"
+
+#include <QDebug>
+#include <QTextStream>
+#include <QStringList>
+#include <QList>
+#include <QHash>
+
+CommandLineParser *CommandLineParser::self = 0;
+
+class CommandLineParser::Private
+{
+public:
+    Private(int argc, char **argv);
+
+    // functions
+    void addDefinitions(const CommandLineOption * options);
+    void setArgumentDefinition(const char *definition);
+    void parse();
+
+    // variables;
+    const int argumentCount;
+    char ** const argumentStrings;
+    bool dirty;
+    int requiredArguments;
+    QString argumentDefinition;
+
+    struct OptionDefinition {
+        OptionDefinition() : optionalParameters(0), requiredParameters(0) { }
+        QString name;
+        QString comment;
+        QChar shortName;
+        int optionalParameters;
+        int requiredParameters;
+    };
+
+    // result of what the user typed
+    struct ParsedOption {
+        QString option;
+        QList<QString> parameters;
+    };
+
+    QList<OptionDefinition> definitions;
+    QHash<QString, ParsedOption> options;
+    QList<QString> arguments;
+    QList<QString> undefinedOptions;
+    QList<QString> errors;
+};
+
+
+CommandLineParser::Private::Private(int argc, char **argv)
+    : argumentCount(argc), argumentStrings(argv), dirty(true),
+    requiredArguments(0)
+{
+}
+
+void CommandLineParser::Private::addDefinitions(const CommandLineOption * options)
+{
+    for (int i=0; options[i].specification != 0; i++) {
+        OptionDefinition definition;
+        QString option = QString::fromLatin1(options[i].specification);
+        // options with optional params are written as "--option required[, optional]
+        if (option.indexOf(QLatin1Char(',')) >= 0 && ( option.indexOf(QLatin1Char('[')) < 0 || option.indexOf(QLatin1Char(']')) < 0) ) {
+            QStringList optionParts = option.split(QLatin1Char(','), QString::SkipEmptyParts);
+            if (optionParts.count() != 2) {
+                qWarning() << "WARN: option definition '" << option << "' is faulty; only one ',' allowed";
+                continue;
+            }
+            foreach (QString s, optionParts) {
+                s = s.trimmed();
+                if (s.startsWith(QLatin1String("--")) && s.length() > 2)
+                    definition.name = s.mid(2);
+                else if (s.startsWith(QLatin1String("-")) && s.length() > 1)
+                    definition.shortName = s.at(1);
+                else {
+                    qWarning() << "WARN: option definition '" << option << "' is faulty; the option should start with a -";
+                    break;
+                }
+            }
+        }
+        else if (option.startsWith(QLatin1String("--")) && option.length() > 2)
+            definition.name = option.mid(2);
+        else
+            qWarning() << "WARN: option definition '" << option << "' has unrecognized format. See the api docs for CommandLineParser for a howto";
+
+        if(definition.name.isEmpty())
+            continue;
+        if (option.indexOf(QLatin1Char(' ')) > 0) {
+            QStringList optionParts = definition.name.split(QLatin1Char(' '), QString::SkipEmptyParts);
+            definition.name = optionParts[0];
+            bool first = true;
+            foreach (QString s, optionParts) {
+                if (first) {
+                    first = false;
+                    continue;
+                }
+                s = s.trimmed();
+                if (s[0].unicode() == '[' && s.endsWith(QLatin1Char(']')))
+                    definition.optionalParameters++;
+                else
+                    definition.requiredParameters++;
+            }
+        }
+
+        definition.comment = QString::fromLatin1(options[i].description);
+        definitions << definition;
+    }
+/*
+    foreach (OptionDefinition def, definitions) {
+        qDebug() << "definition:" << (def.shortName != 0 ? def.shortName : QChar(32)) << "|" << def.name << "|" << def.comment
+            << "|" << def.requiredParameters << "+" << def.optionalParameters;
+    }
+*/
+
+    dirty = true;
+}
+
+void CommandLineParser::Private::setArgumentDefinition(const char *defs)
+{
+    requiredArguments = 0;
+    argumentDefinition = QString::fromLatin1(defs);
+    QStringList optionParts = argumentDefinition.split(QLatin1Char(' '), QString::SkipEmptyParts);
+    bool inArg = false;
+    foreach (QString s, optionParts) {
+        s = s.trimmed();
+        if (s[0].unicode() == '<') {
+            inArg = true;
+            requiredArguments++;
+        }
+        else if (s[0].unicode() == '[')
+            inArg = true;
+        if (s.endsWith(QLatin1Char('>')))
+            inArg = false;
+        else if (!inArg)
+            requiredArguments++;
+    }
+}
+
+void CommandLineParser::Private::parse()
+{
+    if (dirty == false)
+        return;
+    errors.clear();
+    options.clear();
+    arguments.clear();
+    undefinedOptions.clear();
+    dirty = false;
+
+    class OptionProcessor {
+      public:
+        OptionProcessor(Private *d) : clp(d) { }
+
+        void next(Private::ParsedOption &option) {
+            if (! option.option.isEmpty()) {
+                // find the definition to match.
+                OptionDefinition def;
+                foreach (Private::OptionDefinition definition, clp->definitions) {
+                    if (definition.name == option.option) {
+                        def = definition;
+                        break;
+                    }
+                }
+                if (! def.name.isEmpty() && def.requiredParameters >= option.parameters.count() &&
+                        def.requiredParameters + def.optionalParameters <= option.parameters.count())
+                    clp->options.insert(option.option, option);
+                else if (!clp->undefinedOptions.contains(option.option))
+                    clp->undefinedOptions << option.option;
+                else
+                    clp->errors.append(QLatin1String("Not enough arguments passed for option `")
+                            + option.option +QLatin1Char('\''));
+            }
+            option.option.clear();
+            option.parameters.clear();
+        }
+
+      private:
+        CommandLineParser::Private *clp;
+    };
+    OptionProcessor processor(this);
+
+    bool optionsAllowed = true;
+    ParsedOption option;
+    OptionDefinition currentDefinition;
+    for (int i = 1; i < argumentCount; i++) {
+        QString arg = QString::fromLocal8Bit(argumentStrings[i]);
+        if (optionsAllowed) {
+            if (arg == QLatin1String("--")) {
+                optionsAllowed = false;
+                continue;
+            }
+            if (arg.startsWith(QLatin1String("--"))) {
+                processor.next(option);
+                int end = arg.indexOf(QLatin1Char('='));
+                option.option = arg.mid(2, end - 2);
+                if (end > 0)
+                    option.parameters << arg.mid(end+1);
+                continue;
+            }
+            if (arg[0].unicode() == '-' && arg.length() > 1) {
+                for (int x = 1; x < arg.length(); x++) {
+                    bool resolved = false;
+                    foreach (OptionDefinition definition, definitions) {
+                        if (definition.shortName == arg[x]) {
+                            resolved = true;
+                            processor.next(option);
+                            currentDefinition = definition;
+                            option.option = definition.name;
+
+                            if (definition.requiredParameters == 1 && arg.length() >= x+2) {
+                                option.parameters << arg.mid(x+1, arg.length());
+                                x = arg.length();
+                            }
+                            break;
+                        }
+                    }
+                    if (!resolved) { // nothing found; copy char so it ends up in unrecognized
+                        option.option = arg[x];
+                        processor.next(option);
+                    }
+                }
+                continue;
+            }
+        }
+        if (! option.option.isEmpty()) {
+            if (currentDefinition.name != option.option) {
+                // find the definition to match.
+                foreach (OptionDefinition definition, definitions) {
+                    if (definition.name == option.option) {
+                        currentDefinition = definition;
+                        break;
+                    }
+                }
+            }
+            if (currentDefinition.requiredParameters + currentDefinition.optionalParameters <= option.parameters.count())
+                processor.next(option);
+        }
+        if (option.option.isEmpty())
+            arguments << arg;
+        else
+            option.parameters << arg;
+    }
+    processor.next(option);
+
+    if (requiredArguments > arguments.count())
+        errors.append(QLatin1String("Not enough arguments, usage: ") + QString::fromLocal8Bit(argumentStrings[0])
+                + QLatin1Char(' ') + argumentDefinition);
+
+/*
+    foreach (QString key, options.keys()) {
+        ParsedOption p = options[key];
+        qDebug() << "-> " << p.option;
+        foreach (QString v, p.parameters)
+            qDebug() << "   +" << v;
+    }
+    qDebug() << "---";
+    foreach (QString arg, arguments) {
+        qDebug() << arg;
+    }
+*/
+}
+
+// -----------------------------------
+
+
+// static
+void CommandLineParser::init(int argc, char **argv)
+{
+    if (self)
+        delete self;
+    self = new CommandLineParser(argc, argv);
+}
+
+// static
+void CommandLineParser::addOptionDefinitions(const CommandLineOption * optionList)
+{
+    if (!self) {
+        qWarning() << "WARN: CommandLineParser:: Use init before addOptionDefinitions!";
+        return;
+    }
+    self->d->addDefinitions(optionList);
+}
+
+// static
+CommandLineParser *CommandLineParser::instance()
+{
+    return self;
+}
+
+// static
+void CommandLineParser::setArgumentDefinition(const char *definition)
+{
+    if (!self) {
+        qWarning() << "WARN: CommandLineParser:: Use init before addOptionDefinitions!";
+        return;
+    }
+    self->d->setArgumentDefinition(definition);
+}
+
+
+CommandLineParser::CommandLineParser(int argc, char **argv)
+    : d(new Private(argc, argv))
+{
+}
+
+CommandLineParser::~CommandLineParser()
+{
+    delete d;
+}
+
+void CommandLineParser::usage(const QString &name, const QString &argumentDescription)
+{
+    QTextStream cout(stdout, QIODevice::WriteOnly);
+    cout << "Usage: " << d->argumentStrings[0];
+    if (! name.isEmpty())
+        cout << " " << name;
+    if (d->definitions.count())
+        cout << " [OPTION]";
+    if (! argumentDescription.isEmpty())
+        cout << " " << argumentDescription;
+    cout << endl << endl;
+
+    if (d->definitions.count() > 0)
+        cout << "Options:" << endl;
+    int commandLength = 0;
+    foreach (Private::OptionDefinition definition, d->definitions)
+        commandLength = qMax(definition.name.length(), commandLength);
+
+    foreach (Private::OptionDefinition definition, d->definitions) {
+        cout << "    ";
+        if (definition.shortName == 0)
+            cout << "   --";
+        else
+            cout << "-" << definition.shortName << " --";
+        cout << definition.name;
+        for (int i = definition.name.length(); i <= commandLength; i++)
+            cout << ' ';
+         cout << definition.comment <<endl;
+    }
+}
+
+QStringList CommandLineParser::options() const
+{
+    d->parse();
+    return d->options.keys();
+}
+
+bool CommandLineParser::contains(const QString & key) const
+{
+    d->parse();
+    return d->options.contains(key);
+}
+
+QStringList CommandLineParser::arguments() const
+{
+    d->parse();
+    return d->arguments;
+}
+
+QStringList CommandLineParser::undefinedOptions() const
+{
+    d->parse();
+    return d->undefinedOptions;
+}
+
+QString CommandLineParser::optionArgument(const QString &optionName, const QString &defaultValue) const
+{
+    QStringList answer = optionArguments(optionName);
+    if (answer.isEmpty())
+        return defaultValue;
+    return answer.first();
+}
+
+QStringList CommandLineParser::optionArguments(const QString &optionName) const
+{
+    if (! contains(optionName))
+        return QStringList();
+    Private::ParsedOption po = d->options[optionName];
+    return po.parameters;
+}
+
+QStringList CommandLineParser::parseErrors() const
+{
+    d->parse();
+    return d->errors;
+}

Added: user/uqs/git_conv/svn2git/src/CommandLineParser.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/uqs/git_conv/svn2git/src/CommandLineParser.h	Fri Dec  7 13:00:41 2012	(r243982)
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the vng project
+ * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMMANDLINEPARSER_H
+#define COMMANDLINEPARSER_H
+
+#include <QString>
+
+struct CommandLineOption {
+    /**
+     * The specification of an option includes the name of the option the user must pass and optional arguments it has.
+     * Example specifications are;
+     * <ol>
+     * <li>"-a, --all" </li>
+     * <li>"--version" </li>
+     * <li>"--type name" </li>
+     * <li>"--list item[,item]" </li>
+     * <li>"-f, --format name [suffix] [foo]" </li> </ol>
+     * Number 1 allows the user to either type -a or --all (or /A on Windows) to activate this option.
+     * Number 2 allows the user to type --version to activate this option.
+     * Number 3 requires the user to type a single argument after the option.
+     * Number 4 allows the user to use an option that takes a required argument and one or more optional ones
+     * Number 5 Allows the user to either use -f or --format, which is followed by one required argument
+     *          and optionally 2 more arguments.
+     */
+    const char *specification;
+    /**
+     * A textual description of the option that will be printed when the user asks for help.
+     */
+    const char *description;
+};
+
+#define CommandLineLastOption { 0, 0 }
+
+/**
+ * The CommandLineParser singleton
+ */
+class CommandLineParser
+{
+public:
+    static void init(int argc, char *argv[]);
+    static void addOptionDefinitions(const CommandLineOption *definitions);
+    static void setArgumentDefinition(const char *definition);
+    static CommandLineParser *instance();
+
+    ~CommandLineParser();
+
+    void usage(const QString &name, const QString &argumentDescription = QString());
+
+    /// return the options that the user passed
+    QStringList options() const;
+    /**
+     * returns true if the option was found.
+     * Consider the following definition "--expert level"  The user can type as an argument
+     * "--expert 10".  Calling contains("expert") will return true.
+     * @see optionArgument()
+     */
+    bool contains(const QString & key) const;
+
+    /// returns the list of items that are not options, note that the first one is the name of the command called
+    QStringList arguments() const;
+
+    /// return the list of options that the user passed but we don't have a definition for.
+    QStringList undefinedOptions() const;
+
+    /**
+     * Return the argument passed to an option.
+     * Consider the following definition "--expert level"  The user can type as an argument
+     * "--expert 10".  Calling optionArgument("expert") will return a string "10"
+     * @see contains()
+     */
+    QString optionArgument(const QString &optionName, const QString &defaultValue = QString()) const;
+    QStringList optionArguments(const QString &optionName) const;
+
+    QStringList parseErrors() const;
+
+private:
+    CommandLineParser(int argc, char **argv);
+    class Private;
+    Private * const d;
+    static CommandLineParser *self;
+};
+
+#endif
+

Added: user/uqs/git_conv/svn2git/src/main.cpp
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/uqs/git_conv/svn2git/src/main.cpp	Fri Dec  7 13:00:41 2012	(r243982)
@@ -0,0 +1,283 @@
+/*
+ *  Copyright (C) 2007  Thiago Macieira <thiago@kde.org>
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QCoreApplication>
+#include <QFile>
+#include <QStringList>
+#include <QTextStream>
+#include <QDebug>
+
+#include <limits.h>
+#include <stdio.h>
+
+#include "CommandLineParser.h"
+#include "ruleparser.h"
+#include "repository.h"
+#include "svn.h"
+
+QHash<QByteArray, QByteArray> loadIdentityMapFile(const QString &fileName)
+{
+    QHash<QByteArray, QByteArray> result;
+    if (fileName.isEmpty())
+        return result;
+
+    QFile file(fileName);
+    if (!file.open(QIODevice::ReadOnly)) {
+        fprintf(stderr, "Could not open file %s: %s",
+                qPrintable(fileName), qPrintable(file.errorString()));
+        return result;
+    }
+
+    while (!file.atEnd()) {
+        QByteArray line = file.readLine();
+        int comment_pos = line.indexOf('#');
+        if (comment_pos != -1)
+            line.truncate(comment_pos);
+        line = line.trimmed();
+        int space = line.indexOf(' ');
+        if (space == -1)
+            continue;           // invalid line
+
+        // Support git-svn author files, too
+        // - svn2git native:  loginname Joe User <user@example.com>
+        // - git-svn:         loginname = Joe User <user@example.com>
+        int rightspace = line.indexOf(" = ");
+        int leftspace = space;
+        if (rightspace == -1) {
+            rightspace = space;
+        } else {
+          leftspace = rightspace;
+          rightspace += 2;
+        }
+
+        QByteArray realname = line.mid(rightspace).trimmed();
+        line.truncate(leftspace);
+
+        result.insert(line, realname);
+    };
+    file.close();
+
+    return result;
+}
+
+QSet<int> loadRevisionsFile( const QString &fileName, Svn &svn )
+{
+    QRegExp revint("(\\d+)\\s*(?:-\\s*(\\d+|HEAD))?");
+    QSet<int> revisions;
+    if(fileName.isEmpty())
+        return revisions;
+
+    QFile file(fileName);
+    if( !file.open(QIODevice::ReadOnly)) {
+        fprintf(stderr, "Could not open file %s: %s\n", qPrintable(fileName), qPrintable(file.errorString()));
+        return revisions;
+    }
+
+    bool ok;
+    while(!file.atEnd()) {
+        QByteArray line = file.readLine().trimmed();
+        revint.indexIn(line);
+        if( revint.cap(2).isEmpty() ) {
+            int rev = revint.cap(1).toInt(&ok);
+            if(ok) {
+                revisions.insert(rev);
+            } else {
+                fprintf(stderr, "Unable to convert %s to int, skipping revision.\n", qPrintable(QString(line)));
+            }
+        } else if( revint.captureCount() == 2 ) {
+            int rev = revint.cap(1).toInt(&ok);
+            if(!ok) {
+                fprintf(stderr, "Unable to convert %s (%s) to int, skipping revisions.\n", qPrintable(revint.cap(1)), qPrintable(QString(line)));
+                continue;
+            }
+            int lastrev = 0;
+            if(revint.cap(2) == "HEAD") {
+                lastrev = svn.youngestRevision();
+                ok = true;
+            } else {
+                lastrev = revint.cap(2).toInt(&ok);
+            }
+            if(!ok) {
+                fprintf(stderr, "Unable to convert %s (%s) to int, skipping revisions.\n", qPrintable(revint.cap(2)), qPrintable(QString(line)));
+                continue;
+            }
+            for(; rev <= lastrev; ++rev )
+                revisions.insert(rev);
+        } else {
+            fprintf(stderr, "Unable to convert %s to int, skipping revision.\n", qPrintable(QString(line)));
+        }
+    }
+    file.close();
+    return revisions;
+}
+
+static const CommandLineOption options[] = {
+    {"--identity-map FILENAME", "provide map between svn username and email"},
+    {"--identity-domain DOMAIN", "provide user domain if no map was given"},
+    {"--revisions-file FILENAME", "provide a file with revision number that should be processed"},
+    {"--rules FILENAME[,FILENAME]", "the rules file(s) that determines what goes where"},
+    {"--add-metadata", "if passed, each git commit will have svn commit info"},
+    {"--add-metadata-notes", "if passed, each git commit will have notes with svn commit info"},
+    {"--resume-from revision", "start importing at svn revision number"},
+    {"--max-rev revision", "stop importing at svn revision number"},
+    {"--dry-run", "don't actually write anything"},
+    {"--debug-rules", "print what rule is being used for each file"},
+    {"--commit-interval NUMBER", "if passed the cache will be flushed to git every NUMBER of commits"},
+    {"--stats", "after a run print some statistics about the rules"},
+    {"--svn-branches", "Use the contents of SVN when creating branches, Note: SVN tags are branches as well"},
+    {"-h, --help", "show help"},
+    {"-v, --version", "show version"},
+    CommandLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+    printf("Invoked as:'");
+    for(int i = 0; i < argc; ++i)
+        printf(" %s", argv[i]);
+    printf("'\n");
+    CommandLineParser::init(argc, argv);
+    CommandLineParser::addOptionDefinitions(options);
+    Stats::init();
+    CommandLineParser *args = CommandLineParser::instance();
+    if(args->contains(QLatin1String("version"))) {
+        printf("Git version: %s\n", VER);
+        return 0;
+    }
+    if (args->contains(QLatin1String("help")) || args->arguments().count() != 1) {
+        args->usage(QString(), "[Path to subversion repo]");
+        return 0;
+    }
+    if (args->undefinedOptions().count()) {
+        QTextStream out(stderr);
+        out << "svn-all-fast-export failed: ";
+        bool first = true;
+        foreach (QString option, args->undefinedOptions()) {
+            if (!first)
+                out << "          : ";
+            out << "unrecognized option or missing argument for; `" << option << "'" << endl;
+            first = false;
+        }
+        return 10;
+    }
+    if (!args->contains("rules")) {
+        QTextStream out(stderr);
+        out << "svn-all-fast-export failed: please specify the rules using the 'rules' argument\n";
+        return 11;
+    }
+    if (!args->contains("identity-map") && !args->contains("identity-domain")) {
+        QTextStream out(stderr);
+        out << "WARNING; no identity-map or -domain specified, all commits will use default @localhost email address\n\n";
+    }
+
+    QCoreApplication app(argc, argv);
+    // Load the configuration
+    RulesList rulesList(args->optionArgument(QLatin1String("rules")));
+    rulesList.load();
+
+    int resume_from = args->optionArgument(QLatin1String("resume-from")).toInt();
+    int max_rev = args->optionArgument(QLatin1String("max-rev")).toInt();
+
+    // create the repository list
+    QHash<QString, Repository *> repositories;
+
+    int cutoff = resume_from ? resume_from : INT_MAX;
+ retry:
+    int min_rev = 1;
+    foreach (Rules::Repository rule, rulesList.allRepositories()) {
+        Repository *repo = new Repository(rule);
+        if (!repo)
+            return EXIT_FAILURE;
+        repositories.insert(rule.name, repo);
+
+        int repo_next = repo->setupIncremental(cutoff);
+
+        /*
+  * cutoff < resume_from => error exit eventually
+  * repo_next == cutoff => probably truncated log
+  */
+        if (cutoff < resume_from && repo_next == cutoff)
+            /*
+      * Restore the log file so we fail the next time
+      * svn2git is invoked with the same arguments
+      */
+            repo->restoreLog();
+
+        if (cutoff < min_rev)
+            /*
+      * We've rewound before the last revision of some
+      * repository that we've already seen.  Start over
+      * from the beginning.  (since cutoff is decreasing,
+      * we're sure we'll make forward progress eventually)
+      */
+            goto retry;
+
+        if (min_rev < repo_next)
+            min_rev = repo_next;
+    }
+
+    if (cutoff < resume_from) {
+        qCritical() << "Cannot resume from" << resume_from
+                    << "as there are errors in revision" << cutoff;
+        return EXIT_FAILURE;
+    }
+
+    if (min_rev < resume_from)
+        qDebug() << "skipping revisions" << min_rev << "to" << resume_from - 1 << "as requested";
+
+    if (resume_from)
+        min_rev = resume_from;
+
+    Svn::initialize();
+    Svn svn(args->arguments().first());
+    svn.setMatchRules(rulesList.allMatchRules());
+    svn.setRepositories(repositories);
+    svn.setIdentityMap(loadIdentityMapFile(args->optionArgument("identity-map")));
+    // Massage user input a little, no guarantees that input makes sense.
+    QString domain = args->optionArgument("identity-domain").simplified().remove(QChar('@'));
+    if (domain.isEmpty())
+        domain = QString("localhost");
+    svn.setIdentityDomain(domain);
+
+    if (max_rev < 1)
+        max_rev = svn.youngestRevision();
+
+    bool errors = false;
+    QSet<int> revisions = loadRevisionsFile(args->optionArgument(QLatin1String("revisions-file")), svn);
+    const bool filerRevisions = !revisions.isEmpty();
+    for (int i = min_rev; i <= max_rev; ++i) {
+        if(filerRevisions) {
+            if( !revisions.contains(i) ) {
+                printf(".");
+                continue;
+            } else {
+                printf("\n");
+            }
+        }
+        if (!svn.exportRevision(i)) {
+            errors = true;
+            break;
+        }
+    }
+
+    foreach (Repository *repo, repositories) {
+        repo->finalizeTags();
+        delete repo;
+    }
+    Stats::instance()->printStats();
+    return errors ? EXIT_FAILURE : EXIT_SUCCESS;
+}

Added: user/uqs/git_conv/svn2git/src/repository.cpp
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/uqs/git_conv/svn2git/src/repository.cpp	Fri Dec  7 13:00:41 2012	(r243982)
@@ -0,0 +1,802 @@
+/*
+ *  Copyright (C) 2007  Thiago Macieira <thiago@kde.org>
+ *  Copyright (C) 2009 Thomas Zander <zander@kde.org>
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "repository.h"
+#include "CommandLineParser.h"
+#include <QTextStream>
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QLinkedList>
+
+static const int maxSimultaneousProcesses = 100;
+
+static const int maxMark = (1 << 20) - 2; // some versions of git-fast-import are buggy for larger values of maxMark
+
+class ProcessCache: QLinkedList<Repository *>
+{
+public:
+    void touch(Repository *repo)
+    {
+        remove(repo);
+
+        // if the cache is too big, remove from the front
+        while (size() >= maxSimultaneousProcesses)
+            takeFirst()->closeFastImport();
+
+        // append to the end
+        append(repo);
+    }
+
+    inline void remove(Repository *repo)
+    {
+#if QT_VERSION >= 0x040400
+        removeOne(repo);
+#else
+        removeAll(repo);
+#endif
+    }
+};
+static ProcessCache processCache;
+
+static QString marksFileName(QString name)
+{
+    name.replace('/', '_');
+    name.prepend("marks-");
+    return name;
+}
+
+Repository::Repository(const Rules::Repository &rule)
+    : name(rule.name), prefix(rule.forwardTo), fastImport(name), commitCount(0), outstandingTransactions(0),
+      last_commit_mark(0), next_file_mark(maxMark), processHasStarted(false)
+{
+    foreach (Rules::Repository::Branch branchRule, rule.branches) {
+        Branch branch;
+        branch.created = 1;
+
+        branches.insert(branchRule.name, branch);
+    }
+
+    // create the default branch
+    branches["master"].created = 1;
+
+    fastImport.setWorkingDirectory(name);
+    if (!CommandLineParser::instance()->contains("dry-run")) {
+        if (!QDir(name).exists()) { // repo doesn't exist yet.
+            qDebug() << "Creating new repository" << name;
+            QDir::current().mkpath(name);
+            QProcess init;
+            init.setWorkingDirectory(name);
+            init.start("git", QStringList() << "--bare" << "init");
+            init.waitForFinished(-1);
+            // Write description
+            if (!rule.description.isEmpty()) {
+                QFile fDesc(QDir(name).filePath("description"));
+                if (fDesc.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
+                    fDesc.write(rule.description.toUtf8());
+                    fDesc.putChar('\n');
+                    fDesc.close();
+                }
+            }
+            {
+                QFile marks(name + "/" + marksFileName(name));
+                marks.open(QIODevice::WriteOnly);
+                marks.close();
+            }
+        }
+    }
+}
+
+static QString logFileName(QString name)
+{
+    name.replace('/', '_');
+    name.prepend("log-");
+    return name;
+}
+
+static int lastValidMark(QString name)
+{
+    QFile marksfile(name + "/" + marksFileName(name));
+    if (!marksfile.open(QIODevice::ReadOnly))
+        return 0;
+
+    int prev_mark = 0;
+
+    int lineno = 0;
+    while (!marksfile.atEnd()) {
+        QString line = marksfile.readLine();
+        ++lineno;
+        if (line.isEmpty())
+            continue;
+
+        int mark = 0;
+        if (line[0] == ':') {
+            int sp = line.indexOf(' ');
+            if (sp != -1) {
+                QString m = line.mid(1, sp-1);
+                mark = m.toInt();
+            }
+        }
+
+        if (!mark) {
+            qCritical() << marksfile.fileName() << "line" << lineno << "marks file corrupt?";
+            return 0;
+        }
+
+        if (mark == prev_mark) {
+            qCritical() << marksfile.fileName() << "line" << lineno << "marks file has duplicates";
+            return 0;
+        }
+
+        if (mark < prev_mark) {
+            qCritical() << marksfile.fileName() << "line" << lineno << "marks file not sorted";
+            return 0;
+        }
+
+        if (mark > prev_mark + 1)
+            break;
+
+        prev_mark = mark;
+    }
+
+    return prev_mark;
+}
+
+int Repository::setupIncremental(int &cutoff)
+{
+    QFile logfile(logFileName(name));
+    if (!logfile.exists())
+        return 1;
+
+    logfile.open(QIODevice::ReadWrite);
+
+    QRegExp progress("progress SVN r(\\d+) branch (.*) = :(\\d+)");
+
+    int last_valid_mark = lastValidMark(name);
+
+    int last_revnum = 0;
+    qint64 pos = 0;
+    int retval = 0;
+    QString bkup = logfile.fileName() + ".old";
+
+    while (!logfile.atEnd()) {
+        pos = logfile.pos();
+        QByteArray line = logfile.readLine();
+        int hash = line.indexOf('#');
+        if (hash != -1)
+            line.truncate(hash);
+        line = line.trimmed();
+        if (line.isEmpty())
+            continue;
+        if (!progress.exactMatch(line))
+            continue;
+
+        int revnum = progress.cap(1).toInt();
+        QString branch = progress.cap(2);
+        int mark = progress.cap(3).toInt();

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212071300.qB7D0f3I098809>