summaryrefslogtreecommitdiffstats
path: root/akonadish
diff options
context:
space:
mode:
Diffstat (limited to 'akonadish')
-rw-r--r--akonadish/CMakeLists.txt3
-rw-r--r--akonadish/akonadish_utils.cpp28
-rw-r--r--akonadish/main.cpp99
-rw-r--r--akonadish/state.cpp19
-rw-r--r--akonadish/state.h4
-rw-r--r--akonadish/syntax_modules/akonadi_count.cpp2
-rw-r--r--akonadish/syntax_modules/akonadi_list.cpp2
-rw-r--r--akonadish/syntax_modules/akonadi_stat.cpp2
-rw-r--r--akonadish/syntax_modules/akonadi_sync.cpp2
-rw-r--r--akonadish/syntax_modules/core_syntax.cpp26
-rw-r--r--akonadish/utils.cpp42
-rw-r--r--akonadish/utils.h30
12 files changed, 184 insertions, 75 deletions
diff --git a/akonadish/CMakeLists.txt b/akonadish/CMakeLists.txt
index 6761a32..eaedf9a 100644
--- a/akonadish/CMakeLists.txt
+++ b/akonadish/CMakeLists.txt
@@ -18,7 +18,8 @@ set(akonadi2_cli_SRCS
18 akonadish_utils.cpp 18 akonadish_utils.cpp
19 repl/repl.cpp 19 repl/repl.cpp
20 repl/replStates.cpp 20 repl/replStates.cpp
21 state.cpp) 21 state.cpp
22 utils.cpp)
22 23
23include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 24include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
24 25
diff --git a/akonadish/akonadish_utils.cpp b/akonadish/akonadish_utils.cpp
index 070d788..27a863d 100644
--- a/akonadish/akonadish_utils.cpp
+++ b/akonadish/akonadish_utils.cpp
@@ -22,6 +22,8 @@
22 22
23#include "common/clientapi.h" 23#include "common/clientapi.h"
24 24
25#include "utils.h"
26
25namespace AkonadishUtils 27namespace AkonadishUtils
26{ 28{
27 29
@@ -75,8 +77,6 @@ QStringList resourceIds(State &state)
75{ 77{
76 QStringList resources; 78 QStringList resources;
77 Akonadi2::Query query; 79 Akonadi2::Query query;
78 query.syncOnDemand = false;
79 query.processAll = false;
80 query.liveQuery = false; 80 query.liveQuery = false;
81 auto model = AkonadishUtils::loadModel("resource", query); 81 auto model = AkonadishUtils::loadModel("resource", query);
82 82
@@ -98,40 +98,24 @@ QStringList resourceIds(State &state)
98 return resources; 98 return resources;
99} 99}
100 100
101QStringList filtered(const QStringList &list, const QString &fragment)
102{
103 if (fragment.isEmpty()) {
104 return list;
105 }
106
107 QStringList filtered;
108 for (auto item: list) {
109 if (item.startsWith(fragment)) {
110 filtered << item;
111 }
112 }
113
114 return filtered;
115}
116
117QStringList resourceCompleter(const QStringList &, const QString &fragment, State &state) 101QStringList resourceCompleter(const QStringList &, const QString &fragment, State &state)
118{ 102{
119 return filtered(resourceIds(state), fragment); 103 return Utils::filteredCompletions(resourceIds(state), fragment);
120} 104}
121 105
122QStringList resourceOrTypeCompleter(const QStringList &commands, const QString &fragment, State &state) 106QStringList resourceOrTypeCompleter(const QStringList &commands, const QString &fragment, State &state)
123{ 107{
124 static QStringList types = QStringList() << "resource" << "folder" << "mail" << "event"; 108 static QStringList types = QStringList() << "resource" << "folder" << "mail" << "event";
125 if (commands.count() == 1) { 109 if (commands.count() == 1) {
126 return filtered(s_types, fragment); 110 return Utils::filteredCompletions(s_types, fragment);
127 } 111 }
128 112
129 return filtered(resourceIds(state), fragment); 113 return Utils::filteredCompletions(resourceIds(state), fragment);
130} 114}
131 115
132QStringList typeCompleter(const QStringList &commands, const QString &fragment, State &state) 116QStringList typeCompleter(const QStringList &commands, const QString &fragment, State &state)
133{ 117{
134 return filtered(s_types, fragment); 118 return Utils::filteredCompletions(s_types, fragment);
135} 119}
136 120
137QMap<QString, QString> keyValueMapFromArgs(const QStringList &args) 121QMap<QString, QString> keyValueMapFromArgs(const QStringList &args)
diff --git a/akonadish/main.cpp b/akonadish/main.cpp
index f3cbcac..4c00b9b 100644
--- a/akonadish/main.cpp
+++ b/akonadish/main.cpp
@@ -31,71 +31,82 @@
31/* 31/*
32 * modes of operation: 32 * modes of operation:
33 * 33 *
34 * 1. called with no commands: start the REPL and listen for JSON on stin 34 * 1. called with no commands: start the REPL
35 * 2. called with -: listen for JSON on stdin 35 * 2. called with -: listen for commands on stdin
36 * 3. called with commands: try to match to syntx 36 * 3. called with a filename: try to run it as a script
37 * 4. called with commands: try to match to syntax and run the result
37 */ 38 */
38 39
40int enterRepl()
41{
42 if (State::hasEventLoop()) {
43 return 0;
44 }
45
46 Repl *repl = new Repl;
47 QObject::connect(repl, &QStateMachine::finished,
48 repl, &QObject::deleteLater);
49 QObject::connect(repl, &QStateMachine::finished,
50 QCoreApplication::instance(), &QCoreApplication::quit);
51
52 State::setHasEventLoop(true);
53 int rv = QCoreApplication::instance()->exec();
54 State::setHasEventLoop(false);
55 return rv;
56}
57
58bool goInteractive(const QStringList &, State &)
59{
60 enterRepl();
61 return true;
62}
63
64Syntax::List goInteractiveSyntax()
65{
66 Syntax interactive("go_interactive", QString(), &goInteractive);
67 return Syntax::List() << interactive;
68}
69
70void processCommandStream(QTextStream &stream)
71{
72 SyntaxTree::self()->registerSyntax(&goInteractiveSyntax);
73 QString line = stream.readLine();
74 while (!line.isEmpty()) {
75 line = line.trimmed();
76
77 if (!line.isEmpty() && !line.startsWith('#')) {
78 SyntaxTree::self()->run(SyntaxTree::tokenize(line));
79 }
80
81 line = stream.readLine();
82 }
83}
84
39int main(int argc, char *argv[]) 85int main(int argc, char *argv[])
40{ 86{
41 const bool interactive = isatty(fileno(stdin)); 87 const bool interactive = isatty(fileno(stdin));
42 const bool startRepl = (argc == 1) && interactive; 88 const bool startRepl = (argc == 1) && interactive;
43 //TODO: make a json command parse cause that would be awesomesauce 89 //TODO: make a json command parse cause that would be awesomesauce
44 const bool startJsonListener = !startRepl &&
45 (argc == 2 && qstrcmp(argv[1], "-") == 0);
46 const bool fromScript = !startRepl && QFile::exists(argv[1]); 90 const bool fromScript = !startRepl && QFile::exists(argv[1]);
47 91
48 //qDebug() << "state at startup is" << interactive << startRepl << startJsonListener << fromScript; 92 //qDebug() << "state at startup is" << interactive << startRepl << fromScript;
49 93
50 QCoreApplication app(argc, argv); 94 QCoreApplication app(argc, argv);
51 app.setApplicationName(fromScript ? "interactive-app-shell" : argv[0]); 95 app.setApplicationName(fromScript ? "interactive-app-shell" : argv[0]);
52 //app.setApplicationName(argv[0]);
53
54 if (startRepl || startJsonListener) {
55 if (startRepl) {
56 Repl *repl = new Repl;
57 QObject::connect(repl, &QStateMachine::finished,
58 repl, &QObject::deleteLater);
59 QObject::connect(repl, &QStateMachine::finished,
60 &app, &QCoreApplication::quit);
61 }
62
63 if (startJsonListener) {
64// JsonListener listener(syntax);
65 }
66 96
67 State::setHasEventLoop(true); 97 if (startRepl) {
68 return app.exec(); 98 return enterRepl();
69 } else if (fromScript) { 99 } else if (fromScript) {
70 QFile f(argv[1]); 100 QFile f(argv[1]);
71 if (!f.open(QIODevice::ReadOnly)) { 101 if (!f.open(QIODevice::ReadOnly)) {
72 return 1; 102 return 1;
73 } 103 }
74 104
75 QString line = f.readLine(); 105 QTextStream inputStream(&f);
76 while (!line.isEmpty()) { 106 processCommandStream(inputStream);
77 line = line.trimmed();
78
79 if (!line.isEmpty() && !line.startsWith('#')) {
80 SyntaxTree::self()->run(SyntaxTree::tokenize(line));
81 }
82
83 line = f.readLine();
84 }
85 exit(0);
86 } else if (!interactive) { 107 } else if (!interactive) {
87 QTextStream inputStream(stdin); 108 QTextStream inputStream(stdin);
88 109 processCommandStream(inputStream);
89 QString line = inputStream.readLine();
90 while (!line.isEmpty()) {
91 line = line.trimmed();
92
93 if (!line.isEmpty() && !line.startsWith('#')) {
94 SyntaxTree::self()->run(SyntaxTree::tokenize(line));
95 }
96
97 line = inputStream.readLine();
98 }
99 } else { 110 } else {
100 QStringList commands = app.arguments(); 111 QStringList commands = app.arguments();
101 commands.removeFirst(); 112 commands.removeFirst();
diff --git a/akonadish/state.cpp b/akonadish/state.cpp
index f3f5975..9fb5bcc 100644
--- a/akonadish/state.cpp
+++ b/akonadish/state.cpp
@@ -24,6 +24,8 @@
24#include <QEventLoop> 24#include <QEventLoop>
25#include <QTextStream> 25#include <QTextStream>
26 26
27#include "common/log.h"
28
27static bool s_hasEventLoop = false; 29static bool s_hasEventLoop = false;
28 30
29class State::Private 31class State::Private
@@ -112,6 +114,11 @@ void State::setHasEventLoop(bool evented)
112 s_hasEventLoop = evented; 114 s_hasEventLoop = evented;
113} 115}
114 116
117bool State::hasEventLoop()
118{
119 return s_hasEventLoop;
120}
121
115void State::setCommandTiming(bool time) 122void State::setCommandTiming(bool time)
116{ 123{
117 d->timing = time; 124 d->timing = time;
@@ -122,4 +129,16 @@ bool State::commandTiming() const
122 return d->timing; 129 return d->timing;
123} 130}
124 131
132void State::setLoggingLevel(const QString &level) const
133{
134 Akonadi2::Log::setDebugOutputLevel(Akonadi2::Log::debugLevelFromName(level.toLatin1()));
135}
136
137QString State::loggingLevel() const
138{
139 // do not turn this into a single line return: that core dumps due to allocation of
140 // the byte array in Akonadi2::Log
141 QByteArray rv = Akonadi2::Log::debugLevelName(Akonadi2::Log::debugOutputLevel());
142 return rv.toLower();
143}
125 144
diff --git a/akonadish/state.h b/akonadish/state.h
index 9c1ab6f..3c4c2c7 100644
--- a/akonadish/state.h
+++ b/akonadish/state.h
@@ -39,7 +39,11 @@ public:
39 int commandStarted() const; 39 int commandStarted() const;
40 void commandFinished(int returnCode = 0) const; 40 void commandFinished(int returnCode = 0) const;
41 41
42 void setLoggingLevel(const QString &level) const;
43 QString loggingLevel() const;
44
42 static void setHasEventLoop(bool evented); 45 static void setHasEventLoop(bool evented);
46 static bool hasEventLoop();
43 47
44private: 48private:
45 class Private; 49 class Private;
diff --git a/akonadish/syntax_modules/akonadi_count.cpp b/akonadish/syntax_modules/akonadi_count.cpp
index 5acdcdd..bb1cd19 100644
--- a/akonadish/syntax_modules/akonadi_count.cpp
+++ b/akonadish/syntax_modules/akonadi_count.cpp
@@ -53,8 +53,6 @@ bool count(const QStringList &args, State &state)
53 for (const auto &res : resources) { 53 for (const auto &res : resources) {
54 query.resources << res.toLatin1(); 54 query.resources << res.toLatin1();
55 } 55 }
56 query.syncOnDemand = false;
57 query.processAll = false;
58 query.liveQuery = false; 56 query.liveQuery = false;
59 57
60 auto model = AkonadishUtils::loadModel(type, query); 58 auto model = AkonadishUtils::loadModel(type, query);
diff --git a/akonadish/syntax_modules/akonadi_list.cpp b/akonadish/syntax_modules/akonadi_list.cpp
index 82f13b5..7709d3b 100644
--- a/akonadish/syntax_modules/akonadi_list.cpp
+++ b/akonadish/syntax_modules/akonadi_list.cpp
@@ -58,8 +58,6 @@ bool list(const QStringList &args, State &state)
58 for (const auto &res : resources) { 58 for (const auto &res : resources) {
59 query.resources << res.toLatin1(); 59 query.resources << res.toLatin1();
60 } 60 }
61 query.syncOnDemand = false;
62 query.processAll = false;
63 query.liveQuery = false; 61 query.liveQuery = false;
64 62
65 QTime time; 63 QTime time;
diff --git a/akonadish/syntax_modules/akonadi_stat.cpp b/akonadish/syntax_modules/akonadi_stat.cpp
index 9270f9d..d10556f 100644
--- a/akonadish/syntax_modules/akonadi_stat.cpp
+++ b/akonadish/syntax_modules/akonadi_stat.cpp
@@ -69,8 +69,6 @@ void statResources(const QStringList &resources, const State &state)
69bool statAllResources(State &state) 69bool statAllResources(State &state)
70{ 70{
71 Akonadi2::Query query; 71 Akonadi2::Query query;
72 query.syncOnDemand = false;
73 query.processAll = false;
74 query.liveQuery = false; 72 query.liveQuery = false;
75 auto model = AkonadishUtils::loadModel("resource", query); 73 auto model = AkonadishUtils::loadModel("resource", query);
76 74
diff --git a/akonadish/syntax_modules/akonadi_sync.cpp b/akonadish/syntax_modules/akonadi_sync.cpp
index 03abbb4..0c994d0 100644
--- a/akonadish/syntax_modules/akonadi_sync.cpp
+++ b/akonadish/syntax_modules/akonadi_sync.cpp
@@ -43,8 +43,6 @@ bool sync(const QStringList &args, State &state)
43 for (const auto &res : args) { 43 for (const auto &res : args) {
44 query.resources << res.toLatin1(); 44 query.resources << res.toLatin1();
45 } 45 }
46 query.syncOnDemand = true;
47 query.processAll = true;
48 46
49 QTimer::singleShot(0, [query, state]() { 47 QTimer::singleShot(0, [query, state]() {
50 Akonadi2::Store::synchronize(query).then<void>([state]() { 48 Akonadi2::Store::synchronize(query).then<void>([state]() {
diff --git a/akonadish/syntax_modules/core_syntax.cpp b/akonadish/syntax_modules/core_syntax.cpp
index b4812df..ccf96c1 100644
--- a/akonadish/syntax_modules/core_syntax.cpp
+++ b/akonadish/syntax_modules/core_syntax.cpp
@@ -24,6 +24,7 @@
24 24
25#include "state.h" 25#include "state.h"
26#include "syntaxtree.h" 26#include "syntaxtree.h"
27#include "utils.h"
27 28
28namespace CoreSyntax 29namespace CoreSyntax
29{ 30{
@@ -145,6 +146,24 @@ bool printSyntaxTree(const QStringList &, State &state)
145 return true; 146 return true;
146} 147}
147 148
149bool setLoggingLevel(const QStringList &commands, State &state)
150{
151 if (commands.count() != 1) {
152 state.printError(QObject::tr("Wrong number of arguments; expected 1 got %1").arg(commands.count()));
153 return false;
154 }
155
156 state.setLoggingLevel(commands.at(0));
157 return true;
158}
159
160bool printLoggingLevel(const QStringList &commands, State &state)
161{
162 const QString level = state.loggingLevel();
163 state.printLine(level);
164 return true;
165}
166
148Syntax::List syntax() 167Syntax::List syntax()
149{ 168{
150 Syntax::List syntax; 169 Syntax::List syntax;
@@ -158,15 +177,22 @@ Syntax::List syntax()
158 177
159 Syntax set("set", QObject::tr("Sets settings for the session")); 178 Syntax set("set", QObject::tr("Sets settings for the session"));
160 set.children << Syntax("debug", QObject::tr("Set the debug level from 0 to 6"), &CoreSyntax::setDebugLevel); 179 set.children << Syntax("debug", QObject::tr("Set the debug level from 0 to 6"), &CoreSyntax::setDebugLevel);
180
161 Syntax setTiming = Syntax("timing", QObject::tr("Whether or not to print the time commands take to complete")); 181 Syntax setTiming = Syntax("timing", QObject::tr("Whether or not to print the time commands take to complete"));
162 setTiming.children << Syntax("on", QString(), [](const QStringList &, State &state) -> bool { state.setCommandTiming(true); return true; }); 182 setTiming.children << Syntax("on", QString(), [](const QStringList &, State &state) -> bool { state.setCommandTiming(true); return true; });
163 setTiming.children << Syntax("off", QString(), [](const QStringList &, State &state) -> bool { state.setCommandTiming(false); return true; }); 183 setTiming.children << Syntax("off", QString(), [](const QStringList &, State &state) -> bool { state.setCommandTiming(false); return true; });
164 set.children << setTiming; 184 set.children << setTiming;
185
186 Syntax logging("logging", QObject::tr("Set the logging level to one of Trace, Log, Warning or Error"), &CoreSyntax::setLoggingLevel);
187 logging.completer = [](const QStringList &, const QString &fragment, State &state) -> QStringList { return Utils::filteredCompletions(QStringList() << "trace" << "log" << "warning" << "error", fragment, Qt::CaseInsensitive); };
188 set.children << logging;
189
165 syntax << set; 190 syntax << set;
166 191
167 Syntax get("get", QObject::tr("Gets settings for the session")); 192 Syntax get("get", QObject::tr("Gets settings for the session"));
168 get.children << Syntax("debug", QObject::tr("The current debug level from 0 to 6"), &CoreSyntax::printDebugLevel); 193 get.children << Syntax("debug", QObject::tr("The current debug level from 0 to 6"), &CoreSyntax::printDebugLevel);
169 get.children << Syntax("timing", QObject::tr("Whether or not to print the time commands take to complete"), &CoreSyntax::printCommandTiming); 194 get.children << Syntax("timing", QObject::tr("Whether or not to print the time commands take to complete"), &CoreSyntax::printCommandTiming);
195 get.children << Syntax("logging", QObject::tr("The current logging level"), &CoreSyntax::printLoggingLevel);
170 syntax << get; 196 syntax << get;
171 197
172 return syntax; 198 return syntax;
diff --git a/akonadish/utils.cpp b/akonadish/utils.cpp
new file mode 100644
index 0000000..d2a28ed
--- /dev/null
+++ b/akonadish/utils.cpp
@@ -0,0 +1,42 @@
1/*
2 * Copyright (C) 2016 Aaron Seigo <aseigo@kde.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include "utils.h"
21
22namespace Utils
23{
24
25QStringList filteredCompletions(const QStringList &possibleCompletions, const QString &commandFragment, Qt::CaseSensitivity cs)
26{
27 if (commandFragment.isEmpty()) {
28 return possibleCompletions;
29 }
30
31 QStringList filtered;
32 for (auto item: possibleCompletions) {
33 if (item.startsWith(commandFragment, cs)) {
34 filtered << item;
35 }
36 }
37
38 return filtered;
39}
40
41} // namespace Utils
42
diff --git a/akonadish/utils.h b/akonadish/utils.h
new file mode 100644
index 0000000..82be8d5
--- /dev/null
+++ b/akonadish/utils.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2016 Aaron Seigo <aseigo@kde.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#pragma once
21
22#include <QStringList>
23
24namespace Utils
25{
26
27QStringList filteredCompletions(const QStringList &possibleCompletions, const QString &commandFragment, Qt::CaseSensitivity cs = Qt::CaseSensitive);
28
29} // namespace Utils
30