1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmCPackExternalGenerator.h"
4 
5 #include <map>
6 #include <utility>
7 #include <vector>
8 
9 #include <cm/memory>
10 
11 #include <cm3p/json/value.h>
12 #include <cm3p/json/writer.h>
13 
14 #include "cmsys/FStream.hxx"
15 
16 #include "cmCPackComponentGroup.h"
17 #include "cmCPackLog.h"
18 #include "cmMakefile.h"
19 #include "cmStringAlgorithms.h"
20 #include "cmSystemTools.h"
21 #include "cmValue.h"
22 
InitializeInternal()23 int cmCPackExternalGenerator::InitializeInternal()
24 {
25   this->SetOption("CPACK_EXTERNAL_KNOWN_VERSIONS", "1.0");
26 
27   if (!this->ReadListFile("Internal/CPack/CPackExternal.cmake")) {
28     cmCPackLogger(cmCPackLog::LOG_ERROR,
29                   "Error while executing CPackExternal.cmake" << std::endl);
30     return 0;
31   }
32 
33   std::string major = this->GetOption("CPACK_EXTERNAL_SELECTED_MAJOR");
34   if (major == "1") {
35     this->Generator = cm::make_unique<cmCPackExternalVersion1Generator>(this);
36   }
37 
38   return this->Superclass::InitializeInternal();
39 }
40 
PackageFiles()41 int cmCPackExternalGenerator::PackageFiles()
42 {
43   Json::StreamWriterBuilder builder;
44   builder["indentation"] = "  ";
45 
46   std::string filename = "package.json";
47   if (!this->packageFileNames.empty()) {
48     filename = this->packageFileNames[0];
49   }
50 
51   cmsys::ofstream fout(filename.c_str());
52   std::unique_ptr<Json::StreamWriter> jout(builder.newStreamWriter());
53 
54   Json::Value root(Json::objectValue);
55 
56   if (!this->Generator->WriteToJSON(root)) {
57     return 0;
58   }
59 
60   if (jout->write(root, &fout)) {
61     return 0;
62   }
63 
64   cmValue packageScript = this->GetOption("CPACK_EXTERNAL_PACKAGE_SCRIPT");
65   if (cmNonempty(packageScript)) {
66     if (!cmSystemTools::FileIsFullPath(packageScript)) {
67       cmCPackLogger(
68         cmCPackLog::LOG_ERROR,
69         "CPACK_EXTERNAL_PACKAGE_SCRIPT does not contain a full file path"
70           << std::endl);
71       return 0;
72     }
73 
74     bool res = this->MakefileMap->ReadListFile(packageScript);
75 
76     if (cmSystemTools::GetErrorOccuredFlag() || !res) {
77       return 0;
78     }
79 
80     cmValue builtPackages = this->GetOption("CPACK_EXTERNAL_BUILT_PACKAGES");
81     if (builtPackages) {
82       cmExpandList(builtPackages, this->packageFileNames, false);
83     }
84   }
85 
86   return 1;
87 }
88 
SupportsComponentInstallation() const89 bool cmCPackExternalGenerator::SupportsComponentInstallation() const
90 {
91   return true;
92 }
93 
InstallProjectViaInstallCommands(bool setDestDir,const std::string & tempInstallDirectory)94 int cmCPackExternalGenerator::InstallProjectViaInstallCommands(
95   bool setDestDir, const std::string& tempInstallDirectory)
96 {
97   if (this->StagingEnabled()) {
98     return this->cmCPackGenerator::InstallProjectViaInstallCommands(
99       setDestDir, tempInstallDirectory);
100   }
101 
102   return 1;
103 }
104 
InstallProjectViaInstallScript(bool setDestDir,const std::string & tempInstallDirectory)105 int cmCPackExternalGenerator::InstallProjectViaInstallScript(
106   bool setDestDir, const std::string& tempInstallDirectory)
107 {
108   if (this->StagingEnabled()) {
109     return this->cmCPackGenerator::InstallProjectViaInstallScript(
110       setDestDir, tempInstallDirectory);
111   }
112 
113   return 1;
114 }
115 
InstallProjectViaInstalledDirectories(bool setDestDir,const std::string & tempInstallDirectory,const mode_t * default_dir_mode)116 int cmCPackExternalGenerator::InstallProjectViaInstalledDirectories(
117   bool setDestDir, const std::string& tempInstallDirectory,
118   const mode_t* default_dir_mode)
119 {
120   if (this->StagingEnabled()) {
121     return this->cmCPackGenerator::InstallProjectViaInstalledDirectories(
122       setDestDir, tempInstallDirectory, default_dir_mode);
123   }
124 
125   return 1;
126 }
127 
RunPreinstallTarget(const std::string & installProjectName,const std::string & installDirectory,cmGlobalGenerator * globalGenerator,const std::string & buildConfig)128 int cmCPackExternalGenerator::RunPreinstallTarget(
129   const std::string& installProjectName, const std::string& installDirectory,
130   cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
131 {
132   if (this->StagingEnabled()) {
133     return this->cmCPackGenerator::RunPreinstallTarget(
134       installProjectName, installDirectory, globalGenerator, buildConfig);
135   }
136 
137   return 1;
138 }
139 
InstallCMakeProject(bool setDestDir,const std::string & installDirectory,const std::string & baseTempInstallDirectory,const mode_t * default_dir_mode,const std::string & component,bool componentInstall,const std::string & installSubDirectory,const std::string & buildConfig,std::string & absoluteDestFiles)140 int cmCPackExternalGenerator::InstallCMakeProject(
141   bool setDestDir, const std::string& installDirectory,
142   const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
143   const std::string& component, bool componentInstall,
144   const std::string& installSubDirectory, const std::string& buildConfig,
145   std::string& absoluteDestFiles)
146 {
147   if (this->StagingEnabled()) {
148     return this->cmCPackGenerator::InstallCMakeProject(
149       setDestDir, installDirectory, baseTempInstallDirectory, default_dir_mode,
150       component, componentInstall, installSubDirectory, buildConfig,
151       absoluteDestFiles);
152   }
153 
154   return 1;
155 }
156 
StagingEnabled() const157 bool cmCPackExternalGenerator::StagingEnabled() const
158 {
159   return !cmIsOff(this->GetOption("CPACK_EXTERNAL_ENABLE_STAGING"));
160 }
161 
162 cmCPackExternalGenerator::cmCPackExternalVersionGenerator::
cmCPackExternalVersionGenerator(cmCPackExternalGenerator * parent)163   cmCPackExternalVersionGenerator(cmCPackExternalGenerator* parent)
164   : Parent(parent)
165 {
166 }
167 
WriteVersion(Json::Value & root)168 int cmCPackExternalGenerator::cmCPackExternalVersionGenerator::WriteVersion(
169   Json::Value& root)
170 {
171   root["formatVersionMajor"] = this->GetVersionMajor();
172   root["formatVersionMinor"] = this->GetVersionMinor();
173 
174   return 1;
175 }
176 
WriteToJSON(Json::Value & root)177 int cmCPackExternalGenerator::cmCPackExternalVersionGenerator::WriteToJSON(
178   Json::Value& root)
179 {
180   if (!this->WriteVersion(root)) {
181     return 0;
182   }
183 
184   cmValue packageName = this->Parent->GetOption("CPACK_PACKAGE_NAME");
185   if (packageName) {
186     root["packageName"] = *packageName;
187   }
188 
189   cmValue packageVersion = this->Parent->GetOption("CPACK_PACKAGE_VERSION");
190   if (packageVersion) {
191     root["packageVersion"] = *packageVersion;
192   }
193 
194   cmValue packageDescriptionFile =
195     this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
196   if (packageDescriptionFile) {
197     root["packageDescriptionFile"] = *packageDescriptionFile;
198   }
199 
200   cmValue packageDescriptionSummary =
201     this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY");
202   if (packageDescriptionSummary) {
203     root["packageDescriptionSummary"] = *packageDescriptionSummary;
204   }
205 
206   cmValue buildConfigCstr = this->Parent->GetOption("CPACK_BUILD_CONFIG");
207   if (buildConfigCstr) {
208     root["buildConfig"] = *buildConfigCstr;
209   }
210 
211   cmValue defaultDirectoryPermissions =
212     this->Parent->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
213   if (cmNonempty(defaultDirectoryPermissions)) {
214     root["defaultDirectoryPermissions"] = *defaultDirectoryPermissions;
215   }
216   if (cmIsInternallyOn(this->Parent->GetOption("CPACK_SET_DESTDIR"))) {
217     root["setDestdir"] = true;
218     root["packagingInstallPrefix"] =
219       *this->Parent->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
220   } else {
221     root["setDestdir"] = false;
222   }
223 
224   root["stripFiles"] = !cmIsOff(this->Parent->GetOption("CPACK_STRIP_FILES"));
225   root["warnOnAbsoluteInstallDestination"] =
226     this->Parent->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION");
227   root["errorOnAbsoluteInstallDestination"] =
228     this->Parent->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION");
229 
230   Json::Value& projects = root["projects"] = Json::Value(Json::arrayValue);
231   for (auto& project : this->Parent->CMakeProjects) {
232     Json::Value jsonProject(Json::objectValue);
233 
234     jsonProject["projectName"] = project.ProjectName;
235     jsonProject["component"] = project.Component;
236     jsonProject["directory"] = project.Directory;
237     jsonProject["subDirectory"] = project.SubDirectory;
238 
239     Json::Value& installationTypes = jsonProject["installationTypes"] =
240       Json::Value(Json::arrayValue);
241     for (auto& installationType : project.InstallationTypes) {
242       installationTypes.append(installationType->Name);
243     }
244 
245     Json::Value& components = jsonProject["components"] =
246       Json::Value(Json::arrayValue);
247     for (auto& component : project.Components) {
248       components.append(component->Name);
249     }
250 
251     projects.append(jsonProject);
252   }
253 
254   Json::Value& installationTypes = root["installationTypes"] =
255     Json::Value(Json::objectValue);
256   for (auto& installationType : this->Parent->InstallationTypes) {
257     Json::Value& jsonInstallationType =
258       installationTypes[installationType.first] =
259         Json::Value(Json::objectValue);
260 
261     jsonInstallationType["name"] = installationType.second.Name;
262     jsonInstallationType["displayName"] = installationType.second.DisplayName;
263     jsonInstallationType["index"] = installationType.second.Index;
264   }
265 
266   Json::Value& components = root["components"] =
267     Json::Value(Json::objectValue);
268   for (auto& component : this->Parent->Components) {
269     Json::Value& jsonComponent = components[component.first] =
270       Json::Value(Json::objectValue);
271 
272     jsonComponent["name"] = component.second.Name;
273     jsonComponent["displayName"] = component.second.DisplayName;
274     if (component.second.Group) {
275       jsonComponent["group"] = component.second.Group->Name;
276     }
277     jsonComponent["isRequired"] = component.second.IsRequired;
278     jsonComponent["isHidden"] = component.second.IsHidden;
279     jsonComponent["isDisabledByDefault"] =
280       component.second.IsDisabledByDefault;
281     jsonComponent["isDownloaded"] = component.second.IsDownloaded;
282     jsonComponent["description"] = component.second.Description;
283     jsonComponent["archiveFile"] = component.second.ArchiveFile;
284 
285     Json::Value& cmpInstallationTypes = jsonComponent["installationTypes"] =
286       Json::Value(Json::arrayValue);
287     for (auto& installationType : component.second.InstallationTypes) {
288       cmpInstallationTypes.append(installationType->Name);
289     }
290 
291     Json::Value& dependencies = jsonComponent["dependencies"] =
292       Json::Value(Json::arrayValue);
293     for (auto& dep : component.second.Dependencies) {
294       dependencies.append(dep->Name);
295     }
296   }
297 
298   Json::Value& groups = root["componentGroups"] =
299     Json::Value(Json::objectValue);
300   for (auto& group : this->Parent->ComponentGroups) {
301     Json::Value& jsonGroup = groups[group.first] =
302       Json::Value(Json::objectValue);
303 
304     jsonGroup["name"] = group.second.Name;
305     jsonGroup["displayName"] = group.second.DisplayName;
306     jsonGroup["description"] = group.second.Description;
307     jsonGroup["isBold"] = group.second.IsBold;
308     jsonGroup["isExpandedByDefault"] = group.second.IsExpandedByDefault;
309     if (group.second.ParentGroup) {
310       jsonGroup["parentGroup"] = group.second.ParentGroup->Name;
311     }
312 
313     Json::Value& subgroups = jsonGroup["subgroups"] =
314       Json::Value(Json::arrayValue);
315     for (auto& subgroup : group.second.Subgroups) {
316       subgroups.append(subgroup->Name);
317     }
318 
319     Json::Value& groupComponents = jsonGroup["components"] =
320       Json::Value(Json::arrayValue);
321     for (auto& component : group.second.Components) {
322       groupComponents.append(component->Name);
323     }
324   }
325 
326   return 1;
327 }
328