Fix project creation (#1445)
* Add ability to change project name * Fixed several issues where path types were changed * Added PythonBindings CreateProject unit test * Fix python warning format * Validate new project name in CLI * Fix issue creating pathview on linux * Use better testing macros * Refactored the unit_test_engine_template.py test to actually test against the current engine_template.py commands The commands of create-template, create-from-template, create-project and create-gem is now being validated. Registered the unit_test_engine_template.py script with CTest in the smoke test suite so that it runs in Automated Review Fixed issues in the engine_template.py script where the template_restricted_path parameter was required in the create_project and create_gem functions Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
@@ -83,6 +83,8 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_projectName = m_projectName->lineEdit()->text();
|
||||
// currently we don't have separate fields for changing the project name and display name
|
||||
projectInfo.m_displayName = projectInfo.m_projectName;
|
||||
projectInfo.m_path = m_projectPath->lineEdit()->text();
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
@@ -52,8 +52,10 @@ namespace Platform
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
#define Py_To_String(obj) obj.cast<std::string>().c_str()
|
||||
#define Py_To_String(obj) pybind11::str(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
|
||||
#define QString_To_Py_String(value) pybind11::str(value.toStdString())
|
||||
#define QString_To_Py_Path(value) m_pathlib.attr("Path")(value.toStdString())
|
||||
|
||||
namespace RedirectOutput
|
||||
{
|
||||
@@ -298,6 +300,7 @@ namespace O3DE::ProjectManager
|
||||
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
|
||||
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
|
||||
m_editProjectProperties = pybind11::module::import("o3de.project_properties");
|
||||
m_pathlib = pybind11::module::import("pathlib");
|
||||
|
||||
// make sure the engine is registered
|
||||
RegisterThisEngine();
|
||||
@@ -346,7 +349,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
auto result = m_register.attr("register")(m_enginePath.c_str());
|
||||
auto result = m_register.attr("register")(QString_To_Py_Path(QString(m_enginePath.c_str())));
|
||||
registrationResult = (result.cast<int>() == 0);
|
||||
});
|
||||
|
||||
@@ -388,7 +391,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str enginePath = m_manifest.attr("get_this_engine_path")();
|
||||
auto enginePath = m_manifest.attr("get_this_engine_path")();
|
||||
|
||||
auto o3deData = m_manifest.attr("load_o3de_manifest")();
|
||||
if (pybind11::isinstance<pybind11::dict>(o3deData))
|
||||
@@ -399,7 +402,7 @@ namespace O3DE::ProjectManager
|
||||
engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]);
|
||||
engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]);
|
||||
|
||||
pybind11::str defaultThirdPartyFolder = m_manifest.attr("get_o3de_third_party_folder")();
|
||||
auto defaultThirdPartyFolder = m_manifest.attr("get_o3de_third_party_folder")();
|
||||
engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"default_third_party_folder", Py_To_String(defaultThirdPartyFolder));
|
||||
}
|
||||
|
||||
@@ -433,14 +436,8 @@ namespace O3DE::ProjectManager
|
||||
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
|
||||
{
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str enginePath = engineInfo.m_path.toStdString();
|
||||
pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString();
|
||||
pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString();
|
||||
pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString();
|
||||
pybind11::str defaultThirdPartyFolder = engineInfo.m_thirdPartyPath.toStdString();
|
||||
|
||||
auto registrationResult = m_register.attr("register")(
|
||||
enginePath, // engine_path
|
||||
QString_To_Py_Path(engineInfo.m_path),
|
||||
pybind11::none(), // project_path
|
||||
pybind11::none(), // gem_path
|
||||
pybind11::none(), // external_subdir_path
|
||||
@@ -448,11 +445,11 @@ namespace O3DE::ProjectManager
|
||||
pybind11::none(), // restricted_path
|
||||
pybind11::none(), // repo_uri
|
||||
pybind11::none(), // default_engines_folder
|
||||
defaultProjectsFolder,
|
||||
defaultGemsFolder,
|
||||
defaultTemplatesFolder,
|
||||
QString_To_Py_Path(engineInfo.m_defaultProjectsFolder),
|
||||
QString_To_Py_Path(engineInfo.m_defaultGemsFolder),
|
||||
QString_To_Py_Path(engineInfo.m_defaultTemplatesFolder),
|
||||
pybind11::none(), // default_restricted_folder
|
||||
defaultThirdPartyFolder
|
||||
QString_To_Py_Path(engineInfo.m_thirdPartyPath)
|
||||
);
|
||||
|
||||
if (registrationResult.cast<int>() != 0)
|
||||
@@ -466,7 +463,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
AZ::Outcome<GemInfo> PythonBindings::GetGemInfo(const QString& path, const QString& projectPath)
|
||||
{
|
||||
GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString()), pybind11::str(projectPath.toStdString()));
|
||||
GemInfo gemInfo = GemInfoFromPath(QString_To_Py_String(path), QString_To_Py_Path(projectPath));
|
||||
if (gemInfo.IsValid())
|
||||
{
|
||||
return AZ::Success(AZStd::move(gemInfo));
|
||||
@@ -503,7 +500,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
auto result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
auto pyProjectPath = QString_To_Py_Path(projectPath);
|
||||
for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath))
|
||||
{
|
||||
gems.push_back(GemInfoFromPath(path, pyProjectPath));
|
||||
@@ -524,10 +521,9 @@ namespace O3DE::ProjectManager
|
||||
pybind11::str enabledGemsFilename;
|
||||
auto result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
const pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")(
|
||||
pybind11::none(), // project_name
|
||||
pyProjectPath); // project_path
|
||||
QString_To_Py_Path(projectPath)); // project_path
|
||||
});
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
@@ -558,7 +554,7 @@ namespace O3DE::ProjectManager
|
||||
bool result = ExecuteWithLock(
|
||||
[&]
|
||||
{
|
||||
pybind11::str projectPath = path.toStdString();
|
||||
auto projectPath = QString_To_Py_Path(path);
|
||||
auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath);
|
||||
|
||||
// Returns an exit code so boolify it then invert result
|
||||
@@ -574,10 +570,9 @@ namespace O3DE::ProjectManager
|
||||
bool result = ExecuteWithLock(
|
||||
[&]
|
||||
{
|
||||
pybind11::str projectPath = path.toStdString();
|
||||
auto pythonRegistrationResult = m_register.attr("register")(
|
||||
pybind11::none(), // engine_path
|
||||
projectPath, // project_path
|
||||
QString_To_Py_Path(path), // project_path
|
||||
pybind11::none(), // gem_path
|
||||
pybind11::none(), // external_subdir_path
|
||||
pybind11::none(), // template_path
|
||||
@@ -606,14 +601,12 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo createdProjectInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str projectPath = projectInfo.m_path.toStdString();
|
||||
pybind11::str projectName = projectInfo.m_projectName.toStdString();
|
||||
pybind11::str templatePath = projectTemplatePath.toStdString();
|
||||
auto projectPath = QString_To_Py_Path(projectInfo.m_path);
|
||||
|
||||
auto createProjectResult = m_engineTemplate.attr("create_project")(
|
||||
projectPath,
|
||||
projectName,
|
||||
templatePath
|
||||
QString_To_Py_String(projectInfo.m_projectName),
|
||||
QString_To_Py_Path(projectTemplatePath)
|
||||
);
|
||||
if (createProjectResult.cast<int>() == 0)
|
||||
{
|
||||
@@ -633,7 +626,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path)
|
||||
{
|
||||
ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString()));
|
||||
ProjectInfo projectInfo = ProjectInfoFromPath(QString_To_Py_Path(path));
|
||||
if (projectInfo.IsValid())
|
||||
{
|
||||
return AZ::Success(AZStd::move(projectInfo));
|
||||
@@ -745,14 +738,11 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
|
||||
m_enableGemProject.attr("enable_gem_in_project")(
|
||||
pybind11::none(), // gem name not needed as path is provided
|
||||
pyGemPath,
|
||||
QString_To_Py_Path(gemPath),
|
||||
pybind11::none(), // project name not needed as path is provided
|
||||
pyProjectPath
|
||||
QString_To_Py_Path(projectPath)
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -761,21 +751,19 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
|
||||
m_disableGemProject.attr("disable_gem_in_project")(
|
||||
pybind11::none(), // gem name not needed as path is provided
|
||||
pyGemPath,
|
||||
QString_To_Py_Path(gemPath),
|
||||
pybind11::none(), // project name not needed as path is provided
|
||||
pyProjectPath
|
||||
QString_To_Py_Path(projectPath)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::UpdateProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
return ExecuteWithLockErrorHandling([&]
|
||||
bool updateProjectSucceeded = false;
|
||||
auto result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
std::list<std::string> newTags;
|
||||
for (const auto& i : projectInfo.m_userTags)
|
||||
@@ -783,23 +771,36 @@ namespace O3DE::ProjectManager
|
||||
newTags.push_back(i.toStdString());
|
||||
}
|
||||
|
||||
m_editProjectProperties.attr("edit_project_props")(
|
||||
pybind11::str(projectInfo.m_path.toStdString()), // proj_path
|
||||
auto editResult = m_editProjectProperties.attr("edit_project_props")(
|
||||
QString_To_Py_Path(projectInfo.m_path),
|
||||
pybind11::none(), // proj_name not used
|
||||
pybind11::str(projectInfo.m_origin.toStdString()), // new_origin
|
||||
pybind11::str(projectInfo.m_displayName.toStdString()), // new_display
|
||||
pybind11::str(projectInfo.m_summary.toStdString()), // new_summary
|
||||
pybind11::str(projectInfo.m_iconPath.toStdString()), // new_icon
|
||||
QString_To_Py_String(projectInfo.m_projectName),
|
||||
QString_To_Py_String(projectInfo.m_origin),
|
||||
QString_To_Py_String(projectInfo.m_displayName),
|
||||
QString_To_Py_String(projectInfo.m_summary),
|
||||
QString_To_Py_String(projectInfo.m_iconPath), // new_icon
|
||||
pybind11::none(), // add_tags not used
|
||||
pybind11::none(), // remove_tags not used
|
||||
pybind11::list(pybind11::cast(newTags))); // replace_tags
|
||||
pybind11::list(pybind11::cast(newTags)));
|
||||
updateProjectSucceeded = (editResult.cast<int>() == 0);
|
||||
});
|
||||
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (!updateProjectSucceeded)
|
||||
{
|
||||
return AZ::Failure<AZStd::string>("Failed to update project.");
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath)
|
||||
{
|
||||
ProjectTemplateInfo templateInfo;
|
||||
templateInfo.m_path = Py_To_String(pybind11::str(path));
|
||||
templateInfo.m_path = Py_To_String(path);
|
||||
|
||||
auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path, pyProjectPath);
|
||||
if (pybind11::isinstance<pybind11::dict>(data))
|
||||
@@ -848,10 +849,9 @@ namespace O3DE::ProjectManager
|
||||
QVector<ProjectTemplateInfo> templates;
|
||||
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
for (auto path : m_manifest.attr("get_templates_for_project_creation")())
|
||||
{
|
||||
templates.push_back(ProjectTemplateInfoFromPath(path, pyProjectPath));
|
||||
templates.push_back(ProjectTemplateInfoFromPath(path, QString_To_Py_Path(projectPath)));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -75,13 +75,15 @@ namespace O3DE::ProjectManager
|
||||
bool m_pythonStarted = false;
|
||||
|
||||
AZ::IO::FixedMaxPath m_enginePath;
|
||||
pybind11::handle m_engineTemplate;
|
||||
AZStd::recursive_mutex m_lock;
|
||||
|
||||
pybind11::handle m_engineTemplate;
|
||||
pybind11::handle m_cmake;
|
||||
pybind11::handle m_register;
|
||||
pybind11::handle m_manifest;
|
||||
pybind11::handle m_enableGemProject;
|
||||
pybind11::handle m_disableGemProject;
|
||||
pybind11::handle m_editProjectProperties;
|
||||
pybind11::handle m_pathlib;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ set(FILES
|
||||
Resources/ProjectManager.qrc
|
||||
Resources/ProjectManager.qss
|
||||
tests/ApplicationTests.cpp
|
||||
tests/PythonBindingsTests.cpp
|
||||
tests/main.cpp
|
||||
tests/UtilsTests.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/Utils.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <PythonBindings.h>
|
||||
#include <ProjectManager_Test_Traits_Platform.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class PythonBindingsTests
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
|
||||
PythonBindingsTests()
|
||||
{
|
||||
const AZStd::string engineRootPath{ AZ::Test::GetEngineRootPath() };
|
||||
m_pythonBindings = AZStd::make_unique<PythonBindings>(AZ::IO::PathView(engineRootPath));
|
||||
}
|
||||
|
||||
~PythonBindingsTests()
|
||||
{
|
||||
m_pythonBindings.reset();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<ProjectManager::PythonBindings> m_pythonBindings;
|
||||
};
|
||||
|
||||
TEST_F(PythonBindingsTests, PythonBindings_Start_Python_Succeeds)
|
||||
{
|
||||
EXPECT_TRUE(m_pythonBindings->PythonStarted());
|
||||
}
|
||||
|
||||
TEST_F(PythonBindingsTests, PythonBindings_Create_Project_Succeeds)
|
||||
{
|
||||
ASSERT_TRUE(m_pythonBindings->PythonStarted());
|
||||
|
||||
auto templateResults = m_pythonBindings->GetProjectTemplates();
|
||||
ASSERT_TRUE(templateResults.IsSuccess());
|
||||
|
||||
QVector<ProjectTemplateInfo> templates = templateResults.GetValue();
|
||||
ASSERT_FALSE(templates.isEmpty());
|
||||
|
||||
// use the first registered template
|
||||
QString templatePath = templates.at(0).m_path;
|
||||
|
||||
AZ::Test::ScopedAutoTempDirectory tempDir;
|
||||
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_path = QDir::toNativeSeparators(QString(tempDir.GetDirectory()) + "/" + "TestProject");
|
||||
projectInfo.m_projectName = "TestProjectName";
|
||||
|
||||
auto result = m_pythonBindings->CreateProject(templatePath, projectInfo);
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
|
||||
ProjectInfo resultProjectInfo = result.GetValue();
|
||||
EXPECT_EQ(projectInfo.m_path, resultProjectInfo.m_path);
|
||||
EXPECT_EQ(projectInfo.m_projectName, resultProjectInfo.m_projectName);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// {END_LICENSE}
|
||||
// {END_LICENSE}
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace ${SanitizedCppName}
|
||||
class ${SanitizedCppName}Requests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(${SanitizedCppName}Requests, "${Random_Uuid}");
|
||||
AZ_RTTI(${SanitizedCppName}Requests, "{${Random_Uuid}}");
|
||||
virtual ~${SanitizedCppName}Requests() = default;
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
@@ -350,6 +350,7 @@ def _instantiate_template(template_json_data: dict,
|
||||
|
||||
def create_template(source_path: pathlib.Path,
|
||||
template_path: pathlib.Path,
|
||||
source_name: str = None,
|
||||
source_restricted_path: pathlib.Path = None,
|
||||
source_restricted_name: str = None,
|
||||
template_restricted_path: pathlib.Path = None,
|
||||
@@ -365,6 +366,8 @@ def create_template(source_path: pathlib.Path,
|
||||
|
||||
:param source_path: The path to the source that you want to make into a template
|
||||
:param template_path: the path of the template to create, can be absolute or relative to default templates path
|
||||
:param source_name: Name to replace within template folder with ${Name} placeholder
|
||||
If not specified, the basename of the source_path parameter is used as the source_name instead
|
||||
:param source_restricted_path: path to the source restricted folder
|
||||
:param source_restricted_name: name of the source restricted folder
|
||||
:param template_restricted_path: path to the templates restricted folder
|
||||
@@ -395,7 +398,8 @@ def create_template(source_path: pathlib.Path,
|
||||
return 1
|
||||
|
||||
# source_name is now the last component of the source_path
|
||||
source_name = os.path.basename(source_path)
|
||||
if not source_name:
|
||||
source_name = os.path.basename(source_path)
|
||||
sanitized_source_name = utils.sanitize_identifier_for_cpp(source_name)
|
||||
|
||||
# if no template path, error
|
||||
@@ -410,6 +414,16 @@ def create_template(source_path: pathlib.Path,
|
||||
logger.error(f'Template path {template_path} already exists.')
|
||||
return 1
|
||||
|
||||
# Make sure the output directory for the template is outside the source path directory
|
||||
try:
|
||||
template_path.relative_to(source_path)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
logger.error(f'Template output path {template_path} cannot be a subdirectory of the source_path {source_path}:\n'
|
||||
f'{err}')
|
||||
return 1
|
||||
|
||||
# template name is now the last component of the template_path
|
||||
template_name = os.path.basename(template_path)
|
||||
|
||||
@@ -938,7 +952,7 @@ def create_template(source_path: pathlib.Path,
|
||||
s.write(json.dumps(json_data, indent=4) + '\n')
|
||||
|
||||
# copy the default preview.png
|
||||
preview_png_src = this_script_parent / 'resources' /' preview.png'
|
||||
preview_png_src = this_script_parent / 'resources' / 'preview.png'
|
||||
preview_png_dst = template_path / 'Template' / 'preview.png'
|
||||
if not os.path.isfile(preview_png_dst):
|
||||
shutil.copy(preview_png_src, preview_png_dst)
|
||||
@@ -987,6 +1001,7 @@ def create_template(source_path: pathlib.Path,
|
||||
def create_from_template(destination_path: pathlib.Path,
|
||||
template_path: pathlib.Path = None,
|
||||
template_name: str = None,
|
||||
destination_name: str = None,
|
||||
destination_restricted_path: pathlib.Path = None,
|
||||
destination_restricted_name: str = None,
|
||||
template_restricted_path: pathlib.Path = None,
|
||||
@@ -1004,6 +1019,10 @@ def create_from_template(destination_path: pathlib.Path,
|
||||
:param destination_path: the folder you want to instantiate the template into
|
||||
:param template_path: the path to the template you want to instance
|
||||
:param template_name: the name of the template you want to instance, resolves template_path
|
||||
:param destination_name: the name that will be substituted when instantiating the template.
|
||||
The placeholders of ${Name} and ${SanitizedCppName} will be replaced with destination name and a sanitized
|
||||
version of the destination name that is suitable as a C++ identifier. If not specified, defaults to the
|
||||
last path component of the destination_path
|
||||
:param destination_restricted_path: path to the projects restricted folder
|
||||
:param destination_restricted_name: name of the projects restricted folder, resolves destination_restricted_path
|
||||
:param template_restricted_path: path of the templates restricted folder
|
||||
@@ -1043,13 +1062,14 @@ def create_from_template(destination_path: pathlib.Path,
|
||||
if template_name:
|
||||
template_path = manifest.get_registered(template_name=template_name)
|
||||
|
||||
if not template_path:
|
||||
logger.error(f'Could not find the template path using name {template_name}.\n'
|
||||
f'Has the engine been registered yet. It can be registered via the "o3de.py register --this-engine" command')
|
||||
return 1
|
||||
if not os.path.isdir(template_path):
|
||||
logger.error(f'Could not find the template {template_name}=>{template_path}')
|
||||
return 1
|
||||
|
||||
# template folder name is now the last component of the template_path
|
||||
template_folder_name = os.path.basename(template_path)
|
||||
|
||||
# the template.json should be in the template_path, make sure it's there a nd valid
|
||||
template_json = template_path / 'template.json'
|
||||
if not validation.valid_o3de_template_json(template_json):
|
||||
@@ -1130,7 +1150,7 @@ def create_from_template(destination_path: pathlib.Path,
|
||||
return 1
|
||||
|
||||
# check and make sure the restricted exists
|
||||
if not os.path.isdir(template_restricted_path):
|
||||
if template_restricted_path and not os.path.isdir(template_restricted_path):
|
||||
logger.error(f'Template restricted path {template_restricted_path} does not exist.')
|
||||
return 1
|
||||
|
||||
@@ -1183,8 +1203,9 @@ def create_from_template(destination_path: pathlib.Path,
|
||||
else:
|
||||
os.makedirs(destination_path, exist_ok=force)
|
||||
|
||||
# destination name is now the last component of the destination_path
|
||||
destination_name = os.path.basename(destination_path)
|
||||
if not destination_name:
|
||||
# destination name is now the last component of the destination_path
|
||||
destination_name = os.path.basename(destination_path)
|
||||
|
||||
# destination name cannot be the same as a restricted platform name
|
||||
if destination_name in restricted_platforms:
|
||||
@@ -1340,9 +1361,6 @@ def create_project(project_path: pathlib.Path,
|
||||
logger.error(f'Could not find the template {template_name}=>{template_path}')
|
||||
return 1
|
||||
|
||||
# template folder name is now the last component of the template_path
|
||||
template_folder_name = os.path.basename(template_path)
|
||||
|
||||
# the template.json should be in the template_path, make sure it's there and valid
|
||||
template_json = template_path / 'template.json'
|
||||
if not validation.valid_o3de_template_json(template_json):
|
||||
@@ -1423,7 +1441,7 @@ def create_project(project_path: pathlib.Path,
|
||||
return 1
|
||||
|
||||
# check and make sure the restricted exists
|
||||
if not os.path.isdir(template_restricted_path):
|
||||
if template_restricted_path and not os.path.isdir(template_restricted_path):
|
||||
logger.error(f'Template restricted path {template_restricted_path} does not exist.')
|
||||
return 1
|
||||
|
||||
@@ -1574,6 +1592,7 @@ def create_project(project_path: pathlib.Path,
|
||||
return 1
|
||||
|
||||
# We created the project, now do anything extra that a project requires
|
||||
project_json = project_path / 'project.json'
|
||||
|
||||
# If we are not keeping the restricted in the project read the name of the restricted folder from the
|
||||
# restricted json and set that as this projects restricted
|
||||
@@ -1607,7 +1626,6 @@ def create_project(project_path: pathlib.Path,
|
||||
return 1
|
||||
|
||||
# set the "restricted_name": "restricted_name" element of the project.json
|
||||
project_json = project_path / 'project.json'
|
||||
if not validation.valid_o3de_project_json(project_json):
|
||||
logger.error(f'Project json {project_json} is not valid.')
|
||||
return 1
|
||||
@@ -1678,6 +1696,7 @@ def create_project(project_path: pathlib.Path,
|
||||
def create_gem(gem_path: pathlib.Path,
|
||||
template_path: pathlib.Path = None,
|
||||
template_name: str = None,
|
||||
gem_name: str = None,
|
||||
gem_restricted_path: pathlib.Path = None,
|
||||
gem_restricted_name: str = None,
|
||||
template_restricted_path: pathlib.Path = None,
|
||||
@@ -1697,6 +1716,10 @@ def create_gem(gem_path: pathlib.Path,
|
||||
:param gem_path: the gem path, can be absolute or relative to default gems path
|
||||
:param template_path: the template path you want to instance, can be absolute or relative to default templates path
|
||||
:param template_name: the name of the registered template you want to instance, defaults to DefaultGem, resolves template_path
|
||||
:param gem_name: the name that will be substituted when instantiating the template.
|
||||
The placeholders of ${Name} and ${SanitizedCppName} will be replaced with gem name and a sanitized
|
||||
version of the gem name that is suitable as a C++ identifier. If not specified, defaults to the
|
||||
last path component of the gem_path
|
||||
:param gem_restricted_path: path to the gems restricted folder, can be absolute or relative to the restricted='gems'
|
||||
:param gem_restricted_name: str = name of the registered gems restricted path, resolves gem_restricted_path
|
||||
:param template_restricted_path: the templates restricted path, can be absolute or relative to the restricted='templates'
|
||||
@@ -1741,9 +1764,6 @@ def create_gem(gem_path: pathlib.Path,
|
||||
logger.error(f'Could not find the template {template_name}=>{template_path}')
|
||||
return 1
|
||||
|
||||
# template name is now the last component of the template_path
|
||||
template_folder_name = os.path.basename(template_path)
|
||||
|
||||
# the template.json should be in the template_path, make sure it's there and valid
|
||||
template_json = template_path / 'template.json'
|
||||
if not validation.valid_o3de_template_json(template_json):
|
||||
@@ -1822,7 +1842,7 @@ def create_gem(gem_path: pathlib.Path,
|
||||
f' and {template_json_restricted_path} will be used.')
|
||||
return 1
|
||||
# check and make sure the restricted path exists
|
||||
if not os.path.isdir(template_restricted_path):
|
||||
if template_restricted_path and not os.path.isdir(template_restricted_path):
|
||||
logger.error(f'Template restricted path {template_restricted_path} does not exist.')
|
||||
return 1
|
||||
|
||||
@@ -1880,10 +1900,9 @@ def create_gem(gem_path: pathlib.Path,
|
||||
else:
|
||||
os.makedirs(gem_path, exist_ok=force)
|
||||
|
||||
# gem nam
|
||||
#
|
||||
# e is now the last component of the gem_path
|
||||
gem_name = os.path.basename(gem_path)
|
||||
# Default to the gem path basename component if gem_name has not been supplied
|
||||
if not gem_name:
|
||||
gem_name = os.path.basename(gem_path)
|
||||
|
||||
if not utils.validate_identifier(gem_name):
|
||||
logger.error(f'Gem name must be fewer than 64 characters, contain only alphanumeric, "_" or "-" characters, and start with a letter. {gem_name}')
|
||||
@@ -2057,6 +2076,7 @@ def create_gem(gem_path: pathlib.Path,
|
||||
def _run_create_template(args: argparse) -> int:
|
||||
return create_template(args.source_path,
|
||||
args.template_path,
|
||||
args.source_name,
|
||||
args.source_restricted_path,
|
||||
args.source_restricted_name,
|
||||
args.template_restricted_path,
|
||||
@@ -2073,6 +2093,7 @@ def _run_create_from_template(args: argparse) -> int:
|
||||
return create_from_template(args.destination_path,
|
||||
args.template_path,
|
||||
args.template_name,
|
||||
args.destination_path,
|
||||
args.destination_restricted_path,
|
||||
args.destination_restricted_name,
|
||||
args.template_restricted_path,
|
||||
@@ -2109,6 +2130,7 @@ def _run_create_gem(args: argparse) -> int:
|
||||
return create_gem(args.gem_path,
|
||||
args.template_path,
|
||||
args.template_name,
|
||||
args.gem_name,
|
||||
args.gem_restricted_path,
|
||||
args.gem_restricted_name,
|
||||
args.template_restricted_path,
|
||||
@@ -2159,6 +2181,16 @@ def add_args(subparsers) -> None:
|
||||
help='The name of the templates restricted folder. If supplied this will resolve'
|
||||
' the --template-restricted-path.')
|
||||
|
||||
create_template_subparser.add_argument('-sn', '--source-name',
|
||||
type=str,
|
||||
help='Substitutes any file and path entries which match the source'
|
||||
' name within the source-path directory with the ${Name} and'
|
||||
' ${SanitizedCppName}.'
|
||||
'Ex: Path substitution'
|
||||
'--source-name Foo'
|
||||
'<source-path>/Code/Include/FooBus.h -> <source-path>/Code/Include/${Name}Bus.h'
|
||||
'Ex: File content substitution.'
|
||||
'class FooRequests -> class ${SanitizedCppName}Requests')
|
||||
create_template_subparser.add_argument('-srprp', '--source-restricted-platform-relative-path', type=pathlib.Path,
|
||||
required=False,
|
||||
default=None,
|
||||
@@ -2216,6 +2248,13 @@ def add_args(subparsers) -> None:
|
||||
help='The name to the registered template you want to instantiate. If supplied this will'
|
||||
' resolve the --template-path.')
|
||||
|
||||
create_from_template_subparser.add_argument('-dn', '--destination-name', type=str,
|
||||
help='The name to use when substituting the ${Name} placeholder in instantiated template,'
|
||||
' must be alphanumeric, '
|
||||
' and can contain _ and - characters.'
|
||||
' If no name is provided, will use last component of destination path.'
|
||||
' Ex. New_Gem')
|
||||
|
||||
group = create_from_template_subparser.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('-drp', '--destination-restricted-path', type=pathlib.Path, required=False,
|
||||
default=None,
|
||||
@@ -2372,6 +2411,12 @@ def add_args(subparsers) -> None:
|
||||
create_gem_subparser = subparsers.add_parser('create-gem')
|
||||
create_gem_subparser.add_argument('-gp', '--gem-path', type=pathlib.Path, required=True,
|
||||
help='The gem path, can be absolute or relative to default gems path')
|
||||
create_gem_subparser.add_argument('-gn', '--gem-name', type=str,
|
||||
help='The name to use when substituting the ${Name} placeholder for the gem,'
|
||||
' must be alphanumeric, '
|
||||
' and can contain _ and - characters.'
|
||||
' If no name is provided, will use last component of gem path.'
|
||||
' Ex. New_Gem')
|
||||
|
||||
group = create_gem_subparser.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('-tp', '--template-path', type=pathlib.Path, required=False,
|
||||
|
||||
@@ -16,7 +16,7 @@ import pathlib
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from o3de import manifest
|
||||
from o3de import manifest, utils
|
||||
|
||||
logger = logging.getLogger()
|
||||
logging.basicConfig()
|
||||
@@ -29,8 +29,16 @@ def get_project_props(name: str = None, path: pathlib.Path = None) -> dict:
|
||||
return None
|
||||
return proj_json
|
||||
|
||||
def edit_project_props(proj_path, proj_name, new_origin, new_display,
|
||||
new_summary, new_icon, new_tags, delete_tags, replace_tags) -> int:
|
||||
def edit_project_props(proj_path: pathlib.Path,
|
||||
proj_name: str = None,
|
||||
new_name: str = None,
|
||||
new_origin: str = None,
|
||||
new_display: str = None,
|
||||
new_summary: str = None,
|
||||
new_icon: str = None,
|
||||
new_tags: str or list = None,
|
||||
delete_tags: str or list = None,
|
||||
replace_tags: str or list = None) -> int:
|
||||
proj_json = get_project_props(proj_name, proj_path)
|
||||
|
||||
if not proj_json:
|
||||
@@ -38,6 +46,11 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display,
|
||||
|
||||
if new_origin:
|
||||
proj_json['origin'] = new_origin
|
||||
if new_name:
|
||||
if not utils.validate_identifier(new_name):
|
||||
logger.error(f'Project name must be fewer than 64 characters, contain only alphanumeric, "_" or "-" characters, and start with a letter. {new_name}')
|
||||
return 1
|
||||
proj_json['project_name'] = new_name
|
||||
if new_display:
|
||||
proj_json['display_name'] = new_display
|
||||
if new_summary:
|
||||
@@ -54,9 +67,9 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display,
|
||||
if tag in proj_json['user_tags']:
|
||||
proj_json['user_tags'].remove(tag)
|
||||
else:
|
||||
logger.warn(f'{tag} not found in user_tags for removal.')
|
||||
logger.warning(f'{tag} not found in user_tags for removal.')
|
||||
else:
|
||||
logger.warn(f'user_tags property not found for removal of {remove_tags}.')
|
||||
logger.warning('user_tags property not found.')
|
||||
if replace_tags:
|
||||
tag_list = [replace_tags] if isinstance(replace_tags, str) else replace_tags
|
||||
proj_json['user_tags'] = tag_list
|
||||
@@ -67,13 +80,14 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display,
|
||||
def _edit_project_props(args: argparse) -> int:
|
||||
return edit_project_props(args.project_path,
|
||||
args.project_name,
|
||||
args.project_origin,
|
||||
args.project_display,
|
||||
args.project_summary,
|
||||
args.project_icon,
|
||||
args.add_tags,
|
||||
args.delete_tags,
|
||||
args.replace_tags)
|
||||
args.project_new_name,
|
||||
args.project_origin,
|
||||
args.project_display,
|
||||
args.project_summary,
|
||||
args.project_icon,
|
||||
args.add_tags,
|
||||
args.delete_tags,
|
||||
args.replace_tags)
|
||||
|
||||
def add_parser_args(parser):
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
@@ -82,6 +96,8 @@ def add_parser_args(parser):
|
||||
group.add_argument('-pn', '--project-name', type=str, required=False,
|
||||
help='The name of the project.')
|
||||
group = parser.add_argument_group('properties', 'arguments for modifying individual project properties.')
|
||||
group.add_argument('-pnn', '--project-new-name', type=str, required=False,
|
||||
help='Sets the name for the project.')
|
||||
group.add_argument('-po', '--project-origin', type=str, required=False,
|
||||
help='Sets description or url for project origin (such as project host, repository, owner...etc).')
|
||||
group.add_argument('-pd', '--project-display', type=str, required=False,
|
||||
|
||||
@@ -41,3 +41,10 @@ ly_add_pytest(
|
||||
TEST_SUITE smoke
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME o3de_template
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_engine_template.py
|
||||
TEST_SUITE smoke
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
)
|
||||
|
||||
@@ -8,12 +8,17 @@
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
import os
|
||||
import json
|
||||
import pathlib
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from . import engine_template
|
||||
import string
|
||||
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE = """\
|
||||
// {BEGIN_LICENSE}
|
||||
from o3de import engine_template
|
||||
from unittest.mock import patch
|
||||
|
||||
CPP_LICENSE_TEXT = """// {BEGIN_LICENSE}
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
@@ -26,478 +31,198 @@ TEST_TEMPLATED_CONTENT_WITH_LICENSE = """\
|
||||
*
|
||||
*/
|
||||
// {END_LICENSE}
|
||||
"""
|
||||
|
||||
|
||||
TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE = """
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
namespace ${Name}
|
||||
{
|
||||
class ${Name}Requests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(${Name}Requests, "{${Random_Uuid}}");
|
||||
virtual ~${Name}Requests() = default;
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
class ${Name}BusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using ${Name}RequestsBus = AZ::EBus<${Name}Requests>;
|
||||
using ${Name}RequestBus = AZ::EBus<${Name}Requests, ${Name}BusTraits>;
|
||||
using ${Name}Interface = AZ::Interface<${Name}Requests>;
|
||||
|
||||
} // namespace ${Name}
|
||||
|
||||
"""
|
||||
|
||||
TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE = """\
|
||||
#pragma once
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE = CPP_LICENSE_TEXT + TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITHOUT_LICENSE = string.Template(
|
||||
TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'Name': "TestTemplate"})
|
||||
|
||||
namespace ${Name}
|
||||
TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE = string.Template(
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'Name': "TestTemplate"})
|
||||
|
||||
TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITHOUT_LICENSE = string.Template(
|
||||
TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'Name': "TestProject"})
|
||||
|
||||
TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITH_LICENSE = string.Template(
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'Name': "TestProject"})
|
||||
|
||||
TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITHOUT_LICENSE = string.Template(
|
||||
TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'Name': "TestGem"})
|
||||
|
||||
TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITH_LICENSE = string.Template(
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'Name': "TestGem"})
|
||||
|
||||
TEST_TEMPLATE_JSON_CONTENTS = """\
|
||||
{
|
||||
class ${Name}Requests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using ${Name}RequestsBus = AZ::EBus<${Name}Requests>;
|
||||
|
||||
} // namespace ${Name}
|
||||
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITHOUT_LICENSE = """\
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace TestTemplate
|
||||
{
|
||||
class TestTemplateRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using TestTemplateRequestsBus = AZ::EBus<TestTemplateRequests>;
|
||||
|
||||
} // namespace TestTemplate
|
||||
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE = """\
|
||||
// {BEGIN_LICENSE}
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// {END_LICENSE}
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace TestTemplate
|
||||
{
|
||||
class TestTemplateRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using TestTemplateRequestsBus = AZ::EBus<TestTemplateRequests>;
|
||||
|
||||
} // namespace TestTemplate
|
||||
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITHOUT_LICENSE = """\
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace TestProject
|
||||
{
|
||||
class TestProjectRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using TestProjectRequestsBus = AZ::EBus<TestProjectRequests>;
|
||||
|
||||
} // namespace TestProject
|
||||
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITH_LICENSE = """\
|
||||
// {BEGIN_LICENSE}
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// {END_LICENSE}
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace TestProject
|
||||
{
|
||||
class TestProjectRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using TestProjectRequestsBus = AZ::EBus<TestProjectRequests>;
|
||||
|
||||
} // namespace TestProject
|
||||
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITHOUT_LICENSE = """\
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace TestGem
|
||||
{
|
||||
class TestGemRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using TestGemRequestsBus = AZ::EBus<TestGemRequests>;
|
||||
|
||||
} // namespace TestGem
|
||||
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITH_LICENSE = """\
|
||||
// {BEGIN_LICENSE}
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// {END_LICENSE}
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace TestGem
|
||||
{
|
||||
class TestGemRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
using TestGemRequestsBus = AZ::EBus<TestGemRequests>;
|
||||
|
||||
} // namespace TestGem
|
||||
|
||||
"""
|
||||
|
||||
TEST_DEFAULTTEMPLATE_JSON_CONTENTS = """\
|
||||
{
|
||||
"inputPath": "Templates/Default/Template",
|
||||
"template_name": "Templates",
|
||||
"origin": "The primary repo for Templates goes here: i.e. http://www.mydomain.com",
|
||||
"license": "What license Templates uses goes here: i.e. https://opensource.org/licenses/MIT",
|
||||
"display_name": "Templates",
|
||||
"summary": "A short description of Templates.",
|
||||
"canonical_tags": [],
|
||||
"user_tags": [
|
||||
"Templates"
|
||||
],
|
||||
"icon_path": "preview.png",
|
||||
"copyFiles": [
|
||||
{
|
||||
"inFile": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"outFile": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"file": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"origin": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
},
|
||||
{
|
||||
"file": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"origin": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
}
|
||||
],
|
||||
"createDirectories": [
|
||||
{
|
||||
"outDir": "Code"
|
||||
"dir": "Code",
|
||||
"origin": "Code"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include"
|
||||
"dir": "Code/Include",
|
||||
"origin": "Code/Include"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include/Platform"
|
||||
"dir": "Code/Include/${Name}",
|
||||
"origin": "Code/Include/${Name}"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include/${Name}"
|
||||
"dir": "Code/Include/Platform",
|
||||
"origin": "Code/Include/Platform"
|
||||
},
|
||||
{
|
||||
"dir": "Code/Include/Platform/Salem",
|
||||
"origin": "Code/Include/Platform/Salem"
|
||||
}
|
||||
]
|
||||
}\
|
||||
}
|
||||
"""
|
||||
|
||||
TEST_DEFAULTTEMPLATE_RESTRICTED_JSON_CONTENTS = """\
|
||||
{
|
||||
"inputPath": "restricted/Salem/Templates/Default/Template",
|
||||
"copyFiles": [
|
||||
{
|
||||
"inFile": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"outFile": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
}
|
||||
],
|
||||
"createDirectories": [
|
||||
{
|
||||
"outDir": "Code/Include/Platform/Salem"
|
||||
}
|
||||
]
|
||||
}\
|
||||
"""
|
||||
|
||||
TEST_DEFAULTPROJECT_TEMPLATE_JSON_CONTENTS = """\
|
||||
{
|
||||
"inputPath": "Templates/DefaultProject/Template",
|
||||
"copyFiles": [
|
||||
{
|
||||
"inFile": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"outFile": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
}
|
||||
],
|
||||
"createDirectories": [
|
||||
{
|
||||
"outDir": "Code"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include/Platform"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include/${Name}"
|
||||
}
|
||||
]
|
||||
}\
|
||||
"""
|
||||
TEST_CONCRETE_TEMPLATE_JSON_CONTENTS = string.Template(
|
||||
TEST_TEMPLATE_JSON_CONTENTS).safe_substitute({'Name': 'TestTemplate'})
|
||||
|
||||
TEST_DEFAULTPROJECT_TEMPLATE_RESTRICTED_JSON_CONTENTS = """\
|
||||
{
|
||||
"inputPath": "restricted/Salem/Templates/DefaultProject/Template",
|
||||
"copyFiles": [
|
||||
{
|
||||
"inFile": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"outFile": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
}
|
||||
],
|
||||
"createDirectories": [
|
||||
{
|
||||
"outDir": "Code/Include/Platform/Salem"
|
||||
}
|
||||
]
|
||||
}\
|
||||
"""
|
||||
|
||||
TEST_DEFAULTGEM_TEMPLATE_JSON_CONTENTS = """\
|
||||
{
|
||||
"inputPath": "Templates/DefaultGem/Template",
|
||||
"copyFiles": [
|
||||
{
|
||||
"inFile": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"outFile": "Code/Include/${Name}/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
}
|
||||
],
|
||||
"createDirectories": [
|
||||
{
|
||||
"outDir": "Code"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include/Platform"
|
||||
},
|
||||
{
|
||||
"outDir": "Code/Include/${Name}"
|
||||
}
|
||||
]
|
||||
}\
|
||||
"""
|
||||
TEST_CONCRETE_PROJECT_TEMPLATE_JSON_CONTENTS = string.Template(
|
||||
TEST_TEMPLATE_JSON_CONTENTS).safe_substitute({'Name': 'TestProject'})
|
||||
|
||||
TEST_DEFAULTGEM_TEMPLATE_RESTRICTED_JSON_CONTENTS = """\
|
||||
{
|
||||
"inputPath": "restricted/Salem/Templates/DefaultGem/Template",
|
||||
"copyFiles": [
|
||||
{
|
||||
"inFile": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"outFile": "Code/Include/Platform/Salem/${Name}Bus.h",
|
||||
"isTemplated": true,
|
||||
"isOptional": false
|
||||
}
|
||||
],
|
||||
"createDirectories": [
|
||||
{
|
||||
"outDir": "Code/Include/Platform/Salem"
|
||||
}
|
||||
]
|
||||
}\
|
||||
"""
|
||||
|
||||
TEST_CONCRETE_GEM_TEMPLATE_JSON_CONTENTS = string.Template(
|
||||
TEST_TEMPLATE_JSON_CONTENTS).safe_substitute({'Name': 'TestGem'})
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents,"
|
||||
" templated_contents_with_license, templated_contents_without_license,"
|
||||
" keep_license_text, expect_failure,"
|
||||
" template_json_contents, restricted_template_json_contents", [
|
||||
" keep_license_text, force, expect_failure,"
|
||||
" template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE,
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE,
|
||||
True, False,
|
||||
TEST_DEFAULTTEMPLATE_JSON_CONTENTS, TEST_DEFAULTTEMPLATE_RESTRICTED_JSON_CONTENTS),
|
||||
True, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE,
|
||||
TEST_TEMPLATED_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE,
|
||||
False, False,
|
||||
TEST_DEFAULTTEMPLATE_JSON_CONTENTS, TEST_DEFAULTTEMPLATE_RESTRICTED_JSON_CONTENTS)
|
||||
False, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_template(tmpdir,
|
||||
concrete_contents,
|
||||
templated_contents_with_license, templated_contents_without_license,
|
||||
keep_license_text, expect_failure,
|
||||
template_json_contents, restricted_template_json_contents):
|
||||
dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/')
|
||||
os.makedirs(dev_root, exist_ok=True)
|
||||
keep_license_text, force, expect_failure,
|
||||
template_json_contents):
|
||||
engine_root = (pathlib.Path(tmpdir) / 'engine-root').resolve()
|
||||
engine_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
dev_gem_code_include_testgem = f'{dev_root}/TestTemplate/Code/Include/TestTemplate'
|
||||
os.makedirs(dev_gem_code_include_testgem, exist_ok=True)
|
||||
template_source_path = engine_root / 'TestTemplates'
|
||||
|
||||
gem_bus_file = f'{dev_gem_code_include_testgem}/TestTemplateBus.h'
|
||||
if os.path.isfile(gem_bus_file):
|
||||
os.unlink(gem_bus_file)
|
||||
with open(gem_bus_file, 'w') as s:
|
||||
engine_gem_code_include_testgem = template_source_path / 'Code/Include/TestTemplate'
|
||||
engine_gem_code_include_testgem.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
gem_bus_file = engine_gem_code_include_testgem / 'TestTemplateBus.h'
|
||||
with gem_bus_file.open('w') as s:
|
||||
s.write(concrete_contents)
|
||||
|
||||
dev_gem_code_include_platform_salem = f'{dev_root}/TestTemplate/Code/Include/Platform/Salem'
|
||||
os.makedirs(dev_gem_code_include_platform_salem, exist_ok=True)
|
||||
engine_gem_code_include_platform_salem = template_source_path / 'Code/Include/Platform/Salem'
|
||||
engine_gem_code_include_platform_salem.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
restricted_gem_bus_file = f'{dev_gem_code_include_platform_salem}/TestTemplateBus.h'
|
||||
if os.path.isfile(restricted_gem_bus_file):
|
||||
os.unlink(restricted_gem_bus_file)
|
||||
with open(restricted_gem_bus_file, 'w') as s:
|
||||
restricted_gem_bus_file = engine_gem_code_include_platform_salem / 'TestTemplateBus.h'
|
||||
with restricted_gem_bus_file.open('w') as s:
|
||||
s.write(concrete_contents)
|
||||
|
||||
template_folder = f'{dev_root}/Templates'
|
||||
os.makedirs(template_folder, exist_ok=True)
|
||||
template_folder = engine_root / 'Templates'
|
||||
template_folder.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
restricted_folder = f'{dev_root}/restricted'
|
||||
os.makedirs(restricted_folder, exist_ok=True)
|
||||
|
||||
result = engine_template.create_template(dev_root, 'TestTemplate', 'Default', keep_license_text=keep_license_text)
|
||||
result = engine_template.create_template(template_source_path, template_folder, source_name='TestTemplate',
|
||||
keep_license_text=keep_license_text, force=force)
|
||||
|
||||
if expect_failure:
|
||||
assert result != 0
|
||||
else:
|
||||
assert result == 0
|
||||
new_template_folder = f'{template_folder}/Default'
|
||||
assert os.path.isdir(new_template_folder)
|
||||
new_template_json = f'{new_template_folder}/template.json'
|
||||
assert os.path.isfile(new_template_json)
|
||||
with open(new_template_json, 'r') as s:
|
||||
new_template_folder = template_folder
|
||||
assert new_template_folder.is_dir()
|
||||
new_template_json = new_template_folder / 'template.json'
|
||||
assert new_template_json.is_file()
|
||||
with new_template_json.open('r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == template_json_contents
|
||||
assert json.loads(s_data) == json.loads(template_json_contents)
|
||||
|
||||
new_default_name_bus_file = f'{new_template_folder}/Template/Code/Include/' + '${Name}/${Name}Bus.h'
|
||||
assert os.path.isfile(new_default_name_bus_file)
|
||||
with open(new_default_name_bus_file, 'r') as s:
|
||||
template_content_folder = new_template_folder / 'Template'
|
||||
new_default_name_bus_file = template_content_folder / 'Code/Include/${Name}/${Name}Bus.h'
|
||||
assert new_default_name_bus_file.is_file()
|
||||
with new_default_name_bus_file.open('r') as s:
|
||||
s_data = s.read()
|
||||
if keep_license_text:
|
||||
assert s_data == templated_contents_with_license
|
||||
else:
|
||||
assert s_data == templated_contents_without_license
|
||||
|
||||
restricted_template_folder = f'{dev_root}/restricted/Salem/Templates'
|
||||
platform_template_folder = engine_root / 'Salem/Templates'
|
||||
|
||||
new_restricted_template_folder = f'{restricted_template_folder}/Default'
|
||||
assert os.path.isdir(new_restricted_template_folder)
|
||||
new_restricted_template_json = f'{new_restricted_template_folder}/template.json'
|
||||
assert os.path.isfile(new_restricted_template_json)
|
||||
with open(new_restricted_template_json, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == restricted_template_json_contents
|
||||
|
||||
new_restricted_default_name_bus_file = f'{restricted_template_folder}' \
|
||||
f'/Default/Template/Code/Include/Platform/Salem/' + '${Name}Bus.h'
|
||||
assert os.path.isfile(new_restricted_default_name_bus_file)
|
||||
with open(new_restricted_default_name_bus_file, 'r') as s:
|
||||
new_platform_default_name_bus_file = template_content_folder / 'Code/Include/Platform/Salem/${Name}Bus.h'
|
||||
assert new_platform_default_name_bus_file.is_file()
|
||||
with new_platform_default_name_bus_file.open('r') as s:
|
||||
s_data = s.read()
|
||||
if keep_license_text:
|
||||
assert s_data == templated_contents_with_license
|
||||
@@ -505,244 +230,164 @@ def test_create_template(tmpdir,
|
||||
assert s_data == templated_contents_without_license
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents, templated_contents,"
|
||||
" keep_license_text, expect_failure,"
|
||||
" template_json_contents, restricted_template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
True, False,
|
||||
TEST_DEFAULTTEMPLATE_JSON_CONTENTS, TEST_DEFAULTTEMPLATE_RESTRICTED_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITHOUT_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
False, False,
|
||||
TEST_DEFAULTTEMPLATE_JSON_CONTENTS, TEST_DEFAULTTEMPLATE_RESTRICTED_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_from_template(tmpdir,
|
||||
concrete_contents, templated_contents,
|
||||
keep_license_text, expect_failure,
|
||||
template_json_contents, restricted_template_json_contents):
|
||||
dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/')
|
||||
os.makedirs(dev_root, exist_ok=True)
|
||||
class TestCreateTemplate:
|
||||
def instantiate_template_wrapper(self, tmpdir, create_from_template_func, instantiated_name,
|
||||
concrete_contents, templated_contents,
|
||||
keep_license_text, force, expect_failure,
|
||||
template_json_contents, template_file_creation_map = {},
|
||||
**create_from_template_kwargs):
|
||||
# Use a SHA-1 Hash of the destination_name for every Random_Uuid for determinism in the test
|
||||
concrete_contents = string.Template(concrete_contents).safe_substitute(
|
||||
{'Random_Uuid': uuid.uuid5(uuid.NAMESPACE_DNS, instantiated_name)})
|
||||
|
||||
template_default_folder = f'{dev_root}/Templates/Default'
|
||||
os.makedirs(template_default_folder, exist_ok=True)
|
||||
engine_root = (pathlib.Path(tmpdir) / 'engine-root').resolve()
|
||||
engine_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
template_json = f'{template_default_folder}/template.json'
|
||||
if os.path.isfile(template_json):
|
||||
os.unlink(template_json)
|
||||
with open(template_json, 'w') as s:
|
||||
s.write(template_json_contents)
|
||||
template_default_folder = engine_root / 'Templates/Default'
|
||||
template_default_folder.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
default_name_bus_dir = f'{template_default_folder}/Template/Code/Include/' + '${Name}'
|
||||
os.makedirs(default_name_bus_dir, exist_ok=True)
|
||||
template_json = template_default_folder / 'template.json'
|
||||
with template_json.open('w') as s:
|
||||
s.write(template_json_contents)
|
||||
|
||||
default_name_bus_file = f'{default_name_bus_dir}/' + '${Name}Bus.h'
|
||||
if os.path.isfile(default_name_bus_file):
|
||||
os.unlink(default_name_bus_file)
|
||||
with open(default_name_bus_file, 'w') as s:
|
||||
s.write(templated_contents)
|
||||
for file_template_filename, file_template_content in template_file_creation_map.items():
|
||||
file_template_path = template_default_folder / 'Template' / file_template_filename
|
||||
file_template_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with file_template_path.open('w') as file_template_handle:
|
||||
file_template_handle.write(file_template_content)
|
||||
|
||||
restricted_template_default_folder = f'{dev_root}/restricted/Salem/Templates/Default'
|
||||
os.makedirs(restricted_template_default_folder, exist_ok=True)
|
||||
default_name_bus_dir = template_default_folder / 'Template/Code/Include/${Name}'
|
||||
default_name_bus_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
restricted_template_json = f'{restricted_template_default_folder}/template.json'
|
||||
if os.path.isfile(restricted_template_json):
|
||||
os.unlink(restricted_template_json)
|
||||
with open(restricted_template_json, 'w') as s:
|
||||
s.write(restricted_template_json_contents)
|
||||
default_name_bus_file = default_name_bus_dir / '${Name}Bus.h'
|
||||
with default_name_bus_file.open('w') as s:
|
||||
s.write(templated_contents)
|
||||
|
||||
restricted_default_name_bus_dir = f'{restricted_template_default_folder}/Template/Code/Include/Platform/Salem'
|
||||
os.makedirs(restricted_default_name_bus_dir, exist_ok=True)
|
||||
template_content_folder = template_default_folder / 'Template'
|
||||
platform_default_name_bus_dir = template_content_folder / 'Code/Include/Platform/Salem'
|
||||
platform_default_name_bus_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
restricted_default_name_bus_file = f'{restricted_default_name_bus_dir}/' + '${Name}Bus.h'
|
||||
if os.path.isfile(restricted_default_name_bus_file):
|
||||
os.unlink(restricted_default_name_bus_file)
|
||||
with open(restricted_default_name_bus_file, 'w') as s:
|
||||
s.write(templated_contents)
|
||||
platform_default_name_bus_file = platform_default_name_bus_dir / '${Name}Bus.h'
|
||||
with platform_default_name_bus_file.open('w') as s:
|
||||
s.write(templated_contents)
|
||||
|
||||
result = engine_template.create_from_template(dev_root, 'TestTemplate', 'Default',
|
||||
keep_license_text=keep_license_text)
|
||||
if expect_failure:
|
||||
assert result != 0
|
||||
else:
|
||||
assert result == 0
|
||||
template_dest_path = engine_root / instantiated_name
|
||||
with patch('uuid.uuid4', return_value=uuid.uuid5(uuid.NAMESPACE_DNS, instantiated_name)) as uuid4_mock:
|
||||
result = create_from_template_func(template_dest_path, template_path=template_default_folder, force=True,
|
||||
keep_license_text=keep_license_text, **create_from_template_kwargs)
|
||||
if expect_failure:
|
||||
assert result != 0
|
||||
else:
|
||||
assert result == 0
|
||||
|
||||
test_folder = f'{dev_root}/TestTemplate'
|
||||
assert os.path.isdir(test_folder)
|
||||
test_folder = template_dest_path
|
||||
assert test_folder.is_dir()
|
||||
|
||||
test_bus_file = f'{test_folder}/Code/Include/TestTemplate/TestTemplateBus.h'
|
||||
assert os.path.isfile(test_bus_file)
|
||||
with open(test_bus_file, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
test_bus_file = test_folder / f'Code/Include/{instantiated_name}/{instantiated_name}Bus.h'
|
||||
assert test_bus_file.is_file()
|
||||
with test_bus_file.open('r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
|
||||
restricted_test_bus_folder = f'{dev_root}/restricted/Salem/TestTemplate/Code/Include/Platform/Salem'
|
||||
assert os.path.isdir(restricted_test_bus_folder)
|
||||
platform_test_bus_folder = test_folder / 'Code/Include/Platform/Salem'
|
||||
assert platform_test_bus_folder.is_dir()
|
||||
|
||||
restricted_default_name_bus_file = f'{restricted_test_bus_folder}/TestTemplateBus.h'
|
||||
assert os.path.isfile(restricted_default_name_bus_file)
|
||||
with open(restricted_default_name_bus_file, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
platform_default_name_bus_file = platform_test_bus_folder / f'{instantiated_name}Bus.h'
|
||||
assert platform_default_name_bus_file.is_file()
|
||||
with platform_default_name_bus_file.open('r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents, templated_contents,"
|
||||
" keep_license_text, expect_failure,"
|
||||
" template_json_contents, restricted_template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
True, False,
|
||||
TEST_DEFAULTPROJECT_TEMPLATE_JSON_CONTENTS, TEST_DEFAULTPROJECT_TEMPLATE_RESTRICTED_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITHOUT_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
False, False,
|
||||
TEST_DEFAULTPROJECT_TEMPLATE_JSON_CONTENTS, TEST_DEFAULTPROJECT_TEMPLATE_RESTRICTED_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_project(tmpdir,
|
||||
concrete_contents, templated_contents,
|
||||
keep_license_text, expect_failure,
|
||||
template_json_contents, restricted_template_json_contents):
|
||||
dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/')
|
||||
os.makedirs(dev_root, exist_ok=True)
|
||||
# Use a SHA-1 Hash of the destination_name for every Random_Uuid for determinism in the test
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents, templated_contents,"
|
||||
" keep_license_text, force, expect_failure,"
|
||||
" template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
True, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITHOUT_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
False, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_from_template(self, tmpdir, concrete_contents, templated_contents, keep_license_text, force,
|
||||
expect_failure, template_json_contents):
|
||||
|
||||
template_default_folder = f'{dev_root}/Templates/DefaultProject'
|
||||
os.makedirs(template_default_folder, exist_ok=True)
|
||||
|
||||
template_json = f'{template_default_folder}/template.json'
|
||||
if os.path.isfile(template_json):
|
||||
os.unlink(template_json)
|
||||
with open(template_json, 'w') as s:
|
||||
s.write(template_json_contents)
|
||||
|
||||
default_name_bus_dir = f'{template_default_folder}/Template/Code/Include/' + '${Name}'
|
||||
os.makedirs(default_name_bus_dir, exist_ok=True)
|
||||
|
||||
default_name_bus_file = f'{default_name_bus_dir}/' + '${Name}Bus.h'
|
||||
if os.path.isfile(default_name_bus_file):
|
||||
os.unlink(default_name_bus_file)
|
||||
with open(default_name_bus_file, 'w') as s:
|
||||
s.write(templated_contents)
|
||||
|
||||
restricted_template_default_folder = f'{dev_root}/restricted/Salem/Templates/DefaultProject'
|
||||
os.makedirs(restricted_template_default_folder, exist_ok=True)
|
||||
|
||||
restricted_template_json = f'{restricted_template_default_folder}/template.json'
|
||||
if os.path.isfile(restricted_template_json):
|
||||
os.unlink(restricted_template_json)
|
||||
with open(restricted_template_json, 'w') as s:
|
||||
s.write(restricted_template_json_contents)
|
||||
|
||||
restricted_default_name_bus_dir = f'{restricted_template_default_folder}/Template/Code/Include/Platform/Salem'
|
||||
os.makedirs(restricted_default_name_bus_dir, exist_ok=True)
|
||||
|
||||
restricted_default_name_bus_file = f'{restricted_default_name_bus_dir}/' + '${Name}Bus.h'
|
||||
if os.path.isfile(restricted_default_name_bus_file):
|
||||
os.unlink(restricted_default_name_bus_file)
|
||||
with open(restricted_default_name_bus_file, 'w') as s:
|
||||
s.write(templated_contents)
|
||||
|
||||
result = engine_template.create_project(dev_root, 'TestProject', keep_license_text=keep_license_text)
|
||||
|
||||
if expect_failure:
|
||||
assert result != 0
|
||||
else:
|
||||
assert result == 0
|
||||
|
||||
test_project_folder = f'{dev_root}/TestProject'
|
||||
assert os.path.isdir(test_project_folder)
|
||||
|
||||
test_project_bus_file = f'{test_project_folder}/Code/Include/TestProject/TestProjectBus.h'
|
||||
assert os.path.isfile(test_project_bus_file)
|
||||
with open(test_project_bus_file, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
|
||||
restricted_test_project_bus_folder = f'{dev_root}/restricted/Salem/TestProject/Code/Include/Platform/Salem'
|
||||
assert os.path.isdir(restricted_test_project_bus_folder)
|
||||
|
||||
restricted_default_name_bus_file = f'{restricted_test_project_bus_folder}/TestProjectBus.h'
|
||||
assert os.path.isfile(restricted_default_name_bus_file)
|
||||
with open(restricted_default_name_bus_file, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
self.instantiate_template_wrapper(tmpdir, engine_template.create_from_template, 'TestTemplate', concrete_contents,
|
||||
templated_contents, keep_license_text, force, expect_failure,
|
||||
template_json_contents, destination_name='TestTemplate')
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents, templated_contents,"
|
||||
" keep_license_text, expect_failure,"
|
||||
" template_json_contents, restricted_template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
True, False,
|
||||
TEST_DEFAULTGEM_TEMPLATE_JSON_CONTENTS, TEST_DEFAULTGEM_TEMPLATE_RESTRICTED_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITHOUT_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
False, False,
|
||||
TEST_DEFAULTGEM_TEMPLATE_JSON_CONTENTS, TEST_DEFAULTGEM_TEMPLATE_RESTRICTED_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_gem(tmpdir,
|
||||
concrete_contents, templated_contents,
|
||||
keep_license_text, expect_failure,
|
||||
template_json_contents, restricted_template_json_contents):
|
||||
dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/')
|
||||
os.makedirs(dev_root, exist_ok=True)
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents, templated_contents,"
|
||||
" keep_license_text, force, expect_failure,"
|
||||
" template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
True, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITHOUT_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
False, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_project(self, tmpdir, concrete_contents, templated_contents, keep_license_text, force,
|
||||
expect_failure, template_json_contents):
|
||||
template_file_map = { 'project.json':
|
||||
'''
|
||||
{
|
||||
"project_name": "${Name}"
|
||||
}
|
||||
'''}
|
||||
|
||||
template_default_folder = f'{dev_root}/Templates/DefaultGem'
|
||||
os.makedirs(template_default_folder, exist_ok=True)
|
||||
# Append the project.json to the list of files to copy from the template
|
||||
template_json_dict = json.loads(template_json_contents)
|
||||
template_json_dict.setdefault('copyFiles', []).append(
|
||||
{
|
||||
"file": "project.json",
|
||||
"origin": "project.json",
|
||||
"isTemplated": True,
|
||||
"isOptional": False
|
||||
})
|
||||
# Convert the python dictionary back into a json string
|
||||
template_json_contents = json.dumps(template_json_dict, indent=4)
|
||||
self.instantiate_template_wrapper(tmpdir, engine_template.create_project, 'TestProject', concrete_contents,
|
||||
templated_contents, keep_license_text, force, expect_failure,
|
||||
template_json_contents, template_file_map, project_name='TestProject')
|
||||
|
||||
template_json = f'{template_default_folder}/template.json'
|
||||
if os.path.isfile(template_json):
|
||||
os.unlink(template_json)
|
||||
with open(template_json, 'w') as s:
|
||||
s.write(template_json_contents)
|
||||
|
||||
default_name_bus_dir = f'{template_default_folder}/Template/Code/Include/' + '${Name}'
|
||||
os.makedirs(default_name_bus_dir, exist_ok=True)
|
||||
@pytest.mark.parametrize(
|
||||
"concrete_contents, templated_contents,"
|
||||
" keep_license_text, force, expect_failure,"
|
||||
" template_json_contents", [
|
||||
pytest.param(TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITH_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
True, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS),
|
||||
pytest.param(TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITHOUT_LICENSE, TEST_TEMPLATED_CONTENT_WITH_LICENSE,
|
||||
False, True, False,
|
||||
TEST_TEMPLATE_JSON_CONTENTS)
|
||||
]
|
||||
)
|
||||
def test_create_gem(self, tmpdir, concrete_contents, templated_contents, keep_license_text, force,
|
||||
expect_failure, template_json_contents):
|
||||
# Create a gem.json file in the template folder
|
||||
template_file_map = {'gem.json':
|
||||
'''
|
||||
{
|
||||
"gem_name": "${Name}"
|
||||
}
|
||||
'''}
|
||||
|
||||
default_name_bus_file = f'{default_name_bus_dir}/' + '${Name}Bus.h'
|
||||
if os.path.isfile(default_name_bus_file):
|
||||
os.unlink(default_name_bus_file)
|
||||
with open(default_name_bus_file, 'w') as s:
|
||||
s.write(templated_contents)
|
||||
|
||||
restricted_template_default_folder = f'{dev_root}/restricted/Salem/Templates/DefaultGem'
|
||||
os.makedirs(restricted_template_default_folder, exist_ok=True)
|
||||
|
||||
restricted_template_json = f'{restricted_template_default_folder}/template.json'
|
||||
if os.path.isfile(restricted_template_json):
|
||||
os.unlink(restricted_template_json)
|
||||
with open(restricted_template_json, 'w') as s:
|
||||
s.write(restricted_template_json_contents)
|
||||
|
||||
restricted_default_name_bus_dir = f'{restricted_template_default_folder}/Template/Code/Include/Platform/Salem'
|
||||
os.makedirs(restricted_default_name_bus_dir, exist_ok=True)
|
||||
|
||||
restricted_default_name_bus_file = f'{restricted_default_name_bus_dir}/' + '${Name}Bus.h'
|
||||
if os.path.isfile(restricted_default_name_bus_file):
|
||||
os.unlink(restricted_default_name_bus_file)
|
||||
with open(restricted_default_name_bus_file, 'w') as s:
|
||||
s.write(templated_contents)
|
||||
|
||||
result = engine_template.create_gem(dev_root, 'TestGem', keep_license_text=keep_license_text)
|
||||
|
||||
if expect_failure:
|
||||
assert result != 0
|
||||
else:
|
||||
assert result == 0
|
||||
|
||||
test_gem_folder = f'{dev_root}/Gems/TestGem'
|
||||
assert os.path.isdir(test_gem_folder)
|
||||
|
||||
test_gem_bus_file = f'{test_gem_folder}/Code/Include/TestGem/TestGemBus.h'
|
||||
assert os.path.isfile(test_gem_bus_file)
|
||||
with open(test_gem_bus_file, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
|
||||
restricted_test_gem_bus_folder = f'{dev_root}/restricted/Salem/Gems/TestGem/Code/Include/Platform/Salem'
|
||||
assert os.path.isdir(restricted_test_gem_bus_folder)
|
||||
|
||||
restricted_default_name_bus_file = f'{restricted_test_gem_bus_folder}/TestGemBus.h'
|
||||
assert os.path.isfile(restricted_default_name_bus_file)
|
||||
with open(restricted_default_name_bus_file, 'r') as s:
|
||||
s_data = s.read()
|
||||
assert s_data == concrete_contents
|
||||
# Append the gem.json to the list of files to copy from the template
|
||||
template_json_dict = json.loads(template_json_contents)
|
||||
template_json_dict.setdefault('copyFiles', []).append(
|
||||
{
|
||||
"file": "gem.json",
|
||||
"origin": "gem.json",
|
||||
"isTemplated": True,
|
||||
"isOptional": False
|
||||
})
|
||||
self.instantiate_template_wrapper(tmpdir, engine_template.create_gem, 'TestGem', concrete_contents,
|
||||
templated_contents, keep_license_text, force, expect_failure,
|
||||
template_json_contents, gem_name='TestGem')
|
||||
|
||||
Reference in New Issue
Block a user