mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-30 18:16:31 +03:00
405 lines
10 KiB
C++
405 lines
10 KiB
C++
#ifndef ECODE_PROJECTBUILD_HPP
|
|
#define ECODE_PROJECTBUILD_HPP
|
|
|
|
#include "appconfig.hpp"
|
|
#include <eepp/system/process.hpp>
|
|
#include <eepp/system/threadpool.hpp>
|
|
#include <eepp/ui/uitabwidget.hpp>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
using namespace EE;
|
|
using namespace EE::System;
|
|
using namespace EE::UI;
|
|
|
|
namespace ecode {
|
|
|
|
class App;
|
|
class StatusBuildOutputController;
|
|
class StatusAppOutputController;
|
|
|
|
/** reference:
|
|
{
|
|
"ecode": {
|
|
"build": [
|
|
{
|
|
"args": "--with-debug-symbols gmake",
|
|
"command": "premake4",
|
|
"working_dir": "${project_root}"
|
|
},
|
|
{
|
|
"args": "-j${nproc} config=${build_type} ecode",
|
|
"command": "make",
|
|
"working_dir": "${build_dir}"
|
|
}
|
|
],
|
|
"build_types": [
|
|
"debug",
|
|
"release"
|
|
],
|
|
"clean": [
|
|
{
|
|
"args": "config=${build_type} clean",
|
|
"command": "make",
|
|
"working_dir": "${build_dir}"
|
|
}
|
|
],
|
|
"config": {
|
|
"clear_sys_env": false
|
|
},
|
|
"env": {
|
|
"SHELL": "fish"
|
|
},
|
|
"os": [
|
|
"linux"
|
|
],
|
|
"output_parser": {
|
|
"config": {
|
|
"relative_file_paths": true
|
|
},
|
|
"error": [
|
|
{
|
|
"pattern": "([^:]*):(%d+):(%d+):%s?[%w%s]*error:%s?([^\n]*)",
|
|
"pattern_order": {
|
|
"col": 3,
|
|
"file": 1,
|
|
"line": 2,
|
|
"message": 4
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"run": [
|
|
{
|
|
"args": "-x",
|
|
"command": "${project_root}/bin/ecode-debug",
|
|
"name": "ecode-debug",
|
|
"working_dir": "${project_root}/bin/"
|
|
},
|
|
{
|
|
"args": "-x",
|
|
"command": "${project_root}/bin/ecode",
|
|
"name": "ecode-release",
|
|
"working_dir": "${project_root}/bin/"
|
|
}
|
|
],
|
|
"var": {
|
|
"build_dir": "${project_root}/make/${os}"
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
struct ProjectBuildStep {
|
|
std::string cmd;
|
|
std::string args;
|
|
std::string workingDir;
|
|
std::string name;
|
|
bool enabled{ true };
|
|
bool runInTerminal{ false };
|
|
};
|
|
|
|
using ProjectBuildSteps = std::vector<std::unique_ptr<ProjectBuildStep>>;
|
|
using ProjectBuildKeyVal = std::vector<std::pair<std::string, std::string>>;
|
|
|
|
struct ProjectBuildConfig {
|
|
bool clearSysEnv{ false };
|
|
};
|
|
|
|
enum class ProjectOutputParserTypes { Error = 0, Warning = 1, Notice = 2 };
|
|
|
|
struct PatternOrder {
|
|
int file{ 1 };
|
|
int line{ 2 };
|
|
int col{ 3 };
|
|
int message{ 4 };
|
|
};
|
|
|
|
struct ProjectBuildOutputParserConfig {
|
|
static std::string typeToString( ProjectOutputParserTypes type ) {
|
|
switch ( type ) {
|
|
case ProjectOutputParserTypes::Notice:
|
|
return "notice";
|
|
case ProjectOutputParserTypes::Warning:
|
|
return "warning";
|
|
case ProjectOutputParserTypes::Error:
|
|
default:
|
|
return "error";
|
|
}
|
|
}
|
|
|
|
ProjectOutputParserTypes type;
|
|
std::string pattern;
|
|
PatternOrder patternOrder;
|
|
};
|
|
|
|
class ProjectBuildOutputParser {
|
|
public:
|
|
static std::map<std::string, ProjectBuildOutputParser> getPresets();
|
|
|
|
static bool existsPreset( const std::string& name );
|
|
|
|
static ProjectBuildOutputParser getGeneric();
|
|
|
|
const std::vector<ProjectBuildOutputParserConfig>& getPresetConfig() const {
|
|
return mPresetConfig;
|
|
}
|
|
|
|
const std::vector<ProjectBuildOutputParserConfig>& getConfig() const { return mConfig; }
|
|
|
|
bool useRelativeFilePaths() const { return mRelativeFilePaths; }
|
|
|
|
const std::string& getPreset() const { return mPreset; }
|
|
|
|
protected:
|
|
friend class ProjectBuildManager;
|
|
friend class ProjectBuild;
|
|
friend class UIBuildSettings;
|
|
|
|
bool mRelativeFilePaths{ true };
|
|
std::string mPreset;
|
|
std::vector<ProjectBuildOutputParserConfig> mPresetConfig;
|
|
std::vector<ProjectBuildOutputParserConfig> mConfig;
|
|
};
|
|
|
|
class ProjectBuild {
|
|
public:
|
|
using Map = std::unordered_map<std::string, ProjectBuild>;
|
|
|
|
ProjectBuildSteps deepCopySteps( const ProjectBuildSteps& steps ) const;
|
|
|
|
ProjectBuild( const ProjectBuild& other );
|
|
|
|
ProjectBuild& operator=( const ProjectBuild& other );
|
|
|
|
ProjectBuild( ProjectBuild&& ) = default;
|
|
ProjectBuild& operator=( ProjectBuild&& ) = default;
|
|
|
|
ProjectBuild( const std::string& name, const std::string& projectRoot );
|
|
|
|
const ProjectBuildConfig& getConfig() const { return mConfig; }
|
|
|
|
bool isOSSupported( const std::string& os ) const;
|
|
|
|
const std::string& getName() const { return mName; }
|
|
|
|
const std::set<std::string>& buildTypes() const { return mBuildTypes; }
|
|
|
|
const std::set<std::string>& os() const { return mOS; }
|
|
|
|
const ProjectBuildOutputParser& getOutputParser() const { return mOutputParser; }
|
|
|
|
const ProjectBuildSteps& buildSteps() const { return mBuild; }
|
|
|
|
const ProjectBuildSteps& cleanSteps() const { return mClean; }
|
|
|
|
const ProjectBuildSteps& runConfigs() const { return mRun; }
|
|
|
|
const ProjectBuildKeyVal& envs() const { return mEnvs; }
|
|
|
|
const ProjectBuildKeyVal& vars() const { return mVars; }
|
|
|
|
bool hasBuild() const { return !mBuild.empty(); }
|
|
|
|
bool hasClean() const { return !mClean.empty(); }
|
|
|
|
bool hasRun() const {
|
|
return !mRun.empty() && ( !mRun.front()->cmd.empty() || !mRun.front()->args.empty() ||
|
|
!mRun.front()->workingDir.empty() );
|
|
}
|
|
|
|
ProjectBuildStep replaceVars( const ProjectBuildStep& step ) const;
|
|
|
|
ProjectBuildSteps replaceVars( const ProjectBuildSteps& steps ) const;
|
|
|
|
static json serialize( const ProjectBuild::Map& builds );
|
|
|
|
static ProjectBuild::Map deserialize( const json& j, const std::string& projectRoot );
|
|
|
|
protected:
|
|
friend class ProjectBuildManager;
|
|
friend class UIBuildSettings;
|
|
|
|
std::string mName;
|
|
std::string mProjectRoot;
|
|
std::set<std::string> mOS;
|
|
std::set<std::string> mBuildTypes;
|
|
ProjectBuildSteps mBuild;
|
|
ProjectBuildSteps mClean;
|
|
ProjectBuildSteps mRun;
|
|
ProjectBuildKeyVal mEnvs;
|
|
ProjectBuildKeyVal mVars;
|
|
ProjectBuildConfig mConfig;
|
|
ProjectBuildOutputParser mOutputParser;
|
|
};
|
|
|
|
struct ProjectBuildCommand : public ProjectBuildStep {
|
|
ProjectBuildConfig config;
|
|
|
|
ProjectBuildCommand( const ProjectBuildStep& step ) : ProjectBuildStep( step ) {}
|
|
};
|
|
|
|
using ProjectBuildCommands = std::vector<ProjectBuildCommand>;
|
|
|
|
struct ProjectBuildCommandsRes {
|
|
String errorMsg;
|
|
ProjectBuildCommands cmds;
|
|
ProjectBuildKeyVal envs;
|
|
|
|
ProjectBuildCommandsRes() {}
|
|
|
|
ProjectBuildCommandsRes( const String& errMsg ) : errorMsg( errMsg ) {}
|
|
|
|
ProjectBuildCommandsRes( ProjectBuildCommands&& cmds ) : cmds( cmds ) {}
|
|
|
|
bool isValid() { return errorMsg.empty(); }
|
|
};
|
|
|
|
using ProjectBuildProgressFn =
|
|
std::function<void( int curProgress, std::string buffer, const ProjectBuildCommand* cmd )>;
|
|
using ProjectBuildDoneFn = std::function<void( int exitCode, const ProjectBuildCommand* cmd )>;
|
|
using ProjectBuildi18nFn =
|
|
std::function<String( const std::string& /*key*/, const String& /*defaultvalue*/ )>;
|
|
|
|
class ProjectBuildManager {
|
|
public:
|
|
ProjectBuildManager( const std::string& projectRoot, std::shared_ptr<ThreadPool> pool,
|
|
UITabWidget* sidePanel, App* app );
|
|
|
|
~ProjectBuildManager();
|
|
|
|
ProjectBuildCommandsRes build( const std::string& buildName, const ProjectBuildi18nFn& i18n,
|
|
const std::string& buildType = "",
|
|
const ProjectBuildProgressFn& progressFn = {},
|
|
const ProjectBuildDoneFn& doneFn = {}, bool isClean = false );
|
|
|
|
ProjectBuildCommandsRes run( const ProjectBuildCommand& runData, const ProjectBuildi18nFn& i18n,
|
|
const ProjectBuildProgressFn& progressFn = {},
|
|
const ProjectBuildDoneFn& doneFn = {} );
|
|
|
|
ProjectBuildCommandsRes generateBuildCommands( const std::string& buildName,
|
|
const ProjectBuildi18nFn& i18n,
|
|
const std::string& buildType = "",
|
|
bool isClean = false );
|
|
|
|
void replaceDynamicVars( ProjectBuildCommand& cmd );
|
|
|
|
ProjectBuildOutputParser getOutputParser( const std::string& buildName );
|
|
|
|
const ProjectBuild::Map& getBuilds() const { return mBuilds; }
|
|
|
|
const std::string& getProjectRoot() const { return mProjectRoot; }
|
|
|
|
const std::string& getProjectFile() const { return mProjectFile; }
|
|
|
|
std::string getCurrentDocument();
|
|
|
|
ProjectBuild* getBuild( const std::string& buildName );
|
|
|
|
bool hasBuild( const std::string& name ) { return mBuilds.find( name ) != mBuilds.end(); }
|
|
|
|
bool hasBuildCommands( const std::string& name );
|
|
|
|
bool hasCleanCommands( const std::string& name );
|
|
|
|
bool loaded() const { return mLoadedWithBuilds; }
|
|
|
|
bool loading() const { return mLoading; }
|
|
|
|
bool isBuilding() const { return mBuilding; }
|
|
|
|
bool isRunningApp() const { return mRunning; }
|
|
|
|
void cancelBuild();
|
|
|
|
void cancelRun();
|
|
|
|
ProjectBuildConfiguration getConfig() const;
|
|
|
|
void setConfig( const ProjectBuildConfiguration& config );
|
|
|
|
void buildCurrentConfig( StatusBuildOutputController* sboc,
|
|
std::function<void( int exitStatus )> doneFn = {} );
|
|
|
|
void cleanCurrentConfig( StatusBuildOutputController* sboc );
|
|
|
|
void runCurrentConfig( StatusAppOutputController* saoc, bool build,
|
|
StatusBuildOutputController* sboc = nullptr );
|
|
|
|
void editCurrentBuild();
|
|
|
|
bool hasRunConfig();
|
|
|
|
bool hasBuildConfig() const;
|
|
|
|
void selectTab();
|
|
|
|
bool hasBuildConfigWithBuildSteps();
|
|
|
|
std::optional<ProjectBuildStep> getCurrentRunConfig();
|
|
|
|
ProjectBuild* getCurrentBuild();
|
|
|
|
protected:
|
|
std::string mProjectRoot;
|
|
std::string mProjectFile;
|
|
ProjectBuild::Map mBuilds;
|
|
ProjectBuildConfiguration mConfig;
|
|
std::shared_ptr<ThreadPool> mThreadPool;
|
|
UITabWidget* mSidePanel{ nullptr };
|
|
UISceneNode* mUISceneNode{ nullptr };
|
|
UITab* mTab{ nullptr };
|
|
App* mApp{ nullptr };
|
|
std::unique_ptr<Process> mProcess;
|
|
std::unique_ptr<Process> mProcessRun;
|
|
ProjectBuild mNewBuild;
|
|
bool mLoadedWithBuilds{ false };
|
|
bool mLoading{ false };
|
|
bool mBuilding{ false };
|
|
bool mShuttingDown{ false };
|
|
bool mCancelBuild{ false };
|
|
bool mCancelRun{ false };
|
|
bool mRunning{ false };
|
|
std::unordered_map<Node*, std::set<Uint32>> mCbs;
|
|
|
|
void runBuild( const std::string& buildName, const std::string& buildType,
|
|
const ProjectBuildi18nFn& i18n, const ProjectBuildCommandsRes& res,
|
|
const ProjectBuildProgressFn& progressFn = {},
|
|
const ProjectBuildDoneFn& doneFn = {} );
|
|
|
|
void runApp( const ProjectBuildCommand& runStep, const ProjectBuildi18nFn& i18n,
|
|
const ProjectBuildCommandsRes& res, const ProjectBuildProgressFn& progressFn = {},
|
|
const ProjectBuildDoneFn& doneFn = {} );
|
|
|
|
bool load();
|
|
|
|
bool save();
|
|
|
|
bool saveAsync();
|
|
|
|
void buildSidePanelTab();
|
|
|
|
void updateSidePanelTab();
|
|
|
|
void updateBuildType();
|
|
|
|
void updateRunConfig();
|
|
|
|
void addNewBuild();
|
|
|
|
bool cloneBuild( const std::string& build, std::string newBuildName );
|
|
|
|
void addBuild( UIWidget* buildTab );
|
|
|
|
void editBuild( std::string buildName, UIWidget* buildTab );
|
|
|
|
void runConfig( StatusAppOutputController* saoc );
|
|
};
|
|
|
|
} // namespace ecode
|
|
|
|
#endif
|