Skip to content

Commit 9fb09eb

Browse files
authored
flag --stderr and exit messages (#229)
- emit signals - path operations from config.cpp moved to pathtools.cpp - tests fixed and extended - documentation updated
1 parent fc15060 commit 9fb09eb

41 files changed

Lines changed: 798 additions & 464 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/CLIHELP.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,32 @@ Skyscraper -p snes --cache edit --startat "rom name.zip"
847847
Skyscraper -p snes -s thegamesdb --startat "relative/path/to/rom name.zip"
848848
```
849849

850+
### --stderr
851+
852+
Prints a brief one-liner on `stderr` when Skyscraper ran into an error and exits with a non-zero return value. This is mainly useful when you call Skyscraper from another program. If you combine it with a redirect of `stdout` to `/dev/null` you can mute the general Skyscraper output. The format of the one-liner is: `Skyscraper: <cause>: <effect>`, thus it can be easily parsed by the calling program. Additionally, an exit code of 2 means some CLI parameter is wrong, an exit code of 1 is used by Skyscraper to signal other error conditions (with a `config.ini` setting or during runtime).
853+
854+
**Example(s)**
855+
856+
Try these in contrast to see the difference in output:
857+
858+
```bash
859+
# Force an error condition.
860+
$ Skyscraper -p dontexist
861+
[...]
862+
$ Skyscraper --stderr -p dontexist
863+
[...]
864+
$ Skyscraper --stderr -p dontexist > /dev/null
865+
Skyscraper: ambigous platform parameter: Platform parameter missing or unknown platform provided
866+
$ echo $? # returns 2 as platform is not valid
867+
868+
# Assume input folder ~/RetroPie/roms/bbcmicro does not yet exist.
869+
# However, platform name is valid.
870+
```bash
871+
$ Skyscraper --stderr -p bbcmicro > /dev/null
872+
Skyscraper: cannot access '/home/pi/RetroPie/roms/bbcmicro': No such directory
873+
$ echo $? # returns 1 as platform is valid but the input folder does not exist
874+
```
875+
850876
### --verbosity &lt;0-3&gt;
851877

852878
Sets how verbose Skyscraper should be when running. Default level is 0. The higher the value, the more info Skyscraper will output to the terminal while running. Maximum value is 3. Consider setting this in [`config.ini`](CONFIGINI.md#verbosity) instead.

docs/CONFIGINI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ Allowed in sections: `[main]`
447447
This option is _only_ applicable when also setting the `frontend="attractmode"` option. It sets the _emulator_ to be used when generating the `attractmode` game list. On RetroPie the emulator name is mostly the same as the platform.
448448

449449
Default value: unset
450-
Allowed in sections: `[main]`, `[<PLATFORM>]`, `[<FRONTEND>]`
450+
Allowed in sections: `[main]`, `[<PLATFORM>]` and frontend `[attractmode]`
451451

452452
---
453453

skyscraper.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ HEADERS += src/skyscraper.h \
136136
src/fxrotate.h \
137137
src/fxscanlines.h \
138138
src/nametools.h \
139+
src/pathtools.h \
139140
src/queue.h
140141

141142
SOURCES += src/main.cpp \
@@ -190,6 +191,7 @@ SOURCES += src/main.cpp \
190191
src/fxrotate.cpp \
191192
src/fxscanlines.cpp \
192193
src/nametools.cpp \
194+
src/pathtools.cpp \
193195
src/queue.cpp
194196

195197
SUBDIRS += \

src/abstractfrontend.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
#include "abstractfrontend.h"
2727

28-
#include "config.h"
2928
#include "gameentry.h"
29+
#include "pathtools.h"
3030

3131
#include <QDebug>
3232
#include <QDir>
@@ -117,7 +117,7 @@ QString AbstractFrontend::getTargetFilePath(const GameEntry::Types t,
117117
"maybe incomplete.";
118118
}
119119
}
120-
fp = Config::lexicallyNormalPath(fp);
120+
fp = PathTools::lexicallyNormalPath(fp);
121121
} else {
122122
fp = "";
123123
}

src/abstractfrontend.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ class AbstractFrontend : public QObject {
7777
bool copyMedia(GameEntry::Types &, const QString &, const QString &,
7878
GameEntry &);
7979

80+
signals:
81+
void die(const int &, const QString &, const QString &);
82+
8083
protected:
8184
virtual QString getTargetFileName(GameEntry::Types t,
8285
const QString &baseName) {

src/abstractscraper.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -733,16 +733,32 @@ QVector<int> AbstractScraper::getPlatformId(const QString) {
733733
QVariantMap AbstractScraper::readJson(const QString &filename) {
734734
QVariantMap m;
735735
QFile jsonFile(filename);
736-
if (jsonFile.open(QIODevice::ReadOnly)) {
737-
QJsonObject jsonObj =
738-
QJsonDocument::fromJson(jsonFile.readAll()).object();
739-
m = jsonObj.toVariantMap();
740-
jsonFile.close();
741-
} else {
742-
printf("\033[1;31mFile '%s' not found. Please fix.\n\nNow "
743-
"quitting...\033[0m\n",
736+
QJsonObject jsonObj;
737+
bool canRead = jsonFile.open(QIODevice::ReadOnly);
738+
if (canRead) {
739+
jsonObj = QJsonDocument::fromJson(jsonFile.readAll()).object();
740+
if (!jsonObj.isEmpty()) {
741+
m = jsonObj.toVariantMap();
742+
jsonFile.close();
743+
}
744+
}
745+
if (!canRead) {
746+
printf("\033[1;31mFile '%s' not found or not readable. Please "
747+
"fix.\nNot scraping...\n\033[0m",
748+
filename.toUtf8().constData());
749+
} else if (jsonObj.isEmpty()) {
750+
printf("\033[1;31mFile '%s' has invalid JSON format. Please fix.\nNot "
751+
"scraping...\n\033[0m",
744752
filename.toUtf8().constData());
745-
exit(1);
746753
}
747754
return m;
755+
}
756+
757+
void AbstractScraper::bury(const int &returnCode, const QString &effect,
758+
const QString &cause) {
759+
if (config->stdErr) {
760+
fprintf(stderr, "Skyscraper: %s: %s\n", effect.toStdString().c_str(),
761+
cause.toStdString().c_str());
762+
}
763+
exit(returnCode);
748764
}

src/abstractscraper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ class AbstractScraper : public QObject {
6464
void detectRegionFromFilename(const QFileInfo &info);
6565
#endif
6666

67+
signals:
68+
void die(const int &, const QString &, const QString &);
69+
70+
public slots:
71+
void bury(const int &, const QString &, const QString &);
72+
6773
protected:
6874
Settings *config;
6975

src/attractmode.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525

2626
#include "attractmode.h"
2727

28-
#include "config.h"
2928
#include "gameentry.h"
3029
#include "nametools.h"
30+
#include "pathtools.h"
3131
#include "strtools.h"
3232

3333
#include <QDate>
@@ -211,7 +211,9 @@ void AttractMode::checkReqs() {
211211
if (config->frontendExtra.isEmpty()) {
212212
printf("Frontend 'attractmode' requires emulator set with '-e'. Check "
213213
"'--help' for more information.\n");
214-
exit(0);
214+
emit die(
215+
1, "incomplete configuration",
216+
"Frontend 'attractmode' requires '-e' or 'emulator=' to be set");
215217
}
216218
if (!config->frontendExtra.contains(".cfg")) {
217219
config->frontendExtra.append(".cfg");
@@ -230,19 +232,21 @@ void AttractMode::checkReqs() {
230232

231233
printf("Looking for emulator cfg file:\n");
232234

233-
if (checkEmulatorFile(config->frontendExtra)) {
234-
return;
235-
}
236-
237235
// For RetroPie this is linked directly to
238236
// /opt/retropie/configs/all/attractmode/emulators/
239-
if (checkEmulatorFile(QDir::homePath() % "/.attract/emulators/" +
240-
config->frontendExtra)) {
237+
QString altEmuFn =
238+
QDir::homePath() % "/.attract/emulators/" % config->frontendExtra;
239+
if (checkEmulatorFile(config->frontendExtra) ||
240+
checkEmulatorFile(altEmuFn)) {
241241
return;
242242
}
243243

244244
printf("Couldn't locate emulator cfg file, exiting...\n");
245-
exit(1);
245+
emit die(1,
246+
QString("can neither access '%1' nor '%2")
247+
.arg(config->frontendExtra)
248+
.arg(altEmuFn),
249+
"Files do not exist");
246250
}
247251

248252
bool AttractMode::checkEmulatorFile(QString fileName) {
@@ -310,7 +314,7 @@ QString AttractMode::getVideosFolder() {
310314
mediaTypeFolder = getMediaTypeFolder("snap", true);
311315
}
312316
if (mediaTypeFolder.isEmpty()) {
313-
mediaTypeFolder = Config::concatPath(config->mediaFolder, type);
317+
mediaTypeFolder = PathTools::concatPath(config->mediaFolder, type);
314318
}
315319
return mediaTypeFolder;
316320
}
@@ -353,7 +357,7 @@ QString AttractMode::getMediaTypeFolder(QString type, bool detectVideoPath) {
353357
}
354358

355359
if (type != "video" && mediaTypeFolder.isEmpty()) {
356-
mediaTypeFolder = Config::concatPath(config->mediaFolder, type);
360+
mediaTypeFolder = PathTools::concatPath(config->mediaFolder, type);
357361
}
358362

359363
return mediaTypeFolder;

src/cache.cpp

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "cli.h"
3030
#include "config.h"
3131
#include "nametools.h"
32+
#include "pathtools.h"
3233
#include "queue.h"
3334
#include "skyscraper.h"
3435

@@ -367,30 +368,22 @@ void Cache::printCacheEditMenu() {
367368
"\033[1;33mx\033[0m)\n");
368369
}
369370

370-
void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
371-
const QString &type) {
371+
int Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
372+
const QString &type) {
372373
// Check sanity of command and parameters, if any
373-
if (!command.isEmpty()) {
374-
if (command == "new") {
375-
if (!txtTypes().contains(type)) {
376-
QStringList sortedTypes = txtTypes();
377-
sortedTypes.sort();
378-
printf("\033[1;31mUnknown resource type '%s', please specify "
379-
"one of the following:\033[0m '%s'.\n",
380-
type.toStdString().c_str(),
381-
sortedTypes.join("', '").toStdString().c_str());
382-
return;
383-
}
384-
} else {
385-
printf("\033[1;31mUnknown command '%s', please specify one of the "
386-
"following: 'new'.\033[0m\n",
387-
command.toStdString().c_str());
388-
return;
389-
}
374+
if (command == "new" && !txtTypes().contains(type)) {
375+
QStringList sortedTypes = txtTypes();
376+
sortedTypes.sort();
377+
printf("\033[1;31mUnknown resource type '%s', please specify "
378+
"one of the following:\033[0m '%s'.\n",
379+
type.toStdString().c_str(),
380+
sortedTypes.join("', '").toStdString().c_str());
381+
return -1;
390382
}
391383

384+
int retVal = 0;
392385
int queueLength = queue->length();
393-
printf("\033[1mEntering resource cache editing mode! This mode allows "
386+
printf("\033[1mEntering resource cache editing mode.\n\nThis mode allows "
394387
"you to edit textual resources for your files. To add media "
395388
"resources use the 'import' scraping module instead.\nYou "
396389
"can provide one or more file names on command line to edit "
@@ -616,9 +609,9 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
616609
}
617610
resources.append(newRes);
618611
if (updated) {
619-
printf("[*] Updated existing ");
612+
printf("[\033[1;34m*\033[0m] Updated existing ");
620613
} else {
621-
printf("[+] Added ");
614+
printf("[\033[1;32m+\033[0m] Added ");
622615
}
623616
printf("resource with value '\033[1;32m%s\033[0m'\n\n",
624617
value.toStdString().c_str());
@@ -713,7 +706,8 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
713706
QString delType = resources[idxInResList].type;
714707
QString delSource = resources[idxInResList].source;
715708
resources.removeAt(idxInResList);
716-
printf("[-] Removed resource: %s (%s)\n\n",
709+
printf("[\033[1;31m-\033[0m] Removed resource: %s "
710+
"(%s)\n\n",
717711
delType.toStdString().c_str(),
718712
delSource.toStdString().c_str());
719713

@@ -727,7 +721,8 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
727721
while (it.hasNext()) {
728722
Resource res = it.next();
729723
if (res.cacheId == cacheId) {
730-
printf("[-] Removed \033[1;33m%s\033[0m (%s) with "
724+
printf("[\033[1;31m-\033[0m] Removed "
725+
"\033[1;33m%s\033[0m (%s) with "
731726
"value '\033[1;32m%s\033[0m'\n",
732727
res.type.toStdString().c_str(),
733728
res.source.toStdString().c_str(),
@@ -784,7 +779,8 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
784779
removed++;
785780
}
786781
}
787-
printf("[-] Removed %d %s connected to rom from "
782+
printf("[\033[1;31m-\033[0m] Removed %d %s connected to "
783+
"rom from "
788784
"module '\033[1;32m%s\033[0m'\n\n",
789785
removed,
790786
pluralizeWordStd("resource", removed != 1).c_str(),
@@ -842,7 +838,8 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
842838
removed++;
843839
}
844840
}
845-
printf("[-] Removed %d %s connected to rom of "
841+
printf("[\033[1;31m-\033[0m] Removed %d %s connected to "
842+
"rom of "
846843
"type '\033[1;32m%s\033[0m'\n\n",
847844
removed,
848845
pluralizeWordStd("resource", removed != 1).c_str(),
@@ -853,8 +850,11 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
853850
typeInput.c_str());
854851
}
855852
} else if (userInput == "c" || userInput == "x") {
856-
printf("[!] Exiting without saving changes.\n");
857-
exit(0);
853+
printf(
854+
"[\033[1;33m!\033[0m] Exiting without saving changes.\n");
855+
queue->clear();
856+
doneEdit = true;
857+
retVal = 1;
858858
} else if (userInput == "q" || userInput == "w") {
859859
queue->clear();
860860
doneEdit = true;
@@ -865,6 +865,7 @@ void Cache::editResources(QSharedPointer<Queue> queue, const QString &command,
865865
}
866866
}
867867
}
868+
return retVal;
868869
}
869870

870871
bool Cache::purgeResources(QString purgeStr) {
@@ -1008,8 +1009,8 @@ bool Cache::reportAllPlatform(Settings &config, Skyscraper *app) {
10081009
for (const auto &platform :
10091010
cacheDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
10101011
config.platform = platform;
1011-
config.cacheFolder = Config::concatPath(initCacheFolder, platform);
1012-
config.inputFolder = Config::concatPath(initInputFolder, platform);
1012+
config.cacheFolder = PathTools::concatPath(initCacheFolder, platform);
1013+
config.inputFolder = PathTools::concatPath(initInputFolder, platform);
10131014
qDebug() << "reportAllPlatform()" << config.inputFolder;
10141015
Cache cache(config.cacheFolder);
10151016
if (cache.read()) {
@@ -1043,8 +1044,8 @@ void Cache::vacuumAllPlatform(Settings &config, Skyscraper *app) {
10431044
for (const auto &platform :
10441045
cacheDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
10451046
config.platform = platform;
1046-
config.cacheFolder = Config::concatPath(initCacheFolder, platform);
1047-
config.inputFolder = Config::concatPath(initInputFolder, platform);
1047+
config.cacheFolder = PathTools::concatPath(initCacheFolder, platform);
1048+
config.inputFolder = PathTools::concatPath(initInputFolder, platform);
10481049
qDebug() << "vacuumAllPlatform()" << config.inputFolder;
10491050
Cache cache(config.cacheFolder);
10501051
if (cache.read() &&
@@ -1065,8 +1066,8 @@ void Cache::validateAllPlatform(Settings &config, Skyscraper *app) {
10651066
for (const auto &platform :
10661067
cacheDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
10671068
config.platform = platform;
1068-
config.cacheFolder = Config::concatPath(initCacheFolder, platform);
1069-
config.inputFolder = Config::concatPath(initInputFolder, platform);
1069+
config.cacheFolder = PathTools::concatPath(initCacheFolder, platform);
1070+
config.inputFolder = PathTools::concatPath(initInputFolder, platform);
10701071
qDebug() << "validateAllPlatform()" << config.inputFolder;
10711072
Cache cache(cacheDir.filePath(platform));
10721073
if (cache.read()) {
@@ -1240,11 +1241,11 @@ bool Cache::assembleReport(const Settings &config, const QString filter) {
12401241
reportFile.close();
12411242
printf("\033[1;32m Done!\033[0m\n\033[1;33m %d of %d %s "
12421243
"miss the '%s' resource.\033[0m\n",
1243-
missing, fileInfos.length(),
1244+
missing, static_cast<int>(fileInfos.length()),
12441245
pluralizeWordStd("file", fileInfos.length() != 1).c_str(),
12451246
resType.toStdString().c_str());
12461247
if (missing > 0) {
1247-
printf(" Files in: %s\n", Config::pathToCStr(rFn));
1248+
printf(" Files in: %s\n", PathTools::pathToCStr(rFn));
12481249
}
12491250
printf("\n");
12501251
} else {
@@ -1698,12 +1699,6 @@ QList<Resource> Cache::getResources() { return resources; }
16981699

16991700
void Cache::addResources(GameEntry &entry, const Settings &config,
17001701
QString &output) {
1701-
if (entry.source.isEmpty()) {
1702-
printf("Something is wrong, resource with cache id '%s' has no source, "
1703-
"exiting...\n",
1704-
entry.cacheId.toStdString().c_str());
1705-
exit(1);
1706-
}
17071702
if (entry.cacheId.isEmpty()) {
17081703
return;
17091704
}

0 commit comments

Comments
 (0)