2019-04-07 20:22:20 +02:00
|
|
|
#include <QCommandLineParser>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QRegularExpression>
|
|
|
|
#include <QSqlError>
|
|
|
|
#include "commanddelete.h"
|
|
|
|
|
|
|
|
|
2019-04-09 22:03:04 +02:00
|
|
|
int CommandDelete::removeNonExistent(QSqlDatabase &db, bool verbose, bool dryRun, QString pattern)
|
|
|
|
{
|
2019-04-07 20:22:20 +02:00
|
|
|
|
|
|
|
//TODO: port this to QRegularExpression once >5.12 gets more widespread because of this bug
|
|
|
|
//https://bugreports.qt.io/browse/QTBUG-72539?focusedCommentId=439053&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel
|
|
|
|
|
2019-04-09 22:03:04 +02:00
|
|
|
// QRegularExpression regexPattern = QRegularExpression::wildcardToRegularExpression(pattern
|
2019-04-07 20:22:20 +02:00
|
|
|
bool usePattern = ! pattern.isEmpty();
|
|
|
|
QRegExp regexPattern(pattern);
|
|
|
|
regexPattern.setPatternSyntax(QRegExp::PatternSyntax::WildcardUnix);
|
|
|
|
|
|
|
|
|
2019-04-09 22:03:04 +02:00
|
|
|
//TODO: try to translate pattern to SQL WHERE statement
|
|
|
|
QSqlQuery pathsQuery("SELECT path FROM file", db);
|
|
|
|
if(!pathsQuery.exec())
|
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::error() << "Failed to query current paths" << endl;
|
2019-04-09 22:03:04 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2019-04-07 20:22:20 +02:00
|
|
|
|
2019-04-09 22:03:04 +02:00
|
|
|
while(pathsQuery.next())
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-09 22:03:04 +02:00
|
|
|
QString path = pathsQuery.value(0).toString();
|
|
|
|
bool removeFile = true;
|
|
|
|
if(usePattern)
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-09 22:03:04 +02:00
|
|
|
removeFile = regexPattern.exactMatch(path);
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
2019-04-09 22:03:04 +02:00
|
|
|
if(removeFile)
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-09 22:03:04 +02:00
|
|
|
QFile file(path);
|
|
|
|
if(!file.exists())
|
2019-04-09 21:38:15 +02:00
|
|
|
{
|
2019-04-09 22:03:04 +02:00
|
|
|
if(!dryRun)
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-09 22:03:04 +02:00
|
|
|
QSqlQuery query("DELETE FROM file WHERE path = ?", db);
|
|
|
|
query.addBindValue(path);
|
|
|
|
if(!query.exec())
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::error() << "Failed to delete " << path << query.lastError() << endl;
|
2019-04-09 22:03:04 +02:00
|
|
|
return 1;
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
2019-04-09 22:03:04 +02:00
|
|
|
if(verbose)
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::info() << "Deleted " << path << endl;
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-09 22:03:04 +02:00
|
|
|
else
|
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::info() << "Would delete " << path << endl;
|
2019-04-09 22:03:04 +02:00
|
|
|
}
|
|
|
|
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-09 22:03:04 +02:00
|
|
|
}
|
2019-04-07 20:22:20 +02:00
|
|
|
|
2019-04-09 22:03:04 +02:00
|
|
|
int CommandDelete::removePaths(const QStringList &paths, QSqlDatabase &db, bool verbose, bool dryRun)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
for(const QString &file : paths)
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
|
|
|
QFileInfo fileInfo(file);
|
|
|
|
QString absPath = fileInfo.absoluteFilePath();
|
|
|
|
if(fileExistsInDatabase(db, absPath))
|
|
|
|
{
|
2019-04-09 21:38:15 +02:00
|
|
|
if(!dryRun)
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-09 21:38:15 +02:00
|
|
|
QSqlQuery deletionQuery("DELETE FROM file WHERE path = ?", db);
|
|
|
|
deletionQuery.addBindValue(absPath);
|
|
|
|
if(deletionQuery.exec())
|
|
|
|
{
|
|
|
|
if(verbose)
|
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::info() << "Deleted" << absPath << endl;
|
2019-04-09 21:38:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2019-04-07 20:22:20 +02:00
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::error()<< "Failed to delete:" << absPath << deletionQuery.lastError() << endl;
|
2019-04-09 22:03:04 +02:00
|
|
|
result = 1;
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-09 21:38:15 +02:00
|
|
|
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-10 18:57:27 +02:00
|
|
|
Utils::error() << "No such file in database:" << absPath << endl;
|
2019-04-09 22:03:04 +02:00
|
|
|
result = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
int CommandDelete::handle(QStringList arguments)
|
|
|
|
{
|
|
|
|
QCommandLineParser parser;
|
|
|
|
parser.addOptions({
|
|
|
|
{ { "v", "verbose" }, "Print path of the files while deleting them" },
|
|
|
|
{ { "n", "dry-run"}, "Only print which files would be deleted from the database, don't delete them"},
|
|
|
|
{ "pattern", "Only delete files from index matching the pattern, e. g. */.git/*. Only applies to --deleted or standalone.", "pattern" },
|
|
|
|
{ "deleted", "Delete all files from the index that don't exist anymore" }
|
|
|
|
});
|
|
|
|
|
|
|
|
parser.addHelpOption();
|
|
|
|
parser.addPositionalArgument("delete", "Delete paths from the index", "delete [paths...]");
|
|
|
|
|
|
|
|
parser.process(arguments);
|
|
|
|
bool verbose = parser.isSet("verbose");
|
|
|
|
bool dryRun = parser.isSet("dry-run");
|
|
|
|
QString pattern = parser.value("pattern");
|
|
|
|
QSqlDatabase db = dbConnection();
|
|
|
|
|
|
|
|
|
|
|
|
if(parser.isSet("deleted"))
|
|
|
|
{
|
|
|
|
|
|
|
|
int result = removeNonExistent(db, verbose, dryRun, pattern);
|
|
|
|
if(result != 0)
|
|
|
|
{
|
|
|
|
return result;
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
2019-04-09 22:03:04 +02:00
|
|
|
}
|
2019-04-07 20:22:20 +02:00
|
|
|
|
2019-04-09 22:03:04 +02:00
|
|
|
QStringList files = parser.positionalArguments();
|
|
|
|
int result = removePaths(files,db, verbose, dryRun);
|
|
|
|
if(result != 0)
|
|
|
|
{
|
|
|
|
return result;
|
2019-04-07 20:22:20 +02:00
|
|
|
}
|
2019-04-09 22:03:04 +02:00
|
|
|
|
|
|
|
|
2019-04-07 20:22:20 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|