Initial project creation logic
* Add GetProjects, GetProjectTemplates, GetGems * Redirect python output to AZ_TracePrintf * Allow creating projects in empty folders * Enable project creation
This commit is contained in:
@@ -11,16 +11,23 @@
|
||||
*/
|
||||
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QRadioButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QPushButton>
|
||||
#include <QSpacerItem>
|
||||
#include <QStandardPaths>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
constexpr const char* k_pathProperty = "Path";
|
||||
|
||||
NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
@@ -29,19 +36,27 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout(this);
|
||||
|
||||
QLabel* projectNameLabel = new QLabel(this);
|
||||
projectNameLabel->setText("Project Name");
|
||||
QLabel* projectNameLabel = new QLabel(tr("Project Name"), this);
|
||||
vLayout->addWidget(projectNameLabel);
|
||||
|
||||
QLineEdit* projectNameLineEdit = new QLineEdit(this);
|
||||
vLayout->addWidget(projectNameLineEdit);
|
||||
m_projectNameLineEdit = new QLineEdit(tr("New Project"), this);
|
||||
vLayout->addWidget(m_projectNameLineEdit);
|
||||
|
||||
QLabel* projectPathLabel = new QLabel(this);
|
||||
projectPathLabel->setText("Project Location");
|
||||
QLabel* projectPathLabel = new QLabel(tr("Project Location"), this);
|
||||
vLayout->addWidget(projectPathLabel);
|
||||
|
||||
QLineEdit* projectPathLineEdit = new QLineEdit(this);
|
||||
vLayout->addWidget(projectPathLineEdit);
|
||||
{
|
||||
QHBoxLayout* projectPathLayout = new QHBoxLayout(this);
|
||||
|
||||
m_projectPathLineEdit = new QLineEdit(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), this);
|
||||
projectPathLayout->addWidget(m_projectPathLineEdit);
|
||||
|
||||
QPushButton* browseButton = new QPushButton(tr("Browse"), this);
|
||||
connect(browseButton, &QPushButton::pressed, this, &NewProjectSettingsScreen::HandleBrowseButton);
|
||||
projectPathLayout->addWidget(browseButton);
|
||||
|
||||
vLayout->addLayout(projectPathLayout);
|
||||
}
|
||||
|
||||
QLabel* projectTemplateLabel = new QLabel(this);
|
||||
projectTemplateLabel->setText("Project Template");
|
||||
@@ -50,14 +65,21 @@ namespace O3DE::ProjectManager
|
||||
QHBoxLayout* templateLayout = new QHBoxLayout(this);
|
||||
vLayout->addItem(templateLayout);
|
||||
|
||||
QRadioButton* projectTemplateStandardRadioButton = new QRadioButton(this);
|
||||
projectTemplateStandardRadioButton->setText("Standard (Recommened)");
|
||||
projectTemplateStandardRadioButton->setChecked(true);
|
||||
templateLayout->addWidget(projectTemplateStandardRadioButton);
|
||||
m_projectTemplateButtonGroup = new QButtonGroup(this);
|
||||
auto templatesResult = PythonBindingsInterface::Get()->GetProjectTemplates();
|
||||
if (templatesResult.IsSuccess() && !templatesResult.GetValue().isEmpty())
|
||||
{
|
||||
for (auto projectTemplate : templatesResult.GetValue())
|
||||
{
|
||||
QRadioButton* radioButton = new QRadioButton(projectTemplate.m_name, this);
|
||||
radioButton->setProperty(k_pathProperty, projectTemplate.m_path);
|
||||
m_projectTemplateButtonGroup->addButton(radioButton);
|
||||
|
||||
QRadioButton* projectTemplateEmptyRadioButton = new QRadioButton(this);
|
||||
projectTemplateEmptyRadioButton->setText("Empty");
|
||||
templateLayout->addWidget(projectTemplateEmptyRadioButton);
|
||||
templateLayout->addWidget(radioButton);
|
||||
}
|
||||
|
||||
m_projectTemplateButtonGroup->buttons().first()->setChecked(true);
|
||||
}
|
||||
|
||||
QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
vLayout->addItem(verticalSpacer);
|
||||
@@ -76,7 +98,57 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QString NewProjectSettingsScreen::GetNextButtonText()
|
||||
{
|
||||
return "Create Project";
|
||||
return tr("Next");
|
||||
}
|
||||
|
||||
void NewProjectSettingsScreen::HandleBrowseButton()
|
||||
{
|
||||
QString defaultPath = m_projectPathLineEdit->text();
|
||||
if (defaultPath.isEmpty())
|
||||
{
|
||||
defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("New project path"), defaultPath));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
m_projectPathLineEdit->setText(directory);
|
||||
}
|
||||
}
|
||||
|
||||
ProjectInfo NewProjectSettingsScreen::GetProjectInfo()
|
||||
{
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_projectName = m_projectNameLineEdit->text();
|
||||
projectInfo.m_path = QDir::toNativeSeparators(m_projectPathLineEdit->text() + "/" + projectInfo.m_projectName);
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
QString NewProjectSettingsScreen::GetProjectTemplatePath()
|
||||
{
|
||||
return m_projectTemplateButtonGroup->checkedButton()->property(k_pathProperty).toString();
|
||||
}
|
||||
|
||||
bool NewProjectSettingsScreen::Validate()
|
||||
{
|
||||
bool projectNameIsValid = true;
|
||||
if (m_projectNameLineEdit->text().isEmpty())
|
||||
{
|
||||
projectNameIsValid = false;
|
||||
}
|
||||
|
||||
bool projectPathIsValid = true;
|
||||
if (m_projectPathLineEdit->text().isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
}
|
||||
|
||||
QDir path(QDir::toNativeSeparators(m_projectPathLineEdit->text() + "/" + m_projectNameLineEdit->text()));
|
||||
if (path.exists() && !path.isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
}
|
||||
|
||||
return projectNameIsValid && projectPathIsValid;
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -13,8 +13,12 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QButtonGroup)
|
||||
QT_FORWARD_DECLARE_CLASS(QLineEdit)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class NewProjectSettingsScreen
|
||||
@@ -25,6 +29,19 @@ namespace O3DE::ProjectManager
|
||||
~NewProjectSettingsScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
QString GetNextButtonText() override;
|
||||
|
||||
ProjectInfo GetProjectInfo();
|
||||
QString GetProjectTemplatePath();
|
||||
|
||||
bool Validate();
|
||||
|
||||
protected slots:
|
||||
void HandleBrowseButton();
|
||||
|
||||
private:
|
||||
QLineEdit* m_projectNameLineEdit;
|
||||
QLineEdit* m_projectPathLineEdit;
|
||||
QButtonGroup* m_projectTemplateButtonGroup;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -14,12 +14,11 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId,
|
||||
ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew)
|
||||
: m_path(path)
|
||||
, m_projectName(projectName)
|
||||
, m_productName(productName)
|
||||
, m_projectId(projectId)
|
||||
, m_displayName(displayName)
|
||||
, m_imagePath(imagePath)
|
||||
, m_backgroundImagePath(backgroundImagePath)
|
||||
, m_isNew(isNew)
|
||||
@@ -28,6 +27,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
bool ProjectInfo::IsValid() const
|
||||
{
|
||||
return !m_path.isEmpty() && !m_projectId.IsNull();
|
||||
return !m_path.isEmpty() && !m_projectName.isEmpty();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
public:
|
||||
ProjectInfo() = default;
|
||||
ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId,
|
||||
ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew);
|
||||
|
||||
bool IsValid() const;
|
||||
@@ -33,8 +33,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// From project.json
|
||||
QString m_projectName;
|
||||
QString m_productName;
|
||||
AZ::Uuid m_projectId;
|
||||
QString m_displayName;
|
||||
|
||||
// Used on projects home screen
|
||||
QString m_imagePath;
|
||||
|
||||
@@ -12,10 +12,13 @@
|
||||
|
||||
#include <ProjectSettingsCtrl.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -65,7 +68,8 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
void ProjectSettingsCtrl::HandleNextButton()
|
||||
{
|
||||
ProjectManagerScreen screenEnum = m_screensCtrl->GetCurrentScreen()->GetScreenEnum();
|
||||
ScreenWidget* currentScreen = m_screensCtrl->GetCurrentScreen();
|
||||
ProjectManagerScreen screenEnum = currentScreen->GetScreenEnum();
|
||||
auto screenOrderIter = m_screensOrder.begin();
|
||||
for (; screenOrderIter != m_screensOrder.end(); ++screenOrderIter)
|
||||
{
|
||||
@@ -76,6 +80,22 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
if (screenEnum == ProjectManagerScreen::NewProjectSettings)
|
||||
{
|
||||
auto newProjectScreen = reinterpret_cast<NewProjectSettingsScreen*>(currentScreen);
|
||||
if (newProjectScreen)
|
||||
{
|
||||
if (!newProjectScreen->Validate())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_projectInfo = newProjectScreen->GetProjectInfo();
|
||||
m_projectTemplatePath = newProjectScreen->GetProjectTemplatePath();
|
||||
}
|
||||
}
|
||||
|
||||
if (screenOrderIter != m_screensOrder.end())
|
||||
{
|
||||
m_screensCtrl->ChangeToScreen(*screenOrderIter);
|
||||
@@ -83,7 +103,15 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
|
||||
auto result = PythonBindingsInterface::Get()->CreateProject(m_projectTemplatePath, m_projectInfo);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "ProjectInfo.h"
|
||||
#include <ScreenWidget.h>
|
||||
|
||||
#include <ScreensCtrl.h>
|
||||
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class ProjectSettingsCtrl
|
||||
@@ -40,6 +40,9 @@ namespace O3DE::ProjectManager
|
||||
QPushButton* m_backButton;
|
||||
QPushButton* m_nextButton;
|
||||
QVector<ProjectManagerScreen> m_screensOrder;
|
||||
|
||||
QString m_projectTemplatePath;
|
||||
ProjectInfo m_projectInfo;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -53,6 +53,173 @@ namespace Platform
|
||||
#define Py_To_String(obj) obj.cast<std::string>().c_str()
|
||||
#define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string
|
||||
|
||||
namespace RedirectOutput
|
||||
{
|
||||
using RedirectOutputFunc = AZStd::function<void(const char*)>;
|
||||
|
||||
struct RedirectOutput
|
||||
{
|
||||
PyObject_HEAD RedirectOutputFunc write;
|
||||
};
|
||||
|
||||
PyObject* RedirectWrite(PyObject* self, PyObject* args)
|
||||
{
|
||||
std::size_t written(0);
|
||||
RedirectOutput* selfimpl = reinterpret_cast<RedirectOutput*>(self);
|
||||
if (selfimpl->write)
|
||||
{
|
||||
char* data;
|
||||
if (!PyArg_ParseTuple(args, "s", &data))
|
||||
{
|
||||
return PyLong_FromSize_t(0);
|
||||
}
|
||||
selfimpl->write(data);
|
||||
written = strlen(data);
|
||||
}
|
||||
return PyLong_FromSize_t(written);
|
||||
}
|
||||
|
||||
PyObject* RedirectFlush([[maybe_unused]] PyObject* self,[[maybe_unused]] PyObject* args)
|
||||
{
|
||||
// no-op
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
PyMethodDef RedirectMethods[] = {
|
||||
{"write", RedirectWrite, METH_VARARGS, "sys.stdout.write"},
|
||||
{"flush", RedirectFlush, METH_VARARGS, "sys.stdout.flush"},
|
||||
{"write", RedirectWrite, METH_VARARGS, "sys.stderr.write"},
|
||||
{"flush", RedirectFlush, METH_VARARGS, "sys.stderr.flush"},
|
||||
{0, 0, 0, 0} // sentinel
|
||||
};
|
||||
|
||||
PyTypeObject RedirectOutputType = {
|
||||
PyVarObject_HEAD_INIT(0, 0) "azlmbr_redirect.RedirectOutputType", // tp_name
|
||||
sizeof(RedirectOutput), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
"azlmbr_redirect objects", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
RedirectMethods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0 /* tp_new */
|
||||
};
|
||||
|
||||
PyModuleDef RedirectOutputModule = {
|
||||
PyModuleDef_HEAD_INIT, "azlmbr_redirect", 0, -1, 0,
|
||||
};
|
||||
|
||||
// Internal state
|
||||
PyObject* g_redirect_stdout = nullptr;
|
||||
PyObject* g_redirect_stdout_saved = nullptr;
|
||||
PyObject* g_redirect_stderr = nullptr;
|
||||
PyObject* g_redirect_stderr_saved = nullptr;
|
||||
|
||||
PyMODINIT_FUNC PyInit_RedirectOutput(void)
|
||||
{
|
||||
g_redirect_stdout = nullptr;
|
||||
g_redirect_stdout_saved = nullptr;
|
||||
g_redirect_stderr = nullptr;
|
||||
g_redirect_stderr_saved = nullptr;
|
||||
|
||||
RedirectOutputType.tp_new = PyType_GenericNew;
|
||||
if (PyType_Ready(&RedirectOutputType) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* redirectModule = PyModule_Create(&RedirectOutputModule);
|
||||
if (redirectModule)
|
||||
{
|
||||
Py_INCREF(&RedirectOutputType);
|
||||
PyModule_AddObject(redirectModule, "Redirect", reinterpret_cast<PyObject*>(&RedirectOutputType));
|
||||
}
|
||||
return redirectModule;
|
||||
}
|
||||
|
||||
void SetRedirection(const char* funcname, PyObject*& saved, PyObject*& current, RedirectOutputFunc func)
|
||||
{
|
||||
if (PyType_Ready(&RedirectOutputType) < 0)
|
||||
{
|
||||
AZ_Warning("python", false, "RedirectOutputType not ready!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current)
|
||||
{
|
||||
saved = PySys_GetObject(funcname); // borrowed
|
||||
current = RedirectOutputType.tp_new(&RedirectOutputType, 0, 0);
|
||||
}
|
||||
|
||||
RedirectOutput* redirectOutput = reinterpret_cast<RedirectOutput*>(current);
|
||||
redirectOutput->write = func;
|
||||
PySys_SetObject(funcname, current);
|
||||
}
|
||||
|
||||
void ResetRedirection(const char* funcname, PyObject*& saved, PyObject*& current)
|
||||
{
|
||||
if (current)
|
||||
{
|
||||
PySys_SetObject(funcname, saved);
|
||||
}
|
||||
Py_XDECREF(current);
|
||||
current = nullptr;
|
||||
}
|
||||
|
||||
PyObject* s_RedirectModule = nullptr;
|
||||
|
||||
void Intialize(PyObject* module)
|
||||
{
|
||||
s_RedirectModule = module;
|
||||
|
||||
SetRedirection("stdout", g_redirect_stdout_saved, g_redirect_stdout, [](const char* msg) {
|
||||
AZ_TracePrintf("Python", msg);
|
||||
});
|
||||
|
||||
SetRedirection("stderr", g_redirect_stderr_saved, g_redirect_stderr, [](const char* msg) {
|
||||
AZ_TracePrintf("Python", msg);
|
||||
});
|
||||
|
||||
PySys_WriteStdout("RedirectOutput installed");
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
ResetRedirection("stdout", g_redirect_stdout_saved, g_redirect_stdout);
|
||||
ResetRedirection("stderr", g_redirect_stderr_saved, g_redirect_stderr);
|
||||
Py_XDECREF(s_RedirectModule);
|
||||
s_RedirectModule = nullptr;
|
||||
}
|
||||
} // namespace RedirectOutput
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath)
|
||||
@@ -92,6 +259,8 @@ namespace O3DE::ProjectManager
|
||||
AZ_TracePrintf("python", "Py_GetExecPrefix=%ls \n", Py_GetExecPrefix());
|
||||
AZ_TracePrintf("python", "Py_GetProgramFullPath=%ls \n", Py_GetProgramFullPath());
|
||||
|
||||
PyImport_AppendInittab("azlmbr_redirect", RedirectOutput::PyInit_RedirectOutput);
|
||||
|
||||
try
|
||||
{
|
||||
// ignore system location for sites site-packages
|
||||
@@ -101,6 +270,8 @@ namespace O3DE::ProjectManager
|
||||
const bool initializeSignalHandlers = true;
|
||||
pybind11::initialize_interpreter(initializeSignalHandlers);
|
||||
|
||||
RedirectOutput::Intialize(PyImport_ImportModule("azlmbr_redirect"));
|
||||
|
||||
// Acquire GIL before calling Python code
|
||||
AZStd::lock_guard<decltype(m_lock)> lock(m_lock);
|
||||
pybind11::gil_scoped_acquire acquire;
|
||||
@@ -113,6 +284,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// import required modules
|
||||
m_registration = pybind11::module::import("cmake.Tools.registration");
|
||||
m_engineTemplate = pybind11::module::import("cmake.Tools.engine_template");
|
||||
|
||||
return result == 0 && !PyErr_Occurred();
|
||||
} catch ([[maybe_unused]] const std::exception& e)
|
||||
@@ -126,6 +298,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
if (Py_IsInitialized())
|
||||
{
|
||||
RedirectOutput::Shutdown();
|
||||
pybind11::finalize_interpreter();
|
||||
}
|
||||
else
|
||||
@@ -204,9 +377,28 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo)
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo)
|
||||
{
|
||||
return AZ::Failure();
|
||||
ProjectInfo createdProjectInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
|
||||
pybind11::str projectPath = projectInfo.m_path.toStdString();
|
||||
pybind11::str templatePath = projectTemplatePath.toStdString();
|
||||
auto createProjectResult = m_engineTemplate.attr("create_project")(projectPath, templatePath);
|
||||
if (createProjectResult.cast<int>() == 0)
|
||||
{
|
||||
createdProjectInfo = ProjectInfoFromPath(projectPath);
|
||||
}
|
||||
});
|
||||
|
||||
if (!result || !createdProjectInfo.IsValid())
|
||||
{
|
||||
return AZ::Failure();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Success(AZStd::move(createdProjectInfo));
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path)
|
||||
@@ -275,10 +467,8 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
try
|
||||
{
|
||||
// required fields
|
||||
projectInfo.m_productName = Py_To_String(projectData["product_name"]);
|
||||
projectInfo.m_projectName = Py_To_String(projectData["project_name"]);
|
||||
projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"]));
|
||||
projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName);
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace O3DE::ProjectManager
|
||||
AZ::Outcome<QVector<GemInfo>> GetGems() override;
|
||||
|
||||
// Project
|
||||
AZ::Outcome<ProjectInfo> CreateProject(const ProjectTemplateInfo& projectTemplate, const ProjectInfo& projectInfo) override;
|
||||
AZ::Outcome<ProjectInfo> CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) override;
|
||||
AZ::Outcome<ProjectInfo> GetProject(const QString& path) override;
|
||||
AZ::Outcome<QVector<ProjectInfo>> GetProjects() override;
|
||||
bool UpdateProject(const ProjectInfo& projectInfo) override;
|
||||
@@ -62,6 +62,7 @@ namespace O3DE::ProjectManager
|
||||
bool StopPython();
|
||||
|
||||
AZ::IO::FixedMaxPath m_enginePath;
|
||||
pybind11::handle m_engineTemplate;
|
||||
AZStd::recursive_mutex m_lock;
|
||||
pybind11::handle m_registration;
|
||||
};
|
||||
|
||||
@@ -70,11 +70,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
/**
|
||||
* Create a project
|
||||
* @param projectTemplate the project template to use
|
||||
* @param projectTemplatePath the path to the project template to use
|
||||
* @param projectInfo the project info to use
|
||||
* @return an outcome with ProjectInfo on success
|
||||
*/
|
||||
virtual AZ::Outcome<ProjectInfo> CreateProject(const ProjectTemplateInfo& projectTemplate, const ProjectInfo& projectInfo) = 0;
|
||||
virtual AZ::Outcome<ProjectInfo> CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) = 0;
|
||||
|
||||
/**
|
||||
* Get info about a project
|
||||
|
||||
@@ -1480,10 +1480,10 @@ def create_project(project_path: str,
|
||||
logger.info(f'Project Path {project_path} is not a full path, we must assume its relative'
|
||||
f' to default projects path = {new_project_path}')
|
||||
project_path = new_project_path
|
||||
if os.path.isdir(project_path):
|
||||
logger.error(f'Project path {project_path} already exists.')
|
||||
if os.path.isdir(project_path) and len(os.listdir(project_path)) > 0:
|
||||
logger.error(f'Project path {project_path} already exists and is not empty.')
|
||||
return 1
|
||||
else:
|
||||
elif not os.path.isdir(project_path):
|
||||
os.makedirs(project_path)
|
||||
|
||||
# project name is now the last component of the project_path
|
||||
|
||||
Reference in New Issue
Block a user