TDME2  1.9.200
createinstaller-main.cpp
Go to the documentation of this file.
1 #include <cassert>
2 #include <filesystem>
3 #include <fstream>
4 #include <memory>
5 #include <string>
6 #include <vector>
7 
8 #include <ext/zlib/zlib.h>
9 
10 #include <tdme/tdme.h>
12 #include <tdme/engine/Version.h>
17 #include <tdme/utilities/Console.h>
22 #include <tdme/utilities/Time.h>
23 
24 using std::make_unique;
25 using std::ofstream;
26 using std::string;
27 using std::to_string;
28 using std::unique_ptr;
29 using std::vector;
30 
43 
44 namespace tdme {
45 namespace tools {
46 namespace cli {
47 namespace installer {
48  struct FileInformation {
49  string name;
50  uint64_t bytes;
51  uint8_t compressed;
52  uint64_t bytesCompressed;
53  uint64_t offset;
54  bool executable;
55  };
56 };
57 };
58 };
59 };
60 
62 
63 static void scanPathResources(const string& path, vector<string>& totalFiles) {
64  class ListFilter : public virtual FileNameFilter {
65  public:
66  virtual ~ListFilter() {}
67 
68  bool accept(const string& pathName, const string& fileName) override {
69  if (fileName == ".") return false;
70  if (fileName == "..") return false;
71  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) return true;
72  auto fileNameLowerCase = StringTools::toLowerCase(fileName);
73  // audio
74  if (StringTools::endsWith(fileNameLowerCase, ".ogg") == true) return true;
75  // fonts
76  if (StringTools::endsWith(fileNameLowerCase, ".ttf") == true) return true;
77  // images
78  if (StringTools::endsWith(fileNameLowerCase, ".icns") == true) return true;
79  if (StringTools::endsWith(fileNameLowerCase, ".ico") == true) return true;
80  if (StringTools::endsWith(fileNameLowerCase, ".png") == true) return true;
81  // videos
82  if (StringTools::endsWith(fileNameLowerCase, ".mpg") == true) return true;
83  // models
84  if (StringTools::endsWith(fileNameLowerCase, ".dae") == true) return true;
85  if (StringTools::endsWith(fileNameLowerCase, ".fbx") == true) return true;
86  if (StringTools::endsWith(fileNameLowerCase, ".glb") == true) return true;
87  if (StringTools::endsWith(fileNameLowerCase, ".tm") == true) return true;
88  // property files
89  if (StringTools::endsWith(fileNameLowerCase, ".properties") == true) return true;
90  // shader
91  if (StringTools::endsWith(fileNameLowerCase, ".cl") == true) return true;
92  if (StringTools::endsWith(fileNameLowerCase, ".frag") == true) return true;
93  if (StringTools::endsWith(fileNameLowerCase, ".glsl") == true) return true;
94  if (StringTools::endsWith(fileNameLowerCase, ".vert") == true) return true;
95  // tdme empty
96  if (StringTools::endsWith(fileNameLowerCase, ".tempty") == true) return true;
97  // tdme trigger
98  if (StringTools::endsWith(fileNameLowerCase, ".ttrigger") == true) return true;
99  // tdme environment maps
100  if (StringTools::endsWith(fileNameLowerCase, ".tenvmap") == true) return true;
101  // tdme model
102  if (StringTools::endsWith(fileNameLowerCase, ".tmodel") == true) return true;
103  // tdme scene
104  if (StringTools::endsWith(fileNameLowerCase, ".tscene") == true) return true;
105  // tdme particle system
106  if (StringTools::endsWith(fileNameLowerCase, ".tparticle") == true) return true;
107  // tdme terrain
108  if (StringTools::endsWith(fileNameLowerCase, ".tterrain") == true) return true;
109  // tdme script
110  if (StringTools::endsWith(fileNameLowerCase, ".tscript") == true) return true;
111  // xml
112  if (StringTools::endsWith(fileNameLowerCase, ".xml") == true) return true;
113  // plist
114  if (StringTools::endsWith(fileNameLowerCase, ".plist") == true) return true;
115  // markdown
116  if (StringTools::endsWith(fileNameLowerCase, ".md") == true) return true;
117  // license
118  if (fileNameLowerCase == "license") return true;
119  // files without ending
120  if (fileName.rfind(".") == string::npos ||
121  (fileName.rfind("/") != string::npos &&
122  fileName.rfind(".") < fileName.rfind("/"))) {
123  return true;
124  }
125  //
126  return false;
127  }
128  };
129 
130  ListFilter listFilter;
131  vector<string> files;
132 
133  if (FileSystem::getInstance()->exists(path) == false) {
134  Console::println("Error: scanPathResources: file does not exist: " + path);
135  } else
136  if (FileSystem::getInstance()->isPath(path) == false) {
137  if (listFilter.accept(".", path) == true) {
138  totalFiles.push_back(path);
139  } else {
140  Console::println("Error: scanPathResources: file exist, but does not match filter: " + path);
141  }
142  } else {
143  FileSystem::getInstance()->list(path, files, &listFilter);
144  for (const auto& fileName: files) {
145  if (FileSystem::getInstance()->isPath(path + "/" + fileName) == false) {
146  totalFiles.push_back(path + "/" + fileName);
147  } else {
148  scanPathResources(path + "/" + fileName, totalFiles);
149  }
150  }
151  }
152 }
153 
154 static void scanPathLibraries(const string& path, vector<string>& totalFiles) {
155  class ListFilter : public virtual FileNameFilter {
156  public:
157  virtual ~ListFilter() {}
158 
159  bool accept(const string& pathName, const string& fileName) override {
160  if (fileName == ".") return false;
161  if (fileName == "..") return false;
162  // path
163  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) {
164  // Apple: no .dSYM folders
165  #if defined(__APPLE__)
166  if (StringTools::endsWith(fileName, ".dSYM") == true) return false;
167  #endif
168  return true;
169  };
170  // static libraries
171  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".a") == true) return true;
172  // dynamic libraries
173  #if defined(_WIN32)
174  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".dll") == true) return true;
175  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".lib") == true) return true;
176  #elif defined(__APPLE__)
177  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".dylib") == true) return true;
178  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".so") == true) return true;
179  #else
180  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".so") == true) return true;
181  #endif
182  //
183  return false;
184  }
185  };
186 
187  ListFilter listFilter;
188  vector<string> files;
189 
190  if (FileSystem::getInstance()->exists(path) == false) {
191  Console::println("Error: scanPathLibraries: file does not exist: " + path);
192  } else
193  if (FileSystem::getInstance()->isPath(path) == false) {
194  if (listFilter.accept(".", path) == true) {
195  totalFiles.push_back(path);
196  } else {
197  Console::println("Error: scanPathLibraries: file exist, but does not match filter: " + path);
198  }
199  } else {
200  FileSystem::getInstance()->list(path, files, &listFilter);
201  for (const auto& fileName: files) {
202  if (FileSystem::getInstance()->isPath(path + "/" + fileName) == false) {
203  totalFiles.push_back(path + "/" + fileName);
204  } else {
205  scanPathLibraries(path + "/" + fileName, totalFiles);
206  }
207  }
208  }
209 }
210 
211 static void scanPathHeaders(const string& path, vector<string>& totalFiles) {
212  class ListFilter : public virtual FileNameFilter {
213  public:
214  virtual ~ListFilter() {}
215 
216  bool accept(const string& pathName, const string& fileName) override {
217  if (fileName == ".") return false;
218  if (fileName == "..") return false;
219  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) return true;
220  // headers
221  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".h") == true) return true;
222  //
223  return false;
224  }
225  };
226 
227  ListFilter listFilter;
228  vector<string> files;
229 
230  if (FileSystem::getInstance()->exists(path) == false) {
231  Console::println("Error: scanPathHeaders: file does not exist: " + path);
232  } else
233  if (FileSystem::getInstance()->isPath(path) == false) {
234  if (listFilter.accept(".", path) == true) {
235  totalFiles.push_back(path);
236  } else {
237  Console::println("Error: scanPathHeaders: file exist, but does not match filter: " + path);
238  }
239  } else {
240  FileSystem::getInstance()->list(path, files, &listFilter);
241  for (const auto& fileName: files) {
242  if (FileSystem::getInstance()->isPath(path + "/" + fileName) == false) {
243  totalFiles.push_back(path + "/" + fileName);
244  } else {
245  scanPathHeaders(path + "/" + fileName, totalFiles);
246  }
247  }
248  }
249 }
250 
251 static void scanPathExecutables(const string& path, vector<string>& totalFiles) {
252  class ListFilter : public virtual FileNameFilter {
253  public:
254  virtual ~ListFilter() {}
255 
256  bool accept(const string& pathName, const string& fileName) override {
257  if (fileName == ".") return false;
258  if (fileName == "..") return false;
259  // path
260  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) {
261  // Apple: no .dSYM folders
262  #if defined(__APPLE__)
263  if (StringTools::endsWith(fileName, ".dSYM") == true) return false;
264  #endif
265  return true;
266  };
267  // win32
268  #if defined(_WIN32)
269  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".exe") == true) return true;
270  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".dll") == true) return true;
271  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".bat") == true) return true;
272  #elif defined(__APPLE__)
273  // TODO: fix me, paths get submitted here too as filename
274  if (fileName.rfind(".") == string::npos ||
275  (fileName.rfind("/") != string::npos &&
276  fileName.rfind(".") < fileName.rfind("/"))) {
277  return true;
278  }
279  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".dylib") == true) return true;
280  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".so") == true) return true;
281  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".sh") == true) return true;
282  #else
283  // TODO: fix me, paths get submitted here too as filename
284  if (fileName.rfind(".") == string::npos ||
285  (fileName.rfind("/") != string::npos &&
286  fileName.rfind(".") < fileName.rfind("/"))) {
287  return true;
288  }
289  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".so") == true) return true;
290  if (StringTools::endsWith(StringTools::toLowerCase(fileName), ".sh") == true) return true;
291  #endif
292  //
293  return false;
294  }
295  };
296 
297  ListFilter listFilter;
298  vector<string> files;
299 
300  if (FileSystem::getInstance()->exists(path) == false) {
301  Console::println("Error: scanPathExecutables: file does not exist: " + path);
302  } else
303  if (FileSystem::getInstance()->isPath(path) == false) {
304  if (listFilter.accept(".", path) == true) {
305  totalFiles.push_back(path);
306  } else {
307  Console::println("Error: scanPathExecutables: file exist, but does not match filter: " + path);
308  }
309  } else {
310  FileSystem::getInstance()->list(path, files, &listFilter);
311  for (const auto& fileName: files) {
312  if (FileSystem::getInstance()->isPath(path + "/" + fileName) == false) {
313  totalFiles.push_back(path + "/" + fileName);
314  } else {
315  scanPathExecutables(path + "/" + fileName, totalFiles);
316  }
317  }
318  }
319 }
320 
321 void processFile(const string& fileName, vector<FileInformation>& fileInformations, const string& archiveFileName, bool executableFile, const string& basePath, const string& executablePath = string()) {
322  // read content
323  vector<uint8_t> content;
324  FileSystem::getInstance()->getContent(
325  FileSystem::getInstance()->getPathName(fileName),
326  FileSystem::getInstance()->getFileName(fileName),
327  content
328  );
329 
330  auto fileNameToUse = StringTools::startsWith(fileName, basePath + "/") == true?StringTools::substring(fileName, (basePath + "/").size(), fileName.size()):fileName;
331  // remove prefix if requested
332  if (executableFile == true && fileName.find_last_of('/') != string::npos) {
333  fileNameToUse = (executablePath.empty() == false?executablePath + "/":"") + StringTools::substring(fileNameToUse, fileNameToUse.find_last_of('/') + 1);
334  }
335 
336  Console::print(archiveFileName + ": Processing file: " + fileNameToUse);
337 
338  // append to archive
339  ofstream ofs(std::filesystem::u8path(archiveFileName), ofstream::binary | ofstream::app);
340  ofs.seekp(0, ofstream::end);
341  uint64_t fileOffset = ofs.tellp();
342 
343  //
344  uint64_t bytesCompressed = 0;
345  uint8_t compressed = 1;
346 
347  // always use compression for now
348  if (compressed == 1) {
349  // see: https://www.zlib.net/zpipe.c
350  #define CHUNK 16384
351 
352  int ret;
353  int flush;
354  size_t have;
355  z_stream strm;
356  unsigned char in[CHUNK];
357  unsigned char out[CHUNK];
358 
359  /* allocate deflate state */
360  strm.zalloc = Z_NULL;
361  strm.zfree = Z_NULL;
362  strm.opaque = Z_NULL;
363  ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
364  if (ret != Z_OK) {
365  Console::println("processFile(): Error compressing file: Aborting");
366  return;
367  }
368 
369  // compress until end of file
370  size_t inPosition = 0;
371  size_t inBytes = content.size();
372  do {
373  auto inStartPosition = inPosition;
374  for (size_t i = 0; i < CHUNK; i++) {
375  if (inPosition == inBytes) break;
376  in[i] = content[inPosition];
377  inPosition++;
378  }
379  strm.avail_in = inPosition - inStartPosition;
380  flush = inPosition == inBytes?Z_FINISH:Z_NO_FLUSH;
381  strm.next_in = in;
382 
383  // run deflate() on input until output buffer not full, finish compression if all of source has been read in
384  do {
385  strm.avail_out = CHUNK;
386  strm.next_out = out;
387  ret = deflate(&strm, flush); // no bad return value
388  assert(ret != Z_STREAM_ERROR); // state not clobbered
389  have = CHUNK - strm.avail_out;
390  ofs.write((char*)out, have);
391  bytesCompressed+= have;
392  } while (strm.avail_out == 0);
393  assert(strm.avail_in == 0); // all input will be used
394 
395  // done when last data in file processed
396  } while (flush != Z_FINISH);
397  assert(ret == Z_STREAM_END); // stream will be complete
398 
399  // clean up and return
400  (void)deflateEnd(&strm);
401  } else {
402  ofs.write((char*)content.data(), content.size());
403  }
404  ofs.close();
405 
406  // store file information
407  FileInformation fileInformation;
408  fileInformation.name = fileNameToUse;
409  fileInformation.bytes = content.size();
410  fileInformation.compressed = compressed;
411  fileInformation.bytesCompressed = bytesCompressed;
412  fileInformation.offset = fileOffset;
413  fileInformation.executable = executableFile;
414  fileInformations.push_back(fileInformation);
415 
416  // done
417  Console::println(", processed " + to_string(content.size()) + " bytes" + (compressed == 1?", " + to_string(bytesCompressed) + " bytes compressed":""));
418 }
419 
420 #if defined(__APPLE__)
421 void createMacApplication(const Properties& installerProperties, const string& fileName, const string& pathName = string()) {
422  auto _pathName = pathName.empty() == true?"":pathName + "/";
423  auto _fileName = StringTools::substring(fileName, fileName.rfind('/') + 1, fileName.size());
424  auto _filePath = StringTools::substring(fileName, 0, fileName.rfind('/'));
425  auto startMenuName = installerProperties.get("startmenu_" + StringTools::toLowerCase(_fileName), "");
426  if (startMenuName.empty() == false) {
427  auto executablePathName = FileSystem::getInstance()->getPathName(fileName);
428  auto executableFileName = FileSystem::getInstance()->getFileName(fileName);
429  auto iconFileName = StringTools::toLowerCase(executableFileName) + "-icon.icns";
430  if (FileSystem::getInstance()->exists("resources/platforms/macos/" + iconFileName) == false &&
431  FileSystem::getInstance()->exists(executablePathName + "/resources/platforms/macos/" + iconFileName) == false) iconFileName = "default-icon.icns";
432  auto infoplistFile = FileSystem::getInstance()->getContentAsString("resources/platforms/macos", "Info.plist");
433  infoplistFile = StringTools::replace(infoplistFile, "{__EXECUTABLE__}", executableFileName);
434  infoplistFile = StringTools::replace(infoplistFile, "{__EXECUTABLE_LOWERCASE__}", StringTools::toLowerCase(executableFileName));
435  infoplistFile = StringTools::replace(infoplistFile, "{__ICON__}", "icon.icns");
436  infoplistFile = StringTools::replace(infoplistFile, "{__COPYRIGHT__}", Version::getCopyright());
437  infoplistFile = StringTools::replace(infoplistFile, "{__VERSION__}", Version::getVersion());
438  FileSystem::getInstance()->createPath(_pathName + executableFileName + ".app");
439  FileSystem::getInstance()->createPath(_pathName + executableFileName + ".app/Contents");
440  FileSystem::getInstance()->createPath(_pathName + executableFileName + ".app/Contents/MacOS");
441  FileSystem::getInstance()->createPath(_pathName + executableFileName + ".app/Contents/Resources");
442  FileSystem::getStandardFileSystem()->setContentFromString(
443  _pathName + executableFileName + ".app/Contents",
444  "Info.plist",
445  infoplistFile
446  );
447  {
448  vector<uint8_t> content;
449  FileSystem::getInstance()->getContent(
450  "resources/platforms/macos",
451  iconFileName,
452  content
453  );
454  FileSystem::getStandardFileSystem()->setContent(
455  _pathName + executableFileName + ".app/Contents/Resources",
456  "icon.icns",
457  content
458  );
459  }
460  {
461  vector<uint8_t> content;
462  FileSystem::getInstance()->getContent(
463  executablePathName,
464  executableFileName,
465  content
466  );
467  FileSystem::getInstance()->setContent(
468  _pathName + executableFileName + ".app/Contents/MacOS",
469  executableFileName,
470  content
471  );
472  FileSystem::getInstance()->setExecutable(
473  _pathName + executableFileName + ".app/Contents/MacOS",
474  executableFileName
475  );
476  }
477  auto codeSignCommand = "codesign -s \"" + installerProperties.get("macos_codesign_identity", "No identity") + "\" \"" + _pathName + executableFileName + ".app\"";
478  Console::println("Signing '" + fileName + "': " + codeSignCommand);
479  Console::println(Application::execute(codeSignCommand));
480  }
481 }
482 #endif
483 
484 int main(int argc, char** argv)
485 {
486  // TODO: error handling
487 
488  //
489  Console::println(string("create-installer ") + Version::getVersion());
490  Console::println(Version::getCopyright());
491  Console::println();
492 
493  //
494  string tdmePath = "../tdme2";
495  auto cpu = Application::getCPUName();
496  auto os = Application::getOSName();
497  auto fileNameTime = StringTools::replace(StringTools::replace(StringTools::replace(Time::getAsString(), " ", "-" ), ":", ""), "-", "");
498 
499  //
500  Properties installerProperties;
501  installerProperties.load("resources/installer", "installer.properties");
502  for (auto componentIdx = 0; true; componentIdx++) {
503  auto componentId = componentIdx == 0?"installer":"component" + to_string(componentIdx);
504  auto componentName = installerProperties.get(componentId, "");
505  if (componentName.empty() == true) break;
506  Console::println("Having component: " + to_string(componentIdx) + ": " + componentName);
507  auto componentInclude = installerProperties.get(componentId + "_include", "");
508  if (componentInclude.empty() == true) {
509  Console::println("component: " + to_string(componentIdx) + ": missing includes. Skipping.");
510  continue;
511  }
512 
513  //
514  auto componentFileName = os + "-" + cpu + "-" + StringTools::replace(StringTools::replace(componentName, " - ", "-"), " ", "-") + "-" + fileNameTime + ".ta";
515  //
516  Console::println("Component: " + to_string(componentIdx) + ": component file name: " + componentFileName);
517 
518  if (FileSystem::getInstance()->exists("installer") == false) {
519  FileSystem::getInstance()->createPath("installer");
520  }
521 
522  // reset archive
523  {
524  ofstream ofs(std::filesystem::u8path("installer/" + componentFileName), ofstream::binary | ofstream::trunc);
525  ofs.close();
526  }
527 
528  //
529  vector<FileInformation> fileInformations;
530  vector<string> filesData;
531  vector<string> filesBin;
532 
533  // parse includes definitions
534  StringTokenizer t;
535  StringTokenizer t2;
536  t.tokenize(componentInclude, ",");
537  while (t.hasMoreTokens() == true) {
538  auto componentIncludeDefinition = t.nextToken();
539  t2.tokenize(componentIncludeDefinition, ":");
540  string type = t2.hasMoreTokens() == true?t2.nextToken():"";
541  string file = t2.hasMoreTokens() == true?t2.nextToken():"";
542  if (type.empty() == true || file.empty() == true) {
543  Console::println("Component: " + to_string(componentIdx) + ": type or file empty. Skipping");
544  continue;
545  }
546  Console::println("Component: " + to_string(componentIdx) + ": type = " + type + "; file = " + file);
547 
548  // scan files
549  if (type == "exe") {
550  StringTokenizer t;
551  t.tokenize(installerProperties.get("exe_path", ""), ",");
552  while (t.hasMoreTokens() == true) {
553  scanPathExecutables(t.nextToken() + "/" + file, filesBin);
554  }
555  } else
556  if (type == "!exe") {
557  StringTokenizer t;
558  t.tokenize(installerProperties.get("exe_path", ""), ",");
559  while (t.hasMoreTokens() == true) {
560  scanPathExecutables(tdmePath + "/" + t.nextToken() + "/" + file, filesBin);
561  }
562  } else
563  if (type == "res") {
564  scanPathResources(file, filesData);
565  } else
566  if (type == "!res") {
567  scanPathResources(tdmePath + "/" + file, filesData);
568  } else
569  if (type == "lib") {
570  scanPathLibraries(file, filesData);
571  } else
572  if (type == "api") {
573  scanPathHeaders(file, filesData);
574  } else {
575  Console::println("Component: " + to_string(componentIdx) + ": type = " + type + " unsupported!");
576  }
577 
578  // process files
579  Console::println("Component: " + to_string(componentIdx) + ": Processing files");
580  }
581 
582  // add files to archive
583  for (const auto& fileName: filesData) {
584  processFile(fileName, fileInformations, "installer/" + componentFileName, false, tdmePath);
585  }
586 
587  // add files to archive
588  for (const auto& fileName: filesBin) {
589  #if defined(__APPLE__)
590  auto _fileName = StringTools::substring(fileName, fileName.rfind('/') + 1, fileName.size());
591  auto _filePath = StringTools::substring(fileName, 0, fileName.rfind('/'));
592  auto startMenuName = installerProperties.get("startmenu_" + StringTools::toLowerCase(_fileName), "");
593  if (startMenuName.empty() == false) {
594  createMacApplication(installerProperties, fileName);
595  auto executableFileName = FileSystem::getInstance()->getFileName(fileName);
596  processFile(executableFileName + ".app/Contents/Info.plist", fileInformations, "installer/" + componentFileName, false, tdmePath);
597  processFile(executableFileName + ".app/Contents/Resources/icon.icns", fileInformations, "installer/" + componentFileName, false, tdmePath);
598  processFile(executableFileName + ".app/Contents/_CodeSignature/CodeResources", fileInformations, "installer/" + componentFileName, false, tdmePath);
599  processFile(executableFileName + ".app/Contents/MacOS/" + executableFileName, fileInformations, "installer/" + componentFileName, true, tdmePath, executableFileName + ".app/Contents/MacOS");
600  FileSystem::getInstance()->removePath(executableFileName + ".app", true);
601  } else {
602  auto executablePathName = FileSystem::getInstance()->getPathName(fileName);
603  auto executableFileName = FileSystem::getInstance()->getFileName(fileName);
604  FileSystem::getInstance()->createPath("signed-executables");
605  {
606  vector<uint8_t> content;
607  FileSystem::getInstance()->getContent(
608  executablePathName,
609  executableFileName,
610  content
611  );
612  FileSystem::getInstance()->setContent(
613  "signed-executables",
614  executableFileName,
615  content
616  );
617  FileSystem::getInstance()->setExecutable(
618  "signed-executables",
619  executableFileName
620  );
621  }
622  auto signedFileName = "signed-executables/" + executableFileName;
623  auto codeSignCommand = "codesign -s \"" + installerProperties.get("macos_codesign_identity", "No identity") + "\" \"" + signedFileName + "\"";
624  Console::println("Signing '" + fileName + "': " + codeSignCommand);
625  Console::println(Application::execute(codeSignCommand));
626  processFile(signedFileName, fileInformations, "installer/" + componentFileName, true, tdmePath);
627  FileSystem::getInstance()->removePath("signed-executables", true);
628  }
629  #else
630  processFile(fileName, fileInformations, "installer/" + componentFileName, true, tdmePath);
631  #endif
632  }
633 
634  // add file informations
635  {
636  ofstream ofs(std::filesystem::u8path("installer/" + componentFileName), ofstream::binary | ofstream::app);
637  ofs.seekp(0, ofstream::end);
638  uint32_t fileInformationOffsetEnd = 0LL;
639  uint64_t fileInformationOffset = ofs.tellp();
640  for (const auto& fileInformation: fileInformations) {
641  uint32_t nameSize = fileInformation.name.size();
642  ofs.write((char*)&nameSize, sizeof(nameSize));
643  for (auto i = 0; i < nameSize; i++) ofs.write(&fileInformation.name[i], 1);
644  ofs.write((char*)&fileInformation.bytes, sizeof(fileInformation.bytes));
645  ofs.write((char*)&fileInformation.compressed, sizeof(fileInformation.compressed));
646  ofs.write((char*)&fileInformation.bytesCompressed, sizeof(fileInformation.bytesCompressed));
647  ofs.write((char*)&fileInformation.offset, sizeof(fileInformation.offset));
648  ofs.write((char*)&fileInformation.executable, sizeof(fileInformation.executable));
649  }
650  ofs.write((char*)&fileInformationOffsetEnd, sizeof(fileInformationOffsetEnd));
651  ofs.write((char*)&fileInformationOffset, sizeof(fileInformationOffset));
652  ofs.close();
653  }
654 
655  // sha256 hash
656  auto archiveFileSystem = make_unique<ArchiveFileSystem>("installer/" + componentFileName);
657  auto archiveHash = archiveFileSystem->computeSHA256Hash();
658  FileSystem::getStandardFileSystem()->setContentFromString("installer", componentFileName + ".sha256", archiveHash);
659  Console::println("Component: " + to_string(componentIdx) + ": component file name: " + componentFileName + ": hash: " + archiveHash);
660  }
661 
662  // add completion file
663  auto completionFileName = os + "-" + cpu + "-upload-" + fileNameTime;
664  // reset archive
665  {
666  ofstream ofs(std::filesystem::u8path("installer/" + completionFileName), ofstream::binary | ofstream::trunc);
667  ofs.close();
668  }
669 
670  //
671  #if defined(__APPLE__)
672  if (FileSystem::getInstance()->exists("installer-package") == true &&
673  FileSystem::getInstance()->isPath("installer-package") == true) {
674  FileSystem::getInstance()->removePath("installer-package", true);
675  }
676  FileSystem::getInstance()->createPath("installer-package");
677  createMacApplication(installerProperties, "bin/tdme/tools/installer/Installer", "installer-package");
678  #endif
679 
680  //
681  Application::exit(Application::EXITCODE_SUCCESS);
682 }
Application base class, please make sure to allocate application on heap to have correct application ...
Definition: Application.h:41
Archive file system implementation.
File system singleton class.
Definition: FileSystem.h:17
Console class.
Definition: Console.h:29
Properties class, which helps out with storeing or loading key value pairs from/to property files.
Definition: Properties.h:23
const string & get(const string &key, const string &defaultValue) const
Get property value by key.
Definition: Properties.h:46
void load(const string &pathName, const string &fileName, FileSystemInterface *fileSystem=nullptr)
Load property file.
Definition: Properties.cpp:24
String tokenizer class.
void tokenize(const string &str, const string &delimiters, bool emptyTokens=false)
Tokenize.
String tools class.
Definition: StringTools.h:22
Time utility class.
Definition: Time.h:20
void processFile(const string &fileName, vector< FileInformation > &fileInformations, const string &archiveFileName, bool executableFile, const string &basePath, const string &executablePath=string())
#define CHUNK
int main(int argc, char **argv)
static void scanPathResources(const string &path, vector< string > &totalFiles)
static void scanPathHeaders(const string &path, vector< string > &totalFiles)
static void scanPathLibraries(const string &path, vector< string > &totalFiles)
static void scanPathExecutables(const string &path, vector< string > &totalFiles)
std::exception Exception
Exception base class.
Definition: Exception.h:18
Definition: fwd-tdme.h:4
File system file name filter interface.
virtual bool accept(const string &path, const string &file)=0
Accept a file.