2017-08-23 13:27:23 +02:00
|
|
|
|
#include "BackupDialog.h"
|
|
|
|
|
|
#include "ui_BackupDialog.h"
|
2017-02-01 18:01:02 +01:00
|
|
|
|
|
2017-03-05 21:23:36 +01:00
|
|
|
|
#include "BackupFormatModel.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <QFileDialog>
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
#include <QProcess>
|
|
|
|
|
|
#include <QScrollBar>
|
|
|
|
|
|
#include <QStandardPaths>
|
|
|
|
|
|
|
2017-11-26 13:07:21 +01:00
|
|
|
|
#ifdef WIN32
|
|
|
|
|
|
# include <windows.h> // for CreateProcess flags
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2017-02-01 18:01:02 +01:00
|
|
|
|
BackupDialog::BackupDialog(QWidget *parent) :
|
|
|
|
|
|
QDialog(parent),
|
|
|
|
|
|
ui(new Ui::BackupDialog)
|
|
|
|
|
|
{
|
|
|
|
|
|
ui->setupUi(this);
|
2017-03-05 21:23:36 +01:00
|
|
|
|
|
|
|
|
|
|
auto format_model = new BackupFormatModel(this);
|
|
|
|
|
|
ui->backupFormat->setModel(format_model);
|
2017-02-01 18:01:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BackupDialog::~BackupDialog()
|
|
|
|
|
|
{
|
|
|
|
|
|
delete ui;
|
|
|
|
|
|
}
|
2017-03-05 21:23:36 +01:00
|
|
|
|
|
|
|
|
|
|
void BackupDialog::setConfig(const ConnectionConfig &cfg)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_config = cfg;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::ConnectTo(QProcess *process)
|
|
|
|
|
|
{
|
|
|
|
|
|
disconnectCurrentProcess();
|
|
|
|
|
|
m_process = process;
|
|
|
|
|
|
if (process) {
|
|
|
|
|
|
process->setProcessChannelMode(QProcess::MergedChannels);
|
|
|
|
|
|
process->setReadChannel(QProcess::StandardOutput);
|
|
|
|
|
|
|
|
|
|
|
|
connect(process, SIGNAL(readyRead()), this, SLOT(on_process_readyRead()));
|
|
|
|
|
|
connect(process, SIGNAL(errorOccurred(QProcess::ProcessError)), this,
|
|
|
|
|
|
SLOT(on_process_errorOccurred(QProcess::ProcessError)));
|
|
|
|
|
|
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
|
|
|
|
|
SLOT(on_process_finished(int, QProcess::ExitStatus)));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::disconnectCurrentProcess()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_process) {
|
|
|
|
|
|
disconnect(m_process, SIGNAL(readyRead()), this, SLOT(on_process_readyRead()));
|
|
|
|
|
|
disconnect(m_process, SIGNAL(errorOccurred(QProcess::ProcessError)), this,
|
|
|
|
|
|
SLOT(on_process_errorOccurred(QProcess::ProcessError)));
|
|
|
|
|
|
disconnect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
|
|
|
|
|
SLOT(on_process_finished(int, QProcess::ExitStatus)));
|
|
|
|
|
|
m_process = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::writeOutput(QString s)
|
|
|
|
|
|
{
|
|
|
|
|
|
ui->stdOutput->appendPlainText(s);
|
|
|
|
|
|
QScrollBar *bar = ui->stdOutput->verticalScrollBar();
|
|
|
|
|
|
bar->setValue(bar->maximum());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::on_process_readyRead()
|
|
|
|
|
|
{
|
|
|
|
|
|
QByteArray data = m_process->readAllStandardOutput();
|
|
|
|
|
|
writeOutput(QString::fromUtf8(data));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::on_process_errorOccurred(QProcess::ProcessError error)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString msg;
|
|
|
|
|
|
switch (error) {
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
msg = tr("Failed to start");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 1:
|
2017-08-22 12:45:45 +02:00
|
|
|
|
msg = tr("Crashed");
|
2017-03-05 21:23:36 +01:00
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
msg = tr("Timedout");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
msg = tr("Read error");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
|
|
|
msg = tr("Write error");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 5:
|
|
|
|
|
|
msg = tr("Unknown error");
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
msg = tr("Unexpected error");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto res = QMessageBox::critical(this, "pglab", msg, QMessageBox::Close);
|
|
|
|
|
|
if (res == QMessageBox::Yes) {
|
|
|
|
|
|
QApplication::quit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::on_process_finished(int exitCode, QProcess::ExitStatus )
|
|
|
|
|
|
{
|
|
|
|
|
|
writeOutput(tr("Completed, with exitcode %1\n").arg(exitCode));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::setParams(QStringList &args)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString short_args("-");
|
|
|
|
|
|
if (ui->chkbxVerbose->checkState() == Qt::Checked)
|
|
|
|
|
|
short_args += "v";
|
|
|
|
|
|
if (ui->chkbxClean->checkState() == Qt::Checked)
|
|
|
|
|
|
short_args += "c";
|
|
|
|
|
|
if (ui->chkbxCreate->checkState() == Qt::Checked)
|
|
|
|
|
|
short_args += "C";
|
|
|
|
|
|
if (ui->chkbxIncludeBlobs->checkState() == Qt::Checked)
|
|
|
|
|
|
short_args += "b";
|
|
|
|
|
|
switch (ui->what->currentIndex()) {
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
short_args += "a";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
short_args += "s";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ui->oids->checkState() == Qt::Checked)
|
|
|
|
|
|
short_args += "o";
|
|
|
|
|
|
if (ui->noAcl->checkState() == Qt::Checked)
|
|
|
|
|
|
short_args += "x";
|
|
|
|
|
|
if (short_args.length() > 1) // larger then one because always includes '-'
|
|
|
|
|
|
args << short_args;
|
|
|
|
|
|
|
|
|
|
|
|
// Todo check path exists and name is valid?
|
|
|
|
|
|
|
|
|
|
|
|
QFileInfo fi(QDir::fromNativeSeparators(ui->editFilename->text()));
|
|
|
|
|
|
QDir dir(fi.absolutePath());
|
|
|
|
|
|
if (!dir.exists())
|
|
|
|
|
|
dir.mkdir(fi.absolutePath());
|
|
|
|
|
|
|
|
|
|
|
|
args << "-f" << ui->editFilename->text(); // R"-(c:\temp\backup.sql)-";
|
|
|
|
|
|
|
|
|
|
|
|
int format_index = ui->backupFormat->currentIndex();
|
|
|
|
|
|
auto format_model_base = ui->backupFormat->model();
|
|
|
|
|
|
BackupFormatModel *bfm = dynamic_cast<BackupFormatModel *>(format_model_base);
|
|
|
|
|
|
if (bfm) {
|
|
|
|
|
|
QVariant v = bfm->data(bfm->index(format_index, 1));
|
|
|
|
|
|
QString format("-F");
|
|
|
|
|
|
format += v.toString();
|
|
|
|
|
|
args << format;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int jobs = ui->jobs->value();
|
|
|
|
|
|
if (jobs > 0)
|
|
|
|
|
|
args << "-j" << QString::number(jobs);
|
|
|
|
|
|
|
|
|
|
|
|
int compression = ui->compression->value();
|
|
|
|
|
|
if (compression >= 0)
|
|
|
|
|
|
args << "-Z" << QString::number(compression);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::on_btnStart_clicked()
|
|
|
|
|
|
{
|
|
|
|
|
|
ui->stdOutput->clear();
|
|
|
|
|
|
|
2017-08-26 11:44:40 +02:00
|
|
|
|
//QString program = R"-(C:\Prog\bigsql\pg96\bin\pg_dump.exe)-";
|
|
|
|
|
|
QString program = "/usr/bin/pg_dump";
|
2017-03-05 21:23:36 +01:00
|
|
|
|
QStringList arguments;
|
|
|
|
|
|
setParams(arguments);
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-22 12:45:45 +02:00
|
|
|
|
// BOOL res = AllocConsole();
|
|
|
|
|
|
// if (!res) {
|
|
|
|
|
|
// DWORD error = GetLastError();
|
|
|
|
|
|
// QMessageBox::critical(this, "pglab", tr("AllocConsole failed %1").arg(error), QMessageBox::Close);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
|
|
// DWORD written;
|
|
|
|
|
|
// res = WriteConsoleOutputCharacter(out, L"Hello, world!\n", 14, {0, 0}, &written);
|
|
|
|
|
|
|
|
|
|
|
|
// PROCESS_INFORMATION proc_info;
|
|
|
|
|
|
// STARTUPINFO startup_info;
|
|
|
|
|
|
// memset(&startup_info, 0, sizeof(startup_info));
|
|
|
|
|
|
// startup_info.cb = sizeof(startup_info);
|
|
|
|
|
|
// startup_info.lpReserved;
|
|
|
|
|
|
// startup_info.lpDesktop;
|
|
|
|
|
|
// startup_info.lpTitle;
|
|
|
|
|
|
// startup_info.dwX;
|
|
|
|
|
|
// startup_info.dwY;
|
|
|
|
|
|
// startup_info.dwXSize;
|
|
|
|
|
|
// startup_info.dwYSize;
|
|
|
|
|
|
// startup_info.dwXCountChars;
|
|
|
|
|
|
// startup_info.dwYCountChars;
|
|
|
|
|
|
// startup_info.dwFillAttribute;
|
|
|
|
|
|
// startup_info.dwFlags = STARTF_USESTDHANDLES;
|
|
|
|
|
|
// startup_info.wShowWindow;
|
|
|
|
|
|
// startup_info.cbReserved2;
|
|
|
|
|
|
// startup_info.lpReserved2;
|
|
|
|
|
|
// startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
|
|
|
|
|
// startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
|
|
// startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
|
|
|
|
|
// res = CreateProcess(
|
|
|
|
|
|
// LR"_(C:\Prog\build-conoutputtest-Desktop_Qt_5_8_0_MSVC2015_32bit2-Debug\debug\conoutputtest.exe)_",
|
|
|
|
|
|
// NULL, // _Inout_opt_ LPTSTR lpCommandLine,
|
|
|
|
|
|
// NULL, // _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
|
|
|
|
// NULL, // _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
|
|
|
|
// TRUE,
|
|
|
|
|
|
// 0, // _In_ DWORD dwCreationFlags,
|
|
|
|
|
|
// NULL, // _In_opt_ LPVOID lpEnvironment,
|
|
|
|
|
|
// NULL, // _In_opt_ LPCTSTR lpCurrentDirectory,
|
|
|
|
|
|
// &startup_info, // _In_ LPSTARTUPINFO lpStartupInfo,
|
|
|
|
|
|
// &proc_info // _Out_ LPPROCESS_INFORMATION lpProcessInformation
|
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-03-05 21:23:36 +01:00
|
|
|
|
// QString program = R"_(C:\prog\build-conoutputtest-Desktop_Qt_5_8_0_MSVC2015_32bit2-Debug\debug\conoutputtest.exe)_";
|
|
|
|
|
|
// QStringList arguments;
|
|
|
|
|
|
// arguments << "/C" << "DIR /S c:\\";
|
|
|
|
|
|
|
|
|
|
|
|
// Database connection paramters are passed through the environment as this is far less visible to others. Commandline
|
|
|
|
|
|
// parameters can often be viewed even if the user is not the owner of the process.
|
|
|
|
|
|
// We use the systemEnvironment as a sane default. Then we let the connection overwrite all PG variables in it.
|
|
|
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
|
|
|
|
m_config.writeToEnvironment(env);
|
2017-08-26 11:44:40 +02:00
|
|
|
|
//env.insert("SESSIONNAME", "Console");
|
2017-03-05 21:23:36 +01:00
|
|
|
|
auto p = new QProcess(this);
|
|
|
|
|
|
ConnectTo(p);
|
|
|
|
|
|
p->setProcessEnvironment(env);
|
2017-08-26 11:44:40 +02:00
|
|
|
|
#ifdef WIN32
|
2017-08-22 12:45:45 +02:00
|
|
|
|
p->setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
args->flags |= CREATE_NEW_CONSOLE;
|
|
|
|
|
|
args->flags &= ~DETACHED_PROCESS;
|
|
|
|
|
|
args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES;
|
|
|
|
|
|
});
|
2017-08-23 13:27:23 +02:00
|
|
|
|
#endif
|
2017-03-05 21:23:36 +01:00
|
|
|
|
p->start(program, arguments);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-17 19:34:28 +01:00
|
|
|
|
void BackupDialog::on_backupFormat_currentIndexChanged(int /*index*/)
|
2017-03-05 21:23:36 +01:00
|
|
|
|
{
|
|
|
|
|
|
int format_index = ui->backupFormat->currentIndex();
|
|
|
|
|
|
auto format_model_base = ui->backupFormat->model();
|
|
|
|
|
|
BackupFormatModel *bfm = dynamic_cast<BackupFormatModel *>(format_model_base);
|
|
|
|
|
|
if (bfm) {
|
|
|
|
|
|
QVariant v = bfm->data(bfm->index(format_index, 1));
|
|
|
|
|
|
QString format = v.toString();
|
|
|
|
|
|
|
|
|
|
|
|
bool comp_enable = (format == "c" || format == "d");
|
|
|
|
|
|
ui->compression->setEnabled(comp_enable);
|
|
|
|
|
|
if (!comp_enable)
|
|
|
|
|
|
ui->compression->setValue(-1);
|
|
|
|
|
|
|
|
|
|
|
|
bool jobs_enable = (format == "d");
|
|
|
|
|
|
ui->jobs->setEnabled(jobs_enable);
|
|
|
|
|
|
if (!jobs_enable)
|
|
|
|
|
|
ui->jobs->setValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BackupDialog::on_selectDestination_clicked()
|
|
|
|
|
|
{
|
|
|
|
|
|
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
|
|
|
|
|
QString fn = QFileDialog::getSaveFileName(this, tr("Save backup"), home_dir,
|
|
|
|
|
|
tr("Backup file (*.backup)"));
|
|
|
|
|
|
if (!fn.isEmpty()) {
|
|
|
|
|
|
ui->editFilename->setText(QDir::toNativeSeparators(fn));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-08-22 12:45:45 +02:00
|
|
|
|
|