mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 07:55:21 +01:00
Build changes
- Add support for embedded Linux without X, dbus, udisks, ntp, etc. - Misc minor changes
This commit is contained in:
parent
71eefa47cf
commit
5b072f3196
13 changed files with 189 additions and 222 deletions
|
@ -20,21 +20,29 @@ set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
# Adding headers explicity so they are displayed in Qt Creator
|
# Adding headers explicity so they are displayed in Qt Creator
|
||||||
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h
|
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h
|
||||||
downloadthread.h downloadextractthread.h acceleratedcryptographichash.h dependencies/mountutils/src/mountutils.hpp)
|
downloadthread.h downloadextractthread.h dependencies/mountutils/src/mountutils.hpp)
|
||||||
|
|
||||||
# Add 3rd-party dependencies
|
# Add dependencies
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||||
set(DEPENDENCIES mac/macfile.cpp mac/macfile.h mac/Info.plist dependencies/mountutils/src/darwin/functions.cpp
|
set(DEPENDENCIES mac/macfile.cpp mac/macfile.h mac/Info.plist dependencies/mountutils/src/darwin/functions.cpp
|
||||||
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
||||||
enable_language(OBJC C)
|
enable_language(OBJC C)
|
||||||
elseif (UNIX)
|
elseif (UNIX)
|
||||||
set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp linux/udisks2api.cpp linux/udisks2api.h)
|
set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp)
|
||||||
|
find_package(Qt5DBus)
|
||||||
|
if(Qt5DBus_FOUND)
|
||||||
|
set(DEPENDENCIES ${DEPENDENCIES} linux/udisks2api.cpp linux/udisks2api.h)
|
||||||
|
set(EXTRALIBS Qt5::DBus)
|
||||||
|
message("udisks2 support enabled")
|
||||||
|
else()
|
||||||
|
message("DBUS not found. Disabling udisks2 support")
|
||||||
|
endif()
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
set(DEPENDENCIES dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp
|
set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp
|
||||||
windows/winfile.cpp windows/winfile.h
|
windows/winfile.cpp windows/winfile.h
|
||||||
windows/rpi-imager.rc)
|
windows/rpi-imager.rc)
|
||||||
set(EXTRALIBS setupapi)
|
set(EXTRALIBS setupapi)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(BEFORE .)
|
include_directories(BEFORE .)
|
||||||
|
@ -60,10 +68,12 @@ endif()
|
||||||
|
|
||||||
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
|
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
|
||||||
"drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
|
"drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
|
||||||
"driveformatthread.cpp" "powersaveblocker.cpp" "acceleratedcryptographichash.cpp" "qml.qrc")
|
"driveformatthread.cpp" "powersaveblocker.cpp" "qml.qrc")
|
||||||
|
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets)
|
||||||
find_package(Qt5 COMPONENTS Core Quick Widgets LinguistTools REQUIRED)
|
if (Qt5Widgets_FOUND)
|
||||||
|
set(EXTRALIBS ${EXTRALIBS} Qt5::Widgets)
|
||||||
|
endif()
|
||||||
|
|
||||||
#qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
|
#qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
|
||||||
qt5_add_translation(QM_FILES i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
|
qt5_add_translation(QM_FILES i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
|
||||||
|
@ -82,6 +92,8 @@ if (WIN32)
|
||||||
# Target Windows 7 (needed for drivelist module)
|
# Target Windows 7 (needed for drivelist module)
|
||||||
add_definitions(-DWINVER=0x0601 -D_WIN32_WINNT=0x0601)
|
add_definitions(-DWINVER=0x0601 -D_WIN32_WINNT=0x0601)
|
||||||
|
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
# Bundled zlib
|
# Bundled zlib
|
||||||
add_subdirectory(dependencies/zlib-1.2.11)
|
add_subdirectory(dependencies/zlib-1.2.11)
|
||||||
set(ZLIB_LIBRARY zlibstatic)
|
set(ZLIB_LIBRARY zlibstatic)
|
||||||
|
@ -195,9 +207,7 @@ elseif(APPLE)
|
||||||
find_library(CoreFoundation CoreFoundation)
|
find_library(CoreFoundation CoreFoundation)
|
||||||
find_library(DiskArbitration DiskArbitration)
|
find_library(DiskArbitration DiskArbitration)
|
||||||
find_library(Security Security)
|
find_library(Security Security)
|
||||||
#find_package(Qt5 COMPONENTS Svg)
|
set(EXTRALIBS ${EXTRALIBS} ${CoreFoundation} ${DiskArbitration} ${Security} ${Cocoa})
|
||||||
#set(EXTRALIBS ${CoreFoundation} ${DiskArbitration} ${Security} ${Cocoa} Qt5::Svg)
|
|
||||||
set(EXTRALIBS ${CoreFoundation} ${DiskArbitration} ${Security} ${Cocoa})
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE YES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist)
|
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE YES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist)
|
||||||
|
|
||||||
find_program(MACDEPLOYQT "macdeployqt" PATHS "${Qt5_DIR}/../../../bin")
|
find_program(MACDEPLOYQT "macdeployqt" PATHS "${Qt5_DIR}/../../../bin")
|
||||||
|
@ -212,8 +222,7 @@ elseif(APPLE)
|
||||||
else()
|
else()
|
||||||
find_package(CURL REQUIRED 7.32.0)
|
find_package(CURL REQUIRED 7.32.0)
|
||||||
find_package(LibArchive REQUIRED 3.2.0)
|
find_package(LibArchive REQUIRED 3.2.0)
|
||||||
find_package(Qt5 COMPONENTS DBus)
|
find_package(OpenSSL REQUIRED)
|
||||||
set(EXTRALIBS Qt5::DBus)
|
|
||||||
if (NOT CMAKE_CROSSCOMPILING)
|
if (NOT CMAKE_CROSSCOMPILING)
|
||||||
find_program(LSBLK "lsblk")
|
find_program(LSBLK "lsblk")
|
||||||
if (NOT LSBLK)
|
if (NOT LSBLK)
|
||||||
|
@ -232,4 +241,4 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
||||||
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Widgets ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
|
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
#ifdef Q_OS_DARWIN
|
||||||
|
typedef QCryptographicHash AcceleratedCryptographicHash;
|
||||||
|
#else
|
||||||
|
|
||||||
#include "openssl/sha.h"
|
#include "openssl/sha.h"
|
||||||
|
|
||||||
class AcceleratedCryptographicHash
|
class AcceleratedCryptographicHash
|
||||||
|
@ -22,4 +27,5 @@ protected:
|
||||||
SHA256_CTX _sha256;
|
SHA256_CTX _sha256;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif // ACCELERATEDCRYPTOGRAPHICHASH_H
|
#endif // ACCELERATEDCRYPTOGRAPHICHASH_H
|
||||||
|
|
3
config.h
3
config.h
|
@ -10,6 +10,9 @@
|
||||||
/* Repository URL */
|
/* Repository URL */
|
||||||
#define OSLIST_URL "https://downloads.raspberrypi.org/os_list_imagingutility.json"
|
#define OSLIST_URL "https://downloads.raspberrypi.org/os_list_imagingutility.json"
|
||||||
|
|
||||||
|
/* Time synchronization URL (only used on eglfs QPA platform, URL must be HTTP) */
|
||||||
|
#define TIME_URL "http://downloads.raspberrypi.org/os_list_imagingutility.json?time_synchronization"
|
||||||
|
|
||||||
/* Hash algorithm for verifying (uncompressed image) checksum */
|
/* Hash algorithm for verifying (uncompressed image) checksum */
|
||||||
#define OSLIST_HASH_ALGORITHM QCryptographicHash::Sha256
|
#define OSLIST_HASH_ALGORITHM QCryptographicHash::Sha256
|
||||||
|
|
||||||
|
|
36
dependencies/mountutils/example/eject.js
vendored
36
dependencies/mountutils/example/eject.js
vendored
|
@ -1,36 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
/*
|
|
||||||
* Copyright 2017 resin.io
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const mountUtils = require('..');
|
|
||||||
|
|
||||||
let argv = process.argv.slice(2);
|
|
||||||
let disk = argv.shift();
|
|
||||||
|
|
||||||
if (!disk) {
|
|
||||||
console.error(`Usage: node example/eject <disk>`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.env.MOUNTUTILS_DEBUG = true;
|
|
||||||
|
|
||||||
console.log('Ejecting', disk, '...');
|
|
||||||
|
|
||||||
mountUtils.eject(disk, function(error) {
|
|
||||||
console.log(error || 'OK');
|
|
||||||
});
|
|
36
dependencies/mountutils/example/unmount.js
vendored
36
dependencies/mountutils/example/unmount.js
vendored
|
@ -1,36 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
/*
|
|
||||||
* Copyright 2017 resin.io
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const mountUtils = require('..');
|
|
||||||
|
|
||||||
let argv = process.argv.slice(2);
|
|
||||||
let disk = argv.shift();
|
|
||||||
|
|
||||||
if (!disk) {
|
|
||||||
console.error(`Usage: node example/unmount <disk>`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.env.MOUNTUTILS_DEBUG = true;
|
|
||||||
|
|
||||||
console.log('Unmounting', disk, '...');
|
|
||||||
|
|
||||||
mountUtils.unmountDisk(disk, function(error) {
|
|
||||||
console.log(error || 'OK');
|
|
||||||
});
|
|
106
dependencies/mountutils/tests/mountutils.spec.js
vendored
106
dependencies/mountutils/tests/mountutils.spec.js
vendored
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 resin.io
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai');
|
|
||||||
const mountutils = require('../');
|
|
||||||
|
|
||||||
describe('MountUtils', function() {
|
|
||||||
|
|
||||||
describe('.unmountDisk()', function() {
|
|
||||||
|
|
||||||
it('should be a function', function() {
|
|
||||||
chai.expect(mountutils.unmountDisk).to.be.a('function');
|
|
||||||
});
|
|
||||||
|
|
||||||
context('missing / wrong arguments', function() {
|
|
||||||
|
|
||||||
specify('throws on missing device', function() {
|
|
||||||
chai.expect(function() {
|
|
||||||
mountutils.unmountDisk(null, function() {});
|
|
||||||
}).to.throw(/must be a string/i);
|
|
||||||
});
|
|
||||||
|
|
||||||
specify('throws on missing callback', function() {
|
|
||||||
chai.expect(function() {
|
|
||||||
mountutils.unmountDisk('novalue');
|
|
||||||
}).to.throw(/must be a function/i);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
context('invalid device', function() {
|
|
||||||
|
|
||||||
specify('device is a directory', function( done ) {
|
|
||||||
mountutils.unmountDisk( __dirname, function( error ) {
|
|
||||||
chai.expect(error.message).to.match(/Unmount failed/);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
specify('device is an empty string', function( done ) {
|
|
||||||
mountutils.unmountDisk( '', function( error ) {
|
|
||||||
chai.expect(error.message).to.match(/Unmount failed/);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.eject()', function() {
|
|
||||||
|
|
||||||
it('should be a function', function() {
|
|
||||||
chai.expect(mountutils.eject).to.be.a('function');
|
|
||||||
});
|
|
||||||
|
|
||||||
context('missing / wrong arguments', function() {
|
|
||||||
|
|
||||||
specify('throws on missing device', function() {
|
|
||||||
chai.expect(function() {
|
|
||||||
mountutils.eject(null, function() {});
|
|
||||||
}).to.throw(/must be a string/i);
|
|
||||||
});
|
|
||||||
|
|
||||||
specify('throws on missing callback', function() {
|
|
||||||
chai.expect(function() {
|
|
||||||
mountutils.eject('novalue');
|
|
||||||
}).to.throw(/must be a function/i);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
context('invalid device', function() {
|
|
||||||
|
|
||||||
specify('device is a directory', function( done ) {
|
|
||||||
mountutils.eject( __dirname, function( error ) {
|
|
||||||
chai.expect(error.message).to.match(/Eject failed/);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
specify('device is an empty string', function( done ) {
|
|
||||||
mountutils.eject( '', function( error ) {
|
|
||||||
chai.expect(error.message).to.match(/Eject failed/);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -178,6 +178,7 @@ bool DownloadThread::_openAndPrepareDevice()
|
||||||
if (!_file.open(QIODevice::ReadWrite | QIODevice::Unbuffered))
|
if (!_file.open(QIODevice::ReadWrite | QIODevice::Unbuffered))
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
#ifndef QT_NO_DBUS
|
||||||
/* Opening device directly did not work, ask udisks2 to do it for us,
|
/* Opening device directly did not work, ask udisks2 to do it for us,
|
||||||
* if necessary prompting for authorization */
|
* if necessary prompting for authorization */
|
||||||
UDisks2Api udisks;
|
UDisks2Api udisks;
|
||||||
|
@ -187,11 +188,10 @@ bool DownloadThread::_openAndPrepareDevice()
|
||||||
_file.open(fd, QIODevice::ReadWrite | QIODevice::Unbuffered, QFileDevice::AutoCloseHandle);
|
_file.open(fd, QIODevice::ReadWrite | QIODevice::Unbuffered, QFileDevice::AutoCloseHandle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
emit error(tr("Cannot open storage device '%1'.").arg(QString(_filename)));
|
emit error(tr("Cannot open storage device '%1'.").arg(QString(_filename)));
|
||||||
return false;
|
return false;
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,7 @@ void DriveFormatThread::run()
|
||||||
{
|
{
|
||||||
/* Not running as root, try to outsource formatting to udisks2 */
|
/* Not running as root, try to outsource formatting to udisks2 */
|
||||||
|
|
||||||
|
#ifndef QT_NO_DBUS
|
||||||
UDisks2Api udisks2;
|
UDisks2Api udisks2;
|
||||||
if (udisks2.formatDrive(_device))
|
if (udisks2.formatDrive(_device))
|
||||||
{
|
{
|
||||||
|
@ -141,8 +142,11 @@ void DriveFormatThread::run()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
emit error(tr("Error formatting (through udisks2)"));
|
emit error(tr("Error formatting (through udisks2)"));
|
||||||
|
#ifndef QT_NO_DBUS
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,19 @@
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QStorageInfo>
|
#include <QStorageInfo>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#ifndef QT_NO_WIDGETS
|
||||||
|
#include <QFileDialog>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -27,10 +35,19 @@
|
||||||
|
|
||||||
ImageWriter::ImageWriter(QObject *parent)
|
ImageWriter::ImageWriter(QObject *parent)
|
||||||
: QObject(parent), _repo(QUrl(QString(OSLIST_URL))), _dlnow(0), _verifynow(0),
|
: QObject(parent), _repo(QUrl(QString(OSLIST_URL))), _dlnow(0), _verifynow(0),
|
||||||
_engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false)
|
_engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false),
|
||||||
|
_embeddedMode(false), _online(false)
|
||||||
{
|
{
|
||||||
connect(&_polltimer, SIGNAL(timeout()), SLOT(pollProgress()));
|
connect(&_polltimer, SIGNAL(timeout()), SLOT(pollProgress()));
|
||||||
|
|
||||||
|
QString platform = QGuiApplication::platformName();
|
||||||
|
if (platform == "eglfs" || platform == "wayland" || platform == "linuxfb")
|
||||||
|
{
|
||||||
|
_embeddedMode = true;
|
||||||
|
connect(&_networkchecktimer, SIGNAL(timeout()), SLOT(pollNetwork()));
|
||||||
|
_networkchecktimer.start(100);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QProcess *p = new QProcess(this);
|
QProcess *p = new QProcess(this);
|
||||||
p->start("net stop ShellHWDetection");
|
p->start("net stop ShellHWDetection");
|
||||||
|
@ -63,7 +80,7 @@ ImageWriter::ImageWriter(QObject *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
_settings.beginGroup("caching");
|
_settings.beginGroup("caching");
|
||||||
_cachingEnabled = _settings.value("enabled", IMAGEWRITER_ENABLE_CACHE_DEFAULT).toBool();
|
_cachingEnabled = !_embeddedMode && _settings.value("enabled", IMAGEWRITER_ENABLE_CACHE_DEFAULT).toBool();
|
||||||
_cachedFileHash = _settings.value("lastDownloadSHA256").toByteArray();
|
_cachedFileHash = _settings.value("lastDownloadSHA256").toByteArray();
|
||||||
_cacheFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+QDir::separator()+"lastdownload.cache";
|
_cacheFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+QDir::separator()+"lastdownload.cache";
|
||||||
if (!_cachedFileHash.isEmpty())
|
if (!_cachedFileHash.isEmpty())
|
||||||
|
@ -377,6 +394,7 @@ void ImageWriter::onFinalizing()
|
||||||
|
|
||||||
void ImageWriter::openFileDialog()
|
void ImageWriter::openFileDialog()
|
||||||
{
|
{
|
||||||
|
#ifndef QT_NO_WIDGETS
|
||||||
QFileDialog *fd = new QFileDialog(nullptr, tr("Select image"),
|
QFileDialog *fd = new QFileDialog(nullptr, tr("Select image"),
|
||||||
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation),
|
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation),
|
||||||
"Image files (*.img *.zip *.gz *.xz);;All files (*.*)");
|
"Image files (*.img *.zip *.gz *.xz);;All files (*.*)");
|
||||||
|
@ -394,6 +412,7 @@ void ImageWriter::openFileDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
fd->show();
|
fd->show();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageWriter::onFileSelected(QString filename)
|
void ImageWriter::onFileSelected(QString filename)
|
||||||
|
@ -441,6 +460,66 @@ void ImageWriter::_parseCompressedFile()
|
||||||
qDebug() << "Parsed .zip file containing" << numFiles << "files, uncompressed size:" << _extrLen;
|
qDebug() << "Parsed .zip file containing" << numFiles << "files, uncompressed size:" << _extrLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImageWriter::isOnline()
|
||||||
|
{
|
||||||
|
return _online || !_embeddedMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageWriter::pollNetwork()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
/* Check if we have an IP-address other than localhost */
|
||||||
|
QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
|
||||||
|
|
||||||
|
foreach (QHostAddress a, addresses)
|
||||||
|
{
|
||||||
|
if (!a.isLoopback() && a.scopeId().isEmpty())
|
||||||
|
{
|
||||||
|
/* Not a loopback or IPv6 link-local address, so online */
|
||||||
|
_online = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_online)
|
||||||
|
{
|
||||||
|
_networkchecktimer.stop();
|
||||||
|
qDebug() << "Network online. Synchronizing time.";
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||||
|
connect(manager, SIGNAL(finished(QNetworkReply*)), SLOT(onTimeSyncReply(QNetworkReply*)));
|
||||||
|
manager->head(QNetworkRequest(QUrl(TIME_URL)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
if (reply->hasRawHeader("Date"))
|
||||||
|
{
|
||||||
|
QDateTime dt = QDateTime::fromString(reply->rawHeader("Date"), Qt::RFC2822Date);
|
||||||
|
qDebug() << "Received current time from server:" << dt;
|
||||||
|
struct timeval tv = {
|
||||||
|
(time_t) dt.toSecsSinceEpoch(), 0
|
||||||
|
};
|
||||||
|
::settimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
emit networkOnline();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: try again later?
|
||||||
|
}
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageWriter::isEmbeddedMode()
|
||||||
|
{
|
||||||
|
return _embeddedMode;
|
||||||
|
}
|
||||||
|
|
||||||
void MountUtilsLog(std::string msg) {
|
void MountUtilsLog(std::string msg) {
|
||||||
qDebug() << "mountutils:" << msg.c_str();
|
qDebug() << "mountutils:" << msg.c_str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
class QQmlApplicationEngine;
|
class QQmlApplicationEngine;
|
||||||
class DownloadThread;
|
class DownloadThread;
|
||||||
|
class QNetworkReply;
|
||||||
|
|
||||||
class ImageWriter : public QObject
|
class ImageWriter : public QObject
|
||||||
{
|
{
|
||||||
|
@ -71,6 +72,11 @@ public:
|
||||||
/* Return filename part of URL set */
|
/* Return filename part of URL set */
|
||||||
Q_INVOKABLE QString srcFileName();
|
Q_INVOKABLE QString srcFileName();
|
||||||
|
|
||||||
|
/* Returns true if online */
|
||||||
|
Q_INVOKABLE bool isOnline();
|
||||||
|
|
||||||
|
Q_INVOKABLE bool isEmbeddedMode();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/* We are emiting signals with QVariant as parameters because QML likes it that way */
|
/* We are emiting signals with QVariant as parameters because QML likes it that way */
|
||||||
|
|
||||||
|
@ -81,16 +87,19 @@ signals:
|
||||||
void fileSelected(QVariant filename);
|
void fileSelected(QVariant filename);
|
||||||
void cancelled();
|
void cancelled();
|
||||||
void finalizing();
|
void finalizing();
|
||||||
|
void networkOnline();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
void pollProgress();
|
void pollProgress();
|
||||||
|
void pollNetwork();
|
||||||
void onSuccess();
|
void onSuccess();
|
||||||
void onError(QString msg);
|
void onError(QString msg);
|
||||||
void onFileSelected(QString filename);
|
void onFileSelected(QString filename);
|
||||||
void onCancelled();
|
void onCancelled();
|
||||||
void onCacheFileUpdated(QByteArray sha256);
|
void onCacheFileUpdated(QByteArray sha256);
|
||||||
void onFinalizing();
|
void onFinalizing();
|
||||||
|
void onTimeSyncReply(QNetworkReply *reply);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QUrl _src, _repo;
|
QUrl _src, _repo;
|
||||||
|
@ -99,10 +108,10 @@ protected:
|
||||||
quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow;
|
quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow;
|
||||||
DriveListModel _drivelist;
|
DriveListModel _drivelist;
|
||||||
QQmlApplicationEngine *_engine;
|
QQmlApplicationEngine *_engine;
|
||||||
QTimer _polltimer;
|
QTimer _polltimer, _networkchecktimer;
|
||||||
PowerSaveBlocker _powersave;
|
PowerSaveBlocker _powersave;
|
||||||
DownloadThread *_thread;
|
DownloadThread *_thread;
|
||||||
bool _verifyEnabled, _multipleFilesInZip, _cachingEnabled;
|
bool _verifyEnabled, _multipleFilesInZip, _cachingEnabled, _embeddedMode, _online;
|
||||||
QSettings _settings;
|
QSettings _settings;
|
||||||
|
|
||||||
void _parseCompressedFile();
|
void _parseCompressedFile();
|
||||||
|
|
|
@ -103,6 +103,12 @@ namespace Drivelist
|
||||||
bdev["vendor"].toString().trimmed(),
|
bdev["vendor"].toString().trimmed(),
|
||||||
bdev["model"].toString().trimmed()
|
bdev["model"].toString().trimmed()
|
||||||
};
|
};
|
||||||
|
if (name == "/dev/mmcblk0")
|
||||||
|
{
|
||||||
|
dp.removeAll("");
|
||||||
|
if (dp.empty())
|
||||||
|
dp.append(QObject::tr("Internal SD card reader"));
|
||||||
|
}
|
||||||
|
|
||||||
QString mp = bdev["mountpoint"].toString();
|
QString mp = bdev["mountpoint"].toString();
|
||||||
if (!mp.isEmpty())
|
if (!mp.isEmpty())
|
||||||
|
|
13
main.cpp
13
main.cpp
|
@ -13,11 +13,13 @@
|
||||||
#include "imagewriter.h"
|
#include "imagewriter.h"
|
||||||
#include "drivelistmodel.h"
|
#include "drivelistmodel.h"
|
||||||
#include "networkaccessmanagerfactory.h"
|
#include "networkaccessmanagerfactory.h"
|
||||||
#include <QtWidgets/QApplication>
|
|
||||||
#include <QMessageLogContext>
|
#include <QMessageLogContext>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#ifndef QT_NO_WIDGETS
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
#endif
|
||||||
|
|
||||||
static QTextStream cerr(stderr);
|
static QTextStream cerr(stderr);
|
||||||
|
|
||||||
|
@ -29,12 +31,16 @@ static void consoleMsgHandler(QtMsgType, const QMessageLogContext &, const QStri
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// prefer ANGLE (DirectX) over desktop OpenGL
|
// prefer ANGLE (DirectX) over desktop OpenGL
|
||||||
QApplication::setAttribute(Qt::AA_UseOpenGLES);
|
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef QT_NO_WIDGETS
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
#else
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
#endif
|
||||||
app.setOrganizationName("Raspberry Pi");
|
app.setOrganizationName("Raspberry Pi");
|
||||||
app.setOrganizationDomain("raspberrypi.org");
|
app.setOrganizationDomain("raspberrypi.org");
|
||||||
app.setApplicationName("Imager");
|
app.setApplicationName("Imager");
|
||||||
|
@ -146,6 +152,7 @@ int main(int argc, char *argv[])
|
||||||
qmlwindow->connect(&imageWriter, SIGNAL(fileSelected(QVariant)), qmlwindow, SLOT(onFileSelected(QVariant)));
|
qmlwindow->connect(&imageWriter, SIGNAL(fileSelected(QVariant)), qmlwindow, SLOT(onFileSelected(QVariant)));
|
||||||
qmlwindow->connect(&imageWriter, SIGNAL(cancelled()), qmlwindow, SLOT(onCancelled()));
|
qmlwindow->connect(&imageWriter, SIGNAL(cancelled()), qmlwindow, SLOT(onCancelled()));
|
||||||
qmlwindow->connect(&imageWriter, SIGNAL(finalizing()), qmlwindow, SLOT(onFinalizing()));
|
qmlwindow->connect(&imageWriter, SIGNAL(finalizing()), qmlwindow, SLOT(onFinalizing()));
|
||||||
|
qmlwindow->connect(&imageWriter, SIGNAL(networkOnline()), qmlwindow, SLOT(fetchOSlist()));
|
||||||
|
|
||||||
int rc = app.exec();
|
int rc = app.exec();
|
||||||
return rc;
|
return rc;
|
||||||
|
|
46
main.qml
46
main.qml
|
@ -36,6 +36,16 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shortcut {
|
||||||
|
sequence: StandardKey.Quit
|
||||||
|
context: Qt.ApplicationShortcut
|
||||||
|
onActivated: {
|
||||||
|
if (!progressBar.visible) {
|
||||||
|
Qt.quit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: bg
|
id: bg
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
@ -358,17 +368,9 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
httpRequest(imageWriter.constantOsListUrl(), function (x) {
|
if (imageWriter.isOnline()) {
|
||||||
var o = JSON.parse(x.responseText)
|
fetchOSlist();
|
||||||
if (!"os_list" in o) {
|
|
||||||
onError(qsTr("Error parsing os_list.json"))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var oslist = o["os_list"]
|
|
||||||
for (var i in oslist) {
|
|
||||||
osmodel.insert(osmodel.count-2, oslist[i])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +527,13 @@ ApplicationWindow {
|
||||||
osswipeview.setCurrentIndex(1)
|
osswipeview.setCurrentIndex(1)
|
||||||
}
|
}
|
||||||
} else if (url == "") {
|
} else if (url == "") {
|
||||||
|
if (!imageWriter.isEmbeddedMode()) {
|
||||||
imageWriter.openFileDialog()
|
imageWriter.openFileDialog()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// FIXME: provide QML file dialog
|
||||||
|
onError("Using custom images is not implemented on this platform yet.")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
imageWriter.setSrc(url, image_download_size, extract_size, typeof(extract_sha256) != "undefined" ? extract_sha256 : "", typeof(contains_multiple_files) != "undefined" ? contains_multiple_files : false)
|
imageWriter.setSrc(url, image_download_size, extract_size, typeof(extract_sha256) != "undefined" ? extract_sha256 : "", typeof(contains_multiple_files) != "undefined" ? contains_multiple_files : false)
|
||||||
osbutton.text = name
|
osbutton.text = name
|
||||||
|
@ -787,7 +795,7 @@ ApplicationWindow {
|
||||||
Material.foreground: "#ffffff"
|
Material.foreground: "#ffffff"
|
||||||
Material.background: "#c51a4a"
|
Material.background: "#c51a4a"
|
||||||
font.family: roboto.name
|
font.family: roboto.name
|
||||||
visible: false
|
visible: imageWriter.isEmbeddedMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -795,7 +803,7 @@ ApplicationWindow {
|
||||||
text: qsTr("CONTINUE")
|
text: qsTr("CONTINUE")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
msgpopup.close()
|
msgpopup.close()
|
||||||
quitbutton.visible = false
|
quitbutton.visible = imageWriter.isEmbeddedMode()
|
||||||
}
|
}
|
||||||
Material.foreground: "#ffffff"
|
Material.foreground: "#ffffff"
|
||||||
Material.background: "#c51a4a"
|
Material.background: "#c51a4a"
|
||||||
|
@ -931,4 +939,18 @@ ApplicationWindow {
|
||||||
function onFinalizing() {
|
function onFinalizing() {
|
||||||
progressText.text = qsTr("Finalizing...")
|
progressText.text = qsTr("Finalizing...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchOSlist() {
|
||||||
|
httpRequest(imageWriter.constantOsListUrl(), function (x) {
|
||||||
|
var o = JSON.parse(x.responseText)
|
||||||
|
if (!"os_list" in o) {
|
||||||
|
onError(qsTr("Error parsing os_list.json"))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var oslist = o["os_list"]
|
||||||
|
for (var i in oslist) {
|
||||||
|
osmodel.insert(osmodel.count-2, oslist[i])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue