PhoenixGenerator  3.4.0
Generate code from template files and projects in C++, Rust, Python and wrapped C++ to Python
Loading...
Searching...
No Matches
project_generator_load.cpp
Go to the documentation of this file.
1/***************************************
2 Auteur : Pierre Aubert
3 Mail : pierre.aubert@lapp.in2p3.fr
4 Licence : LGPL-3.0-only
5****************************************/
6
7#include "phoenix_color.h"
8#include "parser_toml.h"
10
12
16bool project_generator_split_dependencies(ProjectConfig & config, std::vector<PString> & vecDependencies){
17 for(const PString & depStr : vecDependencies){
18 PString name(""), min_version(""), max_version("");
19 std::istringstream iss(depStr);
20 std::vector<PString> depValues;
21 PString token;
22 while (iss >> token){depValues.push_back(token);}
23 if(!depValues.empty()){
24 name = depValues[0];
25 for(size_t i=1; i<depValues.size(); ++i){
26 if(depValues[i].isSameBegining("==")) {
27 // User specifies the exact version
28 min_version = depValues[i];
29 max_version = "";
30 break;
31 }
32 if(depValues[i].isSameBegining(">=") || depValues[i].isSameBegining(">")) {
33 min_version = depValues[i];
34 if(!min_version.empty() && min_version.back() == ',') min_version.pop_back();
35 }
36 if(depValues[i].isSameBegining("<=") || depValues[i].isSameBegining("<")) {
37 max_version = depValues[i];
38 if(!max_version.empty() && max_version.back() == ',') max_version.pop_back();
39 }
40 }
41 }else{
42 name = depStr;
43 }
44 // Fill the matching attributes
45 config.mapDependencies[name].setName(name);
46 config.mapDependencies[name].setMinVersion(min_version);
47 config.mapDependencies[name].setMaxVersion(max_version);
48 }
49 return true;
50}
51
53
57bool parseProjectMembers(ProjectMembersMap & memberMap, const DicoValue * memberDico){
58 if(memberDico == NULL || !memberDico->hasVec()){
59 return false;
60 }
61 const std::vector<DicoValue> & vecMember = memberDico->getVecChild();
62 for(size_t iMember = 0; iMember < vecMember.size(); iMember++){
63 const DicoValue & memberData = vecMember[iMember];
64 if(memberData.hasMap()){
65 PProjectMembers member;
66 member.setLastName(phoenix_get_string(memberData, "lastName", ""));
67 member.setFirstName(phoenix_get_string(memberData, "firstName", ""));
68 member.setAffiliation(phoenix_get_string(memberData, "affiliation", ""));
69 member.setEmail(phoenix_get_string(memberData, "mail", ""));
70
71 // Use lastName + firstName as key to handle duplicate lastNames
72 PString key = member.getLastName() + "_" + member.getFirstName();
73 memberMap[key] = member;
74 }
75 }
76 return true;
77}
78
80
84bool project_generator_loadConfig(ProjectConfig & config, const PPath & descriptionFile){
85 DicoValue dico;
86 if(!parser_toml(dico, descriptionFile)){
87 std::cerr << termRed() << "project_generator_loadConfig : cannot parse config file '"<<descriptionFile<<"'" << termDefault() << std::endl;
88 return false;
89 }
90 DicoValue * mapProject = dico.getMap("project");
91 if(mapProject == NULL){
92 std::cerr << termRed() << "project_generator_loadConfig : Missing [project] in config file '"<<descriptionFile<<"'" << termDefault() << std::endl;
93 return false;
94 }
95 const PVecString vecRequiredKey{"name", "url", "version", "description", "main_branch", "ci_toolkit_version", "ci_toolkit_url", "authors"};
96 PVecString vecMissingKey;
97 for(const PString & requiredKey : vecRequiredKey){
98 if(!mapProject->isKeyExist(requiredKey)){
99 vecMissingKey.push_back(requiredKey);
100 }
101 }
102 if(!vecMissingKey.empty()){
103 std::cerr << termRed() << "project_generator_loadConfig : missing required attribute(s) in [project] of config file '"<<descriptionFile<<"' : ";
104 for(size_t iMissingKey = 0LU; iMissingKey < vecMissingKey.size(); ++iMissingKey){
105 if(iMissingKey != 0LU){std::cerr << ", ";}
106 std::cerr << vecMissingKey[iMissingKey];
107 }
108 std::cerr << termDefault() << std::endl;
109 return false;
110 }
111 config.name = phoenix_get_string(*mapProject, "name", "MyAwesomeProject");
112 config.url = phoenix_get_string(*mapProject, "url", "need and url");
113 config.version = phoenix_get_string(*mapProject, "version", "0.1.0");
114 config.description = phoenix_get_string(*mapProject, "description", "A very important project");
115 config.mainBranch = phoenix_get_string(*mapProject, "main_branch", "main");
116 config.runnerTag = phoenix_get_string(*mapProject, "runner_tag", ""); //Could be MUST_big_runner
117 config.ciToolkitVersion = phoenix_get_string(*mapProject, "ci_toolkit_version", "8.1.4"); //Default version if not specified
118 config.ciToolkitUrl = phoenix_get_string(*mapProject, "ci_toolkit_url", "https://gitlab.in2p3.fr/CTA-LAPP/PHOENIX_LIBS2/citoolkit/phoenixcitoolkitcpp/phoenix-workflow-cpp");
119
120 //Authors
121 if(mapProject->isKeyExist("authors")){
122 const DicoValue * authorDico = mapProject->getMap("authors");
123 parseProjectMembers(config.authorMap, authorDico);
124 }
125 //Dependencies
126 if(mapProject->isKeyExist("dependencies")){
127 const DicoValue * depDico = mapProject->getMap("dependencies");
128 if(depDico != NULL && depDico->hasVec()){
129 const std::vector<DicoValue> & vecDep = depDico->getVecChild();
130 std::vector<PString> depList;
131 for(size_t iDep = 0; iDep < vecDep.size(); iDep++){
132 depList.push_back(vecDep[iDep].getString());
133 }
134 if(!project_generator_split_dependencies(config, depList)){
135 std::cerr << termRed() << "project_generator_loadConfig : cannot parse dependencies in config file '"<<descriptionFile<<"'" << termDefault() << std::endl;
136 return false;
137 }
138 }
139 }
140 return true;
141}
142
143
145
150bool generate_empty_config(PPath & outFileName, const PString & name, PString& minVersion, PString& maxVersion){
151 PString body;
152 body += "# To fill the package info use the description below, then remove the commented lines.\n";
153 body += "[[Package]]\n";
154 body += "# This is the name of your package (eg on your git repository)\n";
155 body += "name = \"" + name + "\"\n";
156 body += "# # This is the name of your package for the pixi.toml. You can find the name of the pixi package by searching it on prefix.dev \n";
157 body += "pixi_name = \"\"\n";
158 body += "# If your package provides a CMake configuration file (find File), this should be the value used in find_package().\n";
159 body += "cmake_find = \"\"\n";
160 body += "# If your package provides a CMake configuration library, this should be the name of the main library target provided by the package.\n";
161 body += "cmake_lib = \"\"\n";
162 body += "#This is the URL of your package repository if you want to use the pull_extra_module feature of PhoenixCMake (only for Phoenix packages)\n";
163 body += "url = \"\"\n\n";
164 return outFileName.saveFileContent(body);
165}
166
168
174bool check_package_file(const PPath & fileName, const PString & name, const PPath & packageDir, PPackageAttribute & pkgAttr){
175 bool found = false;
176 if(fileName.getExtension() != "toml"){
177 return found;
178 }
179 DicoValue dico;
180 PPath tomlFile = packageDir / fileName;
181 if(!parser_toml(dico, tomlFile)){
182 return found;
183 }
184 const DicoValue* mapPkg = dico.getMap("Package");
185 const std::vector<DicoValue> & vecChild = mapPkg->getVecChild();
186 for(size_t iChild = 0; iChild < vecChild.size() && !found; ++iChild){
187 const DicoValue & pkgBlock = vecChild[iChild];
188 PString tomlName = phoenix_get_string(pkgBlock, "name", "");
189 if(tomlName == name){
190 pkgAttr.setUrl(phoenix_get_string(pkgBlock, "url", ""));
191 pkgAttr.setPixiName(phoenix_get_string(pkgBlock, "pixi_name", ""));
192 pkgAttr.setCmakeFind(phoenix_get_string(pkgBlock, "cmake_find", ""));
193 pkgAttr.setCmakeLib(phoenix_get_string(pkgBlock, "cmake_lib", ""));
194 if(pkgAttr.getUrl() != "" || pkgAttr.getPixiName() != "" || pkgAttr.getCmakeFind() != "" || pkgAttr.getCmakeLib() != ""){
195 found = true;
196 }else{
197 std::cerr << termRed() << "check_package_file : incomplete package file '"<<tomlFile<<"'" << termDefault() << std::endl;
198 }
199 }
200 }
201 return found;
202}
203
205
211bool is_package_in_dir(std::vector<PPath> & packageFileNames, const PString & name, const PPath & packageDir, PPackageAttribute & pkgAttr){
212 for(size_t iFile = 0; iFile < packageFileNames.size(); ++iFile){
213 if(check_package_file(packageFileNames[iFile], name, packageDir, pkgAttr)){
214 std::cout << termGreen() << "Found package '" << name << "' in file '" << packageFileNames[iFile] << "'." << termDefault() << std::endl;
215 return true;
216 }
217 }
218 return false;
219}
220
222
226void is_generate_empty_config_ok(PPath & tomlFile, const PString & name, PPackageAttribute & pkgAttr){
227 if(!generate_empty_config(tomlFile, name, pkgAttr.getMinVersion(), pkgAttr.getMaxVersion())){
228 std::cerr << termRed() << "project_generator_loadPackageInfo : cannot generate empty config file for package '"<<name<<"'" << termDefault() << std::endl;
229 }
230 else{
231 std::cerr << termYellow() << "Package '" << name << "' does not exist in the configuration. A skeleton file has been created at '" << tomlFile << "'. Please complete it manually." << termDefault() << std::endl;
232 }
233}
234
236
240 // 1. Get all files in "share/PhoenixGenerator/Packages"
241 PPath packageDir = PPath(SYSTEM_INSTALL_DIR) / PPath("share") / PPath("PhoenixGenerator") / PPath("Packages");
242 std::cout << "Loading package info from directory '" << packageDir << "'." << std::endl;
243 PVecPath packageFileNames = packageDir.getAllFileInDir();
244 size_t packageNotFound = 0;
245
246 // 2. Search in toml files in PackageDir for each package, and fill other attributes if found
247 for(PackageMap::iterator it = config.mapDependencies.begin(); it != config.mapDependencies.end(); ++it){
248 const PString & name = it->first;
249 PPackageAttribute & pkgAttr = it->second;
250
251 if(!is_package_in_dir(packageFileNames, name, packageDir, pkgAttr)){
252 PPath localPackageDir = PPath::getCurrentDirectory() / PPath("Packages");
253 std::cout << "saving file in local dir: " << localPackageDir << std::endl;
254 PPath tomlFile = localPackageDir / PPath(name + ".toml");
255 if(localPackageDir.isDirectoryExist()){
256 PVecPath localPackageFileNames = localPackageDir.getAllFileInDir();
257 if(!is_package_in_dir(localPackageFileNames, name, localPackageDir, pkgAttr)){
258 is_generate_empty_config_ok(tomlFile, name, pkgAttr);
259 packageNotFound++;
260 }
261 }
262 //If the folder does not exists it means that the package we are looking for is unknown, so we create an empty config file inside the new created Packages/ directory
263 else{
264 localPackageDir.createDirectory();
265 is_generate_empty_config_ok(tomlFile, name, pkgAttr);
266 packageNotFound++;
267 }
268 }
269 }
270 if(packageNotFound != 0){
271 std::cout << termRed() << packageNotFound << " package(s) not found in the package directory." << termDefault() << std::endl;
272 }
273 return packageNotFound == 0;
274}
275
276
Describes a package attributes.
void setCmakeLib(const PString &cmakeLib)
Sets the cmakeLib of the PPackageAttribute.
void setPixiName(const PString &pixiName)
Sets the pixiName of the PPackageAttribute.
const PString & getMaxVersion() const
Gets the maxVersion of the PPackageAttribute.
const PString & getUrl() const
Gets the url of the PPackageAttribute.
const PString & getCmakeFind() const
Gets the cmakeFind of the PPackageAttribute.
const PString & getCmakeLib() const
Gets the cmakeLib of the PPackageAttribute.
void setUrl(const PString &url)
Sets the url of the PPackageAttribute.
void setCmakeFind(const PString &cmakeFind)
Sets the cmakeFind of the PPackageAttribute.
const PString & getMinVersion() const
Gets the minVersion of the PPackageAttribute.
const PString & getPixiName() const
Gets the pixiName of the PPackageAttribute.
Describes a package attributes.
void setAffiliation(const PString &affiliation)
Sets the affiliation of the PProjectMembers.
const PString & getFirstName() const
Gets the firstName of the PProjectMembers.
void setFirstName(const PString &firstName)
Sets the firstName of the PProjectMembers.
void setEmail(const PString &email)
Sets the email of the PProjectMembers.
const PString & getLastName() const
Gets the lastName of the PProjectMembers.
void setLastName(const PString &lastName)
Sets the lastName of the PProjectMembers.
bool is_package_in_dir(std::vector< PPath > &packageFileNames, const PString &name, const PPath &packageDir, PPackageAttribute &pkgAttr)
Search the package in the package directory.
void is_generate_empty_config_ok(PPath &tomlFile, const PString &name, PPackageAttribute &pkgAttr)
Generate an empty package info file skeleton and notify the user.
bool project_generator_loadPackageInfo(ProjectConfig &config)
This function should load the package info file from share/PhoenixGenerator/Packages and retrieve the...
bool check_package_file(const PPath &fileName, const PString &name, const PPath &packageDir, PPackageAttribute &pkgAttr)
Check the package file.
bool generate_empty_config(PPath &outFileName, const PString &name, PString &minVersion, PString &maxVersion)
Generate an empty package info file skeleton.
bool project_generator_split_dependencies(ProjectConfig &config, std::vector< PString > &vecDependencies)
Split dependencies strings into name, min_version, max_version and fill the map of dependencies.
bool parseProjectMembers(ProjectMembersMap &memberMap, const DicoValue *memberDico)
Parse project members (authors, maintainers, contributors) from TOML data.
bool project_generator_loadConfig(ProjectConfig &config, const PPath &descriptionFile)
Load the project configuration.
std::map< PString, PProjectMembers > ProjectMembersMap
Configuration of the project.
PString description
Description of the project.
PString name
Name of the project.
PackageMap mapDependencies
Map of all dependencies of the project with structure PPackageAttribute values.
ProjectMembersMap authorMap
Map of authors of the project.
PString runnerTag
Specific runner tag if needed (could be MUST_big_runner).
PString ciToolkitUrl
CI toolkit url.
PString ciToolkitVersion
Version of the Phoenix CI toolkit component (optional, defaults to 3.0.4).
PString url
Project url.
PString mainBranch
Main branch of hte project.
PString version
Project version.