Compare commits

...

28 Commits

Author SHA1 Message Date
Albert S. 5f19328679 Release v0.4 2022-06-29 19:31:40 +02:00
Albert S. 5ffd7ae97e shared: common: setPdfViewer(): Fix missing spaces between viewer and args 2022-06-29 19:31:40 +02:00
Albert S. 9ed28df09c README.me: Minor changes 2022-06-29 18:00:05 +02:00
Albert S. 69e028daf5 gui: mainwindow: Open new AboutDialog 2022-06-29 18:00:05 +02:00
Albert S. d4b0c1feae gui: Add new AboutDialog to show our licenses "paperwork" 2022-06-29 18:00:05 +02:00
Albert S. 990888efc1 shared: Include license texts as resource 2022-06-29 18:00:05 +02:00
Albert S. 3f8c147182 Add LICENSE-3RD-PARTY 2022-06-29 18:00:05 +02:00
Albert S. ba030169aa gui: previews: Allow filtering file for which to show preview 2022-06-29 18:00:05 +02:00
Albert S. 1636e39c5b shared: ParallelDirScanner: Fix missing progress report from top-level scan 2022-06-27 23:11:26 +02:00
Albert S. bda23670e3 shared: ParallelDirScanner: Correct filter to 'NoDotAndDotDot' from 'NoDotDot' 2022-06-27 23:10:53 +02:00
Albert S. d0fe51c666 README: Mention prebuilt tarball, add sig verification, minor improvements 2022-06-24 19:17:50 +02:00
Albert S. a561032668 shared: Indexer: Adjust for OK_WASEMPTY 2022-06-24 19:17:50 +02:00
Albert S. b8006bde7b shared: FileSaver: Don't launch SandboxedProcessor for empty files 2022-06-24 19:17:50 +02:00
Albert S. 614238edda shared: FileSaver: Print message for OK_WASEMPTY 2022-06-24 19:17:50 +02:00
Albert S. 83ed935790 shared: FileSaver: Return OK_WASEMPTY
We get OK_WASEMPTY from the processor when there
usually should be something. Rarely, this is not the case.

Let the callers know about this state at least
2022-06-24 19:17:50 +02:00
Albert S. 69837ed60f shared: SaveFileResult: Add OK_WASEMPTY when processor could not extract anything 2022-06-24 19:17:50 +02:00
Albert S. 2ad99699bf shared: FileSaver: Adjust to SandboxedProcessor new SaveFileResult value 2022-06-24 19:17:50 +02:00
Albert S. b6b3e2f3c0 shared SandBoxedProcessor: Return SaveFileResult, remove defines
Not entirely ideal as SandboxedProcessor does not save anything,
but an improvement nevertheless over the current mess
2022-06-24 19:17:50 +02:00
Albert S. cf0c940b15 shared: Move SaveFileResult enum to own header 2022-06-24 19:17:50 +02:00
Albert S. 9c41d531b0 gui: mainwindow: Add button to save log of failed paths 2022-06-24 19:17:50 +02:00
Albert S. 780318db6d shared: Indexer: Consider new NOACCESS too 2022-06-24 19:17:50 +02:00
Albert S. 9fd48d4664 shared: FileSaver: Return NOACCESS when no read access 2022-06-24 19:17:50 +02:00
Albert S. e99b2ba091 shared: Indexer: IndexResult: Introduce failedResults() 2022-06-24 19:17:50 +02:00
Albert S. 0867ab294d shared: SandboxedProcessor: Return NO_ACCESS when file not readable 2022-06-24 19:17:50 +02:00
Albert S. 01a6a499c5 shared: SqliteDBService: Add 'NOACCESS'. Add function to convert enum to str 2022-06-24 19:17:50 +02:00
Albert S. b3c6ce3899 cli: main: Improve usage text, print it when unknown command given 2022-06-24 19:17:50 +02:00
Albert S. 72dae1f7be cli: CommandAdd: Mention we read from stdin when no path is given 2022-06-24 19:17:50 +02:00
Albert S. e01f5d6490 shared: ParallelDirScanner: Perform first pass to collect paths
Scan the top directory to collect paths for the threads. This
way we don't launch threads for paths without subdirs. Secondly,
large trees like usually $HOME will be scanned by multiple threads
at first.

Nevertheless, ParallelDirScanner can be improved still as threads may
run quickly out of work, so we may end up with only one anyway again
2022-06-24 19:17:50 +02:00
25 changed files with 1612 additions and 102 deletions

View File

@ -1,5 +1,19 @@
# looqs: Release notes
## 2022-06-29 - v0.4
This release makes several minor improvements and begins prebuilt binaries of looqs that (should) run
on any recent Linux distribution.
- General: Begin new, experimental distro-agnostic tarball containing prebuilt binaries and libs. See the README for more information.
- GUI: In the "Previews" tab, allow filtering by file, to only show previews for a specific file.
- GUI: Add "Show previews" context menu option to files in result (if available)
- General: Fix build with libquazip 1.X
- General: Properly report access errors as a failure during indexing
- GUI: Add button to export a list of all paths that failed
- General: Improve dir scan threading
- CLI: Improve helptext
- General: Add voidlinux build instructions
## 2022-06-14 - v0.3
CHANGES:
- GUI: Add settings tab to configure various settings

1119
LICENSE-3RD-PARTY Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,6 @@ looqs is a tool that creates a full-text search index for your files. It allows
search terms have been found, as shown in the screenshots below.
## Screenshots
The screenshots in this section may occasionally be slightly outdated, but they are usually recent enough to get an overall impression of the current state of the GUI.
### Preview
looqs allow you to look inside files. It marks what you have searched for.
@ -28,9 +26,10 @@ There is no need to write the long form of filters. There are also booleans avai
![Screenshot looqs results](https://garage.quitesimple.org/assets/looqs/looqs_beatles_marley.png)
The screenshots in this section may occasionally be slightly outdated, but they are usually recent enough to get an overall impression of the current state of the GUI.
## Current status
Last version: 2022-06-14, v0.3
Latest version: 2022-06-29, v0.4
Please see [Changelog](CHANGELOG.md) for a human readable list of changes.
@ -58,6 +57,8 @@ Linux (on amd64) is currently the main focus. Currently, I don't plan on support
### Licence
GPLv3.
For the dependencies/third-party libraries, see: LICENSE-3RD-PARTY
### Contributing
Please see the [Contribution guidelines](CONTRIBUTING.md) file.
@ -106,7 +107,35 @@ sudo apt-get update
sudo apt-get install looqs
```
### Prebuilt tarball (distro-agnostic) (EXPERIMENTAL)
looqs is also distributed as a tarball containing prebuilt binaries and its library dependencies. The tarball is
built using the Gentoo Hardened toolchain and the Qt version is smaller than what distributions usually
include. It does not include libraries that should mess with fontrendering or the graphics stack. The binaries should run on any recent Linux distribution (requires glibc 2.34 or newer at least) and expects
dependencies such as libGL to be provided by your distribution already (should be the case).
It's considered experimental for two reasons. Firstly, looqs has no updater (yet). You will have to manually check for updates. Secondly, I can't guarantee that I'll be quick with updates of the tarball specifically if the library versions become outdated between looqs updates.
You are therefore encouraged to use distro-native packages or to build it yourself if possible.
The tarball can be obtained here: https://repo.quitesimple.org/tarball/looqs
Quick start:
```
# Verify sig, see the end of this document: gpg --verify looqs-v0.4.tar.xz.sig
tar xf looqs-v0.4.tar.xz # Replace with the actual version you have obtained
cd looqs-v0.4
./looqs-gui # or ./looqs for the CLI
```
An AppImage may accompany the tarball in the future.
### Other distros
I'll probably add a package for voidlinux at some point and maybe will provide a Gentoo ebuild. However, I would appreciate help for others distros. If you create a package, let me know!
As for distro-agnostic packages, I will also take a look into appimage / flatpak etc. and/or maybe just provide a self-contained archive.
### Signature verification
Release tags can be verified with [my PGP public key](https://quitesimple.org/share/pubkey). For what little it's worth, its fingerprint is: `C342 CA02 D2EC 2E14 F3C3 D5FF 7F7B 4C08 02CD 02F2`
Packages can be verified with the [repo-specific public key](https://repo.quitesimple.org/repo.quitesimple.org.asc). For what little it's worth, its fingerprint is: `1B49 45B3 16B2 468A 3DAC C1E0 75EF 3FE8 D753 C8F9`

View File

@ -47,7 +47,8 @@ int CommandAdd::handle(QStringList arguments)
{{"t", "threads"}, "Number of threads to use.", "threads"}});
parser.addHelpOption();
parser.addPositionalArgument("add", "Add paths to the index", "add [paths...]");
parser.addPositionalArgument("add", "Add paths to the index",
"add [paths...]. If no path is given, read from stdin, one path per line.");
parser.process(arguments);
this->keepGoing = parser.isSet("continue");

View File

@ -30,6 +30,7 @@
void printUsage(QString argv0)
{
qInfo() << "Usage:" << argv0 << "command";
qInfo() << "Valid commands: add, update, delete, search, list. Each command has a --help option.";
}
Command *commandFromName(QString name, SqliteDbService &dbService)
@ -97,7 +98,7 @@ int main(int argc, char *argv[])
QString file = args.at(1);
SandboxedProcessor processor(file);
return processor.process();
return static_cast<int>(processor.process());
}
Command *cmd = commandFromName(commandName, dbService);
if(cmd != nullptr)
@ -116,7 +117,7 @@ int main(int argc, char *argv[])
}
else
{
Logger::error() << "Unknown command:" << commandName << Qt::endl;
printUsage(argv0);
return 1;
}

74
gui/aboutdialog.cpp Normal file
View File

@ -0,0 +1,74 @@
#include <QTabWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QTextBrowser>
#include <QPushButton>
#include "aboutdialog.h"
#include "common.h"
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout(this);
QTabWidget *tabWidget = new QTabWidget(this);
this->setWindowTitle("About looqs");
QHBoxLayout *closeLayout = new QHBoxLayout();
QPushButton *closeButton = new QPushButton(this);
closeButton->setText("Close");
closeButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(closeButton, &QPushButton::clicked, this, &QDialog::close);
closeLayout->setMargin(10);
closeLayout->addStretch(10);
closeLayout->addWidget(closeButton);
layout->addWidget(tabWidget);
layout->addLayout(closeLayout);
QFrame *frame = new QFrame(this);
QVBoxLayout *aboutLayout = new QVBoxLayout(frame);
frame->setLayout(aboutLayout);
QLabel *aboutLooqs = new QLabel(this);
QString html = "<h2>looqs</h2>";
html += "Full-text search with previews for your files<br><br>";
html += "Copyright (c) 2018-2022: Albert Schwarzkopf<br><br>";
html += QString("Version: %1<br><br>").arg(Common::versionText());
html += "Contact: looqs at quitesimple dot org<br><br>";
html += "Website: <a href=\"https://quitesimple.org\">https://quitesimple.org</a><br><br>";
html += "Source code: <a "
"href=\"https://github.com/quitesimpleorg/looqs\">https://github.com/quitesimpleorg/looqs</a><br><br>";
html += "License: GPLv3<br><br>";
html += "looqs is open source and free of charge in the hope it will be useful. The author(s) do not "
"give any warranty. In the unlikely event of any damage, the author(s) cannot be held responsible. "
"You are using looqs at your own risk<br><br>";
html += "looqs uses third-party libraries, please see the corresponding tab.";
aboutLooqs->setText(html);
aboutLooqs->setTextFormat(Qt::RichText);
QLabel *logo = new QLabel(this);
QImage image(QString(":/looqs.svg"));
logo->setPixmap(QPixmap::fromImage(image));
aboutLayout->addWidget(logo);
aboutLayout->addWidget(aboutLooqs);
tabWidget->addTab(frame, "About");
QFile license(QString(":/LICENSE"));
license.open(QIODevice::ReadOnly);
QString licenseText = license.readAll();
QFile thirdPartyLicense(QString(":./LICENSE-3RD-PARTY"));
thirdPartyLicense.open(QIODevice::ReadOnly);
QString thirdPartyLicenseInfo = thirdPartyLicense.readAll();
QTextBrowser *licenseTextBrowser = new QTextBrowser(this);
licenseTextBrowser->setText(licenseText);
QTextBrowser *thirdPartyLicenceTextBrowser = new QTextBrowser(this);
thirdPartyLicenceTextBrowser->setText(thirdPartyLicenseInfo);
tabWidget->addTab(licenseTextBrowser, "License");
tabWidget->addTab(thirdPartyLicenceTextBrowser, "Third-party libraries");
}

12
gui/aboutdialog.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef ABOUTDIALOG_H
#define ABOUTDIALOG_H
#include <QDialog>
class AboutDialog : public QDialog
{
Q_OBJECT
public:
AboutDialog(QWidget *parent = nullptr);
};
#endif // ABOUTDIALOG_H

View File

@ -27,6 +27,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
aboutdialog.cpp \
ipcpreviewclient.cpp \
ipcpreviewworker.cpp \
ipcserver.cpp \
@ -44,6 +45,7 @@ SOURCES += \
rendertarget.cpp
HEADERS += \
aboutdialog.h \
ipc.h \
ipcpreviewclient.h \
ipcpreviewworker.h \

View File

@ -114,7 +114,7 @@ int main(int argc, char *argv[])
QString file = args.at(2);
SandboxedProcessor processor(file);
return processor.process();
return static_cast<int>(processor.process());
}
}
QString ipcSocketPath = Common::ipcSocketPath();

View File

@ -23,6 +23,7 @@
#include "../shared/common.h"
#include "ipcpreviewclient.h"
#include "previewgenerator.h"
#include "aboutdialog.h"
MainWindow::MainWindow(QWidget *parent, QString socketPath)
: QMainWindow(parent), ui(new Ui::MainWindow), progressDialog(this)
@ -40,6 +41,7 @@ MainWindow::MainWindow(QWidget *parent, QString socketPath)
{
this->ui->previewProcessBar->setValue(this->ui->previewProcessBar->maximum());
this->ui->spinPreviewPage->setEnabled(true);
this->ui->comboPreviewFiles->setEnabled(true);
});
connect(&ipcPreviewClient, &IPCPreviewClient::error, this,
[this](QString msg)
@ -82,6 +84,13 @@ MainWindow::MainWindow(QWidget *parent, QString socketPath)
ui->spinPreviewPage->setValue(1);
ui->spinPreviewPage->setMinimum(1);
ui->btnOpenFailed->setVisible(false);
ui->comboPreviewFiles->setVisible(false);
auto policy = ui->btnOpenFailed->sizePolicy();
policy.setRetainSizeWhenHidden(true);
ui->btnOpenFailed->setSizePolicy(policy);
}
void MainWindow::addPathToIndex()
@ -172,26 +181,13 @@ void MainWindow::connectSignals()
}
}
});
connect(
ui->menuAboutAction, &QAction::triggered, this,
[this](bool checked)
{
QString html = "<h2>looqs</h2>";
html += "Full-text search with previews for your files<br><br>";
html += "Copyright (c) 2018-2022: Albert Schwarzkopf<br><br>";
html += QString("Version: %1<br><br>").arg(Common::versionText());
html += "Contact: looqs at quitesimple dot org<br><br>";
html += "Website: <a href=\"https://quitesimple.org\">https://quitesimple.org</a><br><br>";
html +=
"Source code: <a "
"href=\"https://github.com/quitesimpleorg/looqs\">https://github.com/quitesimpleorg/looqs</a><br><br>";
html += "License: GPLv3<br><br><br>";
html += "looqs is open source and free of charge in the hope it will be useful. The author(s) do not "
"give any warranty. In the unlikely event of any damage, the author(s) cannot be held responsible. "
"You are using looqs at your own risk";
connect(ui->menuAboutAction, &QAction::triggered, this,
[this](bool checked)
{
AboutDialog aboutDialog(this);
QMessageBox::about(this, "About looqs", html);
});
aboutDialog.exec();
});
connect(ui->menuAboutQtAction, &QAction::triggered, this,
[this](bool checked) { QMessageBox::aboutQt(this, "About Qt"); });
connect(ui->menuSyncIndexAction, &QAction::triggered, this, &MainWindow::startIndexSync);
@ -210,6 +206,35 @@ void MainWindow::connectSignals()
connect(this, &MainWindow::beginIndexSync, indexSyncer, &IndexSyncer::sync);
connect(&this->progressDialog, &QProgressDialog::canceled, indexSyncer, &IndexSyncer::cancel);
connect(ui->btnSaveSettings, &QPushButton::clicked, this, &MainWindow::saveSettings);
connect(ui->btnOpenFailed, &QPushButton::clicked, this, &MainWindow::exportFailedPaths);
connect(
ui->comboPreviewFiles, qOverload<int>(&QComboBox::currentIndexChanged), this, [&]() { makePreviews(1); },
Qt::QueuedConnection);
}
void MainWindow::exportFailedPaths()
{
QString filename =
QString("/tmp/looqs_indexresult_failed_%1").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss"));
QFile outFile(filename);
if(!outFile.open(QIODevice::WriteOnly | QIODevice::Text))
{
QMessageBox::critical(this, "Failed to write log file", "An error occured while trying to create log file");
return;
}
QTextStream stream(&outFile);
IndexResult result = this->indexer->getResult();
stream << "Failed to index the following paths:\n";
for(FileScanResult &fsr : result.failedResults())
{
stream << fsr.first << " " << SaveFileResultToString(fsr.second) << '\n';
}
QDesktopServices::openUrl(filename);
}
void MainWindow::startIndexSync()
@ -254,6 +279,7 @@ void MainWindow::startIndexing()
ui->txtSearch->setEnabled(false);
ui->previewProcessBar->setValue(0);
ui->previewProcessBar->setVisible(true);
ui->btnOpenFailed->setVisible(false);
QVector<QString> paths;
QStringList pathSettingsValue;
@ -289,6 +315,10 @@ void MainWindow::finishIndexing()
ui->settingsTab->setEnabled(true);
ui->txtPathScanAdd->setEnabled(true);
ui->txtSearch->setEnabled(true);
if(result.erroredPaths > 0)
{
ui->btnOpenFailed->setVisible(true);
}
}
void MainWindow::comboScaleChanged(int i)
@ -477,6 +507,9 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
{
this->previewableSearchResults.clear();
ui->treeResultsList->clear();
ui->comboPreviewFiles->clear();
ui->comboPreviewFiles->addItem("All previews");
ui->comboPreviewFiles->setVisible(true);
bool hasDeleted = false;
for(const SearchResult &result : results)
@ -505,6 +538,7 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
if(PreviewGenerator::get(pathInfo) != nullptr)
{
this->previewableSearchResults.append(result);
ui->comboPreviewFiles->addItem(result.fileData.absPath);
}
}
}
@ -582,6 +616,13 @@ void MainWindow::makePreviews(int page)
QVector<RenderTarget> targets;
for(SearchResult &sr : this->previewableSearchResults)
{
if(ui->comboPreviewFiles->currentIndex() != 0)
{
if(sr.fileData.absPath != ui->comboPreviewFiles->currentText())
{
continue;
}
}
RenderTarget renderTarget;
renderTarget.path = sr.fileData.absPath;
@ -602,6 +643,7 @@ void MainWindow::makePreviews(int page)
ui->previewProcessBar->setVisible(this->previewableSearchResults.size() > 0);
++this->currentPreviewGeneration;
this->ui->spinPreviewPage->setEnabled(false);
this->ui->comboPreviewFiles->setEnabled(false);
emit startIpcPreviews(renderConfig, targets);
}
@ -617,6 +659,20 @@ void MainWindow::createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo)
menu.addAction("Copy full path to clipboard",
[&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.absoluteFilePath()); });
menu.addAction("Open containing folder", [this, &fileInfo] { this->openFile(fileInfo.absolutePath()); });
auto result =
std::find_if(this->previewableSearchResults.begin(), this->previewableSearchResults.end(),
[this, &fileInfo](SearchResult &a) { return fileInfo.absoluteFilePath() == a.fileData.absPath; });
if(result != this->previewableSearchResults.end())
{
menu.addAction("Show previews for this file",
[this, &fileInfo]
{
ui->tabWidget->setCurrentIndex(1);
this->ui->comboPreviewFiles->setCurrentText(fileInfo.absoluteFilePath());
});
}
}
void MainWindow::openDocument(QString path, int num)

View File

@ -75,6 +75,7 @@ class MainWindow : public QMainWindow
void addPathToIndex();
void startIndexSync();
void saveSettings();
void exportFailedPaths();
signals:
void startIpcPreviews(RenderConfig config, const QVector<RenderTarget> &targets);

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1280</width>
<height>736</height>
<height>855</height>
</rect>
</property>
<property name="windowTitle">
@ -27,7 +27,7 @@
<enum>QTabWidget::South</enum>
</property>
<property name="currentIndex">
<number>3</number>
<number>1</number>
</property>
<widget class="QWidget" name="resultsTab">
<attribute name="title">
@ -82,7 +82,7 @@
<x>0</x>
<y>0</y>
<width>1244</width>
<height>446</height>
<height>565</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout"/>
@ -162,6 +162,16 @@
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboPreviewFiles">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
@ -184,6 +194,16 @@
<string>Index</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="0">
<widget class="QLineEdit" name="txtIgnorePatterns"/>
</item>
<item row="11" column="0">
<widget class="QPushButton" name="btnStartIndexing">
<property name="text">
<string>Start indexing</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBoxPaths">
<property name="title">
@ -243,6 +263,12 @@
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="lblPathsFound">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Paths found:</string>
</property>
@ -250,17 +276,42 @@
</item>
<item>
<widget class="QLabel" name="lblPathsFoundValue">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="lblAdded">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
@ -274,17 +325,42 @@
</item>
<item>
<widget class="QLabel" name="lblAddedValue">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="lblSkipped">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
@ -298,17 +374,42 @@
</item>
<item>
<widget class="QLabel" name="lblSkippedValue">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="lblFailed">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
@ -322,26 +423,35 @@
</item>
<item>
<widget class="QLabel" name="lblFailedValue">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnOpenFailed">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Open log of failed paths</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="6" column="0">
<widget class="QLineEdit" name="txtIgnorePatterns"/>
</item>
<item row="10" column="0">
<widget class="QPushButton" name="btnStartIndexing">
<property name="text">
<string>Start indexing</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="settingsTab">

View File

@ -17,6 +17,7 @@
inline void initResources()
{
Q_INIT_RESOURCE(migrations);
Q_INIT_RESOURCE(plaintexts);
}
bool Common::initSqliteDatabase(QString path)
@ -68,11 +69,11 @@ void Common::setPdfViewer()
}
else if(evincePath != "")
{
value = evincePath + "-i %p %f";
value = evincePath + " -i %p %f";
}
else if(qpdfviewPath != "")
{
value = qpdfviewPath + "%f#%p";
value = qpdfviewPath + " %f#%p";
}
QSettings settings;

View File

@ -19,9 +19,12 @@ void DirScanWorker::run()
QString path;
/* TODO: if we have e. g. only one path, then only one thread will scan this path.
*
* Thus, we must resubmit to the queue directories so other threads can help
the current one (requires a new logic for threads in ParallelDirScanner). Alterantively,
start new DirScanWorkers ourselves here... */
* Thus, we must submit new directory paths to the queue so other threads can help
the current one.
It also may not be guaranteed enqueuing new paths is faster than just scanning them,
at least not for dirs with a small number of files
*/
while(queue->dequeue(path))
{
if(wildcardMatcher.match(path))

View File

@ -87,6 +87,10 @@ int FileSaver::processFiles(const QVector<QString> paths, std::function<SaveFile
{
Logger::info() << "Saved" << path << Qt::endl;
}
else if(result == OK_WASEMPTY)
{
Logger::info() << "Saved (but content was empty)" << path << Qt::endl;
}
}
}
});
@ -98,7 +102,12 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
QVector<PageData> pageData;
QString canonicalPath = fileInfo.canonicalFilePath();
int status = -1;
int processorReturnCode = -1;
if(!fileInfo.isReadable())
{
return NOACCESS;
}
if(!fileInfo.exists())
{
@ -115,44 +124,45 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
}
}
QProcess process;
QStringList args;
args << "process" << canonicalPath;
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
process.start("/proc/self/exe", args);
process.waitForStarted();
process.waitForFinished();
/* TODO: This is suboptimal as it eats lots of mem
* but avoids a weird QDataStream/QProcess behaviour
* where it thinks the process has ended when it has not...
*
* Also, there seem to be issues with reads not being blocked, so
* the only reliable way appears to be waiting until the process
* finishes.
*/
QDataStream in(process.readAllStandardOutput());
while(!in.atEnd())
if(fileInfo.size() > 0)
{
PageData pd;
in >> pd;
pageData.append(pd);
}
status = process.exitCode();
if(status != 0 && status != NOTHING_PROCESSED)
{
Logger::error() << "FileSaver::saveFile(): Error while processing" << canonicalPath << ":"
<< "Exit code " << status << Qt::endl;
QProcess process;
QStringList args;
args << "process" << canonicalPath;
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
process.start("/proc/self/exe", args);
process.waitForStarted();
process.waitForFinished();
return PROCESSFAIL;
/* TODO: This is suboptimal as it eats lots of mem
* but avoids a weird QDataStream/QProcess behaviour
* where it thinks the process has ended when it has not...
*
* Also, there seem to be issues with reads not being blocked, so
* the only reliable way appears to be waiting until the process
* finishes.
*/
QDataStream in(process.readAllStandardOutput());
while(!in.atEnd())
{
PageData pd;
in >> pd;
pageData.append(pd);
}
processorReturnCode = process.exitCode();
if(processorReturnCode != OK && processorReturnCode != OK_WASEMPTY)
{
Logger::error() << "FileSaver::saveFile(): Error while processing" << canonicalPath << ":"
<< "Exit code " << processorReturnCode << Qt::endl;
return static_cast<SaveFileResult>(processorReturnCode);
}
}
}
// Could happen if a file corrupted for example
if(pageData.isEmpty() && status != NOTHING_PROCESSED)
SaveFileResult result = this->dbService->saveFile(fileInfo, pageData);
if(result == OK && processorReturnCode == OK_WASEMPTY)
{
Logger::error() << "Could not get any content for " << canonicalPath << Qt::endl;
return OK_WASEMPTY;
}
return this->dbService->saveFile(fileInfo, pageData);
return result;
}

View File

@ -120,7 +120,7 @@ void Indexer::dirScanProgress(int current, int total)
void Indexer::processFileScanResult(FileScanResult result)
{
if(result.second == DBFAIL || result.second == PROCESSFAIL || result.second == NOTFOUND)
if(result.second != OK || result.second != OK_WASEMPTY || result.second != SKIPPED)
{
this->currentIndexResult.results.append(result);
if(!keepGoing)
@ -138,7 +138,8 @@ void Indexer::processFileScanResult(FileScanResult result)
}
}
if(result.second == OK)
/* TODO: OK_WASEMPTY might need a special list */
if(result.second == OK || result.second == OK_WASEMPTY)
{
++this->currentIndexResult.addedPaths;
}

View File

@ -22,19 +22,30 @@ class IndexResult
return addedPaths + skippedPaths + erroredPaths;
}
QVector<QString> failedPaths() const
QVector<FileScanResult> failedResults() const
{
QVector<QString> result;
QVector<FileScanResult> result;
std::for_each(results.begin(), results.end(),
[&result](FileScanResult res)
{
if(res.second == DBFAIL || res.second == PROCESSFAIL || res.second == NOTFOUND)
if(res.second == DBFAIL || res.second == PROCESSFAIL || res.second == NOTFOUND ||
res.second == NOACCESS)
{
result.append(res.first);
result.append(res);
}
});
return result;
}
QVector<QString> failedPaths() const
{
QVector<QString> result;
QVector<FileScanResult> results = failedResults();
std::for_each(results.begin(), results.end(), [&result](FileScanResult res) { result.append(res.first); });
return result;
}
};
class Indexer : public QObject

View File

@ -71,7 +71,35 @@ void ParallelDirScanner::scan()
this->targetPathsQueue.clear();
this->resultPathsQueue.clear();
this->targetPathsQueue.enqueue(this->paths);
/* First scan without subdirs. This way we collect paths for the threads */
WildcardMatcher matcher;
matcher.setPatterns(this->ignorePatterns);
for(QString &path : this->paths)
{
QDirIterator iterator(path, QStringList{}, QDir::Dirs | QDir::QDir::Files | QDir::NoDotAndDotDot);
while(iterator.hasNext())
{
QString path = iterator.next();
if(matcher.match(path))
{
continue;
}
QFileInfo info = iterator.fileInfo();
if(!info.isSymLink())
{
if(info.isDir())
{
this->targetPathsQueue.enqueue(info.absoluteFilePath());
}
else
{
this->resultPathsQueue.enqueue(info.absoluteFilePath());
this->processedPaths += 1;
}
}
}
}
emit this->progress(this->processedPaths, this->processedPaths);
int threadsNum = getThreadsNum();
if(threadsNum == 0)
{

6
shared/plaintexts.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource>
<file>../LICENSE</file>
<file>../LICENSE-3RD-PARTY</file>
</qresource>
</RCC>

View File

@ -10,8 +10,6 @@ enum DataSource
ARRAY
};
#define NOTHING_PROCESSED 4
class Processor
{
public:

View File

@ -80,7 +80,7 @@ void SandboxedProcessor::printResults(const QVector<PageData> &pageData)
fsstdout.close();
}
int SandboxedProcessor::process()
SaveFileResult SandboxedProcessor::process()
{
QFileInfo fileInfo(this->filePath);
Processor *processor = processors.value(fileInfo.suffix(), nullptr);
@ -92,10 +92,14 @@ int SandboxedProcessor::process()
processor = defaultTextProcessor;
}
}
if(!fileInfo.isReadable())
{
return NOACCESS;
}
if(processor == nullptr || processor == nothingProcessor)
{
/* Nothing to do */
return NOTHING_PROCESSED;
return OK;
}
QVector<PageData> pageData;
@ -119,9 +123,9 @@ int SandboxedProcessor::process()
catch(LooqsGeneralException &e)
{
Logger::error() << "SandboxedProcessor: Error while processing" << absPath << ":" << e.message << Qt::endl;
return 3 /* PROCESSFAIL */;
return PROCESSFAIL;
}
printResults(pageData);
return 0;
return pageData.isEmpty() ? OK_WASEMPTY : OK;
}

View File

@ -3,6 +3,7 @@
#include <QString>
#include <QMimeDatabase>
#include "pagedata.h"
#include "savefileresult.h"
class SandboxedProcessor
{
@ -19,7 +20,7 @@ class SandboxedProcessor
this->filePath = filepath;
}
int process();
SaveFileResult process();
};
#endif // SANDBOXEDPROCESSOR_H

33
shared/savefileresult.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef SAVEFILERESULT_H
#define SAVEFILERESULT_H
#include <QStringList>
enum SaveFileResult
{
OK,
OK_WASEMPTY, /* The file was successfully read but no content could be extracted. Might be just an empty document or
so*/
SKIPPED, /* The file was not processed/saved, because it has not changed */
DBFAIL, /* A database error occured */
PROCESSFAIL, /* General processor failure */
NOTFOUND, /* The file was not found */
NOACCESS /* The process can't read the file */
};
static inline QString SaveFileResultToString(SaveFileResult sfr)
{
QStringList SaveFileResultStr;
SaveFileResultStr << "OK"
<< "OK_WASEMPTY"
<< "SKIPPED"
<< "DBFAIL"
<< "PROCESSFAIL"
<< "NOTFOUND"
<< "NOACCESS";
return SaveFileResultStr[(int)sfr];
}
#endif // SAVEFILERESULT_H

View File

@ -88,6 +88,7 @@ HEADERS += sqlitesearch.h \
pdfprocessor.h \
processor.h \
sandboxedprocessor.h \
savefileresult.h \
searchresult.h \
sqlitedbservice.h \
tagstripperprocessor.h \
@ -100,3 +101,4 @@ unix {
INSTALLS += target
}
RESOURCES = migrations/migrations.qrc
RESOURCES += plaintexts.qrc

View File

@ -7,14 +7,7 @@
#include "filedata.h"
#include "../shared/sqlitesearch.h"
#include "../shared/token.h"
enum SaveFileResult
{
OK,
SKIPPED,
DBFAIL,
PROCESSFAIL,
NOTFOUND
};
#include "savefileresult.h"
class SqliteDbService
{