From fdca73532ff949b9ecae201369202515c5b676f3 Mon Sep 17 00:00:00 2001 From: tastytea Date: Tue, 3 Sep 2019 17:47:39 +0200 Subject: [PATCH] Add JSON export. --- cmake/remwhareadConfig.cmake.in | 2 +- include/export/json.hpp | 46 +++++++++++++++++++++++++ include/types.hpp | 3 +- man/remwharead.1.adoc | 14 +++++--- pkg-config/remwharead.pc.in | 2 +- src/cli/main.cpp | 14 ++++++++ src/cli/parse_options.cpp | 4 +++ src/lib/CMakeLists.txt | 6 ++-- src/lib/export/json.cpp | 61 +++++++++++++++++++++++++++++++++ 9 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 include/export/json.hpp create mode 100644 src/lib/export/json.cpp diff --git a/cmake/remwhareadConfig.cmake.in b/cmake/remwhareadConfig.cmake.in index 5076289..14c485a 100644 --- a/cmake/remwhareadConfig.cmake.in +++ b/cmake/remwhareadConfig.cmake.in @@ -2,7 +2,7 @@ include(CMakeFindDependencyMacro) include(GNUInstallDirs) find_depencency(Poco - COMPONENTS Foundation Net NetSSL Data DataSQLite + COMPONENTS Foundation Net NetSSL Data DataSQLite JSON CONFIG REQUIRED) find_dependency(PkgConfig REQUIRED) pkg_check_modules(libxdg-basedir REQUIRED IMPORTED_TARGET libxdg-basedir) diff --git a/include/export/json.hpp b/include/export/json.hpp new file mode 100644 index 0000000..1afa662 --- /dev/null +++ b/include/export/json.hpp @@ -0,0 +1,46 @@ +/* This file is part of remwharead. + * Copyright © 2019 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef REMWHAREAD_JSON_HPP +#define REMWHAREAD_JSON_HPP + +#include +#include "export.hpp" + +namespace remwharead +{ +namespace Export +{ + using std::string; + + /*! + * @brief Export as JSON array. + * + * @since 0.8.0 + * + * @headerfile json.hpp remwharead/export/json.hpp + */ + class JSON : protected ExportBase + { + public: + using ExportBase::ExportBase; + + virtual void print() const override; + }; +} +} + +#endif // REMWHAREAD_JSON_HPP diff --git a/include/types.hpp b/include/types.hpp index 6e08daf..2b38c50 100644 --- a/include/types.hpp +++ b/include/types.hpp @@ -34,7 +34,8 @@ namespace remwharead csv, asciidoc, bookmarks, - simple + simple, + json }; } diff --git a/man/remwharead.1.adoc b/man/remwharead.1.adoc index 42ee24a..27c5300 100644 --- a/man/remwharead.1.adoc +++ b/man/remwharead.1.adoc @@ -2,7 +2,7 @@ :doctype: manpage :Author: tastytea :Email: tastytea@tastytea.de -:Date: 2019-08-09 +:Date: 2019-09-03 :Revision: 0.0.0 :man source: remwharead :man manual: General Commands Manual @@ -24,7 +24,7 @@ remwharead - Saves URIs of things you want to remember in a database the full text of the page and optional tags. The database can be filtered by time, tags and full text and exported to CSV, -AsciiDoc or a bookmarks file. +AsciiDoc, a bookmarks file or JSON. Archiving is done using the Wayback machine from the https://archive.org/[Internet Archive]. @@ -35,8 +35,8 @@ https://archive.org/[Internet Archive]. Add tags to _URI_, delimited by commas. *-e* _format_, *--export* _format_:: -Export to _format_. Possible values are _csv_, _asciidoc_, _bookmarks_ or -_simple_. See _FORMATS_. +Export to _format_. Possible values are _csv_, _asciidoc_, _bookmarks_, +_simple_ or _json_. See _FORMATS_. *-f* _file_, *--file* _file_:: Save output to _file_. Default is stdout. @@ -133,6 +133,12 @@ understood by most browsers. Simple, human readable, list. Outputs date, title and URI. +=== json + +Export as JSON array. See https://tools.ietf.org/html/rfc8259[RFC 8259]. Each +object contains the members _uri_, _archive_uri_, _datetime_, _tags_ (array), +_title_, _description_ and _fulltext_. + == SEARCH EXPRESSIONS A search expression is either a single term, or several terms separated by _AND_ diff --git a/pkg-config/remwharead.pc.in b/pkg-config/remwharead.pc.in index ba6eb5a..f572fcb 100644 --- a/pkg-config/remwharead.pc.in +++ b/pkg-config/remwharead.pc.in @@ -10,4 +10,4 @@ Version: @PROJECT_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -l${name} -lPocoData -lstdc++fs Requires.private: libxdg-basedir, icu-uc, icu-i18n -Libs.private: -lPocoFoundation -lPocoNet -lPocoNetSSL -lPocoDataSQLite +Libs.private: -lPocoFoundation -lPocoNet -lPocoNetSSL -lPocoDataSQLite -lPocoJSON diff --git a/src/cli/main.cpp b/src/cli/main.cpp index f8058b8..01f9c95 100644 --- a/src/cli/main.cpp +++ b/src/cli/main.cpp @@ -28,6 +28,7 @@ #include "export/adoc.hpp" #include "export/bookmarks.hpp" #include "export/simple.hpp" +#include "export/json.hpp" #include "search.hpp" using namespace remwharead; @@ -177,6 +178,19 @@ int App::main(const std::vector &args) } break; } + case export_format::json: + { + if (file.is_open()) + { + Export::JSON(entries, file).print(); + file.close(); + } + else + { + Export::JSON(entries).print(); + } + break; + } default: { break; diff --git a/src/cli/parse_options.cpp b/src/cli/parse_options.cpp index 21dfb06..3a16507 100644 --- a/src/cli/parse_options.cpp +++ b/src/cli/parse_options.cpp @@ -139,6 +139,10 @@ void App::handle_options(const std::string &name, const std::string &value) { _format = export_format::simple; } + else if (value == "json") + { + _format = export_format::json; + } else { cerr << "Error: Unknown format.\n"; diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 33e063b..329ca44 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -3,7 +3,7 @@ include(GNUInstallDirs) find_package(PkgConfig REQUIRED) pkg_check_modules(libxdg-basedir REQUIRED IMPORTED_TARGET libxdg-basedir) # Some distributions do not contain Poco*Config.cmake recipes. -find_package(Poco COMPONENTS Foundation Net NetSSL Data DataSQLite CONFIG) +find_package(Poco COMPONENTS Foundation Net NetSSL Data DataSQLite JSON CONFIG) file(GLOB_RECURSE sources_lib *.cpp) file(GLOB_RECURSE headers_lib ../../include/*.hpp) @@ -28,7 +28,7 @@ target_link_libraries(${PROJECT_NAME} # If no Poco*Config.cmake recipes are found, look for headers in standard dirs. if(PocoNetSSL_FOUND) target_link_libraries(${PROJECT_NAME} - PRIVATE Poco::Foundation Poco::Net Poco::NetSSL Poco::DataSQLite + PRIVATE Poco::Foundation Poco::Net Poco::NetSSL Poco::DataSQLite Poco::JSON PUBLIC Poco::Data) else() find_file(Poco_h NAMES "Poco/Poco.h" @@ -42,7 +42,7 @@ else() "but the files seem to be in the standard directories. " "Let's hope this works.") target_link_libraries(${PROJECT_NAME} - PRIVATE PocoFoundation PocoNet PocoNetSSL PocoDataSQLite + PRIVATE PocoFoundation PocoNet PocoNetSSL PocoDataSQLite PocoJSON PUBLIC PocoData) endif() endif() diff --git a/src/lib/export/json.cpp b/src/lib/export/json.cpp new file mode 100644 index 0000000..2b9bf07 --- /dev/null +++ b/src/lib/export/json.cpp @@ -0,0 +1,61 @@ +/* This file is part of remwharead. + * Copyright © 2019 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "time.hpp" +#include "export/json.hpp" + +namespace remwharead +{ + using std::cerr; + using std::endl; + + void Export::JSON::print() const + { + try + { + Poco::JSON::Array root = Poco::JSON::Array(); + + for (const Database::entry &entry : _entries) + { + Poco::JSON::Object json_entry = Poco::JSON::Object(); + + json_entry.set("uri", entry.uri); + json_entry.set("archive_uri", entry.archive_uri); + json_entry.set("datetime", timepoint_to_string(entry.datetime)); + Poco::JSON::Array tags = Poco::JSON::Array(); + for (const string &tag : entry.tags) + { + tags.add(tag); + } + json_entry.set("tags", tags); + json_entry.set("title", entry.title); + json_entry.set("description", entry.description); + json_entry.set("fulltext", entry.fulltext); + + root.add(json_entry); + } + + root.stringify(_out); + _out << endl; + } + catch (std::exception &e) + { + cerr << "Error in " << __func__ << ": " << e.what() << endl; + } + } +}