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"
20 #include "GitRunner.h"
21 #include "AbstractCommand.h"
24 #include <QMutexLocker>
31 #define EditedFilesDatabase "vng-editedfiles"
33 Configuration::Configuration(const QString
§ion
)
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();
56 QDir
Configuration::repositoryMetaDir() const
58 const_cast<Configuration
*> (this)->readConfig();
59 return m_repoMetaDataDir
;
62 void Configuration::readConfig()
67 QObject deleterParent
;
69 QDir dir
= QDir::current();
74 m_repoMetaDataDir
= git
;
75 QDir
refs(git
.absoluteFilePath("refs/heads"));
76 m_emptyRepo
= refs
.count() == 2; // only '.' and '..'
81 } while(!dir
.isRoot());
83 QString home
= QDir::homePath();
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";
96 qint64 lineLength
= config
->readLine(buf
, sizeof(buf
));
99 QString line
= QString::fromUtf8(buf
, lineLength
);
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(' ');
108 m_options
.insert(option
.left(index
).trimmed(), option
.mid(index
).trimmed());
111 m_options
.insert(option
, QString());
118 QString
Configuration::optionArgument(const QString
&optionName
, const QString
&defaultValue
) const
120 if (m_options
.contains(optionName
))
121 return m_options
[optionName
];
125 bool Configuration::colorTerm() const
129 return QString(getenv("TERM")) != QString("dumb") && !Logger::hasNonColorPager();
134 bool Configuration::isEmptyRepo() const
136 const_cast<Configuration
*> (this)->readConfig();
140 QList
<Branch
> Configuration::allBranches()
143 QList
<Branch
> answer
;
144 answer
+= m_localBranches
;
145 answer
+= m_remoteBranches
;
149 QList
<Branch
> Configuration::branches()
152 return m_localBranches
;
155 QList
<Branch
> Configuration::remoteBranches()
158 return m_remoteBranches
;
161 void Configuration::fetchBranches()
163 if (m_fetchedBranches
)
165 m_fetchedBranches
= true;
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
) {
177 qint64 lineLength
= Vng::readLine(&git
, buf
, sizeof(buf
));
178 if (lineLength
== -1)
180 if (lineLength
> 46) { // only take stuff that is in the 'refs' dir.
181 QString
name(buf
+ 46);
182 name
= name
.trimmed(); // remove linefeed
184 if (name
.startsWith("remotes"))
185 m_remoteBranches
.append(branch
);
187 m_localBranches
.append(branch
);
192 bool Configuration::useEditMode() const
194 if (m_editMode
== StateUnknown
) {
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
)
207 editMode
= StateFalse
;
210 qint64 lineLength
= Vng::readLine(&git
, buf
, sizeof(buf
));
211 if (lineLength
== -1)
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
)
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()
234 return QList
<QByteArray
>();
235 QMutexLocker
locker(&m_editedFilesLock
);
236 // TODO do some file-locking
237 if (!m_editedFilesFetched
) {
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
>();
248 openedFiles
.waitForReadyRead(-1);
249 qint64 len
= openedFiles
.readLine(buf
, sizeof(buf
));
252 if (len
== 1 || buf
[0] == '#')
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)
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";
274 // TODO make sure we don't write the same filename to the DB twice.
277 m_editedFilesFetched
= false;
278 m_editedFiles
.clear();
280 foreach(QByteArray ba
, newFileNames
) {
283 editedFiles
.write(ba
);
284 if (ba
[ba
.size()-1] != '\n')
285 editedFiles
.write("\n", 1);
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)
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())
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";
325 m_editedFiles
.clear();
327 foreach (QByteArray ba
, currentContent
) {
329 foreach (QByteArray rem
, fileNames
) {
330 if (ba
.length() == rem
.length() && ba
.indexOf(rem
) == 0) { // thats the file to remove.
337 editedFiles
.write(ba
);
338 if (ba
[ba
.size()-1] != '\n')
339 editedFiles
.write("\n", 1);