From 86735399fd07b8f1900e576f6cb19be507432eed Mon Sep 17 00:00:00 2001 From: Martchus Date: Fri, 26 Feb 2016 01:27:57 +0100 Subject: [PATCH] minimize web files --- CMakeLists.txt | 100 ++++++++++++++++++++++++++++-------- alpm/package.cpp | 2 +- alpm/packageinfolookup.cpp | 4 +- alpm/packagelookup.h | 4 +- alpm/suggestionslookup.cpp | 3 ++ alpm/upgradelookup.cpp | 39 ++++++++++---- alpm/upgradelookup.h | 2 + jsmin.sh | 2 + network/connection.cpp | 24 ++++----- web/index.html | 2 +- web/js/client.js | 20 ++++---- web/js/entrymanagement.js | 5 +- web/js/packagemanagement.js | 12 +++-- 13 files changed, 156 insertions(+), 63 deletions(-) create mode 100755 jsmin.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 7632237..9395339 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,22 +45,15 @@ set(SRC_FILES network/networkaccessmanager.cpp ) set(WEB_FILES - web/3rdparty/bootstrap/css/bootstrap-theme.css - web/3rdparty/bootstrap/css/bootstrap-theme.css.map web/3rdparty/bootstrap/css/bootstrap-theme.min.css - web/3rdparty/bootstrap/css/bootstrap.css - web/3rdparty/bootstrap/css/bootstrap.css.map web/3rdparty/bootstrap/css/bootstrap.min.css web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.eot web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.svg web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.ttf web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.woff web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.woff2 - web/3rdparty/bootstrap/js/bootstrap.js web/3rdparty/bootstrap/js/bootstrap.min.js - web/3rdparty/bootstrap/js/npm.js web/3rdparty/bootstrap_dropdowns_enhancement/css/dropdowns-enhancement.min.css - web/3rdparty/bootstrap_dropdowns_enhancement/js/dropdowns-enhancement.js web/css/core.css web/css/dashboard.css web/js/client.js @@ -83,8 +76,8 @@ set(META_APP_AUTHOR "Martchus") set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") set(META_APP_DESCRIPTION "Arch Linux repository browser") set(META_VERSION_MAJOR 0) -set(META_VERSION_MINOR 1) -set(META_VERSION_PATCH 1) +set(META_VERSION_MINOR 2) +set(META_VERSION_PATCH 0) # stringification of meta data set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"") @@ -142,6 +135,10 @@ add_definitions( -D_GLIBCXX_USE_CXX11_ABI=0 -DCMAKE_BUILD ) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DDEBUG_BUILD) + message(STATUS "Debug build enabled.") +endif() # executable and linking add_executable(${META_PROJECT_NAME} ${HEADER_FILES} ${SRC_FILES} ${WEB_FILES} ${RES_FILES}) @@ -150,6 +147,78 @@ set_target_properties(${META_PROJECT_NAME} PROPERTIES CXX_STANDARD 11 ) +# add install target for web files / minimizing +# -> don't minimize debug builds +if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + # find JavaScript/CSS minimizer + find_program(YUI_EXECUTABLE yuicompressor) + if(YUI_EXECUTABLE) + set(JS_MIN_EXECUTABLE "${CMAKE_CURRENT_SOURCE_DIR}/jsmin.sh") + endif() + if(NOT JS_MIN_EXECUTABLE) + message(STATUS "YUI compressor not found -> installing JavaScript/CSS files unminimized") + endif() + # find html minimizer + find_program(HTML_MIN_EXECUTABLE htmlmin) +endif() +if(NOT HTML_MIN_EXECUTABLE) + message(STATUS "htmlmin not found -> installing HTML files unminimized") + # install unminimized index.html + install( + FILES "${PROJECT_BINARY_DIR}/web/index.html" + DESTINATION share/${META_PROJECT_NAME}/web + COMPONENT web + ) +else() + # minimize index.html + set(MIN_FILE "${PROJECT_BINARY_DIR}/web/index.min/index.html") + add_custom_command( + OUTPUT ${MIN_FILE} + COMMAND "${HTML_MIN_EXECUTABLE}" + ARGS "${HTML_MIN_EXECUTABLE}" "${PROJECT_BINARY_DIR}/web/index.html" "${MIN_FILE}" + ) + install( + FILES ${MIN_FILE} + DESTINATION share/${META_PROJECT_NAME}/web + COMPONENT web + ) + list(APPEND HTML_MIN_FILES "${MIN_FILE}") +endif() +foreach(WEB_FILE ${WEB_FILES}) + # check whether file can be minimized + get_filename_component(WEB_DIR ${WEB_FILE} DIRECTORY) + get_filename_component(WEB_EXT ${WEB_FILE} EXT) + if(JS_MIN_EXECUTABLE AND (${WEB_EXT} STREQUAL ".js" OR ${WEB_EXT} STREQUAL ".css")) + # minimize web file + set(MIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/min/${WEB_FILE}") + add_custom_command( + OUTPUT ${MIN_FILE} + COMMAND "${JS_MIN_EXECUTABLE}" + ARGS "${YUI_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/${WEB_FILE}" "${MIN_FILE}" + ) + install( + FILES ${MIN_FILE} + DESTINATION share/${META_PROJECT_NAME}/${WEB_DIR} + COMPONENT web + ) + list(APPEND JS_MIN_FILES "${MIN_FILE}") + else() + # install unminimized version of web file + install( + FILES ${WEB_FILE} + DESTINATION share/${META_PROJECT_NAME}/${WEB_DIR} + COMPONENT web + ) + endif() +endforeach() +# add target for minimizing +if(HTML_MIN_FILES) + add_custom_target(htmlmin ALL DEPENDS ${HTML_MIN_FILES}) +endif() +if(JS_MIN_FILES) + add_custom_target(jsmin ALL DEPENDS ${JS_MIN_FILES}) +endif() + # add install target install(TARGETS ${META_PROJECT_NAME} RUNTIME DESTINATION bin @@ -163,19 +232,6 @@ install(FILES resources/settings/${META_PROJECT_NAME}.conf.js DESTINATION share/${META_PROJECT_NAME}/skel COMPONENT config ) -foreach(WEB_FILE ${WEB_FILES}) - get_filename_component(WEB_DIR ${WEB_FILE} DIRECTORY) - install( - FILES ${WEB_FILE} - DESTINATION share/${META_PROJECT_NAME}/${WEB_DIR} - COMPONENT web - ) -endforeach() -install( - FILES ${PROJECT_BINARY_DIR}/web/index.html - DESTINATION share/${META_PROJECT_NAME}/web - COMPONENT web -) if(NOT TARGET install-binary) add_custom_target(install-binary DEPENDS ${META_PROJECT_NAME} diff --git a/alpm/package.cpp b/alpm/package.cpp index cc72ffd..d6c9f88 100644 --- a/alpm/package.cpp +++ b/alpm/package.cpp @@ -285,7 +285,7 @@ QJsonObject Package::basicInfo(bool includeRepoAndName) const } put(info, QStringLiteral("ver"), version()); put(info, QStringLiteral("desc"), description()); - put(info, QStringLiteral("flagdate"), outOfDate()); + put(info, QStringLiteral("fdate"), outOfDate()); put(info, QStringLiteral("arch"), buildArchitecture()); put(info, QStringLiteral("bdate"), buildDate()); put(info, QStringLiteral("archs"), architectures()); diff --git a/alpm/packageinfolookup.cpp b/alpm/packageinfolookup.cpp index 778e861..c40a23f 100644 --- a/alpm/packageinfolookup.cpp +++ b/alpm/packageinfolookup.cpp @@ -10,7 +10,7 @@ namespace RepoIndex { PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &request, QObject *parent) : PackageLookup(parent), m_manager(manager), - m_what(request.value(QStringLiteral("what")).toString()), + m_what(request.value(QStringLiteral("w")).toString()), m_part(Manager::None) { m_id = request.value(QStringLiteral("id")); @@ -54,12 +54,14 @@ PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &reques void PackageInfoLookup::performLookup() { + m_waitingForBusyRepos = false; for(auto &entry : m_repos) { if(Repository *repo = entry.first) { const QStringList &packagesToBeRequested = entry.second; if(repo->isBusy()) { // repo is busy -> try again when available connect(repo, &Repository::available, this, &PackageInfoLookup::performLookup); + m_waitingForBusyRepos = true; } else { // disconnect to ensure the lookup isn't done twice disconnect(repo, nullptr, this, nullptr); diff --git a/alpm/packagelookup.h b/alpm/packagelookup.h index 448d83d..defb657 100644 --- a/alpm/packagelookup.h +++ b/alpm/packagelookup.h @@ -19,6 +19,7 @@ signals: void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value); protected: + bool m_waitingForBusyRepos; unsigned int m_remainingReplies; QJsonValue m_id; QJsonArray m_errors; @@ -27,6 +28,7 @@ protected: inline PackageLookup::PackageLookup(QObject *parent) : QObject(parent), + m_waitingForBusyRepos(false), m_remainingReplies(0) {} @@ -42,7 +44,7 @@ inline const QJsonArray &PackageLookup::results() const inline bool PackageLookup::finished() const { - return !m_remainingReplies && m_errors.isEmpty(); + return !m_waitingForBusyRepos && !m_remainingReplies && m_errors.isEmpty(); } #endif // PACKAGELOOKUP_H diff --git a/alpm/suggestionslookup.cpp b/alpm/suggestionslookup.cpp index 93ca49d..f15a17d 100644 --- a/alpm/suggestionslookup.cpp +++ b/alpm/suggestionslookup.cpp @@ -30,6 +30,7 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques m_errors << QStringLiteral("The specified repository \"%1\" does not exist.").arg(repoName.toString()); } } + performLookup(); return; } deleteLater(); @@ -37,11 +38,13 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques void SuggestionsLookup::performLookup() { + m_waitingForBusyRepos = false; for(Repository *&repo : m_repos) { if(repo) { if(repo->isBusy()) { // repo is busy -> try again when available connect(repo, &Repository::available, this, &SuggestionsLookup::performLookup); + m_waitingForBusyRepos = true; } else { // disconnect to ensure the lookup isn't done twice disconnect(repo, nullptr, this, nullptr); diff --git a/alpm/upgradelookup.cpp b/alpm/upgradelookup.cpp index f2c4fce..277bea1 100644 --- a/alpm/upgradelookup.cpp +++ b/alpm/upgradelookup.cpp @@ -68,16 +68,8 @@ inline const UpgradeLookupResults &UpgradeLookupProcess::results() const */ void UpgradeLookupProcess::requestSources() { - // ensure the repository to check and the upgrade source are both not busy - if(m_toCheck->isBusy()) { - connect(m_toCheck, &Repository::available, this, &UpgradeLookupProcess::requestSources); - } else { - disconnect(m_toCheck, nullptr, this, nullptr); - } - if(m_upgradeSource->isBusy()) { - connect(m_upgradeSource, &Repository::available, this, &UpgradeLookupProcess::requestSources); - } else { - disconnect(m_upgradeSource, nullptr, this, nullptr); + if(ensureNotBusy()) { + return; } // request sources if required switch(m_upgradeSource->requestsRequired()) { @@ -109,6 +101,9 @@ void UpgradeLookupProcess::requestSources() */ void UpgradeLookupProcess::sourceReady() { + if(ensureNotBusy()) { + return; + } // if a request was required, check whether an error occured if(m_reply && !m_reply->error().isEmpty()) { m_results.errors << m_reply->error(); @@ -129,6 +124,28 @@ void UpgradeLookupProcess::checkUpgrades() m_toCheck->checkForUpgrades(m_results, QList() << m_upgradeSource); } +/*! + * \brief Ensures the repository to check and the upgrade source are both not busy. + * \returns Returns whether the repositories are busy. In this case the lookup will + * continue with the "step" requestSources() when the repos are available again. + */ +bool UpgradeLookupProcess::ensureNotBusy() +{ + if(m_toCheck->isBusy()) { + connect(m_toCheck, &Repository::available, this, &UpgradeLookupProcess::requestSources); + return true; + } else { + disconnect(m_toCheck, nullptr, this, nullptr); + } + if(m_upgradeSource->isBusy()) { + connect(m_upgradeSource, &Repository::available, this, &UpgradeLookupProcess::requestSources); + return true; + } else { + disconnect(m_upgradeSource, nullptr, this, nullptr); + } + return false; +} + /*! * \class UpgradeLookup * \brief The UpgradeLookup class performs an async upgrade lookup for using multiple upgrade sources. @@ -281,7 +298,7 @@ void UpgradeLookupJson::processFinished() if(!m_errorsArray.isEmpty()) { results.insert(QStringLiteral("errors"), m_errorsArray); } - emit resultsAvailable(m_request.value(QStringLiteral("what")), m_request.value(QStringLiteral("id")), results); + emit resultsAvailable(m_request.value(QStringLiteral("w")), m_request.value(QStringLiteral("id")), results); // lookup done, delete this helper object deleteLater(); } diff --git a/alpm/upgradelookup.h b/alpm/upgradelookup.h index 14b2b67..7c1b7d6 100644 --- a/alpm/upgradelookup.h +++ b/alpm/upgradelookup.h @@ -96,6 +96,8 @@ private slots: void checkUpgrades(); private: + bool ensureNotBusy(); + const Repository *m_toCheck; Repository *m_upgradeSource; PackageReply *m_reply; diff --git a/jsmin.sh b/jsmin.sh new file mode 100755 index 0000000..21b2323 --- /dev/null +++ b/jsmin.sh @@ -0,0 +1,2 @@ +#!/bin/sh +mkdir -p "${3%/*}" && "$1" "$2" -o "$3" diff --git a/network/connection.cpp b/network/connection.cpp index 274ac8e..975ed28 100644 --- a/network/connection.cpp +++ b/network/connection.cpp @@ -40,7 +40,7 @@ void Connection::sendJson(const QJsonObject &obj) void Connection::sendError(const QString &msg, const QJsonValue &id) { QJsonObject response; - response.insert(QStringLiteral("class"), QStringLiteral("error")); + response.insert(QStringLiteral("c"), QStringLiteral("error")); response.insert(QStringLiteral("msg"), msg); if(!id.isNull() && !id.isUndefined()) { response.insert(QStringLiteral("id"), id); @@ -51,9 +51,9 @@ void Connection::sendError(const QString &msg, const QJsonValue &id) void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value) { QJsonObject response; - response.insert(QStringLiteral("class"), QStringLiteral("results")); - response.insert(QStringLiteral("what"), what); - response.insert(QStringLiteral("value"), value); + response.insert(QStringLiteral("c"), QStringLiteral("results")); + response.insert(QStringLiteral("w"), what); + response.insert(QStringLiteral("v"), value); if(!id.isNull() && !id.isUndefined()) { response.insert("id", id); } @@ -63,9 +63,9 @@ void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const QJsonValue &values) { QJsonObject response; - response.insert(QStringLiteral("class"), QStringLiteral("results")); - response.insert(QStringLiteral("what"), what); - response.insert(QStringLiteral("values"), values); + response.insert(QStringLiteral("c"), QStringLiteral("results")); + response.insert(QStringLiteral("w"), what); + response.insert(QStringLiteral("v"), values); if(!id.isNull() && !id.isUndefined()) { response.insert("id", id); } @@ -89,13 +89,13 @@ void Connection::performLookup(const QJsonObject &request, Args &&...args) if(lookup->finished()) { // the lookup has already finished when constructing the lookup object // -> send the results immidiately - sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), lookup->results()); + sendResult(request.value(QStringLiteral("w")), request.value(QStringLiteral("id")), lookup->results()); } else if(!lookup->errors().isEmpty()) { // error occured during the construction of the lookup object // -> send the errors immidiately QJsonObject results; results.insert(QStringLiteral("errors"), lookup->errors()); - sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), results); + sendResult(request.value(QStringLiteral("w")), request.value(QStringLiteral("id")), results); } else { // the lookup object has been created without errors but the lookup is not done yet // -> send results when available @@ -106,7 +106,7 @@ void Connection::performLookup(const QJsonObject &request, Args &&...args) void Connection::handleQuery(const QJsonObject &obj) { - const auto what = obj.value(QStringLiteral("what")).toString(); + const auto what = obj.value(QStringLiteral("w")).toString(); const auto id = obj.value(QStringLiteral("id")); if(what == QLatin1String("basicrepoinfo")) { m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested); @@ -129,7 +129,7 @@ void Connection::handleQuery(const QJsonObject &obj) void Connection::handleCmd(const QJsonObject &obj) { - const auto what = obj.value(QStringLiteral("what")).toString(); + const auto what = obj.value(QStringLiteral("w")).toString(); const auto id = obj.value(QStringLiteral("id")); if(what == QLatin1String("stop")) { if(m_socket->peerAddress().isLoopback()) { @@ -173,7 +173,7 @@ void Connection::processTextMessage(const QString &message) const QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error); if(error.error == QJsonParseError::NoError) { const QJsonObject obj = doc.object(); - const QString msgClass = obj.value(QStringLiteral("class")).toString(); + const QString msgClass = obj.value(QStringLiteral("c")).toString(); if(msgClass == QLatin1String("query")) { handleQuery(obj); } else if(msgClass == QLatin1String("cmd")) { diff --git a/web/index.html b/web/index.html index 0deae09..c03a31a 100644 --- a/web/index.html +++ b/web/index.html @@ -130,7 +130,7 @@ - ArchRepoNameVersionDescriptionBuild dateFlag + ArchRepoNameVersionDescriptionBuild date diff --git a/web/js/client.js b/web/js/client.js index cca531e..d2b68af 100644 --- a/web/js/client.js +++ b/web/js/client.js @@ -81,12 +81,12 @@ this.socket.onmessage = function(event) { var msg = JSON.parse(event.data); - switch(msg.class) { + switch(msg.c) { case "error": repoindex.pageManager.addError("Server replied error: " + msg.msg); break; case "results": - this.client.parseResults(msg.id, msg.what, msg.values ? msg.values : msg.value); + this.client.parseResults(msg.id, msg.w, msg.v); break; } }; @@ -127,8 +127,8 @@ this.scheduleRequest = function(type, params, callback) { // add request information to params - params.class = "query"; - params.what = type; + params.c = "query"; + params.w = type; // check whether the same kind of request has already been scheduled var i = 0; switch(type) { @@ -136,7 +136,7 @@ case repoindex.RequestType.GroupInfo: // -> upgrade existing reuquest in this case for(; i < this.scheduledRequests.length; ++i) { - if(this.scheduledRequests[i].params.class === "query" && this.scheduledRequests[i].params.what === type) { + if(this.scheduledRequests[i].params.c === "query" && this.scheduledRequests[i].params.w === type) { // there is already such a request this.scheduledRequests[i].callbacks.push(callback); // add callback params.id = this.scheduledRequests[i].params.id; // keep the old ID @@ -262,7 +262,7 @@ this.sendCmd = function(cmd) { if(this.isOpen()) { - this.socket.send(JSON.stringify({class: "cmd", what: cmd})); + this.socket.send(JSON.stringify({c: "cmd", w: cmd})); } else { repoindex.pageManager.addError("Not connected to a server."); } @@ -374,13 +374,13 @@ var value = values[i]; var repo = repoindex.client.repos[value.repo]; if(repo) { - var package = repo.packages[value.name]; - if(package) { + var pkg = repo.packages[value.name]; + if(pkg) { if(value.basics) { - package.basics = value.basics; + pkg.basics = value.basics; } if(value.details) { - package.details = value.details; + pkg.details = value.details; } } else { repoindex.pageManager.addError("Package info replied by server refers to unknown package."); diff --git a/web/js/entrymanagement.js b/web/js/entrymanagement.js index cb9a587..cbb8d65 100644 --- a/web/js/entrymanagement.js +++ b/web/js/entrymanagement.js @@ -14,9 +14,12 @@ // row element this.rowElement = document.createElement("tr"); this.rowElement.entry = this; - this.rowElement.addCell = function(text) { + this.rowElement.addCell = function(text, color) { var cellElement = document.createElement("td"); if(text) { + if(color) { + cellElement.style.color = color; + } cellElement.appendChild(document.createTextNode(text)); } this.appendChild(cellElement); diff --git a/web/js/packagemanagement.js b/web/js/packagemanagement.js index bb61cf3..8bf2054 100644 --- a/web/js/packagemanagement.js +++ b/web/js/packagemanagement.js @@ -25,9 +25,15 @@ var srcOnly = this.repoEntry && this.repoEntry.info.srcOnly; var pkgOnly = this.repoEntry && this.repoEntry.info.pkgOnly; var version = this.curVer ? (this.curVer + " → " + (basics.ver ? basics.ver : "?")) : basics.ver; - var values = [srcOnly ? "n/a" : basics.arch, this.info.repo, this.name, version, basics.desc, srcOnly ? "n/a" : basics.bdate, pkgOnly ? "n/a" : basics.flagdate]; - for(var i = 0; i < 7; ++i) { - this.rowElement.addCell(repoindex.makeStr(values[i])); + var values = [srcOnly ? "n/a" : basics.arch, this.info.repo, this.name, version, basics.desc, srcOnly ? "n/a" : basics.bdate]; + if(basics.fdate) { + for(var i = 0; i < 6; ++i) { + this.rowElement.addCell(repoindex.makeStr(values[i]), i === 2 ? "red" : undefined); + } + } else { + for(var i = 0; i < 6; ++i) { + this.rowElement.addCell(repoindex.makeStr(values[i])); + } } };