Skip to content

Commit 1090a19

Browse files
Vampiretnyblom
authored andcommitted
Obey svn-ignore parameter on branching with svn-branches parameter being used
1 parent c5c2f21 commit 1090a19

File tree

2 files changed

+160
-68
lines changed

2 files changed

+160
-68
lines changed

src/svn.cpp

+78-64
Original file line numberDiff line numberDiff line change
@@ -319,68 +319,6 @@ static bool wasDir(svn_fs_t *fs, int revnum, const char *pathname, apr_pool_t *p
319319
return is_dir;
320320
}
321321

322-
static int recursiveDumpDir(Repository::Transaction *txn, svn_fs_t *fs, svn_fs_root_t *fs_root,
323-
const QByteArray &pathname, const QString &finalPathName,
324-
apr_pool_t *pool, svn_revnum_t revnum,
325-
const Rules::Match &rule, const MatchRuleList &matchRules,
326-
bool ruledebug)
327-
{
328-
if (!wasDir(fs, revnum, pathname.data(), pool)) {
329-
if (dumpBlob(txn, fs_root, pathname, finalPathName, pool) == EXIT_FAILURE)
330-
return EXIT_FAILURE;
331-
return EXIT_SUCCESS;
332-
}
333-
334-
// get the dir listing
335-
apr_hash_t *entries;
336-
SVN_ERR(svn_fs_dir_entries(&entries, fs_root, pathname, pool));
337-
AprAutoPool dirpool(pool);
338-
339-
// While we get a hash, put it in a map for sorted lookup, so we can
340-
// repeat the conversions and get the same git commit hashes.
341-
QMap<QByteArray, svn_node_kind_t> map;
342-
for (apr_hash_index_t *i = apr_hash_first(pool, entries); i; i = apr_hash_next(i)) {
343-
const void *vkey;
344-
void *value;
345-
apr_hash_this(i, &vkey, NULL, &value);
346-
svn_fs_dirent_t *dirent = reinterpret_cast<svn_fs_dirent_t *>(value);
347-
map.insertMulti(QByteArray(dirent->name), dirent->kind);
348-
}
349-
350-
QMapIterator<QByteArray, svn_node_kind_t> i(map);
351-
while (i.hasNext()) {
352-
dirpool.clear();
353-
i.next();
354-
QByteArray entryName = pathname + '/' + i.key();
355-
QString entryFinalName = finalPathName + QString::fromUtf8(i.key());
356-
357-
if (i.value() == svn_node_dir) {
358-
entryFinalName += '/';
359-
QString entryNameQString = entryName + '/';
360-
361-
MatchRuleList::ConstIterator match = findMatchRule(matchRules, revnum, entryNameQString);
362-
if (match == matchRules.constEnd()) continue; // no match of parent repo? (should not happen)
363-
364-
const Rules::Match &matchedRule = *match;
365-
if (matchedRule.action != Rules::Match::Export || matchedRule.repository != rule.repository) {
366-
if (ruledebug)
367-
qDebug() << "recursiveDumpDir:" << entryNameQString << "skip entry for different/ignored repository";
368-
continue;
369-
}
370-
371-
if (recursiveDumpDir(txn, fs, fs_root, entryName, entryFinalName, dirpool, revnum, rule, matchRules, ruledebug) == EXIT_FAILURE)
372-
return EXIT_FAILURE;
373-
} else if (i.value() == svn_node_file) {
374-
printf("+");
375-
fflush(stdout);
376-
if (dumpBlob(txn, fs_root, entryName, entryFinalName, dirpool) == EXIT_FAILURE)
377-
return EXIT_FAILURE;
378-
}
379-
}
380-
381-
return EXIT_SUCCESS;
382-
}
383-
384322
time_t get_epoch(const char* svn_date)
385323
{
386324
struct tm tm;
@@ -450,6 +388,11 @@ class SvnRevision
450388
private:
451389
void splitPathName(const Rules::Match &rule, const QString &pathName, QString *svnprefix_p,
452390
QString *repository_p, QString *effectiveRepository_p, QString *branch_p, QString *path_p);
391+
int recursiveDumpDir(Repository::Transaction *txn, svn_fs_t *fs, svn_fs_root_t *fs_root,
392+
const QByteArray &pathname, const QString &finalPathName,
393+
apr_pool_t *pool, svn_revnum_t revnum,
394+
const Rules::Match &rule, const MatchRuleList &matchRules,
395+
bool ruledebug, int ignoreSet);
453396
};
454397

455398
int SvnPrivate::exportRevision(int revnum)
@@ -876,7 +819,7 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
876819
qDebug() << "Create a true SVN copy of branch (" << key << "->" << branch << path << ")";
877820
txn->deleteFile(path);
878821
checkParentNotEmpty(pool, key, path, fs_root, txn);
879-
recursiveDumpDir(txn, fs, fs_root, key, path, pool, revnum, rule, matchRules, ruledebug);
822+
recursiveDumpDir(txn, fs, fs_root, key, path, pool, revnum, rule, matchRules, ruledebug, false);
880823
}
881824
if (rule.annotate) {
882825
// create an annotated tag
@@ -959,7 +902,7 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
959902
}
960903
}
961904

962-
recursiveDumpDir(txn, fs, fs_root, key, path, pool, revnum, rule, matchRules, ruledebug);
905+
recursiveDumpDir(txn, fs, fs_root, key, path, pool, revnum, rule, matchRules, ruledebug, ignoreSet);
963906
}
964907

965908
if (rule.annotate) {
@@ -972,6 +915,77 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
972915
return EXIT_SUCCESS;
973916
}
974917

918+
int SvnRevision::recursiveDumpDir(Repository::Transaction *txn, svn_fs_t *fs, svn_fs_root_t *fs_root,
919+
const QByteArray &pathname, const QString &finalPathName,
920+
apr_pool_t *pool, svn_revnum_t revnum,
921+
const Rules::Match &rule, const MatchRuleList &matchRules,
922+
bool ruledebug, int ignoreSet)
923+
{
924+
if (!wasDir(fs, revnum, pathname.data(), pool)) {
925+
if (dumpBlob(txn, fs_root, pathname, finalPathName, pool) == EXIT_FAILURE)
926+
return EXIT_FAILURE;
927+
return EXIT_SUCCESS;
928+
}
929+
930+
if ((ignoreSet == false) && CommandLineParser::instance()->contains("svn-ignore")) {
931+
QString svnignore;
932+
if (fetchIgnoreProps(&svnignore, pool, pathname, fs_root) != EXIT_SUCCESS) {
933+
qWarning() << "Error fetching svn-properties (" << pathname << ")";
934+
} else if (!svnignore.isNull()) {
935+
addGitIgnore(pool, pathname, finalPathName, fs_root, txn, svnignore.toStdString().c_str());
936+
}
937+
}
938+
939+
// get the dir listing
940+
apr_hash_t *entries;
941+
SVN_ERR(svn_fs_dir_entries(&entries, fs_root, pathname, pool));
942+
AprAutoPool dirpool(pool);
943+
944+
// While we get a hash, put it in a map for sorted lookup, so we can
945+
// repeat the conversions and get the same git commit hashes.
946+
QMap<QByteArray, svn_node_kind_t> map;
947+
for (apr_hash_index_t *i = apr_hash_first(pool, entries); i; i = apr_hash_next(i)) {
948+
const void *vkey;
949+
void *value;
950+
apr_hash_this(i, &vkey, NULL, &value);
951+
svn_fs_dirent_t *dirent = reinterpret_cast<svn_fs_dirent_t *>(value);
952+
map.insertMulti(QByteArray(dirent->name), dirent->kind);
953+
}
954+
955+
QMapIterator<QByteArray, svn_node_kind_t> i(map);
956+
while (i.hasNext()) {
957+
dirpool.clear();
958+
i.next();
959+
QByteArray entryName = pathname + '/' + i.key();
960+
QString entryFinalName = finalPathName + QString::fromUtf8(i.key());
961+
962+
if (i.value() == svn_node_dir) {
963+
entryFinalName += '/';
964+
QString entryNameQString = entryName + '/';
965+
966+
MatchRuleList::ConstIterator match = findMatchRule(matchRules, revnum, entryNameQString);
967+
if (match == matchRules.constEnd()) continue; // no match of parent repo? (should not happen)
968+
969+
const Rules::Match &matchedRule = *match;
970+
if (matchedRule.action != Rules::Match::Export || matchedRule.repository != rule.repository) {
971+
if (ruledebug)
972+
qDebug() << "recursiveDumpDir:" << entryNameQString << "skip entry for different/ignored repository";
973+
continue;
974+
}
975+
976+
if (recursiveDumpDir(txn, fs, fs_root, entryName, entryFinalName, dirpool, revnum, rule, matchRules, ruledebug, false) == EXIT_FAILURE)
977+
return EXIT_FAILURE;
978+
} else if (i.value() == svn_node_file) {
979+
printf("+");
980+
fflush(stdout);
981+
if (dumpBlob(txn, fs_root, entryName, entryFinalName, dirpool) == EXIT_FAILURE)
982+
return EXIT_FAILURE;
983+
}
984+
}
985+
986+
return EXIT_SUCCESS;
987+
}
988+
975989
int SvnRevision::recurse(const char *path, const svn_fs_path_change2_t *change,
976990
const char *path_from, const MatchRuleList &matchRules, svn_revnum_t rev_from,
977991
apr_hash_t *changes, apr_pool_t *pool)

test/svn-ignore.bats

+82-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ load 'common'
1212
create repository git-repo
1313
end repository
1414
15-
match /([^/]+(/|$))
15+
match /
1616
repository git-repo
1717
branch master
18-
prefix \1
1918
end match
2019
")
2120

@@ -38,10 +37,9 @@ load 'common'
3837
create repository git-repo
3938
end repository
4039
41-
match /([^/]+(/|$))
40+
match /
4241
repository git-repo
4342
branch master
44-
prefix \1
4543
end match
4644
")
4745

@@ -51,3 +49,83 @@ load 'common'
5149
EOF
5250
)"
5351
}
52+
53+
@test 'svn-ignore translation should be done if svn-branches parameter is used' {
54+
svn mkdir trunk
55+
svn commit -m 'create trunk'
56+
svn propset svn:ignore $'ignore-a\nignore-b' trunk
57+
svn commit -m 'ignore ignore-a and ignore-b on root'
58+
svn propset svn:global-ignores 'ignore-c' trunk
59+
svn commit -m 'ignore ignore-c everywhere'
60+
svn mkdir branches
61+
svn copy trunk branches/branch-a
62+
svn commit -m 'create branch branch-a'
63+
64+
cd "$TEST_TEMP_DIR"
65+
svn2git "$SVN_REPO" --svn-ignore --svn-branches --rules <(echo "
66+
create repository git-repo
67+
end repository
68+
69+
match /trunk/
70+
repository git-repo
71+
branch master
72+
end match
73+
74+
match /branches/$
75+
action recurse
76+
end match
77+
78+
match /branches/([^/]+)/
79+
repository git-repo
80+
branch \1
81+
end match
82+
")
83+
84+
assert_equal "$(git -C git-repo show master:.gitignore)" "$(cat <<-EOF
85+
/ignore-a
86+
/ignore-b
87+
ignore-c
88+
EOF
89+
)"
90+
assert_equal "$(git -C git-repo show branch-a:.gitignore)" "$(cat <<-EOF
91+
/ignore-a
92+
/ignore-b
93+
ignore-c
94+
EOF
95+
)"
96+
}
97+
98+
@test 'svn-ignore translation should be done transitively when copying a directory' {
99+
svn mkdir --parents dir-a/subdir-a
100+
svn commit -m 'add dir-a/subdir-a'
101+
svn propset svn:ignore $'ignore-a\nignore-b' dir-a/subdir-a
102+
svn commit -m 'ignore ignore-a and ignore-b on dir-a/subdir-a'
103+
svn propset svn:global-ignores 'ignore-c' dir-a/subdir-a
104+
svn commit -m 'ignore ignore-c on dir-a/subdir-a and descendents'
105+
svn copy dir-a dir-b
106+
svn commit -m 'copy dir-a to dir-b'
107+
108+
cd "$TEST_TEMP_DIR"
109+
svn2git "$SVN_REPO" --svn-ignore --rules <(echo "
110+
create repository git-repo
111+
end repository
112+
113+
match /
114+
repository git-repo
115+
branch master
116+
end match
117+
")
118+
119+
assert_equal "$(git -C git-repo show master:dir-a/subdir-a/.gitignore)" "$(cat <<-EOF
120+
/ignore-a
121+
/ignore-b
122+
ignore-c
123+
EOF
124+
)"
125+
assert_equal "$(git -C git-repo show master:dir-b/subdir-a/.gitignore)" "$(cat <<-EOF
126+
/ignore-a
127+
/ignore-b
128+
ignore-c
129+
EOF
130+
)"
131+
}

0 commit comments

Comments
 (0)