From a85ac9698a77da1cd446e7d91010ebe62cbc5f76 Mon Sep 17 00:00:00 2001 From: Torgny Nyblom Date: Tue, 28 Sep 2010 20:40:05 +0200 Subject: Unify debug messages and Match structs --- src/repository.cpp | 2 +- src/ruleparser.cpp | 4 +++- src/ruleparser.h | 26 ++++++++++++++++++++------ src/svn.cpp | 6 +++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/repository.cpp b/src/repository.cpp index d4cb2ad..2a2b436 100644 --- a/src/repository.cpp +++ b/src/repository.cpp @@ -275,7 +275,7 @@ Repository *makeRepository(const Rules::Repository &rule, const QHash #include #include +#include class Rules { public: - struct Repository + struct Rule + { + QString filename; + int lineNumber; + Rule() : lineNumber(0) {} + }; + struct Repository : Rule { struct Branch { @@ -35,15 +42,19 @@ public: QString name; QList branches; - int lineNumber; QString forwardTo; QString prefix; - Repository() : lineNumber(0) { } + Repository() { } + const QString info() const { + const QString info = Rule::filename % ":" % QByteArray::number(Rule::lineNumber); + return info; + } + }; - struct Match + struct Match : Rule { QRegExp rx; QString repository; @@ -51,7 +62,6 @@ public: QString prefix; int minRevision; int maxRevision; - int lineNumber; bool annotate; enum Action { @@ -60,7 +70,11 @@ public: Recurse } action; - Match() : minRevision(-1), maxRevision(-1), lineNumber(0), annotate(false), action(Ignore) { } + Match() : minRevision(-1), maxRevision(-1), annotate(false), action(Ignore) { } + const QString info() const { + const QString info = rx.pattern() % " (" % Rule::filename % ":" % QByteArray::number(Rule::lineNumber) % ")"; + return info; + } }; Rules(const QString &filename); diff --git a/src/svn.cpp b/src/svn.cpp index dd3ce53..7298e08 100644 --- a/src/svn.cpp +++ b/src/svn.cpp @@ -584,17 +584,17 @@ int SvnRevision::exportDispatch(const char *key, const svn_fs_path_change_t *cha case Rules::Match::Recurse: if(ruledebug) - qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.lineNumber << "(" << rule.rx.pattern() << ")" << " " << "recursing."; + qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.info() << " " << "recursing."; return recurse(key, change, path_from, rev_from, changes, pool); case Rules::Match::Export: if(ruledebug) - qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.lineNumber << "(" << rule.rx.pattern() << ")" << " " << "exporting."; + qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.info() << " " << "exporting."; if (exportInternal(key, change, path_from, rev_from, current, rule) == EXIT_SUCCESS) return EXIT_SUCCESS; if (change->change_kind != svn_fs_path_change_delete) { if(ruledebug) - qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.lineNumber << "(" << rule.rx.pattern() << ")" << " " << "Unable to export non path removal."; + qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.info() << " " << "Unable to export non path removal."; return EXIT_FAILURE; } // we know that the default action inside recurse is to recurse further or to ignore, -- cgit v1.2.1 From d1737a1713da27f825682fff0e9838b559ea81a3 Mon Sep 17 00:00:00 2001 From: Torgny Nyblom Date: Wed, 29 Sep 2010 19:45:20 +0200 Subject: Die when a rule file contains an invalid regexp --- src/ruleparser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ruleparser.cpp b/src/ruleparser.cpp index 5927c5a..1744969 100644 --- a/src/ruleparser.cpp +++ b/src/ruleparser.cpp @@ -193,6 +193,10 @@ void Rules::load() state = ReadingMatch; match = Match(); match.rx = QRegExp(matchLine.cap(1), Qt::CaseSensitive, QRegExp::RegExp2); + if( !match.rx.isValid() ) + qFatal("Malformed regular expression '%s' in file:'%s':%d, Error: %s", + qPrintable(matchLine.cap(1)), qPrintable(filename), lineNumber, + qPrintable(match.rx.errorString())); match.lineNumber = lineNumber; match.filename = filename; } else if (isVariableRule) { -- cgit v1.2.1 From 7ca174999ae5fa86e5fc39a0b1b7b02c06c80840 Mon Sep 17 00:00:00 2001 From: Torgny Nyblom Date: Wed, 29 Sep 2010 19:46:09 +0200 Subject: const++ --- src/ruleparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ruleparser.cpp b/src/ruleparser.cpp index 1744969..d8467ac 100644 --- a/src/ruleparser.cpp +++ b/src/ruleparser.cpp @@ -31,12 +31,12 @@ Rules::~Rules() { } -QList Rules::repositories() +const QList Rules::repositories() const { return m_repositories; } -QList Rules::matchRules() +const QList Rules::matchRules() const { return m_matchRules; } -- cgit v1.2.1 From a741bdb1913c28a320ff0e01518e4d39ed430289 Mon Sep 17 00:00:00 2001 From: Torgny Nyblom Date: Wed, 29 Sep 2010 19:53:24 +0200 Subject: Allow more then one rule file to be used in a single run. --- src/CommandLineParser.cpp | 3 +- src/CommandLineParser.h | 4 ++- src/main.cpp | 10 +++---- src/ruleparser.cpp | 35 +++++++++++++++++++++++ src/ruleparser.h | 22 +++++++++++++-- src/svn.cpp | 72 +++++++++++++++++++++++++++-------------------- src/svn.h | 2 +- 7 files changed, 108 insertions(+), 40 deletions(-) diff --git a/src/CommandLineParser.cpp b/src/CommandLineParser.cpp index 7e7658a..39f40d6 100644 --- a/src/CommandLineParser.cpp +++ b/src/CommandLineParser.cpp @@ -77,7 +77,8 @@ void CommandLineParser::Private::addDefinitions(const CommandLineOption * option for (int i=0; options[i].specification != 0; i++) { OptionDefinition definition; QString option = QString::fromLatin1(options[i].specification); - if (option.indexOf(QLatin1Char(',')) >= 0) { + // 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() << "option definition '" << option << "' is faulty; only one ',' allowed"; diff --git a/src/CommandLineParser.h b/src/CommandLineParser.h index 62c04bb..f5515d1 100644 --- a/src/CommandLineParser.h +++ b/src/CommandLineParser.h @@ -29,11 +29,13 @@ struct CommandLineOption { *
  • "-a, --all"
  • *
  • "--version"
  • *
  • "--type name"
  • + *
  • "--list item[,item]"
  • *
  • "-f, --format name [suffix] [foo]"
  • * 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 either use -f or --format, which is followed by one required argument + * 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; diff --git a/src/main.cpp b/src/main.cpp index 73d2378..7de7e45 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,7 +69,7 @@ QHash loadIdentityMapFile(const QString &fileName) static const CommandLineOption options[] = { {"--identity-map FILENAME", "provide map between svn username and email"}, - {"--rules FILENAME", "the rules file that determines what goes where"}, + {"--rules FILENAME[,FILENAME]", "the rules file(s) that determines what goes where"}, {"--add-metadata", "if passed, each git commit will have svn commit info"}, {"--resume-from revision", "start importing at svn revision number"}, {"--max-rev revision", "stop importing at svn revision number"}, @@ -114,8 +114,8 @@ int main(int argc, char **argv) QCoreApplication app(argc, argv); // Load the configuration - Rules rules(args->optionArgument(QLatin1String("rules"))); - rules.load(); + 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(); @@ -126,7 +126,7 @@ int main(int argc, char **argv) int cutoff = resume_from ? resume_from : INT_MAX; retry: int min_rev = 1; - foreach (Rules::Repository rule, rules.repositories()) { + foreach (Rules::Repository rule, rulesList.allRepositories()) { Repository *repo = makeRepository(rule, repositories); if (!repo) return EXIT_FAILURE; @@ -172,7 +172,7 @@ int main(int argc, char **argv) Svn::initialize(); Svn svn(args->arguments().first()); - svn.setMatchRules(rules.matchRules()); + svn.setMatchRules(rulesList.allMatchRules()); svn.setRepositories(repositories); svn.setIdentityMap(loadIdentityMapFile(args->optionArgument("identity-map"))); diff --git a/src/ruleparser.cpp b/src/ruleparser.cpp index d8467ac..4ab8f08 100644 --- a/src/ruleparser.cpp +++ b/src/ruleparser.cpp @@ -22,6 +22,41 @@ #include "ruleparser.h" +RulesList::RulesList(const QString &filenames) + : m_filenames(filenames) +{ +} + +RulesList::~RulesList() {} + +void RulesList::load() +{ + foreach(const QString filename, m_filenames.split(',') ) { + qDebug() << "Loading rules from:" << filename; + Rules *rules = new Rules(filename); + m_rules.append(rules); + rules->load(); + m_allrepositories.append(rules->repositories()); + QList matchRules = rules->matchRules(); + m_allMatchRules.append( QList(matchRules)); + } +} + +const QList RulesList::allRepositories() const +{ + return m_allrepositories; +} + +const QList > RulesList::allMatchRules() const +{ + return m_allMatchRules; +} + +const QList RulesList::rules() const +{ + return m_rules; +} + Rules::Rules(const QString &fn) : filename(fn) { diff --git a/src/ruleparser.h b/src/ruleparser.h index e5cbaea..5d05d1c 100644 --- a/src/ruleparser.h +++ b/src/ruleparser.h @@ -80,8 +80,8 @@ public: Rules(const QString &filename); ~Rules(); - QList repositories(); - QList matchRules(); + const QList repositories() const; + const QList matchRules() const; void load(); QStringList readRules(const QString &filename) const; @@ -92,6 +92,24 @@ private: QList m_matchRules; }; +class RulesList +{ +public: + RulesList( const QString &filenames); + ~RulesList(); + + const QList allRepositories() const; + const QList > allMatchRules() const; + const QList rules() const; + void load(); + +private: + QString m_filenames; + QList m_rules; + QList m_allrepositories; + QList > m_allMatchRules; +}; + #ifndef QT_NO_DEBUG_STREAM class QDebug; QDebug operator<<(QDebug, const Rules::Match &); diff --git a/src/svn.cpp b/src/svn.cpp index 7298e08..c9b0f81 100644 --- a/src/svn.cpp +++ b/src/svn.cpp @@ -74,7 +74,7 @@ public: class SvnPrivate { public: - MatchRuleList matchRules; + QList allMatchRules; RepositoryHash repositories; IdentityHash identities; @@ -113,9 +113,9 @@ Svn::~Svn() delete d; } -void Svn::setMatchRules(const MatchRuleList &matchRules) +void Svn::setMatchRules(const QList &allMatchRules) { - d->matchRules = matchRules; + d->allMatchRules = allMatchRules; } void Svn::setRepositories(const RepositoryHash &repositories) @@ -370,7 +370,7 @@ class SvnRevision public: AprAutoPool pool; QHash transactions; - MatchRuleList matchRules; + QList allMatchRules; RepositoryHash repositories; IdentityHash identities; @@ -404,19 +404,19 @@ public: int exportDispatch(const char *path, const svn_fs_path_change_t *change, const char *path_from, svn_revnum_t rev_from, apr_hash_t *changes, const QString ¤t, const Rules::Match &rule, - apr_pool_t *pool); + const MatchRuleList &matchRules, apr_pool_t *pool); int exportInternal(const char *path, const svn_fs_path_change_t *change, const char *path_from, svn_revnum_t rev_from, - const QString ¤t, const Rules::Match &rule); + const QString ¤t, const Rules::Match &rule, const MatchRuleList &matchRules); int recurse(const char *path, const svn_fs_path_change_t *change, - const char *path_from, svn_revnum_t rev_from, + const char *path_from, const MatchRuleList &matchRules, svn_revnum_t rev_from, apr_hash_t *changes, apr_pool_t *pool); }; int SvnPrivate::exportRevision(int revnum) { SvnRevision rev(revnum, fs, global_pool); - rev.matchRules = matchRules; + rev.allMatchRules = allMatchRules; rev.repositories = repositories; rev.identities = identities; @@ -544,20 +544,33 @@ int SvnRevision::exportEntry(const char *key, const svn_fs_path_change_t *change if (is_dir) current += '/'; - // find the first rule that matches this pathname - MatchRuleList::ConstIterator match = findMatchRule(matchRules, revnum, current); - if (match != matchRules.constEnd()) { - const Rules::Match &rule = *match; - return exportDispatch(key, change, path_from, rev_from, changes, current, rule, revpool); + //MultiRule: loop start + //Replace all returns with continue, + bool isHandled = false; + foreach ( const MatchRuleList matchRules, allMatchRules ) { + // find the first rule that matches this pathname + MatchRuleList::ConstIterator match = findMatchRule(matchRules, revnum, current); + if (match != matchRules.constEnd()) { + const Rules::Match &rule = *match; + if ( exportDispatch(key, change, path_from, rev_from, changes, current, rule, matchRules, revpool) == EXIT_FAILURE ) + return EXIT_FAILURE; + isHandled = true; + } else if (is_dir && path_from != NULL) { + qDebug() << current << "is a copy-with-history, auto-recursing"; + if ( recurse(key, change, path_from, matchRules, rev_from, changes, revpool) == EXIT_FAILURE ) + return EXIT_FAILURE; + isHandled = true; + } else if (is_dir && change->change_kind == svn_fs_path_change_delete) { + qDebug() << current << "deleted, auto-recursing"; + if ( recurse(key, change, path_from, matchRules, rev_from, changes, revpool) == EXIT_FAILURE ) + return EXIT_FAILURE; + isHandled = true; + } } - - if (is_dir && path_from != NULL) { - qDebug() << current << "is a copy-with-history, auto-recursing"; - return recurse(key, change, path_from, rev_from, changes, revpool); - } else if (is_dir && change->change_kind == svn_fs_path_change_delete) { - qDebug() << current << "deleted, auto-recursing"; - return recurse(key, change, path_from, rev_from, changes, revpool); - } else if (wasDir(fs, revnum - 1, key, revpool)) { + if ( isHandled ) { + return EXIT_SUCCESS; + } + if (wasDir(fs, revnum - 1, key, revpool)) { qDebug() << current << "was a directory; ignoring"; } else if (change->change_kind == svn_fs_path_change_delete) { qDebug() << current << "is being deleted but I don't know anything about it; ignoring"; @@ -565,14 +578,13 @@ int SvnRevision::exportEntry(const char *key, const svn_fs_path_change_t *change qCritical() << current << "did not match any rules; cannot continue"; return EXIT_FAILURE; } - return EXIT_SUCCESS; } int SvnRevision::exportDispatch(const char *key, const svn_fs_path_change_t *change, const char *path_from, svn_revnum_t rev_from, apr_hash_t *changes, const QString ¤t, - const Rules::Match &rule, apr_pool_t *pool) + const Rules::Match &rule, const MatchRuleList &matchRules, apr_pool_t *pool) { //if(ruledebug) // qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.lineNumber << "(" << rule.rx.pattern() << ")"; @@ -585,12 +597,12 @@ int SvnRevision::exportDispatch(const char *key, const svn_fs_path_change_t *cha case Rules::Match::Recurse: if(ruledebug) qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.info() << " " << "recursing."; - return recurse(key, change, path_from, rev_from, changes, pool); + return recurse(key, change, path_from, matchRules, rev_from, changes, pool); case Rules::Match::Export: if(ruledebug) qDebug() << "rev" << revnum << qPrintable(current) << "matched rule:" << rule.info() << " " << "exporting."; - if (exportInternal(key, change, path_from, rev_from, current, rule) == EXIT_SUCCESS) + if (exportInternal(key, change, path_from, rev_from, current, rule, matchRules) == EXIT_SUCCESS) return EXIT_SUCCESS; if (change->change_kind != svn_fs_path_change_delete) { if(ruledebug) @@ -600,7 +612,7 @@ int SvnRevision::exportDispatch(const char *key, const svn_fs_path_change_t *cha // we know that the default action inside recurse is to recurse further or to ignore, // either of which is reasonably safe for deletion qWarning() << "deleting unknown path" << current << "; auto-recursing"; - return recurse(key, change, path_from, rev_from, changes, pool); + return recurse(key, change, path_from, matchRules, rev_from, changes, pool); } // never reached @@ -609,7 +621,7 @@ int SvnRevision::exportDispatch(const char *key, const svn_fs_path_change_t *cha int SvnRevision::exportInternal(const char *key, const svn_fs_path_change_t *change, const char *path_from, svn_revnum_t rev_from, - const QString ¤t, const Rules::Match &rule) + const QString ¤t, const Rules::Match &rule, const MatchRuleList &matchRules) { QString svnprefix, repository, branch, path; splitPathName(rule, current, &svnprefix, &repository, &branch, &path); @@ -746,7 +758,7 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change_t *cha } int SvnRevision::recurse(const char *path, const svn_fs_path_change_t *change, - const char *path_from, svn_revnum_t rev_from, + const char *path_from, const MatchRuleList &matchRules, svn_revnum_t rev_from, apr_hash_t *changes, apr_pool_t *pool) { svn_fs_root_t *fs_root = this->fs_root; @@ -797,13 +809,13 @@ int SvnRevision::recurse(const char *path, const svn_fs_path_change_t *change, MatchRuleList::ConstIterator match = findMatchRule(matchRules, revnum, current); if (match != matchRules.constEnd()) { if (exportDispatch(entry, change, entryFrom.isNull() ? 0 : entryFrom.constData(), - rev_from, changes, current, *match, dirpool) == EXIT_FAILURE) + rev_from, changes, current, *match, matchRules, dirpool) == EXIT_FAILURE) return EXIT_FAILURE; } else { qDebug() << current << "rev" << revnum << "did not match any rules; auto-recursing"; if (recurse(entry, change, entryFrom.isNull() ? 0 : entryFrom.constData(), - rev_from, changes, dirpool) == EXIT_FAILURE) + matchRules, rev_from, changes, dirpool) == EXIT_FAILURE) return EXIT_FAILURE; } } diff --git a/src/svn.h b/src/svn.h index 10fd22c..5fb3245 100644 --- a/src/svn.h +++ b/src/svn.h @@ -33,7 +33,7 @@ public: Svn(const QString &pathToRepository); ~Svn(); - void setMatchRules(const QList &matchRules); + void setMatchRules(const QList > &matchRules); void setRepositories(const QHash &repositories); void setIdentityMap(const QHash &identityMap); -- cgit v1.2.1