diff --git a/ecl/eclcc/eclcc.cpp b/ecl/eclcc/eclcc.cpp index 878b574c332..bfde52da235 100644 --- a/ecl/eclcc/eclcc.cpp +++ b/ecl/eclcc/eclcc.cpp @@ -1252,6 +1252,12 @@ void EclCC::processSingleQuery(const EclRepositoryManager & localRepositoryManag } IErrorReceiver & errorProcessor = *severityMapper; + //Associate the error handler - so that failures to fetch from git can be reported as errors, but also mapped + //to warnings to ensure that automated tasks do not fail because the could not connect to git. + localRepositoryManager.setErrorReceiver(&errorProcessor); + //Ensure the error processor is cleared up when we exit this function + COnScopeExit scoped([&]() { localRepositoryManager.setErrorReceiver(NULL); }); + //All dlls/exes are essentially cloneable because you may be running multiple instances at once //The only exception would be a dll created for a one-time query. (Currently handled by eclserver.) instance.wu->setCloneable(true); @@ -1507,7 +1513,10 @@ void EclCC::processSingleQuery(const EclRepositoryManager & localRepositoryManag { StringBuffer s; e->errorMessage(s); - errorProcessor.reportError(3, s.str(), defaultErrorPathname, 1, 0, 0); + unsigned errorCode = e->errorCode(); + if ((errorCode < HQL_ERROR_START) || (errorCode > HQL_ERROR_END)) + errorCode = ERR_UNKNOWN_EXCEPTION; + errorProcessor.reportError(errorCode, s.str(), defaultErrorPathname, 1, 0, 0); e->Release(); } diff --git a/ecl/hql/hqlerrors.hpp b/ecl/hql/hqlerrors.hpp index 6c9394b3e5a..3ae79a49b13 100644 --- a/ecl/hql/hqlerrors.hpp +++ b/ecl/hql/hqlerrors.hpp @@ -442,6 +442,10 @@ #define ERR_INVALID_PROBABILITY 2403 #define ERR_DEFAULT_VIRTUAL_CLASH 2404 #define ERR_EMBEDERROR 2405 +#define ERR_FAIL_CLONE_REPO 2406 +#define ERR_FAIL_UPDATE_REPO 2407 +#define ERR_CANNOT_RESOLVE_BRANCH 2408 +#define ERR_UNKNOWN_EXCEPTION 2409 #define ERR_CPP_COMPILE_ERROR 2999 diff --git a/ecl/hql/hqlrepository.cpp b/ecl/hql/hqlrepository.cpp index 75ca659e302..8d2c2d8aae1 100644 --- a/ecl/hql/hqlrepository.cpp +++ b/ecl/hql/hqlrepository.cpp @@ -821,6 +821,7 @@ IEclSourceCollection * EclRepositoryManager::resolveGitCollection(const char * r } bool ok = false; + Owned error; CCycleTimer gitDownloadTimer; if (alreadyExists) { @@ -828,7 +829,10 @@ IEclSourceCollection * EclRepositoryManager::resolveGitCollection(const char * r { unsigned retCode = runGitCommand(nullptr, "fetch origin", repoPath, true); if (retCode != 0) - DBGLOG("Failed to download the latest version of %s", defaultUrl); + { + VStringBuffer msg("Failed to download the latest version of '%s' error code (%u)", defaultUrl, retCode); + error.setown(createError(CategoryError, SeverityError, ERR_FAIL_UPDATE_REPO, msg.str(), nullptr, 0, 0, 0)); + } } ok = true; @@ -844,17 +848,30 @@ IEclSourceCollection * EclRepositoryManager::resolveGitCollection(const char * r VStringBuffer params("clone %s \"%s\" --no-checkout", repoUrn.str(), repo.str()); unsigned retCode = runGitCommand(nullptr, params, options.eclRepoPath, true); if (retCode != 0) - throw makeStringExceptionV(99, "Failed to clone dependency '%s'", defaultUrl); + { + VStringBuffer msg("Failed to clone dependency '%s' error code (%u)", defaultUrl, retCode); + error.setown(createError(CategoryError, SeverityError, ERR_FAIL_CLONE_REPO, msg.str(), nullptr, 0, 0, 0)); + } ok = true; } } gitDownloadCycles += gitDownloadTimer.elapsedCycles(); + if (error) + { + if (errorReceiver) + { + error.setown(errorReceiver->mapError(error)); // MORE: This mapping should really be done within reportError() + errorReceiver->report(error); + } + else + throw error.getClear(); + } if (!ok) throw makeStringExceptionV(99, "Cannot locate the source code for dependency '%s'. --fetchrepos not enabled", defaultUrl); if (startsWith(version, "semver:")) - throw makeStringExceptionV(99, "Semantic versioning not yet supported for dependency '%s'.", defaultUrl); + throw makeStringExceptionV(ERR_CANNOT_RESOLVE_BRANCH, "Semantic versioning not yet supported for dependency '%s'.", defaultUrl); // Really the version should be a SHA, but for flexibility version could be a sha, a tag or a branch (on origin). // Check for a remote branch first - because it appears that when git clones a repo, it creates a local branch for @@ -879,7 +896,7 @@ IEclSourceCollection * EclRepositoryManager::resolveGitCollection(const char * r DBGLOG("Version '%s' resolved to sha '%s'", version.str(), sha.str()); if (sha.isEmpty()) - throw makeStringExceptionV(99, "Branch/tag '%s' could not be found for dependency '%s'.", version.str(), defaultUrl); + throw makeStringExceptionV(ERR_CANNOT_RESOLVE_BRANCH, "Branch/tag '%s' could not be found for dependency '%s'.", version.str(), defaultUrl); path.append(repoPath).appendf("/.git/{%s", sha.str()); if (options.gitUser) diff --git a/ecl/hql/hqlrepository.hpp b/ecl/hql/hqlrepository.hpp index 34600e17dcc..a69febb6159 100644 --- a/ecl/hql/hqlrepository.hpp +++ b/ecl/hql/hqlrepository.hpp @@ -74,7 +74,10 @@ class HQL_API EclRepositoryManager } IEclSourceCollection * resolveGitCollection(const char * repoPath, const char * defaultUrl); - + void setErrorReceiver(IErrorReceiver * _errorReceiver) const + { + errorReceiver = _errorReceiver; + } protected: IEclRepository * createNewSourceFileEclRepository(IErrorReceiver *errs, const char * path, unsigned flags, unsigned trace, bool includeInArchive); IEclRepository * createGitRepository(IErrorReceiver *errs, const char * path, const char * urn, unsigned flags, unsigned trace, bool includeInArchive); @@ -85,6 +88,7 @@ class HQL_API EclRepositoryManager IEclPackage * queryRepository(IIdAtom * name, const char * defaultUrl, IEclSourceCollection * overrideSource, bool includeDefinitions); private: + mutable IErrorReceiver * errorReceiver = nullptr; // mutable to allow const methods to set it, it logically doesn't change the object using DependencyInfo = std::pair>; CIArrayOf repos; std::vector dependencies;