Made GitClient a Qt-object. Impreoved several utility functions handling git commands.
Added slot onIsmasUpdatesAvailable(). Added helpers getLastCommit(), gitBlob(), gitCommitForBlob(), gitIsFileTracked().
This commit is contained in:
parent
d91d4261d9
commit
3c54d8de6d
@ -1,36 +1,97 @@
|
|||||||
#include "git_client.h"
|
#include "git_client.h"
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
|
#include "worker.h"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
GitClient::GitClient(QString const &workingDirectory, QString const &branchName)
|
|
||||||
: m_workingDirectory(workingDirectory)
|
GitClient::GitClient(QString const &repositoryPath,
|
||||||
, m_branchName(branchName) {
|
QString const &customerId,
|
||||||
|
QString const &workingDirectory,
|
||||||
|
QString const &branchName,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_worker(qobject_cast<Worker *>(parent))
|
||||||
|
, m_repositoryPath(repositoryPath)
|
||||||
|
, m_customerId(customerId)
|
||||||
|
, m_workingDirectory(workingDirectory)
|
||||||
|
, m_branchName(branchName)
|
||||||
|
, m_customerRepository(QDir::cleanPath(m_workingDirectory
|
||||||
|
+ QDir::separator()
|
||||||
|
+ m_customerId)) {
|
||||||
|
if (!m_worker) {
|
||||||
|
qCritical() << "ERROR CASTING PARENT TO WORKER FAILED";
|
||||||
}
|
}
|
||||||
|
|
||||||
void GitClient::setWorkingDirectory(QString const &workingDirectory) {
|
connect(this, SIGNAL(ismasUpdatesAvailable()),
|
||||||
m_workingDirectory = workingDirectory;
|
this, SLOT(onIsmasUpdatesAvailable()), Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GitClient::workingDirectory() const {
|
void GitClient::onIsmasUpdatesAvailable() {
|
||||||
return m_workingDirectory;
|
if (QDir(m_customerRepository).exists()) {
|
||||||
|
qInfo() << "FETCHING OF" << m_repositoryPath
|
||||||
|
<< "INTO" << m_customerRepository;
|
||||||
|
std::optional<QString> changes = gitFetch();
|
||||||
|
if (changes) {
|
||||||
|
std::optional<QStringList> changedFileNames = gitDiff(changes.value());
|
||||||
|
if (changedFileNames) {
|
||||||
|
for (int i=0;i<changedFileNames.value().size();++i) {
|
||||||
|
QString fname = changedFileNames.value().at(i);
|
||||||
|
QString lastCommit = gitLastCommit(fname);
|
||||||
|
qDebug() << "CCCC" << changedFileNames.value().at(i) << lastCommit;
|
||||||
|
}
|
||||||
|
if (gitPull()) {
|
||||||
|
emit m_worker->handleChangedFiles(changedFileNames.value());
|
||||||
|
} else {
|
||||||
|
qCritical() << "PULL FAILED FOR" << m_repositoryPath
|
||||||
|
<< "IN " << m_customerRepository;
|
||||||
|
emit m_worker->terminateUpdateProcess();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCritical() << "NO CHANGES IN" << m_repositoryPath
|
||||||
|
<< "(" << m_customerRepository << ")";
|
||||||
|
emit m_worker->finishUpdateProcess(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCritical() << "NO CHANGES IN" << m_repositoryPath
|
||||||
|
<< "(" << m_customerRepository << ")";
|
||||||
|
emit m_worker->finishUpdateProcess(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (gitCloneAndCheckoutBranch()) {
|
||||||
|
qInfo() << "CLONED" << m_repositoryPath
|
||||||
|
<< "AND CHECKED OUT INTO" << m_customerRepository;
|
||||||
|
if (m_worker) {
|
||||||
|
qDebug() << "WORKER EXECUTE OPKG COMMANDS";
|
||||||
|
QStringList opkgCommands;
|
||||||
|
// To make sure that opkg upgrade does not break your system
|
||||||
|
// because of an unstable connection
|
||||||
|
// Add a line "option cache cachedir" to /etc/opkg/opkg.conf to
|
||||||
|
// avoid the --cache option on command line.
|
||||||
|
opkgCommands << "opkg update";
|
||||||
|
//opkgCommands << "opkg --cache cachedir --download-only upgrade";
|
||||||
|
//opkgCommands << "opkg --cache cachedir upgrade";
|
||||||
|
emit m_worker->executeOpkgCommands(opkgCommands);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCritical() << "ERROR CLONING " << m_repositoryPath
|
||||||
|
<< "AND/OR CHECKING OUT INTO" << m_customerRepository;
|
||||||
|
emit m_worker->terminateUpdateProcess();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GitClient::setBranchName(QString const &branchName) {
|
bool GitClient::gitCloneCustomerRepository() {
|
||||||
m_branchName = branchName;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString GitClient::branchName() const {
|
|
||||||
return m_branchName;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<QString> GitClient::gitCloneRepository(QString const &repPath) {
|
|
||||||
QString gitCommand("git clone ");
|
QString gitCommand("git clone ");
|
||||||
gitCommand += repPath;
|
gitCommand += m_repositoryPath;
|
||||||
Command c(gitCommand);
|
Command c(gitCommand);
|
||||||
if (c.execute(m_workingDirectory)) {
|
|
||||||
|
qInfo() << "IN CURRENT WD" << m_workingDirectory
|
||||||
|
<< "CLONE" << m_repositoryPath << "...";
|
||||||
|
|
||||||
|
if (c.execute(m_workingDirectory)) { // execute the command in wd
|
||||||
QString result = c.getCommandResult();
|
QString result = c.getCommandResult();
|
||||||
if (!result.isEmpty()) {
|
if (!result.isEmpty()) {
|
||||||
// Cloning into 'customer_281'...\n
|
// Cloning into 'customer_281'...\n
|
||||||
@ -38,42 +99,65 @@ std::optional<QString> GitClient::gitCloneRepository(QString const &repPath) {
|
|||||||
QRegularExpressionMatch match = re.match(result);
|
QRegularExpressionMatch match = re.match(result);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||||
return match.captured(2);
|
if (match.captured(2).trimmed() == m_customerId) {
|
||||||
|
qInfo() << "CLONING" << m_repositoryPath << "OK";
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
qCritical() << "ERROR CLONE RESULT HAS WRONG FORMAT";
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitClient::gitCheckout(QString const &branchName) {
|
bool GitClient::copyGitConfigFromMaster() { // only allowed when called in
|
||||||
|
// master branch
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
|
QString const cp = QString("cp .gitconfig .git/config");
|
||||||
|
Command c("bash");
|
||||||
|
if (c.execute(m_customerRepository, QStringList() << "-c" << cp)) {
|
||||||
|
qInfo() << "cp .gitconfig .git/config OK";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
qCritical() << "ERROR cp .gitconfig .git/config";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GitClient::gitCheckoutBranch() {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
QString gitCommand("git checkout ");
|
QString gitCommand("git checkout ");
|
||||||
gitCommand += branchName;
|
gitCommand += m_branchName;
|
||||||
Command c(gitCommand);
|
Command c(gitCommand);
|
||||||
return c.execute(m_workingDirectory);
|
return c.execute(m_customerRepository); // execute command in customerRepo
|
||||||
|
}
|
||||||
|
qCritical() << "ERROR" << m_customerRepository << "DOES NOT EXIST";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QString> GitClient::gitCloneBranch(QString const &repPath,
|
bool GitClient::gitCloneAndCheckoutBranch() {
|
||||||
QString const &branchName) {
|
qInfo() << "CLONE" << m_repositoryPath << "AND CHECKOUT" << m_branchName;
|
||||||
if (std::optional<QString> rep = gitCloneRepository(repPath)) {
|
if (gitCloneCustomerRepository()) {
|
||||||
QDir wd(m_workingDirectory);
|
if (copyGitConfigFromMaster()) {
|
||||||
if (wd.cd(rep.value())) {
|
return gitCheckoutBranch();
|
||||||
m_workingDirectory = wd.absolutePath();
|
|
||||||
if (gitCheckout(branchName)) {
|
|
||||||
return branchName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Zu beachten: wird eine datei neu hinzugefuegt (git add/commit) dann aber gleich
|
||||||
|
wieder geloscht, so wird sie im diff nicht angezeigt.
|
||||||
|
*/
|
||||||
std::optional<QStringList> GitClient::gitDiff(QString const &commits) {
|
std::optional<QStringList> GitClient::gitDiff(QString const &commits) {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
// 409f198..6c22726
|
// 409f198..6c22726
|
||||||
QString gitCommand("git diff --compact-summary ");
|
QString gitCommand("git diff --compact-summary ");
|
||||||
gitCommand += commits;
|
gitCommand += commits;
|
||||||
|
|
||||||
Command c(gitCommand);
|
Command c(gitCommand);
|
||||||
if (c.execute(m_workingDirectory)) {
|
if (c.execute(m_customerRepository)) { // execute command in local customerRepo
|
||||||
QString s = c.getCommandResult().trimmed();
|
QString s = c.getCommandResult().trimmed();
|
||||||
QStringList lines = Update::split(s, '\n');
|
QStringList lines = Update::split(s, '\n');
|
||||||
QStringList fileNames;
|
QStringList fileNames;
|
||||||
@ -81,7 +165,9 @@ std::optional<QStringList> GitClient::gitDiff(QString const &commits) {
|
|||||||
// or the format "etc/psa_config/DC2C_print01.json (new) | 1 +
|
// or the format "etc/psa_config/DC2C_print01.json (new) | 1 +
|
||||||
// the filenames are relativ to the repository
|
// the filenames are relativ to the repository
|
||||||
for (int i = 0; i < lines.size(); ++i) {
|
for (int i = 0; i < lines.size(); ++i) {
|
||||||
int newIndex = lines.at(i).indexOf("(new)");
|
// TODO: koennte auch (delete) kommen ?
|
||||||
|
int newIndex = lines.at(i).indexOf("(new)"); // for new files
|
||||||
|
// int goneIndex = lines.at(i).indexOf("(gone)"); // for removed files
|
||||||
if (newIndex != -1) {
|
if (newIndex != -1) {
|
||||||
QString fileName = lines.at(i).mid(0, newIndex).trimmed();
|
QString fileName = lines.at(i).mid(0, newIndex).trimmed();
|
||||||
fileNames << fileName;
|
fileNames << fileName;
|
||||||
@ -97,13 +183,21 @@ std::optional<QStringList> GitClient::gitDiff(QString const &commits) {
|
|||||||
return fileNames;
|
return fileNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Hat sich nichts geaendert, so werden auch keine Commits <>..<> angezeigt
|
||||||
|
*/
|
||||||
std::optional<QString> GitClient::gitFetch() {
|
std::optional<QString> GitClient::gitFetch() {
|
||||||
|
QString const &customerRepository
|
||||||
|
= QDir::cleanPath(m_workingDirectory + QDir::separator() + m_customerId);
|
||||||
|
if (QDir(customerRepository).exists()) {
|
||||||
Command c("git fetch");
|
Command c("git fetch");
|
||||||
if (c.execute(m_workingDirectory)) {
|
if (c.execute(customerRepository)) {
|
||||||
QString s = c.getCommandResult().trimmed();
|
QString const s = c.getCommandResult().trimmed();
|
||||||
|
if (!s.isEmpty()) {
|
||||||
QStringList lines = Update::split(s, '\n');
|
QStringList lines = Update::split(s, '\n');
|
||||||
if (!lines.empty()) {
|
if (!lines.empty()) {
|
||||||
// 409f198..6c22726 zg1/zone1 -> origin/zg1/zone1
|
// 409f198..6c22726 zg1/zone1 -> origin/zg1/zone1
|
||||||
@ -112,9 +206,21 @@ std::optional<QString> GitClient::gitFetch() {
|
|||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||||
return match.captured(2);
|
return match.captured(2);
|
||||||
|
} else {
|
||||||
|
qCritical() << "ERROR WRONG CAPTURE COUNT FOR 'GIT FETCH'" << re.captureCount();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCritical() << "ERROR NO MATCH OF COMMITS FOR 'GIT FETCH'";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCritical() << "ERROR WRONG FORMAT FOR RESULT FOR 'GIT FETCH'" << s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCritical() << "ERROR EMPTY RESULT FROM 'GIT FETCH'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
qCritical() << "ERROR" << customerRepository << "DOES NOT EXIST";
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -129,8 +235,15 @@ bool GitClient::gitFetchAndDiff() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GitClient::gitPull() {
|
bool GitClient::gitPull() {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
Command c("git pull");
|
Command c("git pull");
|
||||||
return c.execute(m_workingDirectory);
|
if (c.execute(m_customerRepository)) {
|
||||||
|
qInfo() << "PULLED INTO" << m_customerRepository;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
qCritical() << "PULL INTO" << m_customerRepository << "FAILED";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QStringList> GitClient::gitMerge() {
|
std::optional<QStringList> GitClient::gitMerge() {
|
||||||
@ -142,3 +255,65 @@ std::optional<QStringList> GitClient::gitMerge() {
|
|||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString GitClient::gitLastCommit(QString fileName) {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
|
QString const filePath
|
||||||
|
= QDir::cleanPath(m_customerRepository + QDir::separator() + fileName);
|
||||||
|
QString const gitCommand = QString("git log %1 | head -n 1").arg(fileName);
|
||||||
|
Command c("bash");
|
||||||
|
if (c.execute(m_customerRepository, QStringList() << "-c" << gitCommand)) {
|
||||||
|
QString const r = c.getCommandResult();
|
||||||
|
int const idx = r.indexOf("commit ");
|
||||||
|
if (idx != -1) {
|
||||||
|
return r.mid(idx + 8).trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the blob of the file(name) passed as $1
|
||||||
|
// note: this can be used for any file in the filesystem
|
||||||
|
QString GitClient::gitBlob(QString fileName) {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
|
QString const filePath
|
||||||
|
= QDir::cleanPath(m_customerRepository + QDir::separator() + fileName);
|
||||||
|
QString const gitCommand = QString("git hash-object %1").arg(fileName);
|
||||||
|
Command c(gitCommand);
|
||||||
|
if (c.execute(m_customerRepository)) {
|
||||||
|
return c.getCommandResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GitClient::gitCommitForBlob(QString blob) {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
|
QString const gitCommand
|
||||||
|
= QString("git whatchanged --all --find-object=%1 | head -n 1").arg(blob);
|
||||||
|
Command c(gitCommand);
|
||||||
|
if (c.execute(m_customerRepository)) {
|
||||||
|
return c.getCommandResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GitClient::gitIsFileTracked(QString fName) {
|
||||||
|
if (QDir(m_customerRepository).exists()) {
|
||||||
|
QString const gitCommand
|
||||||
|
= QString("git ls-files --error-unmatch %1").arg(fName);
|
||||||
|
Command c(gitCommand);
|
||||||
|
return c.execute(m_customerRepository);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//get_commit_for_blob () {
|
||||||
|
// # search for the blob in all commits for the file(name) $1
|
||||||
|
// echo $(git log --all --pretty=format:%H -- $2 |
|
||||||
|
// xargs -I{} bash -c "git ls-tree {} -- $2 |
|
||||||
|
// grep -q $1 && echo -n {} && head -n 1")
|
||||||
|
//}
|
||||||
|
Loading…
Reference in New Issue
Block a user