Make committer email the same as author email, better fix
[vng.git] / Configuration.cpp
blobe286ce9d9572540e397aa8d1d5b1abe7918feba7
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/>.
18 #include "Configuration.h"
19 #include "Logger.h"
20 #include "GitRunner.h"
21 #include "AbstractCommand.h"
23 #include <QDebug>
24 #include <QMutexLocker>
25 #include <QProcess>
27 #ifndef Q_OS_WIN
28 #include <unistd.h>
29 #endif
31 #define EditedFilesDatabase "vng-editedfiles"
33 Configuration::Configuration(const QString &section)
34 : m_repoDir("."),
35 m_section(section),
36 m_dirty(true),
37 m_emptyRepo(false),
38 m_fetchedBranches(false),
39 m_editedFilesFetched(false),
40 m_editMode(StateUnknown)
44 bool Configuration::contains(const QString & key) const
46 const_cast<Configuration*> (this)->readConfig();
47 return m_options.contains(key);
50 QDir Configuration::repository() const
52 const_cast<Configuration*> (this)->readConfig();
53 return m_repoDir;
56 QDir Configuration::repositoryMetaDir() const
58 const_cast<Configuration*> (this)->readConfig();
59 return m_repoMetaDataDir;
62 void Configuration::readConfig()
64 if (!m_dirty)
65 return;
66 m_dirty = false;
67 QObject deleterParent;
69 QDir dir = QDir::current();
70 do {
71 QDir git = dir;
72 if (git.cd(".git")) {
73 m_repoDir = dir;
74 m_repoMetaDataDir = git;
75 QDir refs(git.absoluteFilePath("refs/heads"));
76 m_emptyRepo = refs.count() == 2; // only '.' and '..'
77 break;
79 if (!dir.cdUp())
80 break;
81 } while(!dir.isRoot());
83 QString home = QDir::homePath();
84 QFile *config;
85 config = new QFile(home + "/.vng/config", &deleterParent);
86 if (! config->exists())
87 config = new QFile(home + "/.darcs/defaults", &deleterParent);
88 if (config->exists()) {
89 if (! config->open(QIODevice::ReadOnly)) {
90 Logger::error() << "Failed to open config file, is it readable?\n";
91 return;
94 char buf[1024];
95 while(true) {
96 qint64 lineLength = config->readLine(buf, sizeof(buf));
97 if (lineLength == -1)
98 break;
99 QString line = QString::fromUtf8(buf, lineLength);
100 QString option;
101 if (line.startsWith("ALL "))
102 option = line.mid(3).trimmed();
103 else if (line.length() > m_section.length() && line.startsWith(m_section))
104 option = line.mid(m_section.length()).trimmed();
105 if (! option.isEmpty()) {
106 const int index = option.indexOf(' ');
107 if (index > 0) {
108 m_options.insert(option.left(index).trimmed(), option.mid(index).trimmed());
110 else
111 m_options.insert(option, QString());
114 config->close();
118 QString Configuration::optionArgument(const QString &optionName, const QString &defaultValue) const
120 if (m_options.contains(optionName))
121 return m_options[optionName];
122 return defaultValue;
125 bool Configuration::colorTerm() const
127 #ifndef Q_OS_WIN
128 if (isatty(1))
129 return QString(getenv("TERM")) != QString("dumb") && !Logger::hasNonColorPager();
130 #endif
131 return false;
134 bool Configuration::isEmptyRepo() const
136 const_cast<Configuration*> (this)->readConfig();
137 return m_emptyRepo;
140 QList<Branch> Configuration::allBranches()
142 fetchBranches();
143 QList<Branch> answer;
144 answer += m_localBranches;
145 answer += m_remoteBranches;
146 return answer;
149 QList<Branch> Configuration::branches()
151 fetchBranches();
152 return m_localBranches;
155 QList<Branch> Configuration::remoteBranches()
157 fetchBranches();
158 return m_remoteBranches;
161 void Configuration::fetchBranches()
163 if (m_fetchedBranches)
164 return;
165 m_fetchedBranches = true;
167 QProcess git;
168 QStringList arguments;
169 arguments << "ls-remote" << ".";
170 GitRunner runner(git, arguments);
171 AbstractCommand::ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput);
172 if (rc != AbstractCommand::Ok) {
173 return;
175 char buf[1024];
176 while(true) {
177 qint64 lineLength = Vng::readLine(&git, buf, sizeof(buf));
178 if (lineLength == -1)
179 break;
180 if (lineLength > 46) { // only take stuff that is in the 'refs' dir.
181 QString name(buf + 46);
182 name = name.trimmed(); // remove linefeed
183 Branch branch(name);
184 if (name.startsWith("remotes"))
185 m_remoteBranches.append(branch);
186 else
187 m_localBranches.append(branch);
192 bool Configuration::useEditMode() const
194 if (m_editMode == StateUnknown) {
195 TryState editMode;
197 QProcess git;
198 QStringList arguments;
199 arguments << "config" << "--bool" << "vng.useEditMode";
200 GitRunner runner(git, arguments);
201 AbstractCommand::ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput, GitRunner::FailureAccepted);
202 if (git.exitCode() == 1) // unregistered var means false.
203 editMode = StateFalse;
204 else if (rc != AbstractCommand::Ok)
205 return false;
206 else {
207 editMode = StateFalse;
208 char buf[1024];
209 while(true) {
210 qint64 lineLength = Vng::readLine(&git, buf, sizeof(buf));
211 if (lineLength == -1)
212 break;
213 if (lineLength > 3 && QString(buf).startsWith("true"))
214 editMode = StateTrue;
217 const_cast<Configuration*> (this)->m_editMode = editMode;
219 return m_editMode == StateTrue;
222 void Configuration::setEditMode(bool enabled)
224 QProcess git;
225 QStringList arguments;
226 arguments << "config" << "--replace-all" << "vng.useEditMode" << (enabled ? "true" : "false");
227 GitRunner runner(git, arguments);
228 runner.start(GitRunner::WaitUntilFinished);
231 QList<QByteArray> Configuration::editedFiles()
233 if (! useEditMode())
234 return QList<QByteArray>();
235 QMutexLocker locker(&m_editedFilesLock);
236 // TODO do some file-locking
237 if (!m_editedFilesFetched) {
238 readConfig();
239 if (! m_repoMetaDataDir.exists())
240 return QList<QByteArray> ();
241 QFile openedFiles(m_repoMetaDataDir.filePath(EditedFilesDatabase));
242 if (!openedFiles.open(QIODevice::ReadOnly)) {
243 Logger::error() << "Vng failed to read the database of opened files ('" << openedFiles.fileName() << "`)\n";
244 return QList<QByteArray>();
246 char buf[1024];
247 while (true) {
248 openedFiles.waitForReadyRead(-1);
249 qint64 len = openedFiles.readLine(buf, sizeof(buf));
250 if (len == -1)
251 break;
252 if (len == 1 || buf[0] == '#')
253 continue;
254 m_editedFiles << QByteArray(buf, len-1);
257 m_editedFilesFetched = true;
260 return m_editedFiles;
263 void Configuration::addEditedFiles(const QList<QByteArray> &newFileNames)
265 if (newFileNames.size() == 0)
266 return;
267 // TODO do some file-locking
268 QMutexLocker locker(&m_editedFilesLock);
269 QFile editedFiles(m_repoMetaDataDir.filePath(EditedFilesDatabase));
270 if (! editedFiles.open(QIODevice::WriteOnly | QIODevice::Append)) {
271 Logger::error() << "vng-failed: Could not write to the database of edited files\n";
272 return;
274 // TODO make sure we don't write the same filename to the DB twice.
276 // remove old stuff
277 m_editedFilesFetched = false;
278 m_editedFiles.clear();
280 foreach(QByteArray ba, newFileNames) {
281 if (ba.size() == 0)
282 continue;
283 editedFiles.write(ba);
284 if (ba[ba.size()-1] != '\n')
285 editedFiles.write("\n", 1);
287 editedFiles.close();
290 void Configuration::addEditedFiles(const QStringList &newFileNames)
292 QList<QByteArray> fileNames;
293 foreach(QString s, newFileNames) {
294 fileNames << s.toLocal8Bit();
296 addEditedFiles(fileNames);
299 void Configuration::removeEditedFiles(const QStringList &fileNames)
301 QList<QByteArray> files;
302 foreach(QString s, fileNames) {
303 files << s.toLocal8Bit();
305 removeEditedFiles(files);
308 void Configuration::removeEditedFiles(const QList<QByteArray> &fileNames)
310 if (fileNames.size() == 0)
311 return;
312 // TODO do some file-locking
313 QList<QByteArray> currentContents = editedFiles();
314 QMutexLocker locker(&m_editedFilesLock);
316 QList<QByteArray> currentContent = m_editedFiles;
317 if (currentContent.isEmpty())
318 return;
320 QFile editedFiles(m_repoMetaDataDir.filePath(EditedFilesDatabase));
321 if (! editedFiles.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
322 Logger::error() << "vng-failed: Could not write to the database of edited files\n";
323 return;
325 m_editedFiles.clear();
327 foreach (QByteArray ba, currentContent) {
328 bool found = false;
329 foreach (QByteArray rem, fileNames) {
330 if (ba.length() == rem.length() && ba.indexOf(rem) == 0) { // thats the file to remove.
331 found = true;
332 break;
335 if (! found) {
336 m_editedFiles << ba;
337 editedFiles.write(ba);
338 if (ba[ba.size()-1] != '\n')
339 editedFiles.write("\n", 1);
342 editedFiles.close();