From 05c11d1b7c4e53ac9a3207bb9a20cf79d8db9492 Mon Sep 17 00:00:00 2001 From: Balazs Gyurak Date: Wed, 19 Jun 2019 01:42:19 +0100 Subject: [PATCH] CLI: Add 'flatten' option to the 'ls' command (#3276) * Fixes #925 * Add 'flatten' option to CLI ls command * Add test for Group::hierarchy() and man page for ls --flatten * Rename group sort test to align with others --- CHANGELOG | 1 + src/cli/List.cpp | 10 ++++-- src/cli/List.h | 1 + src/cli/keepassxc-cli.1 | 2 ++ src/core/Group.cpp | 36 ++++++++++++++----- src/core/Group.h | 4 +-- tests/TestCli.cpp | 36 +++++++++++++++++-- tests/TestGroup.cpp | 67 ++++++++++++++++++++++++++++++++++-- tests/TestGroup.h | 3 +- tests/data/NewDatabase.kdbx | Bin 11486 -> 15006 bytes 10 files changed, 141 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4a6c9d3f..043fe67c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ 2.5.0-Beta1 (2019-07-05) ========================= - Group sorting feature [#3282] +- CLI: Add 'flatten' option to the 'ls' command [#3276] 2.4.3 (2019-06-12) ========================= diff --git a/src/cli/List.cpp b/src/cli/List.cpp index 37eb6f84..7f6ea128 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -31,11 +31,16 @@ const QCommandLineOption List::RecursiveOption = << "recursive", QObject::tr("Recursively list the elements of the group.")); +const QCommandLineOption List::FlattenOption = QCommandLineOption(QStringList() << "f" + << "flatten", + QObject::tr("Flattens the output to single lines.")); + List::List() { name = QString("ls"); description = QObject::tr("List database entries."); options.append(List::RecursiveOption); + options.append(List::FlattenOption); optionalArguments.append( {QString("group"), QObject::tr("Path of the group to list. Default is /"), QString("[group]")}); } @@ -51,10 +56,11 @@ int List::executeWithDatabase(QSharedPointer database, QSharedPointer< const QStringList args = parser->positionalArguments(); bool recursive = parser->isSet(List::RecursiveOption); + bool flatten = parser->isSet(List::FlattenOption); // No group provided, defaulting to root group. if (args.size() == 1) { - outputTextStream << database->rootGroup()->print(recursive) << flush; + outputTextStream << database->rootGroup()->print(recursive, flatten) << flush; return EXIT_SUCCESS; } @@ -65,6 +71,6 @@ int List::executeWithDatabase(QSharedPointer database, QSharedPointer< return EXIT_FAILURE; } - outputTextStream << group->print(recursive) << flush; + outputTextStream << group->print(recursive, flatten) << flush; return EXIT_SUCCESS; } diff --git a/src/cli/List.h b/src/cli/List.h index 51026271..1b579707 100644 --- a/src/cli/List.h +++ b/src/cli/List.h @@ -29,6 +29,7 @@ public: int executeWithDatabase(QSharedPointer db, QSharedPointer parser); static const QCommandLineOption RecursiveOption; + static const QCommandLineOption FlattenOption; }; #endif // KEEPASSXC_LIST_H diff --git a/src/cli/keepassxc-cli.1 b/src/cli/keepassxc-cli.1 index bd7f5d5c..511eeea4 100644 --- a/src/cli/keepassxc-cli.1 +++ b/src/cli/keepassxc-cli.1 @@ -152,6 +152,8 @@ be printed to STDERR. .IP "-R, --recursive" Recursively list the elements of the group. +.IP "-f, --flatten" +Flattens the output to single lines. When this option is enabled, subgroups and subentries will be displayed with a relative group path instead of indentation. .SS "Generate options" diff --git a/src/core/Group.cpp b/src/core/Group.cpp index a5d5087f..39c4a932 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -504,16 +504,25 @@ void Group::setParent(Database* db) QObject::setParent(db); } -QStringList Group::hierarchy() const +QStringList Group::hierarchy(int height) const { QStringList hierarchy; const Group* group = this; const Group* parent = m_parent; + + if (height == 0) { + return hierarchy; + } + hierarchy.prepend(group->name()); - while (parent) { + int level = 1; + bool heightReached = level == height; + + while (parent && !heightReached) { group = group->parentGroup(); parent = group->parentGroup(); + heightReached = ++level == height; hierarchy.prepend(group->name()); } @@ -720,25 +729,34 @@ Group* Group::findGroupByPathRecursive(const QString& groupPath, const QString& return nullptr; } -QString Group::print(bool recursive, int depth) +QString Group::print(bool recursive, bool flatten, int depth) { - QString response; - QString indentation = QString(" ").repeated(depth); + QString prefix; + + if (flatten) { + const QString separator("/"); + prefix = hierarchy(depth).join(separator); + if (!prefix.isEmpty()) { + prefix += separator; + } + } else { + prefix = QString(" ").repeated(depth); + } if (entries().isEmpty() && children().isEmpty()) { - response += indentation + tr("[empty]", "group has no children") + "\n"; + response += prefix + tr("[empty]", "group has no children") + "\n"; return response; } for (Entry* entry : entries()) { - response += indentation + entry->title() + "\n"; + response += prefix + entry->title() + "\n"; } for (Group* innerGroup : children()) { - response += indentation + innerGroup->name() + "/\n"; + response += prefix + innerGroup->name() + "/\n"; if (recursive) { - response += innerGroup->print(recursive, depth + 1); + response += innerGroup->print(recursive, flatten, depth + 1); } } diff --git a/src/core/Group.h b/src/core/Group.h index 048c0885..e9dbcdb9 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -143,7 +143,7 @@ public: Group* parentGroup(); const Group* parentGroup() const; void setParent(Group* parent, int index = -1); - QStringList hierarchy() const; + QStringList hierarchy(int height = -1) const; bool hasChildren() const; Database* database(); @@ -163,7 +163,7 @@ public: CloneFlags groupFlags = DefaultCloneFlags) const; void copyDataFrom(const Group* other); - QString print(bool recursive = false, int depth = 0); + QString print(bool recursive = false, bool flatten = false, int depth = 0); void addEntry(Entry* entry); void removeEntry(Entry* entry); diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index b1da5f1a..530e1eab 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -847,7 +847,38 @@ void TestCli::testList() "eMail/\n" " [empty]\n" "Homebanking/\n" - " [empty]\n")); + " Subgroup/\n" + " Subgroup Entry\n")); + + pos = m_stdoutFile->pos(); + Utils::Test::setNextPassword("a"); + listCmd.execute({"ls", "-R", "-f", m_dbFile->fileName()}); + m_stdoutFile->seek(pos); + m_stdoutFile->readLine(); // skip password prompt + QCOMPARE(m_stdoutFile->readAll(), + QByteArray("Sample Entry\n" + "General/\n" + "General/[empty]\n" + "Windows/\n" + "Windows/[empty]\n" + "Network/\n" + "Network/[empty]\n" + "Internet/\n" + "Internet/[empty]\n" + "eMail/\n" + "eMail/[empty]\n" + "Homebanking/\n" + "Homebanking/Subgroup/\n" + "Homebanking/Subgroup/Subgroup Entry\n")); + + pos = m_stdoutFile->pos(); + Utils::Test::setNextPassword("a"); + listCmd.execute({"ls", "-R", "-f", m_dbFile->fileName(), "/Homebanking"}); + m_stdoutFile->seek(pos); + m_stdoutFile->readLine(); // skip password prompt + QCOMPARE(m_stdoutFile->readAll(), + QByteArray("Subgroup/\n" + "Subgroup/Subgroup Entry\n")); pos = m_stdoutFile->pos(); Utils::Test::setNextPassword("a"); @@ -921,7 +952,8 @@ void TestCli::testLocate() locateCmd.execute({"locate", tmpFile.fileName(), "Entry"}); m_stdoutFile->seek(pos); m_stdoutFile->readLine(); // skip password prompt - QCOMPARE(m_stdoutFile->readAll(), QByteArray("/Sample Entry\n/General/New Entry\n")); + QCOMPARE(m_stdoutFile->readAll(), + QByteArray("/Sample Entry\n/General/New Entry\n/Homebanking/Subgroup/Subgroup Entry\n")); } void TestCli::testMerge() diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 7d42f161..9c3e5223 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -635,28 +635,57 @@ void TestGroup::testPrint() Group* group1 = new Group(); group1->setName("group1"); + group1->setParent(db->rootGroup()); Entry* entry2 = new Entry(); - entry2->setTitle(QString("entry2")); entry2->setGroup(group1); entry2->setUuid(QUuid::createUuid()); - group1->setParent(db->rootGroup()); + Group* group2 = new Group(); + group2->setName("group2"); + group2->setParent(db->rootGroup()); + + Group* subGroup = new Group(); + subGroup->setName("subgroup"); + subGroup->setParent(group2); + + Entry* entry3 = new Entry(); + entry3->setTitle(QString("entry3")); + entry3->setGroup(subGroup); + entry3->setUuid(QUuid::createUuid()); output = db->rootGroup()->print(); QVERIFY(output.contains(QString("entry1\n"))); QVERIFY(output.contains(QString("group1/\n"))); QVERIFY(!output.contains(QString(" entry2\n"))); + QVERIFY(output.contains(QString("group2/\n"))); + QVERIFY(!output.contains(QString(" subgroup\n"))); output = db->rootGroup()->print(true); QVERIFY(output.contains(QString("entry1\n"))); QVERIFY(output.contains(QString("group1/\n"))); QVERIFY(output.contains(QString(" entry2\n"))); + QVERIFY(output.contains(QString("group2/\n"))); + QVERIFY(output.contains(QString(" subgroup/\n"))); + QVERIFY(output.contains(QString(" entry3\n"))); + + output = db->rootGroup()->print(true, true); + QVERIFY(output.contains(QString("entry1\n"))); + QVERIFY(output.contains(QString("group1/\n"))); + QVERIFY(output.contains(QString("group1/entry2\n"))); + QVERIFY(output.contains(QString("group2/\n"))); + QVERIFY(output.contains(QString("group2/subgroup/\n"))); + QVERIFY(output.contains(QString("group2/subgroup/entry3\n"))); output = group1->print(); QVERIFY(!output.contains(QString("group1/\n"))); QVERIFY(output.contains(QString("entry2\n"))); + + output = group2->print(true, true); + QVERIFY(!output.contains(QString("group2/\n"))); + QVERIFY(output.contains(QString("subgroup/\n"))); + QVERIFY(output.contains(QString("subgroup/entry3\n"))); } void TestGroup::testLocate() @@ -841,7 +870,7 @@ void TestGroup::testEquals() QVERIFY(group->equals(group.data(), CompareItemDefault)); } -void TestGroup::sortChildrenRecursively() +void TestGroup::testChildrenSort() { auto createTestGroupWithUnorderedChildren = []() -> Group* { Group* parent = new Group(); @@ -1020,3 +1049,35 @@ void TestGroup::sortChildrenRecursively() QCOMPARE(children[8]->name(), QString("sub_000")); delete parent; } + +void TestGroup::testHierarchy() +{ + Group* group1 = new Group(); + group1->setName("group1"); + + Group* group2 = new Group(); + group2->setName("group2"); + group2->setParent(group1); + + Group* group3 = new Group(); + group3->setName("group3"); + group3->setParent(group2); + + QStringList hierarchy = group3->hierarchy(); + QVERIFY(hierarchy.size() == 3); + QVERIFY(hierarchy.contains("group1")); + QVERIFY(hierarchy.contains("group2")); + QVERIFY(hierarchy.contains("group3")); + + hierarchy = group3->hierarchy(0); + QVERIFY(hierarchy.size() == 0); + + hierarchy = group3->hierarchy(1); + QVERIFY(hierarchy.size() == 1); + QVERIFY(hierarchy.contains("group3")); + + hierarchy = group3->hierarchy(2); + QVERIFY(hierarchy.size() == 2); + QVERIFY(hierarchy.contains("group2")); + QVERIFY(hierarchy.contains("group3")); +} diff --git a/tests/TestGroup.h b/tests/TestGroup.h index 9355a0c9..6242e4ff 100644 --- a/tests/TestGroup.h +++ b/tests/TestGroup.h @@ -45,7 +45,8 @@ private slots: void testIsRecycled(); void testCopyDataFrom(); void testEquals(); - void sortChildrenRecursively(); + void testChildrenSort(); + void testHierarchy(); }; #endif // KEEPASSX_TESTGROUP_H diff --git a/tests/data/NewDatabase.kdbx b/tests/data/NewDatabase.kdbx index a8dfb5bd5e077aebc59017a1217a0d0b68109ae1..3008cce7c9fcb53524f2bd500afd2615b7bb1afc 100644 GIT binary patch literal 15006 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 o8nvVbWIxlby6`N-@OaK4? literal 11486 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