some fixed, increased version
This commit is contained in:
parent
69a3d6de9d
commit
1cffbcb468
132
CMakeLists.txt
132
CMakeLists.txt
|
@ -23,7 +23,6 @@ set(HEADER_FILES
|
||||||
alpm/packagefinder.h
|
alpm/packagefinder.h
|
||||||
)
|
)
|
||||||
set(SRC_FILES
|
set(SRC_FILES
|
||||||
main.cpp
|
|
||||||
alpm/manager.cpp
|
alpm/manager.cpp
|
||||||
alpm/package.cpp
|
alpm/package.cpp
|
||||||
alpm/utilities.cpp
|
alpm/utilities.cpp
|
||||||
|
@ -44,6 +43,21 @@ set(SRC_FILES
|
||||||
network/userrepository.cpp
|
network/userrepository.cpp
|
||||||
network/networkaccessmanager.cpp
|
network/networkaccessmanager.cpp
|
||||||
)
|
)
|
||||||
|
set(CLI_HEADER_FILES
|
||||||
|
)
|
||||||
|
set(CLI_SRC_FILES
|
||||||
|
cli/main.cpp
|
||||||
|
)
|
||||||
|
set(GUI_HEADER_FILES
|
||||||
|
gui/mainwindow.h
|
||||||
|
gui/webpage.h
|
||||||
|
gui/webviewprovider.h
|
||||||
|
)
|
||||||
|
set(GUI_SRC_FILES
|
||||||
|
gui/main.cpp
|
||||||
|
gui/mainwindow.cpp
|
||||||
|
gui/webpage.cpp
|
||||||
|
)
|
||||||
set(WEB_FILES
|
set(WEB_FILES
|
||||||
web/3rdparty/bootstrap/css/bootstrap-theme.min.css
|
web/3rdparty/bootstrap/css/bootstrap-theme.min.css
|
||||||
web/3rdparty/bootstrap/css/bootstrap.min.css
|
web/3rdparty/bootstrap/css/bootstrap.min.css
|
||||||
|
@ -71,13 +85,13 @@ set(WEB_FILES
|
||||||
|
|
||||||
# meta data
|
# meta data
|
||||||
set(META_PROJECT_NAME repoindex)
|
set(META_PROJECT_NAME repoindex)
|
||||||
set(META_APP_NAME "Repository browser")
|
set(META_APP_NAME "Repository Browser")
|
||||||
set(META_APP_AUTHOR "Martchus")
|
set(META_APP_AUTHOR "Martchus")
|
||||||
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
||||||
set(META_APP_DESCRIPTION "Arch Linux repository browser")
|
set(META_APP_DESCRIPTION "Repository browser for Arch Linux")
|
||||||
set(META_VERSION_MAJOR 0)
|
set(META_VERSION_MAJOR 0)
|
||||||
set(META_VERSION_MINOR 2)
|
set(META_VERSION_MINOR 2)
|
||||||
set(META_VERSION_PATCH 1)
|
set(META_VERSION_PATCH 2)
|
||||||
|
|
||||||
# stringification of meta data
|
# stringification of meta data
|
||||||
set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"")
|
set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"")
|
||||||
|
@ -119,6 +133,9 @@ if(MINGW)
|
||||||
enable_language(RC)
|
enable_language(RC)
|
||||||
endif(MINGW)
|
endif(MINGW)
|
||||||
|
|
||||||
|
# read cached variables
|
||||||
|
set(WEBVIEW_PROVIDER "auto" CACHE STRING "specifies the webview provider: auto, webkit or webengine")
|
||||||
|
|
||||||
# check required Qt 5 modules
|
# check required Qt 5 modules
|
||||||
find_package(Qt5Core REQUIRED)
|
find_package(Qt5Core REQUIRED)
|
||||||
find_package(Qt5Concurrent REQUIRED)
|
find_package(Qt5Concurrent REQUIRED)
|
||||||
|
@ -126,6 +143,36 @@ find_package(Qt5Network REQUIRED)
|
||||||
find_package(Qt5WebSockets REQUIRED)
|
find_package(Qt5WebSockets REQUIRED)
|
||||||
find_package(KF5Archive REQUIRED)
|
find_package(KF5Archive REQUIRED)
|
||||||
|
|
||||||
|
# select Qt module providing webview (either Qt WebKit or Qt WebEngine)
|
||||||
|
if(${WEBVIEW_PROVIDER} STREQUAL "none")
|
||||||
|
set(WEBVIEW_PROVIDER OFF)
|
||||||
|
message(STATUS "Webview disabled, not building GUI.")
|
||||||
|
elseif(${WEBVIEW_PROVIDER} STREQUAL "auto")
|
||||||
|
find_package(Qt5WebEngineWidgets)
|
||||||
|
if(Qt5WebEngineWidgets_FOUND)
|
||||||
|
set(WEBVIEW_PROVIDER Qt5::WebEngineWidgets)
|
||||||
|
set(WEBVIEW_DEFINITION -DREPOINDEX_USE_WEBENGINE)
|
||||||
|
message(STATUS "No webview provider explicitely specified, defaulting to Qt WebEngine.")
|
||||||
|
else()
|
||||||
|
find_package(Qt5WebKitWidgets REQUIRED)
|
||||||
|
set(WEBVIEW_PROVIDER Qt5::WebKitWidgets)
|
||||||
|
message(STATUS "No webview provider explicitely specified, defaulting to Qt WebKit.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if(${WEBVIEW_PROVIDER} STREQUAL "webkit")
|
||||||
|
find_package(Qt5WebKitWidgets REQUIRED)
|
||||||
|
set(WEBVIEW_PROVIDER Qt5::WebKitWidgets)
|
||||||
|
message(STATUS "Using Qt WebKit as webview provider.")
|
||||||
|
elseif(${WEBVIEW_PROVIDER} STREQUAL "webengine")
|
||||||
|
find_package(Qt5WebEngineWidgets REQUIRED)
|
||||||
|
set(WEBVIEW_PROVIDER Qt5::WebEngineWidgets)
|
||||||
|
set(WEBVIEW_DEFINITION -DREPOINDEX_USE_WEBENGINE)
|
||||||
|
message(STATUS "Using Qt WebEngine as webview provider.")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "The specified webview provider '${WEBVIEW_PROVIDER}' is unknown.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# enable moc
|
# enable moc
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
@ -134,18 +181,33 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_definitions(
|
add_definitions(
|
||||||
-D_GLIBCXX_USE_CXX11_ABI=0
|
-D_GLIBCXX_USE_CXX11_ABI=0
|
||||||
-DCMAKE_BUILD
|
-DCMAKE_BUILD
|
||||||
|
${WEBVIEW_DEFINITION}
|
||||||
)
|
)
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
add_definitions(-DDEBUG_BUILD)
|
add_definitions(-DDEBUG_BUILD)
|
||||||
message(STATUS "Debug build enabled.")
|
message(STATUS "Debug build enabled.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# executable and linking
|
# executable and linking
|
||||||
add_executable(${META_PROJECT_NAME} ${HEADER_FILES} ${SRC_FILES} ${WEB_FILES} ${RES_FILES})
|
add_library(${META_PROJECT_NAME}-lib SHARED ${HEADER_FILES} ${SRC_FILES} ${WEB_FILES})
|
||||||
target_link_libraries(${META_PROJECT_NAME} c++utilities Qt5::Core Qt5::Concurrent Qt5::Network Qt5::WebSockets KF5::Archive)
|
target_link_libraries(${META_PROJECT_NAME}-lib c++utilities Qt5::Core Qt5::Concurrent Qt5::Network Qt5::WebSockets KF5::Archive)
|
||||||
|
set_target_properties(${META_PROJECT_NAME}-lib PROPERTIES
|
||||||
|
VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}
|
||||||
|
SOVERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}
|
||||||
|
CXX_STANDARD 11
|
||||||
|
OUTPUT_NAME ${META_PROJECT_NAME}
|
||||||
|
)
|
||||||
|
add_executable(${META_PROJECT_NAME} ${CLI_HEADER_FILES} ${CLI_SRC_FILES})
|
||||||
|
target_link_libraries(${META_PROJECT_NAME} c++utilities ${META_PROJECT_NAME}-lib Qt5::Core Qt5::Network Qt5::WebSockets)
|
||||||
set_target_properties(${META_PROJECT_NAME} PROPERTIES
|
set_target_properties(${META_PROJECT_NAME} PROPERTIES
|
||||||
CXX_STANDARD 11
|
CXX_STANDARD 11
|
||||||
)
|
)
|
||||||
|
if(NOT ${WEBVIEW_PROVIDER} STREQUAL "none")
|
||||||
|
add_executable(${META_PROJECT_NAME}-gui ${GUI_HEADER_FILES} ${GUI_SRC_FILES})
|
||||||
|
target_link_libraries(${META_PROJECT_NAME}-gui c++utilities qtutilities ${META_PROJECT_NAME}-lib Qt5::Core Qt5::Network Qt5::WebSockets ${WEBVIEW_PROVIDER})
|
||||||
|
set_target_properties(${META_PROJECT_NAME}-gui PROPERTIES
|
||||||
|
CXX_STANDARD 11
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# add install target for web files / minimizing
|
# add install target for web files / minimizing
|
||||||
# -> don't minimize debug builds
|
# -> don't minimize debug builds
|
||||||
|
@ -211,6 +273,11 @@ foreach(WEB_FILE ${WEB_FILES})
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
install(
|
||||||
|
FILES resources/icons/hicolor/scalable/apps/${META_PROJECT_NAME}.svg
|
||||||
|
DESTINATION share/${META_PROJECT_NAME}/web/img
|
||||||
|
COMPONENT web
|
||||||
|
)
|
||||||
# add target for minimizing
|
# add target for minimizing
|
||||||
if(HTML_MIN_FILES)
|
if(HTML_MIN_FILES)
|
||||||
add_custom_target(htmlmin ALL DEPENDS ${HTML_MIN_FILES})
|
add_custom_target(htmlmin ALL DEPENDS ${HTML_MIN_FILES})
|
||||||
|
@ -220,10 +287,32 @@ if(JS_MIN_FILES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# add install target
|
# add install target
|
||||||
|
foreach(HEADER_FILE ${HEADER_FILES})
|
||||||
|
get_filename_component(HEADER_DIR ${HEADER_FILE} DIRECTORY)
|
||||||
|
install(
|
||||||
|
FILES ${HEADER_FILE}
|
||||||
|
DESTINATION include/${META_PROJECT_NAME}/${HEADER_DIR}
|
||||||
|
COMPONENT header
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
install(TARGETS ${META_PROJECT_NAME}
|
install(TARGETS ${META_PROJECT_NAME}
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
COMPONENT binary
|
COMPONENT binary
|
||||||
)
|
)
|
||||||
|
if(NOT ${WEBVIEW_PROVIDER} STREQUAL "none")
|
||||||
|
install(TARGETS ${META_PROJECT_NAME}-gui
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
COMPONENT binary-gui
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
install(TARGETS ${META_PROJECT_NAME}-lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
COMPONENT binary
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
COMPONENT binary
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
COMPONENT binary
|
||||||
|
)
|
||||||
install(FILES resources/systemd/${META_PROJECT_NAME}.service
|
install(FILES resources/systemd/${META_PROJECT_NAME}.service
|
||||||
DESTINATION lib/systemd/system
|
DESTINATION lib/systemd/system
|
||||||
COMPONENT service
|
COMPONENT service
|
||||||
|
@ -232,18 +321,45 @@ install(FILES resources/settings/${META_PROJECT_NAME}.conf.js
|
||||||
DESTINATION share/${META_PROJECT_NAME}/skel
|
DESTINATION share/${META_PROJECT_NAME}/skel
|
||||||
COMPONENT config
|
COMPONENT config
|
||||||
)
|
)
|
||||||
|
install(FILES resources/icons/hicolor/scalable/apps/${META_PROJECT_NAME}.svg
|
||||||
|
DESTINATION share/icons/hicolor/scalable/apps
|
||||||
|
COMPONENT desktop
|
||||||
|
)
|
||||||
|
install(FILES resources/desktop/applications/${META_PROJECT_NAME}.desktop
|
||||||
|
DESTINATION share/applications
|
||||||
|
COMPONENT desktop
|
||||||
|
)
|
||||||
if(NOT TARGET install-binary)
|
if(NOT TARGET install-binary)
|
||||||
add_custom_target(install-binary
|
add_custom_target(install-binary
|
||||||
DEPENDS ${META_PROJECT_NAME}
|
DEPENDS ${META_PROJECT_NAME}
|
||||||
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
if((NOT ${WEBVIEW_PROVIDER} STREQUAL "none") AND (NOT TARGET install-binary-gui))
|
||||||
|
set(GUI_INSTALL_TARGET "install-binary-gui")
|
||||||
|
add_custom_target(install-binary-gui
|
||||||
|
DEPENDS ${META_PROJECT_NAME}
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=binary-gui -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(NOT TARGET install-header)
|
||||||
|
add_custom_target(install-header
|
||||||
|
DEPENDS ${META_PROJECT_NAME}
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=header -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
if(NOT TARGET install-service)
|
if(NOT TARGET install-service)
|
||||||
add_custom_target(install-service
|
add_custom_target(install-service
|
||||||
DEPENDS ${META_PROJECT_NAME}
|
DEPENDS ${META_PROJECT_NAME}
|
||||||
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=service -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=service -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
if(NOT TARGET install-desktop)
|
||||||
|
add_custom_target(install-desktop
|
||||||
|
DEPENDS ${META_PROJECT_NAME}
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=desktop -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
if(NOT TARGET install-config)
|
if(NOT TARGET install-config)
|
||||||
add_custom_target(install-config
|
add_custom_target(install-config
|
||||||
DEPENDS ${META_PROJECT_NAME}
|
DEPENDS ${META_PROJECT_NAME}
|
||||||
|
@ -258,7 +374,7 @@ if(NOT TARGET install-web)
|
||||||
endif()
|
endif()
|
||||||
if(NOT TARGET install-mingw-w64)
|
if(NOT TARGET install-mingw-w64)
|
||||||
add_custom_target(install-mingw-w64
|
add_custom_target(install-mingw-w64
|
||||||
DEPENDS install-binary
|
DEPENDS install-binary ${GUI_INSTALL_TARGET} install-header
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(NOT TARGET install-binary-strip)
|
if(NOT TARGET install-binary-strip)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace ChronoUtilities;
|
||||||
|
|
||||||
namespace RepoIndex {
|
namespace RepoIndex {
|
||||||
|
|
||||||
|
@ -37,25 +38,31 @@ using namespace Utilities;
|
||||||
class LoadPackage
|
class LoadPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LoadPackage(AlpmDatabase *database, PackageOrigin origin) :
|
LoadPackage(AlpmDatabase *database, PackageOrigin origin, DateTime descriptionsLastModified) :
|
||||||
m_db(database),
|
m_db(database),
|
||||||
m_origin(origin)
|
m_origin(origin),
|
||||||
|
m_descriptionsLastModified(descriptionsLastModified)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void operator()(const QPair<QString, QList<QByteArray> > &description)
|
void operator()(const QPair<QString, QList<QByteArray> > &description)
|
||||||
{
|
{
|
||||||
m_db->addPackageFromDescription(description.first, description.second, m_origin);
|
m_db->addPackageFromDescription(description.first, description.second, m_origin, m_descriptionsLastModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AlpmDatabase *const m_db;
|
AlpmDatabase *const m_db;
|
||||||
const PackageOrigin m_origin;
|
const PackageOrigin m_origin;
|
||||||
|
const DateTime m_descriptionsLastModified;
|
||||||
};
|
};
|
||||||
|
|
||||||
DatabaseError AlpmDatabase::loadDescriptions(QList<QPair<QString, QList<QByteArray> > > &descriptions)
|
DatabaseError AlpmDatabase::loadDescriptions(QList<QPair<QString, QList<QByteArray> > > &descriptions, ChronoUtilities::DateTime *lastModified)
|
||||||
{
|
{
|
||||||
QFileInfo pathInfo(databasePath());
|
QFileInfo pathInfo(databasePath());
|
||||||
if(pathInfo.isDir()) {
|
if(pathInfo.isDir()) {
|
||||||
|
if(lastModified) {
|
||||||
|
// just use current date here since this is usually the local db
|
||||||
|
*lastModified = DateTime::gmtNow();
|
||||||
|
}
|
||||||
static const QStringList relevantFiles = QStringList() << QStringLiteral("desc") << QStringLiteral("files");
|
static const QStringList relevantFiles = QStringList() << QStringLiteral("desc") << QStringLiteral("files");
|
||||||
QDir dbDir(databasePath());
|
QDir dbDir(databasePath());
|
||||||
QStringList pkgDirNames = dbDir.entryList(QDir::Dirs | QDir::Readable | QDir::Executable | QDir::NoDotAndDotDot);
|
QStringList pkgDirNames = dbDir.entryList(QDir::Dirs | QDir::Readable | QDir::Executable | QDir::NoDotAndDotDot);
|
||||||
|
@ -83,6 +90,9 @@ DatabaseError AlpmDatabase::loadDescriptions(QList<QPair<QString, QList<QByteArr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(pathInfo.isFile()) {
|
} else if(pathInfo.isFile()) {
|
||||||
|
if(lastModified) {
|
||||||
|
*lastModified = DateTime::fromTimeStampGmt(pathInfo.lastModified().toUTC().toTime_t());
|
||||||
|
}
|
||||||
KTar tar(databasePath());
|
KTar tar(databasePath());
|
||||||
const KArchiveDirectory *dbDir;
|
const KArchiveDirectory *dbDir;
|
||||||
if(tar.open(QIODevice::ReadOnly) && (dbDir = tar.directory())) {
|
if(tar.open(QIODevice::ReadOnly) && (dbDir = tar.directory())) {
|
||||||
|
@ -125,8 +135,8 @@ DatabaseError AlpmDatabase::loadDescriptions(QList<QPair<QString, QList<QByteArr
|
||||||
AlpmPackageLoader::AlpmPackageLoader(AlpmDatabase *repository, PackageOrigin origin) :
|
AlpmPackageLoader::AlpmPackageLoader(AlpmDatabase *repository, PackageOrigin origin) :
|
||||||
m_db(repository)
|
m_db(repository)
|
||||||
{
|
{
|
||||||
if((m_error = repository->loadDescriptions(m_descriptions)) == DatabaseError::NoError) {
|
if((m_error = repository->loadDescriptions(m_descriptions, &m_descriptionsLastModified)) == DatabaseError::NoError) {
|
||||||
m_future = QtConcurrent::map(m_descriptions, LoadPackage(repository, origin));
|
m_future = QtConcurrent::map(m_descriptions, LoadPackage(repository, origin, m_descriptionsLastModified));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,9 +167,6 @@ AlpmPackageLoader *AlpmDatabase::internalInit()
|
||||||
origin = PackageOrigin::SyncDb;
|
origin = PackageOrigin::SyncDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wipe current packages
|
|
||||||
wipePackages();
|
|
||||||
|
|
||||||
// initialization of packages is done concurrently via AlpmPackageLoader
|
// initialization of packages is done concurrently via AlpmPackageLoader
|
||||||
return new AlpmPackageLoader(this, origin);
|
return new AlpmPackageLoader(this, origin);
|
||||||
|
|
||||||
|
@ -211,17 +218,19 @@ QNetworkRequest AlpmDatabase::filesDatabaseRequest()
|
||||||
* - Does nothing if there is not at least one server URL available.
|
* - Does nothing if there is not at least one server URL available.
|
||||||
* - Status messages are printed via cerr.
|
* - Status messages are printed via cerr.
|
||||||
*/
|
*/
|
||||||
void AlpmDatabase::downloadDatabase(const QString &targetDir, bool filesDatabase)
|
bool AlpmDatabase::downloadDatabase(const QString &targetDir, bool filesDatabase)
|
||||||
{
|
{
|
||||||
QWriteLocker locker(lock());
|
QWriteLocker locker(lock());
|
||||||
if(serverUrls().isEmpty()) {
|
if(serverUrls().isEmpty()) {
|
||||||
return; // no server URLs available
|
return false; // no server URLs available
|
||||||
}
|
}
|
||||||
|
addBusyFlag();
|
||||||
cerr << shchar << "Downloading " << (filesDatabase ? "files" : "regular") << " database for [" << name().toLocal8Bit().data() << "] from mirror " << serverUrls().front().toLocal8Bit().data() << " ..." << endl;
|
cerr << shchar << "Downloading " << (filesDatabase ? "files" : "regular") << " database for [" << name().toLocal8Bit().data() << "] from mirror " << serverUrls().front().toLocal8Bit().data() << " ..." << endl;
|
||||||
QNetworkReply *reply = networkAccessManager().get(filesDatabase ? filesDatabaseRequest() : regularDatabaseRequest());
|
QNetworkReply *reply = networkAccessManager().get(filesDatabase ? filesDatabaseRequest() : regularDatabaseRequest());
|
||||||
reply->setProperty("filesDatabase", filesDatabase);
|
reply->setProperty("filesDatabase", filesDatabase);
|
||||||
m_downloadTargetDir = targetDir.isEmpty() ? QString(QChar('.')) : targetDir;
|
m_downloadTargetDir = targetDir.isEmpty() ? QString(QChar('.')) : targetDir;
|
||||||
connect(reply, &QNetworkReply::finished, this, &AlpmDatabase::databaseDownloadFinished);
|
connect(reply, &QNetworkReply::finished, this, &AlpmDatabase::databaseDownloadFinished);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -234,10 +243,8 @@ void AlpmDatabase::downloadDatabase(const QString &targetDir, bool filesDatabase
|
||||||
*/
|
*/
|
||||||
void AlpmDatabase::refresh(const QString &targetDir)
|
void AlpmDatabase::refresh(const QString &targetDir)
|
||||||
{
|
{
|
||||||
if(serverUrls().isEmpty()) {
|
if(!downloadDatabase(targetDir, true)) {
|
||||||
init();
|
init();
|
||||||
} else {
|
|
||||||
downloadDatabase(targetDir, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +259,7 @@ std::unique_ptr<Package> AlpmDatabase::emptyPackage()
|
||||||
*/
|
*/
|
||||||
void AlpmDatabase::databaseDownloadFinished()
|
void AlpmDatabase::databaseDownloadFinished()
|
||||||
{
|
{
|
||||||
|
removeBusyFlag();
|
||||||
auto *reply = static_cast<QNetworkReply *>(sender());
|
auto *reply = static_cast<QNetworkReply *>(sender());
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
bool filesDatabase = reply->property("filesDatabase").toBool();
|
bool filesDatabase = reply->property("filesDatabase").toBool();
|
||||||
|
|
|
@ -38,6 +38,7 @@ private:
|
||||||
AlpmDatabase *const m_db;
|
AlpmDatabase *const m_db;
|
||||||
DatabaseError m_error;
|
DatabaseError m_error;
|
||||||
QList<QPair<QString, QList<QByteArray> > > m_descriptions;
|
QList<QPair<QString, QList<QByteArray> > > m_descriptions;
|
||||||
|
ChronoUtilities::DateTime m_descriptionsLastModified;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -73,7 +74,7 @@ public:
|
||||||
void setDatabasePath(const QString &dbPath);
|
void setDatabasePath(const QString &dbPath);
|
||||||
|
|
||||||
// updating/refreshing
|
// updating/refreshing
|
||||||
void downloadDatabase(const QString &targetDir, bool filesDatabase = true);
|
bool downloadDatabase(const QString &targetDir, bool filesDatabase = true);
|
||||||
void refresh(const QString &targetDir);
|
void refresh(const QString &targetDir);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -83,7 +84,7 @@ private slots:
|
||||||
void databaseDownloadFinished();
|
void databaseDownloadFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DatabaseError loadDescriptions(QList<QPair<QString, QList<QByteArray> > > &descriptions);
|
DatabaseError loadDescriptions(QList<QPair<QString, QList<QByteArray> > > &descriptions, ChronoUtilities::DateTime *lastModified = nullptr);
|
||||||
QNetworkRequest regularDatabaseRequest();
|
QNetworkRequest regularDatabaseRequest();
|
||||||
QNetworkRequest filesDatabaseRequest();
|
QNetworkRequest filesDatabaseRequest();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
rootdirArg("root-dir", "r", "specifies the root directory (default is /)"),
|
rootdirArg("root-dir", "r", "specifies the root directory (default is /)"),
|
||||||
dbpathArg("db-path", "d", "specifies the pacman database path (default is /var/lib/pacman)"),
|
dbpathArg("db-path", "d", "specifies the pacman database path (default is /var/lib/pacman)"),
|
||||||
pacmanConfArg("pacman-conf", "p", "specifies the path of the pacman config file (default is /etc/pacman.conf"),
|
pacmanConfArg("pacman-conf", "p", "specifies the path of the pacman config file (default is /etc/pacman.conf"),
|
||||||
|
reposFromPacmanConfEnabled("repos-from-pacman-conf", string(), "enables repositories from the pacman config file"),
|
||||||
websocketAddrArg("addr", string(), "specifies the listening address for the websocket server, default is 127.0.0.1"),
|
websocketAddrArg("addr", string(), "specifies the listening address for the websocket server, default is 127.0.0.1"),
|
||||||
websocketPortArg("port", string(), "specifies the listening port for the websocket server, default is 1234"),
|
websocketPortArg("port", string(), "specifies the listening port for the websocket server, default is 1234"),
|
||||||
certFileArg("cert-file", string(), "specifies the SSL certificate"),
|
certFileArg("cert-file", string(), "specifies the SSL certificate"),
|
||||||
|
@ -84,6 +86,7 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
pacmanConfArg.setCombinable(true);
|
pacmanConfArg.setCombinable(true);
|
||||||
pacmanConfArg.setValueNames(pathValueName);
|
pacmanConfArg.setValueNames(pathValueName);
|
||||||
pacmanConfArg.setRequiredValueCount(1);
|
pacmanConfArg.setRequiredValueCount(1);
|
||||||
|
reposFromPacmanConfEnabled.setCombinable(true);
|
||||||
websocketAddrArg.setCombinable(true);
|
websocketAddrArg.setCombinable(true);
|
||||||
websocketAddrArg.setValueNames({"IP address"});
|
websocketAddrArg.setValueNames({"IP address"});
|
||||||
websocketAddrArg.setRequiredValueCount(1);
|
websocketAddrArg.setRequiredValueCount(1);
|
||||||
|
@ -127,7 +130,7 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
shSyntaxArg.setCombinable(true);
|
shSyntaxArg.setCombinable(true);
|
||||||
repoArg.setRequiredValueCount(1);
|
repoArg.setRequiredValueCount(1);
|
||||||
repoArg.setValueNames({"repo name"});
|
repoArg.setValueNames({"repo name"});
|
||||||
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &websocketAddrArg, &websocketPortArg, &insecureArg, &aurArg, &shSyntaxArg});
|
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &reposFromPacmanConfEnabled, &certFileArg, &keyFileArg, &websocketAddrArg, &websocketPortArg, &insecureArg, &aurArg, &shSyntaxArg});
|
||||||
upgradeLookupArg.setSecondaryArguments({&shSyntaxArg});
|
upgradeLookupArg.setSecondaryArguments({&shSyntaxArg});
|
||||||
buildOrderArg.setSecondaryArguments({&aurArg, &addSourceOnlyDepsArg, &requireSourcesArg, &verboseArg, &shSyntaxArg});
|
buildOrderArg.setSecondaryArguments({&aurArg, &addSourceOnlyDepsArg, &requireSourcesArg, &verboseArg, &shSyntaxArg});
|
||||||
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg, &defaultIconThemeArg, &extraPackagesArg});
|
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg, &defaultIconThemeArg, &extraPackagesArg});
|
||||||
|
@ -137,7 +140,7 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
storageDirArg.setCombinable(true);
|
storageDirArg.setCombinable(true);
|
||||||
storageDirArg.setRequiredValueCount(1);
|
storageDirArg.setRequiredValueCount(1);
|
||||||
storageDirArg.setValueNames(pathValueName);
|
storageDirArg.setValueNames(pathValueName);
|
||||||
parser.setMainArguments({&buildOrderArg, &upgradeLookupArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &cacheDirArg, &helpArg});
|
parser.setMainArguments({&buildOrderArg, &upgradeLookupArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &cacheDirArg, &storageDirArg, &helpArg});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -157,6 +160,7 @@ Config::Config() :
|
||||||
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
||||||
m_websocketServerListeningPort(1234),
|
m_websocketServerListeningPort(1234),
|
||||||
m_serverInsecure(false),
|
m_serverInsecure(false),
|
||||||
|
m_serverCloseable(true),
|
||||||
m_localEnabled(true),
|
m_localEnabled(true),
|
||||||
m_reposFromPacmanConfEnabled(false),
|
m_reposFromPacmanConfEnabled(false),
|
||||||
m_aurEnabled(true),
|
m_aurEnabled(true),
|
||||||
|
@ -280,8 +284,8 @@ void Config::loadFromConfigFile(const ConfigArgs &args)
|
||||||
loadFromConfigFile(QString::fromLocal8Bit(args.repoindexConfArg.values().front().data()));
|
loadFromConfigFile(QString::fromLocal8Bit(args.repoindexConfArg.values().front().data()));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
for(const auto &defaultPath : {QStringLiteral("./repoindex.conf"), QStringLiteral("/etc/repoindex.conf")}) {
|
for(const auto &defaultPath : {QStringLiteral("./repoindex.conf"), QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + QStringLiteral("/repoindex.conf"), QStringLiteral("/etc/repoindex.conf")}) {
|
||||||
if(QFile::exists(defaultPath)) {
|
if(!defaultPath.isEmpty() && QFile::exists(defaultPath)) {
|
||||||
loadFromConfigFile(defaultPath);
|
loadFromConfigFile(defaultPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -322,6 +326,18 @@ void Config::loadFromArgs(const ConfigArgs &args)
|
||||||
if(args.storageDirArg.isPresent()) {
|
if(args.storageDirArg.isPresent()) {
|
||||||
m_storageDir = QString::fromLocal8Bit(args.storageDirArg.values().front().data());
|
m_storageDir = QString::fromLocal8Bit(args.storageDirArg.values().front().data());
|
||||||
}
|
}
|
||||||
|
if(args.reposFromPacmanConfEnabled.isPresent()) {
|
||||||
|
m_reposFromPacmanConfEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Ensures that the server is only accessable from the local machine.
|
||||||
|
*/
|
||||||
|
void Config::loadLocalOnlySetup()
|
||||||
|
{
|
||||||
|
m_websocketServerListeningAddr = QHostAddress::LocalHost;
|
||||||
|
m_serverInsecure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RepoEntry::RepoEntry() :
|
RepoEntry::RepoEntry() :
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
ApplicationUtilities::Argument rootdirArg;
|
ApplicationUtilities::Argument rootdirArg;
|
||||||
ApplicationUtilities::Argument dbpathArg;
|
ApplicationUtilities::Argument dbpathArg;
|
||||||
ApplicationUtilities::Argument pacmanConfArg;
|
ApplicationUtilities::Argument pacmanConfArg;
|
||||||
|
ApplicationUtilities::Argument reposFromPacmanConfEnabled;
|
||||||
ApplicationUtilities::Argument websocketAddrArg;
|
ApplicationUtilities::Argument websocketAddrArg;
|
||||||
ApplicationUtilities::Argument websocketPortArg;
|
ApplicationUtilities::Argument websocketPortArg;
|
||||||
ApplicationUtilities::Argument certFileArg;
|
ApplicationUtilities::Argument certFileArg;
|
||||||
|
@ -143,6 +144,8 @@ public:
|
||||||
const QString &serverCertFile() const;
|
const QString &serverCertFile() const;
|
||||||
const QString &serverKeyFile() const;
|
const QString &serverKeyFile() const;
|
||||||
bool serverInsecure() const;
|
bool serverInsecure() const;
|
||||||
|
bool isServerCloseable() const;
|
||||||
|
void setServerCloseable(bool closeable);
|
||||||
bool isLocalDatabaseEnabled() const;
|
bool isLocalDatabaseEnabled() const;
|
||||||
bool areReposFromPacmanConfEnabled() const;
|
bool areReposFromPacmanConfEnabled() const;
|
||||||
const QList<RepoEntry> &repoEntries() const;
|
const QList<RepoEntry> &repoEntries() const;
|
||||||
|
@ -154,6 +157,7 @@ public:
|
||||||
void loadFromConfigFile(const QString &args);
|
void loadFromConfigFile(const QString &args);
|
||||||
void loadFromConfigFile(const ConfigArgs &args);
|
void loadFromConfigFile(const ConfigArgs &args);
|
||||||
void loadFromArgs(const ConfigArgs &args);
|
void loadFromArgs(const ConfigArgs &args);
|
||||||
|
void loadLocalOnlySetup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_alpmRootDir;
|
QString m_alpmRootDir;
|
||||||
|
@ -167,6 +171,7 @@ private:
|
||||||
QString m_serverCertFile;
|
QString m_serverCertFile;
|
||||||
QString m_serverKeyFile;
|
QString m_serverKeyFile;
|
||||||
bool m_serverInsecure;
|
bool m_serverInsecure;
|
||||||
|
bool m_serverCloseable;
|
||||||
|
|
||||||
QList<RepoEntry> m_repoEntries;
|
QList<RepoEntry> m_repoEntries;
|
||||||
bool m_localEnabled;
|
bool m_localEnabled;
|
||||||
|
@ -226,6 +231,16 @@ inline bool Config::serverInsecure() const
|
||||||
return m_serverInsecure;
|
return m_serverInsecure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Config::isServerCloseable() const
|
||||||
|
{
|
||||||
|
return m_serverCloseable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Config::setServerCloseable(bool closeable)
|
||||||
|
{
|
||||||
|
m_serverCloseable = closeable;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool Config::isLocalDatabaseEnabled() const
|
inline bool Config::isLocalDatabaseEnabled() const
|
||||||
{
|
{
|
||||||
return m_localEnabled;
|
return m_localEnabled;
|
||||||
|
|
|
@ -523,9 +523,6 @@ void Manager::initAlpmDataBases()
|
||||||
delete loader;
|
delete loader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto &syncDbEntry : m_syncDbMap) {
|
|
||||||
syncDbEntry.second->updateGroups();
|
|
||||||
}
|
|
||||||
if(m_config.isVerbose() || m_config.runServer()) {
|
if(m_config.isVerbose() || m_config.runServer()) {
|
||||||
cerr << "DONE" << endl;
|
cerr << "DONE" << endl;
|
||||||
}
|
}
|
||||||
|
@ -547,6 +544,10 @@ void Manager::computeRequiredBy(Repository *repo)
|
||||||
} else {
|
} else {
|
||||||
relevantDbs.reserve(m_syncDbs.size());
|
relevantDbs.reserve(m_syncDbs.size());
|
||||||
for(auto &syncDb : m_syncDbs) {
|
for(auto &syncDb : m_syncDbs) {
|
||||||
|
if(syncDb->isBusy()) {
|
||||||
|
syncDb->asSoonAsPossible(bind(&Manager::computeRequiredBy, this, repo));
|
||||||
|
return;
|
||||||
|
}
|
||||||
relevantDbs << syncDb.get();
|
relevantDbs << syncDb.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -590,6 +591,7 @@ void Manager::writeCache()
|
||||||
// could iterate through all repos and check isCachingUseful() but
|
// could iterate through all repos and check isCachingUseful() but
|
||||||
// currently its just the AUR which is needed to be cached
|
// currently its just the AUR which is needed to be cached
|
||||||
if(userRepository()) {
|
if(userRepository()) {
|
||||||
|
QDir().mkpath(config().cacheDir());
|
||||||
QFile file(config().cacheDir() % QChar('/') % userRepository()->name() % QStringLiteral(".cache"));
|
QFile file(config().cacheDir() % QChar('/') % userRepository()->name() % QStringLiteral(".cache"));
|
||||||
if(file.open(QFileDevice::WriteOnly)) {
|
if(file.open(QFileDevice::WriteOnly)) {
|
||||||
QDataStream stream(&file);
|
QDataStream stream(&file);
|
||||||
|
@ -690,13 +692,17 @@ void Manager::setAutoUpdateEnabled(bool enabled)
|
||||||
void Manager::updateAlpmDatabases()
|
void Manager::updateAlpmDatabases()
|
||||||
{
|
{
|
||||||
if(localDatabase()) {
|
if(localDatabase()) {
|
||||||
|
QReadLocker locker(localDatabase()->lock());
|
||||||
if(localDatabase()->hasOutdatedPackages()) {
|
if(localDatabase()->hasOutdatedPackages()) {
|
||||||
|
locker.unlock();
|
||||||
localDatabase()->init();
|
localDatabase()->init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto &syncDbEntry : m_syncDbMap) {
|
for(auto &syncDb : m_syncDbs) {
|
||||||
if(syncDbEntry.second->hasOutdatedPackages()) {
|
QReadLocker locker(syncDb->lock());
|
||||||
syncDbEntry.second->refresh(m_config.storageDir() + QStringLiteral("/sync"));
|
if(syncDb->hasOutdatedPackages()) {
|
||||||
|
locker.unlock();
|
||||||
|
syncDb->refresh(m_config.storageDir() + QStringLiteral("/sync"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ namespace RepoIndex {
|
||||||
Package::Package(const QString &name, Repository *repository) :
|
Package::Package(const QString &name, Repository *repository) :
|
||||||
m_origin(PackageOrigin::Unknown),
|
m_origin(PackageOrigin::Unknown),
|
||||||
m_repository(repository),
|
m_repository(repository),
|
||||||
m_timeStamp(DateTime::now()),
|
|
||||||
m_hasGeneralInfo(false),
|
m_hasGeneralInfo(false),
|
||||||
m_hasAllGeneralInfo(false),
|
m_hasAllGeneralInfo(false),
|
||||||
m_name(name),
|
m_name(name),
|
||||||
|
|
|
@ -229,6 +229,7 @@ public:
|
||||||
PackageOrigin origin() const;
|
PackageOrigin origin() const;
|
||||||
Repository *repository() const;
|
Repository *repository() const;
|
||||||
ChronoUtilities::DateTime timeStamp() const;
|
ChronoUtilities::DateTime timeStamp() const;
|
||||||
|
void setTimeStamp(ChronoUtilities::DateTime timeStamp);
|
||||||
bool hasGeneralInfo() const;
|
bool hasGeneralInfo() const;
|
||||||
bool hasAllGeneralInfo() const;
|
bool hasAllGeneralInfo() const;
|
||||||
const QString &name() const;
|
const QString &name() const;
|
||||||
|
@ -427,6 +428,14 @@ inline ChronoUtilities::DateTime Package::timeStamp() const
|
||||||
return m_timeStamp;
|
return m_timeStamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Sets the package's timestamp.
|
||||||
|
*/
|
||||||
|
inline void Package::setTimeStamp(ChronoUtilities::DateTime timeStamp)
|
||||||
|
{
|
||||||
|
m_timeStamp = timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns whether general information is available for the package.
|
* \brief Returns whether general information is available for the package.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -73,6 +73,12 @@ const QStringList Repository::packageNames() const
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Updates the groups.
|
||||||
|
*
|
||||||
|
* This method is automatically after initialization, so there is usually no need
|
||||||
|
* to call this method manually.
|
||||||
|
*/
|
||||||
void Repository::updateGroups()
|
void Repository::updateGroups()
|
||||||
{
|
{
|
||||||
m_groups.clear();
|
m_groups.clear();
|
||||||
|
@ -101,9 +107,12 @@ PackageLoader *Repository::init()
|
||||||
{
|
{
|
||||||
addBusyFlag();
|
addBusyFlag();
|
||||||
QWriteLocker locker(lock());
|
QWriteLocker locker(lock());
|
||||||
|
// wipe current packages
|
||||||
|
wipePackages();
|
||||||
if(PackageLoader *loader = internalInit()) {
|
if(PackageLoader *loader = internalInit()) {
|
||||||
if(loader->future().isRunning()) {
|
if(loader->future().isRunning()) {
|
||||||
auto watcher = new QFutureWatcher<void>;
|
auto watcher = new QFutureWatcher<void>;
|
||||||
|
connect(watcher, &QFutureWatcher<void>::finished, this, &Repository::updateGroups);
|
||||||
connect(watcher, &QFutureWatcher<void>::finished, this, &Repository::removeBusyFlag);
|
connect(watcher, &QFutureWatcher<void>::finished, this, &Repository::removeBusyFlag);
|
||||||
connect(watcher, &QFutureWatcher<void>::finished, this, &Repository::initialized);
|
connect(watcher, &QFutureWatcher<void>::finished, this, &Repository::initialized);
|
||||||
connect(watcher, &QFutureWatcher<void>::finished, watcher, &QFutureWatcher<void>::deleteLater);
|
connect(watcher, &QFutureWatcher<void>::finished, watcher, &QFutureWatcher<void>::deleteLater);
|
||||||
|
@ -111,20 +120,30 @@ PackageLoader *Repository::init()
|
||||||
}
|
}
|
||||||
return loader;
|
return loader;
|
||||||
} else {
|
} else {
|
||||||
|
updateGroups();
|
||||||
|
removeBusyFlag();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repository::initAsSoonAsPossible()
|
void Repository::initAsSoonAsPossible()
|
||||||
|
{
|
||||||
|
asSoonAsPossible(bind(&Repository::init, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Performs the specified \a operation as soon as possible.
|
||||||
|
*/
|
||||||
|
void Repository::asSoonAsPossible(std::function<void ()> operation)
|
||||||
{
|
{
|
||||||
if(isBusy()) {
|
if(isBusy()) {
|
||||||
auto connection = make_shared<QMetaObject::Connection>();
|
auto connection = make_shared<QMetaObject::Connection>();
|
||||||
*connection = connect(this, &Repository::available, [connection, this] {
|
*connection = connect(this, &Repository::available, [connection, operation] {
|
||||||
disconnect(*connection);
|
disconnect(*connection);
|
||||||
init();
|
operation();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
init();
|
operation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,30 +302,6 @@ QList<Package *> Repository::packageByFilter(std::function<bool (const Package *
|
||||||
* \cond
|
* \cond
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Blocker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Blocker(const QList<Repository *> &relevantRepos)
|
|
||||||
{
|
|
||||||
m_blockedRepos.reserve(relevantRepos.size());
|
|
||||||
for(Repository *repo : relevantRepos) {
|
|
||||||
if(repo->lock()->tryLockForWrite()) {
|
|
||||||
m_blockedRepos << repo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Blocker()
|
|
||||||
{
|
|
||||||
for(Repository *repo : m_blockedRepos) {
|
|
||||||
repo->lock()->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QList<Repository *> m_blockedRepos;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ComputeRequired
|
class ComputeRequired
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -555,7 +550,7 @@ void Repository::restoreFromCacheStream(QDataStream &in, bool skipOutdated)
|
||||||
quint32 packageCount;
|
quint32 packageCount;
|
||||||
in >> packageCount;
|
in >> packageCount;
|
||||||
bool good = true;
|
bool good = true;
|
||||||
const auto now = DateTime::now();
|
const auto now = DateTime::gmtNow();
|
||||||
for(quint32 i = 0; i < packageCount && good && in.status() == QDataStream::Ok; ++i) {
|
for(quint32 i = 0; i < packageCount && good && in.status() == QDataStream::Ok; ++i) {
|
||||||
if(auto package = emptyPackage()) {
|
if(auto package = emptyPackage()) {
|
||||||
package->restoreFromCacheStream(in);
|
package->restoreFromCacheStream(in);
|
||||||
|
@ -632,7 +627,7 @@ void Repository::cleanOutdatedPackages()
|
||||||
if(maxPackageAge().isInfinity()) {
|
if(maxPackageAge().isInfinity()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto now = DateTime::now();
|
auto now = DateTime::gmtNow();
|
||||||
for(auto i = m_packages.begin(); i != m_packages.end(); ) {
|
for(auto i = m_packages.begin(); i != m_packages.end(); ) {
|
||||||
const Package &pkg = *i->second;
|
const Package &pkg = *i->second;
|
||||||
if((now - pkg.timeStamp()) > maxPackageAge()) {
|
if((now - pkg.timeStamp()) > maxPackageAge()) {
|
||||||
|
@ -652,10 +647,9 @@ bool Repository::hasOutdatedPackages()
|
||||||
if(maxPackageAge().isInfinity()) {
|
if(maxPackageAge().isInfinity()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto now = DateTime::now();
|
auto now = DateTime::gmtNow();
|
||||||
for(auto i = m_packages.begin(); i != m_packages.end(); ) {
|
for(const auto &pkgEntry : m_packages) {
|
||||||
const Package &pkg = *i->second;
|
if((now - pkgEntry.second->timeStamp()) > maxPackageAge()) {
|
||||||
if((now - pkg.timeStamp()) > maxPackageAge()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -866,7 +860,7 @@ void Repository::parseDescriptions(const QList<QByteArray> &descriptions, QStrin
|
||||||
* \returns Returns the added/updated packages. In the case of a split package more then
|
* \returns Returns the added/updated packages. In the case of a split package more then
|
||||||
* one package is returned.
|
* one package is returned.
|
||||||
*/
|
*/
|
||||||
QList<Package *> Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
|
QList<Package *> Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo, ChronoUtilities::DateTime timeStamp)
|
||||||
{
|
{
|
||||||
// define states
|
// define states
|
||||||
enum {
|
enum {
|
||||||
|
@ -965,6 +959,7 @@ QList<Package *> Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
|
||||||
pkg = emptyPackage();
|
pkg = emptyPackage();
|
||||||
}
|
}
|
||||||
currentPackage = pkg.get();
|
currentPackage = pkg.get();
|
||||||
|
currentPackage->setTimeStamp(timeStamp);
|
||||||
packageInfo.clear();
|
packageInfo.clear();
|
||||||
}
|
}
|
||||||
// add field to ...
|
// add field to ...
|
||||||
|
@ -1007,7 +1002,7 @@ QList<Package *> Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
|
||||||
* - If \a name is empty and the description doesn't provide a name either, the package can not be added.
|
* - If \a name is empty and the description doesn't provide a name either, the package can not be added.
|
||||||
* \returns Returns the added/updated package or nullptr if no package could be added.
|
* \returns Returns the added/updated package or nullptr if no package could be added.
|
||||||
*/
|
*/
|
||||||
Package *Repository::addPackageFromDescription(QString name, const QList<QByteArray> &descriptions, PackageOrigin origin)
|
Package *Repository::addPackageFromDescription(QString name, const QList<QByteArray> &descriptions, PackageOrigin origin, DateTime timeStamp)
|
||||||
{
|
{
|
||||||
// parse fields
|
// parse fields
|
||||||
QList<QPair<QString, QStringList> > fields;
|
QList<QPair<QString, QStringList> > fields;
|
||||||
|
@ -1021,6 +1016,7 @@ Package *Repository::addPackageFromDescription(QString name, const QList<QByteAr
|
||||||
// find/create package for description
|
// find/create package for description
|
||||||
auto pkg = emptyPackage();
|
auto pkg = emptyPackage();
|
||||||
Package *pkgRawPtr = pkg.get();
|
Package *pkgRawPtr = pkg.get();
|
||||||
|
pkgRawPtr->setTimeStamp(timeStamp);
|
||||||
pkgRawPtr->putDescription(name, fields, origin);
|
pkgRawPtr->putDescription(name, fields, origin);
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&m_lock);
|
QWriteLocker locker(&m_lock);
|
||||||
|
|
|
@ -212,16 +212,16 @@ public:
|
||||||
bool isPackageOnly() const;
|
bool isPackageOnly() const;
|
||||||
std::map<QString, QList<Package *> > &groups();
|
std::map<QString, QList<Package *> > &groups();
|
||||||
const std::map<QString, QList<Package *> > &groups() const;
|
const std::map<QString, QList<Package *> > &groups() const;
|
||||||
void updateGroups();
|
Q_SLOT void updateGroups();
|
||||||
const QStringList &serverUrls() const;
|
const QStringList &serverUrls() const;
|
||||||
QStringList &serverUrls();
|
QStringList &serverUrls();
|
||||||
SignatureLevel sigLevel() const;
|
SignatureLevel sigLevel() const;
|
||||||
void setSigLevel(SignatureLevel sigLevel);
|
void setSigLevel(SignatureLevel sigLevel);
|
||||||
|
|
||||||
// gathering data
|
// gathering data
|
||||||
public:
|
Q_SLOT PackageLoader *init();
|
||||||
PackageLoader *init();
|
|
||||||
void initAsSoonAsPossible();
|
void initAsSoonAsPossible();
|
||||||
|
void asSoonAsPossible(std::function<void(void)> operation);
|
||||||
virtual PackageLoader *internalInit();
|
virtual PackageLoader *internalInit();
|
||||||
virtual PackageDetailAvailability requestsRequired(PackageDetail packageDetail = PackageDetail::Basics) const;
|
virtual PackageDetailAvailability requestsRequired(PackageDetail packageDetail = PackageDetail::Basics) const;
|
||||||
virtual SuggestionsReply *requestSuggestions(const QString &phrase);
|
virtual SuggestionsReply *requestSuggestions(const QString &phrase);
|
||||||
|
@ -273,8 +273,8 @@ public:
|
||||||
// parsing src/pkg info
|
// parsing src/pkg info
|
||||||
static void parsePkgInfo(const QByteArray &pkgInfo, QString &name, QList<QPair<QString, QString> > packageInfo);
|
static void parsePkgInfo(const QByteArray &pkgInfo, QString &name, QList<QPair<QString, QString> > packageInfo);
|
||||||
static void parseDescriptions(const QList<QByteArray> &descriptions, QString &name, QList<QPair<QString, QStringList> > &fields);
|
static void parseDescriptions(const QList<QByteArray> &descriptions, QString &name, QList<QPair<QString, QStringList> > &fields);
|
||||||
QList<Package *> addPackagesFromSrcInfo(const QByteArray &srcInfo);
|
QList<Package *> addPackagesFromSrcInfo(const QByteArray &srcInfo, ChronoUtilities::DateTime timeStamp);
|
||||||
Package *addPackageFromDescription(QString name, const QList<QByteArray> &descriptions, PackageOrigin origin);
|
Package *addPackageFromDescription(QString name, const QList<QByteArray> &descriptions, PackageOrigin origin, ChronoUtilities::DateTime timeStamp);
|
||||||
|
|
||||||
// thread synchronization
|
// thread synchronization
|
||||||
QReadWriteLock *lock() const;
|
QReadWriteLock *lock() const;
|
||||||
|
@ -576,6 +576,7 @@ inline void Repository::setMaxPackageAge(ChronoUtilities::TimeSpan maxPackageAge
|
||||||
inline void Repository::wipePackages()
|
inline void Repository::wipePackages()
|
||||||
{
|
{
|
||||||
m_packages.clear();
|
m_packages.clear();
|
||||||
|
m_groups.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QReadWriteLock>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ApplicationUtilities;
|
using namespace ApplicationUtilities;
|
||||||
using namespace RepoIndex;
|
using namespace RepoIndex;
|
|
@ -0,0 +1,106 @@
|
||||||
|
#include "./alpm/manager.h"
|
||||||
|
#include "./alpm/utilities.h"
|
||||||
|
#include "./alpm/config.h"
|
||||||
|
|
||||||
|
#include "./network/server.h"
|
||||||
|
|
||||||
|
#include "./gui/mainwindow.h"
|
||||||
|
|
||||||
|
#include "resources/config.h"
|
||||||
|
|
||||||
|
#include <qtutilities/resources/qtconfigarguments.h>
|
||||||
|
#include <qtutilities/resources/resources.h>
|
||||||
|
|
||||||
|
#include <c++utilities/application/argumentparser.h>
|
||||||
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
#include <c++utilities/application/failure.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace ApplicationUtilities;
|
||||||
|
using namespace RepoIndex;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// setup the argument parser
|
||||||
|
ArgumentParser parser;
|
||||||
|
SET_APPLICATION_INFO;
|
||||||
|
SET_QT_APPLICATION_INFO;
|
||||||
|
QT_CONFIG_ARGUMENTS qtConfigArgs;
|
||||||
|
ConfigArgs configArgs(parser);
|
||||||
|
parser.setIgnoreUnknownArguments(false);
|
||||||
|
Argument webdirArg("web-dir", string(), "specifies the directory of the web files");
|
||||||
|
webdirArg.setCombinable(true);
|
||||||
|
webdirArg.setRequiredValueCount(1);
|
||||||
|
webdirArg.setValueNames({"path"});
|
||||||
|
for(Argument *arg : initializer_list<Argument *>{&configArgs.rootdirArg, &configArgs.dbpathArg, &configArgs.pacmanConfArg, &configArgs.reposFromPacmanConfEnabled, &configArgs.aurArg}) {
|
||||||
|
qtConfigArgs.qtWidgetsGuiArg().addSecondaryArgument(arg);
|
||||||
|
}
|
||||||
|
parser.setMainArguments({&qtConfigArgs.qtWidgetsGuiArg(), &configArgs.repoindexConfArg, &configArgs.repoindexConfArg, &webdirArg, &configArgs.cacheDirArg, &configArgs.storageDirArg, &configArgs.helpArg});
|
||||||
|
// parse command line arguments
|
||||||
|
try {
|
||||||
|
parser.parseArgs(argc, argv);
|
||||||
|
} catch (const Failure &e) {
|
||||||
|
cerr << shchar << "Unable to parse arguments: " << e.what() << endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// load configuration
|
||||||
|
Config config;
|
||||||
|
config.loadFromConfigFile(configArgs);
|
||||||
|
config.loadFromArgs(configArgs);
|
||||||
|
config.loadLocalOnlySetup();
|
||||||
|
config.setServerCloseable(false);
|
||||||
|
|
||||||
|
if(qtConfigArgs.qtWidgetsGuiArg().isPresent()) {
|
||||||
|
// configure Qt
|
||||||
|
qtConfigArgs.applySettings();
|
||||||
|
|
||||||
|
// find directory with web files
|
||||||
|
QString webdir;
|
||||||
|
if(webdirArg.isPresent()) {
|
||||||
|
webdir = QString::fromLocal8Bit(webdirArg.values().front().data());
|
||||||
|
} else {
|
||||||
|
webdir = QStringLiteral("/usr/share/" PROJECT_NAME "/web");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create app
|
||||||
|
QApplication application(argc, argv);
|
||||||
|
MainWindow mainWindow(webdir);
|
||||||
|
mainWindow.show();
|
||||||
|
|
||||||
|
// setup manager
|
||||||
|
Manager manager(config);
|
||||||
|
cerr << shchar << "Loading databases ..." << endl;
|
||||||
|
if(config.areReposFromPacmanConfEnabled()) {
|
||||||
|
manager.addDataBasesFromPacmanConfig();
|
||||||
|
}
|
||||||
|
manager.addDatabasesFromRepoIndexConfig();
|
||||||
|
manager.initAlpmDataBases();
|
||||||
|
cerr << shchar << "Restoring cache ... ";
|
||||||
|
manager.restoreCache();
|
||||||
|
cerr << shchar << "DONE" << endl;
|
||||||
|
|
||||||
|
// setup the server
|
||||||
|
Server server(manager, manager.config());
|
||||||
|
manager.setAutoCacheMaintenanceEnabled(true);
|
||||||
|
manager.setAutoUpdateEnabled(true);
|
||||||
|
|
||||||
|
// run Qt event loop
|
||||||
|
return application.exec();
|
||||||
|
|
||||||
|
} else if(!configArgs.helpArg.isPresent()) {
|
||||||
|
if(useShSyntax) {
|
||||||
|
cerr << "export REPOINDEX_ERROR='No command line arguments specified. See --help for available commands.'" << endl;
|
||||||
|
} else {
|
||||||
|
cerr << "No command line arguments specified. See --help for available commands." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const exception &ex) {
|
||||||
|
Utilities::printError(ex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include "./mainwindow.h"
|
||||||
|
#include "./webpage.h"
|
||||||
|
|
||||||
|
#include "resources/config.h"
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
namespace RepoIndex {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a new main window.
|
||||||
|
*/
|
||||||
|
MainWindow::MainWindow(const QString &webdir)
|
||||||
|
{
|
||||||
|
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||||
|
setWindowTitle(QStringLiteral(APP_NAME));
|
||||||
|
setWindowIcon(QIcon::fromTheme(QStringLiteral(PROJECT_NAME)));
|
||||||
|
m_webView.setPage(new WebPage(&m_webView));
|
||||||
|
QUrl url(QStringLiteral("file://") % webdir % QStringLiteral("/index.html"));
|
||||||
|
url.setFragment(settings.value(QStringLiteral("fragment"), QStringLiteral("packages")).toString());
|
||||||
|
m_webView.setUrl(url);
|
||||||
|
m_webView.setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(&m_webView, &QWidget::customContextMenuRequested, this, &MainWindow::showInfoWebViewContextMenu);
|
||||||
|
setCentralWidget(&m_webView);
|
||||||
|
restoreGeometry(settings.value(QStringLiteral("geometry")).toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::event(QEvent *event)
|
||||||
|
{
|
||||||
|
switch(event->type()) {
|
||||||
|
case QEvent::KeyRelease: {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
switch(keyEvent->key()) {
|
||||||
|
case Qt::Key_Left:
|
||||||
|
case Qt::Key_Back:
|
||||||
|
m_webView.back();
|
||||||
|
return true;
|
||||||
|
case Qt::Key_Right:
|
||||||
|
case Qt::Key_Forward:
|
||||||
|
m_webView.forward();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} case QEvent::MouseButtonPress: {
|
||||||
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||||
|
switch(mouseEvent->button()) {
|
||||||
|
case Qt::BackButton:
|
||||||
|
m_webView.back();
|
||||||
|
return true;
|
||||||
|
case Qt::ForwardButton:
|
||||||
|
m_webView.forward();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} case QEvent::Close: {
|
||||||
|
// save settings
|
||||||
|
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
|
||||||
|
settings.setValue(QStringLiteral("geometry"), saveGeometry());
|
||||||
|
settings.setValue(QStringLiteral("fragment"), m_webView.url().fragment());
|
||||||
|
break;
|
||||||
|
} default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return QMainWindow::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Shows the context menu for the info web view.
|
||||||
|
*/
|
||||||
|
void MainWindow::showInfoWebViewContextMenu(const QPoint &)
|
||||||
|
{
|
||||||
|
QAction copyAction(QIcon::fromTheme(QStringLiteral("edit-copy")), tr("Copy"), nullptr);
|
||||||
|
copyAction.setDisabled(m_webView.selectedText().isEmpty());
|
||||||
|
connect(©Action, &QAction::triggered, this, &MainWindow::copyInfoWebViewSelection);
|
||||||
|
QMenu menu;
|
||||||
|
menu.addAction(©Action);
|
||||||
|
menu.exec(QCursor::pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Copies the current selection of the info web view.
|
||||||
|
*/
|
||||||
|
void MainWindow::copyInfoWebViewSelection()
|
||||||
|
{
|
||||||
|
QGuiApplication::clipboard()->setText(m_webView.selectedText());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include "./webviewprovider.h"
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#ifdef REPOINDEX_USE_WEBENGINE
|
||||||
|
# include <QWebEngineView>
|
||||||
|
#else
|
||||||
|
# include <QWebView>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace RepoIndex {
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MainWindow(const QString &webdir);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *event);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void showInfoWebViewContextMenu(const QPoint &);
|
||||||
|
void copyInfoWebViewSelection();
|
||||||
|
|
||||||
|
private:
|
||||||
|
WEB_VIEW_PROVIDER m_webView;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,51 @@
|
||||||
|
#include "./webpage.h"
|
||||||
|
|
||||||
|
#include "resources/config.h"
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#ifdef REPOINDEX_USE_WEBENGINE
|
||||||
|
# include <QWebEngineSettings>
|
||||||
|
# include <QWebEngineView>
|
||||||
|
#else
|
||||||
|
# include <QWebSettings>
|
||||||
|
# include <QWebView>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace RepoIndex {
|
||||||
|
|
||||||
|
WebPage::WebPage(WEB_VIEW_PROVIDER *view) :
|
||||||
|
WEB_PAGE_PROVIDER(view),
|
||||||
|
m_view(view)
|
||||||
|
{
|
||||||
|
#ifdef REPOINDEX_USE_WEBENGINE
|
||||||
|
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
|
||||||
|
#else
|
||||||
|
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
|
||||||
|
#endif
|
||||||
|
if(!m_view) {
|
||||||
|
// delegate to external browser if no view is assigned
|
||||||
|
connect(this, &WebPage::urlChanged, this, &WebPage::delegateToExternalBrowser);
|
||||||
|
m_view = new WEB_VIEW_PROVIDER;
|
||||||
|
m_view->setPage(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WEB_PAGE_PROVIDER *WebPage::createWindow(QWebEnginePage::WebWindowType type)
|
||||||
|
{
|
||||||
|
return new WebPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPage::delegateToExternalBrowser(const QUrl &url)
|
||||||
|
{
|
||||||
|
openUrlExternal(url);
|
||||||
|
// this page and the associated view are useless
|
||||||
|
m_view->deleteLater();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPage::openUrlExternal(const QUrl &url)
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef WEBPAGE_H
|
||||||
|
#define WEBPAGE_H
|
||||||
|
|
||||||
|
#include "./webviewprovider.h"
|
||||||
|
|
||||||
|
#ifdef REPOINDEX_USE_WEBENGINE
|
||||||
|
# include <QWebEnginePage>
|
||||||
|
#else
|
||||||
|
# include <QWebPage>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(WEB_VIEW_PROVIDER)
|
||||||
|
|
||||||
|
namespace RepoIndex {
|
||||||
|
|
||||||
|
class WebPage : public WEB_PAGE_PROVIDER
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
WebPage(WEB_VIEW_PROVIDER *view = nullptr);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void openUrlExternal(const QUrl &url);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
WEB_PAGE_PROVIDER *createWindow(WebWindowType type);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void delegateToExternalBrowser(const QUrl &url);
|
||||||
|
|
||||||
|
private:
|
||||||
|
WEB_VIEW_PROVIDER *m_view;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBPAGE_H
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef WEB_VIEW_PROVIDER
|
||||||
|
#ifdef REPOINDEX_USE_WEBENGINE
|
||||||
|
# define WEB_VIEW_PROVIDER QWebEngineView
|
||||||
|
# define WEB_PAGE_PROVIDER QWebEnginePage
|
||||||
|
#else
|
||||||
|
# define WEB_VIEW_PROVIDER QWebView
|
||||||
|
# define WEB_PAGE_PROVIDER QWebPage
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -132,7 +132,7 @@ void Connection::handleCmd(const QJsonObject &obj)
|
||||||
const auto what = obj.value(QStringLiteral("w")).toString();
|
const auto what = obj.value(QStringLiteral("w")).toString();
|
||||||
const auto id = obj.value(QStringLiteral("id"));
|
const auto id = obj.value(QStringLiteral("id"));
|
||||||
if(what == QLatin1String("stop")) {
|
if(what == QLatin1String("stop")) {
|
||||||
if(m_socket->peerAddress().isLoopback()) {
|
if(m_manager.config().isServerCloseable() && m_socket->peerAddress().isLoopback()) {
|
||||||
cerr << shchar << "Info: Server stopped via web interface." << endl;
|
cerr << shchar << "Info: Server stopped via web interface." << endl;
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -55,6 +55,7 @@ void AurPackageReply::processData(QNetworkReply *reply)
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
|
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
|
||||||
if(error.error == QJsonParseError::NoError) {
|
if(error.error == QJsonParseError::NoError) {
|
||||||
|
auto now = DateTime::gmtNow();
|
||||||
QWriteLocker locker(m_repo->lock());
|
QWriteLocker locker(m_repo->lock());
|
||||||
auto &packages = m_repo->packages();
|
auto &packages = m_repo->packages();
|
||||||
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
|
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
|
||||||
|
@ -67,6 +68,7 @@ void AurPackageReply::processData(QNetworkReply *reply)
|
||||||
} else {
|
} else {
|
||||||
package = make_unique<AurPackage>(obj, static_cast<UserRepository *>(m_userRepo));
|
package = make_unique<AurPackage>(obj, static_cast<UserRepository *>(m_userRepo));
|
||||||
}
|
}
|
||||||
|
package->setTimeStamp(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -113,7 +115,7 @@ void AurFullPackageReply::processData(QNetworkReply *reply)
|
||||||
if(srcInfoEntry && srcInfoEntry->isFile()) {
|
if(srcInfoEntry && srcInfoEntry->isFile()) {
|
||||||
const auto srcInfo = static_cast<const KArchiveFile *>(srcInfoEntry)->data();
|
const auto srcInfo = static_cast<const KArchiveFile *>(srcInfoEntry)->data();
|
||||||
QWriteLocker locker(m_userRepo->lock());
|
QWriteLocker locker(m_userRepo->lock());
|
||||||
const auto packages = m_userRepo->addPackagesFromSrcInfo(srcInfo);
|
const auto packages = m_userRepo->addPackagesFromSrcInfo(srcInfo, DateTime::gmtNow());
|
||||||
// TODO: error handling
|
// TODO: error handling
|
||||||
for(const auto &entryName : baseDir->entries()) {
|
for(const auto &entryName : baseDir->entries()) {
|
||||||
if(entryName != QLatin1String(".SRCINFO")) {
|
if(entryName != QLatin1String(".SRCINFO")) {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env xdg-open
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Repository Browser
|
||||||
|
Comment=An Arch Linux repository browser.
|
||||||
|
Exec=sh -c "repoindex-gui --repos-from-pacman-conf --cache-dir \\"\\$HOME/.cache/Martchus/Repository Browser\\" --storage-dir \\"\\$HOME/.config/Martchus/Repository Browser\\""
|
||||||
|
Icon=repoindex
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Utility;
|
|
@ -0,0 +1,286 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="128.47652mm"
|
||||||
|
height="128.47652mm"
|
||||||
|
viewBox="0 0 455.23172 455.23175"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="repoindex.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient4156">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0088cc;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4158" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#005b88;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop4160" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient4342">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffe247;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop4344" />
|
||||||
|
<stop
|
||||||
|
id="stop4350"
|
||||||
|
offset="0.67710614"
|
||||||
|
style="stop-color:#ffe113;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#eeff88;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop4346" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="-30.507242 : 472.74589 : 1"
|
||||||
|
inkscape:vp_y="0 : 590.9609 : 0"
|
||||||
|
inkscape:vp_z="1084.0486 : 472.74589 : 1"
|
||||||
|
inkscape:persp3d-origin="526.77064 : 369.09507 : 1"
|
||||||
|
id="perspective4148" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4342"
|
||||||
|
id="radialGradient4352"
|
||||||
|
cx="321.2179"
|
||||||
|
cy="524.50543"
|
||||||
|
fx="321.2179"
|
||||||
|
fy="524.50543"
|
||||||
|
r="150.79008"
|
||||||
|
gradientTransform="matrix(1,0,0,1.0631051,-255.83411,84.518479)"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4156"
|
||||||
|
id="linearGradient4162"
|
||||||
|
x1="291.74536"
|
||||||
|
y1="713.38061"
|
||||||
|
x2="452.79324"
|
||||||
|
y2="761.86792"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4156"
|
||||||
|
id="linearGradient4178"
|
||||||
|
x1="396.44601"
|
||||||
|
y1="557.31207"
|
||||||
|
x2="439.7518"
|
||||||
|
y2="461.3476"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4156"
|
||||||
|
id="linearGradient4186"
|
||||||
|
x1="134.08012"
|
||||||
|
y1="532.63721"
|
||||||
|
x2="333.1778"
|
||||||
|
y2="477.0788"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.98994949"
|
||||||
|
inkscape:cx="172.38789"
|
||||||
|
inkscape:cy="222.01635"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1039"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="18"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-95.085314,-386.88471)">
|
||||||
|
<path
|
||||||
|
style="fill:#6ccfff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.954;stroke-linecap:butt;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:1.99954295;stroke-opacity:1"
|
||||||
|
d="m 154.4949,579.62112 167.59343,-58.47155 164.83869,74.78194 -189.49553,65.00691 z"
|
||||||
|
id="rect4358"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient4178);fill-opacity:1;stroke:#ffffff;stroke-width:2.95759749;stroke-linecap:butt;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:2;stroke-opacity:1"
|
||||||
|
d="m 319.56719,519.77647 69.28807,-53.41761 160.99173,68.71253 -61.3275,58.59649 z"
|
||||||
|
id="rect4214-0"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient4186);fill-opacity:1;stroke:#ffffff;stroke-width:2.95759749;stroke-linecap:butt;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1"
|
||||||
|
d="m 96.802346,515.47264 162.667844,-52.81423 65.66299,57.4282 -171.00252,60.24593 z"
|
||||||
|
id="rect4214"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#radialGradient4352);fill-opacity:1;fill-rule:nonzero;stroke:#434343;stroke-width:2.854;stroke-linecap:butt;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:2;stroke-opacity:1"
|
||||||
|
id="path4140"
|
||||||
|
sodipodi:type="arc"
|
||||||
|
sodipodi:cx="74.886345"
|
||||||
|
sodipodi:cy="642.12262"
|
||||||
|
sodipodi:rx="159.61505"
|
||||||
|
sodipodi:ry="159.61505"
|
||||||
|
sodipodi:start="0.55248493"
|
||||||
|
sodipodi:end="5.7870476"
|
||||||
|
d="M 210.75436,725.88925 A 159.61505,159.61505 0 0 1 29.193706,795.05773 159.61505,159.61505 0 0 1 -84.665363,637.62628 159.61505,159.61505 0 0 1 37.879134,486.85694 159.61505,159.61505 0 0 1 215.25624,566.14067 L 74.886345,642.12262 Z"
|
||||||
|
transform="matrix(0.91759584,-0.39751462,0.39751462,0.91759584,0,0)" />
|
||||||
|
<circle
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#434343;stroke-width:2.183;stroke-linecap:butt;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:1.99954295;stroke-opacity:1"
|
||||||
|
id="path4144"
|
||||||
|
cx="95.899529"
|
||||||
|
cy="548.30194"
|
||||||
|
r="21.144077"
|
||||||
|
transform="matrix(0.91759584,-0.39751462,0.39751462,0.91759584,0,0)" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4202"
|
||||||
|
style="fill:url(#linearGradient4162);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.95759749;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:2;stroke-opacity:1"
|
||||||
|
d="m 293.22416,660.48706 2.11255,172.15066 195.37368,-65.01376 0,-173.50047 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4202-6"
|
||||||
|
style="fill:#0088cc;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.95759749;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:2;stroke-opacity:1"
|
||||||
|
d="m 298.74404,658.26061 -2.11338,172.15066 -146.8618,-84.02688 4.22513,-167.16276 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<g
|
||||||
|
id="g4269"
|
||||||
|
transform="matrix(0.40448316,-0.14264259,0,0.40448316,264.26281,440.48667)">
|
||||||
|
<g
|
||||||
|
style="fill:#ffffff;fill-opacity:1"
|
||||||
|
id="g2809"
|
||||||
|
transform="matrix(0.55789384,0,0,0.55789384,-34.632645,718.71563)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2284"
|
||||||
|
d="m 339.96875,309.09375 c -14.47141,-0.0239 -26.4812,2.94367 -31.125,4.5625 l -4.78125,25.8125 c -0.0116,0.0951 23.79543,-6.34855 34.28125,-5.96875 17.36158,0.62381 18.95948,6.63541 18.65625,14.75 0.29595,0.47462 -4.47933,-7.33192 -19.5,-7.59375 -18.94961,-0.32687 -45.69284,6.70947 -45.65625,35.3125 -0.51086,32.17412 24.03361,41.63882 40.75,41.8125 15.02821,-0.27364 22.0777,-5.69136 25.9375,-8.59375 5.07124,-5.30236 10.87308,-10.63447 16.40625,-17.03125 -5.23567,9.51278 -9.77472,16.0898 -14.5,21.125 l 0,4.25 22.84375,-3.84375 0.15625,-62.09375 c -0.23141,-8.78839 5.04123,-42.41827 -43.46875,-42.5 z m -3.28125,54.0625 c 9.46889,0.12995 20.32788,4.79708 20.34375,16.03125 0.049,10.21821 -12.80005,15.71183 -21.15625,15.625 -8.35976,-0.0868 -19.45093,-6.56982 -19.5,-16.53125 0.16016,-8.90444 10.45953,-15.35418 20.3125,-15.125 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2286"
|
||||||
|
d="m 398.50106,314.83145 -0.15505,102.82693 26.61213,-5.12724 0.0449,-58.30157 c 0.006,-8.68089 12.40554,-18.82451 27.9627,-18.66287 3.30202,-5.97408 9.5087,-21.24219 11.02088,-24.71514 -34.75649,-0.0833 -35.19897,9.98993 -41.24398,14.94517 -0.0631,-9.45285 -0.0213,-15.12741 -0.0213,-15.12741 l -24.2202,4.16213 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2288"
|
||||||
|
d="m 548.2688,328.33058 c -0.25696,-0.12068 -13.87938,-15.93419 -41.26638,-16.0589 -25.65249,-0.42638 -54.42578,9.51895 -54.88631,52.5328 0.22457,37.81852 27.6402,52.59809 55.0314,52.88627 29.31292,0.30451 40.97654,-18.32947 41.67615,-18.79124 -3.49762,-3.0321 -16.59792,-16.0131 -16.59792,-16.0131 0,0 -8.18236,11.65102 -24.05802,11.79913 -15.87942,0.1512 -29.68245,-12.27325 -29.87805,-29.60905 -0.20349,-17.33595 12.68881,-26.72821 29.99725,-27.48687 14.98466,-0.003 23.6297,9.67334 23.6297,9.67334 l 16.35218,-18.93238 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2290"
|
||||||
|
d="m 581.8125,278.84375 -25.125,5.90625 0.1875,133.9375 24.75,-4.46875 0.28125,-63.03125 c 0.0529,-6.60927 9.56127,-16.75916 25.4375,-16.4375 15.17973,0.15775 18.57236,10.11767 18.53125,11.375 l 0.4375,72.96875 24.40625,-4.3125 0.0937,-77.375 c 0.1607,-7.44539 -16.30833,-23.16954 -42.78125,-23.28125 -12.58087,0.0202 -19.54815,2.86825 -23.09375,4.96875 -6.06656,4.68565 -12.9998,9.17543 -19.8125,14.90625 6.29809,-8.09099 11.58551,-13.68516 16.75,-17.84375 l -0.0625,-37.3125 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
id="g5326"
|
||||||
|
transform="matrix(0.82595102,0,0.01168815,0.82595102,1.9788752,356.03908)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2292"
|
||||||
|
d="m 400.67581,629.79609 7.68167,-1.91575 -0.92851,91.20792 -7.79574,1.32426 1.04258,-90.61643 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2294"
|
||||||
|
d="m 421.10266,657.01757 6.75064,-2.9867 -0.86808,65.39931 -6.49779,1.33915 0.61523,-63.75176 z m -1.26059,-23.58316 5.47167,-4.41533 4.42261,4.99952 -5.47558,4.53221 -4.4187,-5.1164 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2296"
|
||||||
|
d="m 440.44273,655.82614 7.67755,-1.56201 -0.1573,13.6722 c -0.007,0.58717 4.4194,-15.27364 24.68502,-14.92094 19.67986,0.10952 22.68401,15.34634 22.5291,18.76237 l -0.43759,48.0783 -6.73044,1.45631 0.63316,-47.489 c 0.0974,-1.38684 -2.88144,-13.11441 -16.78906,-13.15754 -13.90509,-0.0404 -23.68364,10.10048 -23.75821,16.57937 l -0.48127,41.83477 -7.80388,2.0313 0.63292,-65.28513 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2298"
|
||||||
|
d="m 561.53301,720.20203 -7.6776,1.56186 0.15737,-13.67198 c 0.007,-0.58742 -4.42201,15.27361 -24.68504,14.92086 -19.67983,-0.10944 -22.68399,-15.34626 -22.52908,-18.76229 l 0.43757,-48.07861 8.15674,-1.64226 -0.54644,47.48988 c -0.0149,1.29682 1.36845,13.29979 15.27604,13.3426 13.90511,0.0405 23.76622,-8.37359 24.01453,-21.04416 l 0.43105,-37.46902 7.5978,-1.93195 -0.63294,65.28507 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path2300"
|
||||||
|
d="m 577.45461,655.28678 -5.42715,4.20017 20.19894,26.93328 -22.39092,31.11622 5.63499,4.226 21.04365,-28.8967 20.8779,29.58159 5.32727,-4.20103 -22.37578,-31.62866 18.56963,-25.5775 -5.53193,-4.73429 -16.92109,23.66778 -19.00551,-24.68686 z"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="matrix(0.8746356,0,0,0.8746356,-66.545022,716.81646)"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:8.44138241px;font-family:'DejaVu Sans Mono';fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
id="text2634">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff"
|
||||||
|
id="path7858"
|
||||||
|
d="m 685.46692,263.83624 0,-5.32944 -1.99082,0 0,-0.71307 4.7895,0 0,0.71307 -1.99906,0 0,5.32944 -0.79962,0"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff"
|
||||||
|
id="path7860"
|
||||||
|
d="m 689.0982,263.83624 0,-6.04251 1.20355,0 1.43026,4.2784 c 0.13189,0.39843 0.22806,0.69658 0.28852,0.89442 0.0687,-0.21983 0.17586,-0.5427 0.3215,-0.96862 l 1.44674,-4.2042 1.07578,0 0,6.04251 -0.77077,0 0,-5.05741 -1.75587,5.05741 -0.72131,0 -1.74763,-5.14396 0,5.14396 -0.77077,0"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="text2638"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:8.25130367px;font-family:'DejaVu Sans Mono';fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
transform="matrix(0.8746356,0,0,0.8746356,136.49564,557.21236)">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 239.84053,313.69965 0,-5.20945 -1.94598,0 0,-0.697 4.68164,0 0,0.697 -1.95404,0 0,5.20945 -0.78162,0"
|
||||||
|
id="path7853"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 243.39004,313.69965 0,-5.90645 1.17646,0 1.39805,4.18205 c 0.12892,0.38947 0.22293,0.6809 0.28202,0.87429 0.0671,-0.21488 0.1719,-0.53048 0.31426,-0.94681 l 1.41417,-4.10953 1.05155,0 0,5.90645 -0.75341,0 0,-4.94353 -1.71634,4.94353 -0.70506,0 -1.70828,-5.02814 0,5.02814 -0.75342,0"
|
||||||
|
id="path7855"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="fill:#0088cc;fill-opacity:1;stroke:#ffffff;stroke-width:2.95759749;stroke-linecap:butt;stroke-miterlimit:1.45000005;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1"
|
||||||
|
d="m 106.65363,647.21618 46.11221,-67.92278 146.48421,78.50104 -44.86588,74.74063 z"
|
||||||
|
id="rect4214-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 397.52991,637.10169 c -4.91286,13.77761 -7.87608,22.70147 -13.34592,36.31744 3.3537,2.37223 7.47021,5.0604 14.15539,7.37845 -7.18724,-0.42289 -12.08981,-1.66325 -15.75358,-3.4524 -7.00035,17.07601 -17.9679,41.75123 -40.22458,89.59085 17.49302,-16.26801 31.05326,-27.27622 43.69078,-34.10863 -0.54266,-2.1426 -0.85118,-4.55844 -0.83023,-7.20003 l 0.0207,-0.56771 c 0.27757,-11.30518 6.10759,-21.97959 13.01382,-23.82991 6.90623,-1.85034 12.27437,5.82171 11.99681,17.1269 -0.0522,2.12726 -0.29008,4.23986 -0.7057,6.26802 12.50031,-1.96301 25.91556,-0.48374 43.17189,3.39314 -3.40263,-5.06448 -6.43974,-9.64038 -9.34007,-13.99569 -4.56852,-1.92979 -9.3337,-4.85783 -19.05376,-6.41897 6.68102,-0.62015 11.46453,-0.30414 15.19319,0.61964 -29.48858,-44.50331 -31.87652,-50.95656 -41.98881,-71.12108 z"
|
||||||
|
id="path2518-2"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 16 KiB |
|
@ -21,10 +21,12 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"repos": {
|
"repos": {
|
||||||
|
"localEnabled": true,
|
||||||
"fromPacmanConfig": true,
|
"fromPacmanConfig": true,
|
||||||
|
|
||||||
"add": [
|
"//add": [
|
||||||
{"name": "examplerepo",
|
{"name": "examplerepo",
|
||||||
|
"maxAge": 3600
|
||||||
"dataBaseFile": "path/to/database/file",
|
"dataBaseFile": "path/to/database/file",
|
||||||
"sourcesDir": "path/to/local/source/dir",
|
"sourcesDir": "path/to/local/source/dir",
|
||||||
"packagesDir": "path/to/local/pkg/dir",
|
"packagesDir": "path/to/local/pkg/dir",
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
"upgradeSources": ["aur"],
|
"upgradeSources": ["aur"],
|
||||||
"server": [
|
"server": [
|
||||||
"https://localhost/repo/arch/$repo/os/$arch"
|
"https://localhost/repo/arch/$repo/os/$arch"
|
||||||
]
|
],
|
||||||
|
"maxAge": 3600
|
||||||
},
|
},
|
||||||
|
|
||||||
{"name": "local", "maxAge": 3600},
|
{"name": "local", "maxAge": 3600},
|
||||||
|
|
|
@ -229,6 +229,7 @@
|
||||||
<h4 class="modal-title">About</h4>
|
<h4 class="modal-title">About</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" style="text-align: center;">
|
<div class="modal-body" style="text-align: center;">
|
||||||
|
<img src="img/@META_PROJECT_NAME@.svg" style="width: 256px; height: 256px;" />
|
||||||
<h2>@META_APP_NAME@</h2>
|
<h2>@META_APP_NAME@</h2>
|
||||||
<p>@META_APP_VERSION@</p>
|
<p>@META_APP_VERSION@</p>
|
||||||
<p style="margin: 25px 0px;">
|
<p style="margin: 25px 0px;">
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
this.socket.onerror = function(event) {
|
this.socket.onerror = function(event) {
|
||||||
repoindex.pageManager.addError("Connecting to server failed: " + event.reason);
|
repoindex.pageManager.addError("Connecting to server failed.");
|
||||||
repoindex.pageManager.setConnectionStatus(repoindex.ConnectionStatus.Disconnected);
|
repoindex.pageManager.setConnectionStatus(repoindex.ConnectionStatus.Disconnected);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -514,11 +514,14 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// create a global client used within the entire document
|
// create a global client used within the entire document
|
||||||
repoindex.client = new Client((window.location.protocol === "https:" ? "wss://" : "ws://") + document.domain + ":1234");
|
repoindex.client = new Client((window.location.protocol === "https:" ? "wss://" : "ws://") + (window.location.protocol === "file:" ? "localhost" : document.domain) + ":1234");
|
||||||
if(!repoindex.isLoopback(document.domain)) {
|
if(!repoindex.isLoopback(document.domain)) {
|
||||||
// hide stop button if server is not on loopback interface
|
// hide stop button if server is not on loopback interface
|
||||||
document.getElementById("nav_server").style.display = "none";
|
document.getElementById("nav_server").style.display = "none";
|
||||||
}
|
}
|
||||||
|
if(window.location.protocol === "file:") {
|
||||||
|
document.getElementById("nav_connect").style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
return repoindex;
|
return repoindex;
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,8 @@
|
||||||
repoArray.push({index: entry.info.index, name: entry.info.name});
|
repoArray.push({index: entry.info.index, name: entry.info.name});
|
||||||
}
|
}
|
||||||
entriesRequired = true;
|
entriesRequired = true;
|
||||||
|
} else {
|
||||||
|
entry.updateTableRow();
|
||||||
}
|
}
|
||||||
}, mgr.filteredEntries.length);
|
}, mgr.filteredEntries.length);
|
||||||
var updateTableRows = function() {
|
var updateTableRows = function() {
|
||||||
|
|
|
@ -37,7 +37,9 @@
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
this.link.appendChild(document.createTextNode(repoName));
|
this.link.appendChild(document.createTextNode(repoName));
|
||||||
this.link.title = repoInfo.desc;
|
if(repoInfo.desc) {
|
||||||
|
this.link.title = repoInfo.desc;
|
||||||
|
}
|
||||||
|
|
||||||
// use Bootstrap tooltip
|
// use Bootstrap tooltip
|
||||||
this.link.setAttribute("data-placement", "bottom");
|
this.link.setAttribute("data-placement", "bottom");
|
||||||
|
|
Loading…
Reference in New Issue