Make sure we don't ignore hidden files.
[vng.git] / src / ExcludeMatcher.cpp
blob2032ac24579cc7e7307b93122240d6df26863451
1 /*
2 * This file is part of the vng project
3 * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "ExcludeMatcher.h"
20 #include "GitRunner.h"
21 #include "Logger.h"
23 #include <QDebug>
25 ExcludeMatcher::ExcludeMatcher(const Configuration &configuration)
26 : m_configuration(&configuration)
30 bool ExcludeMatcher::isExcluded(const QString &entry)
32 Q_ASSERT(QDir::current() == m_configuration->repository());
33 Q_ASSERT(! entry.startsWith(QLatin1Char('/'))); // assert relative dir
34 QString relativePath = QLatin1String("./")+ entry;
35 if (m_baseMatches.isEmpty()) {
36 // TODO call git config --get core.excludesfile
37 QString path = m_configuration->repositoryMetaDir().path() + QLatin1String("/info/exclude");
38 readExcludes(path);
39 m_baseMatches << m_cachedMatches[path];
42 // split entry into separate dirs.
43 QStringList pathSegments = entry.split(QDir::separator(), QString::SkipEmptyParts);
44 QString fileName = pathSegments.takeLast(); // remove last entry (the actual filename);
46 if (isExcluded(m_baseMatches, relativePath, fileName))
47 return true;
49 pathSegments.insert(0, QLatin1String("."));
50 QString path;
51 foreach(QString segment, pathSegments) {
52 path = path + segment + QDir::separator();
53 QString ignoreFile = path + QLatin1String(".gitignore");
54 readExcludes(ignoreFile);
55 if (isExcluded(m_cachedMatches[ignoreFile], relativePath, fileName))
56 return true;
58 return false;
61 void ExcludeMatcher::readExcludes(const QString &fileName)
63 if (m_cachedMatches.contains(fileName))
64 return;
65 QList<IgnoreLine> items;
66 QFile ignoreFile(fileName);
67 if (ignoreFile.exists()) {
68 if (ignoreFile.open(QFile::ReadOnly)) {
69 QTextStream file(&ignoreFile);
70 int line=0;
71 while(true) {
72 ++line;
73 QString line = file.readLine();
74 if (line.isNull())
75 break;
76 if (line.isEmpty() || line[0].unicode() == '#')
77 continue;
78 IgnoreLine ignoreLine;
79 ignoreLine.inverted = line[0].unicode() == '!';
80 if (ignoreLine.inverted)
81 line = line.mid(1);
82 ignoreLine.matchOnFileOnly = !line.contains(QLatin1Char('/'));
83 if (! ignoreLine.matchOnFileOnly && !line.startsWith(QLatin1Char('*')))
84 line = QLatin1String("*") + line;
85 QRegExp re(line, Qt::CaseInsensitive, QRegExp::Wildcard);
86 ignoreLine.regExp = re;
87 if (re.isValid())
88 items << ignoreLine;
89 else
90 Logger::debug() << "invalid entry in " << ignoreFile.fileName() << " line " << line;
92 ignoreFile.close();
95 m_cachedMatches.insert(fileName, items);
98 bool ExcludeMatcher::isExcluded(const QList<IgnoreLine> &ignores, const QString &path, const QString &fileName)
100 //qDebug() << "isExcluded" << path << fileName;
101 foreach (IgnoreLine il, ignores) {
102 bool matches;
103 if (il.matchOnFileOnly)
104 matches = il.regExp.exactMatch(fileName);
105 else
106 matches = il.regExp.exactMatch(path);
107 //qDebug() << "trying on " << il.regExp.pattern() << "fileOnly:" << il.matchOnFileOnly << "inverted:" << il.inverted << (matches?" *** Match!":"");
108 if (matches != il.inverted)
109 return true;
111 return false;