BuildBase.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Atomic/IO/Log.h>
  23. #include <Atomic/IO/FileSystem.h>
  24. #include "../Subprocess/SubprocessSystem.h"
  25. #include "../Project/Project.h"
  26. #include "../ToolEnvironment.h"
  27. #include "BuildSystem.h"
  28. #include "BuildEvents.h"
  29. #include "BuildBase.h"
  30. #include "ResourcePackager.h"
  31. namespace ToolCore
  32. {
  33. BuildBase::BuildBase(Context * context, Project* project, PlatformID platform) : Object(context),
  34. platformID_(platform),
  35. containsMDL_(false),
  36. buildFailed_(false)
  37. {
  38. if (UseResourcePackager())
  39. resourcePackager_ = new ResourcePackager(context, this);
  40. project_ = project;
  41. }
  42. BuildBase::~BuildBase()
  43. {
  44. for (unsigned i = 0; i < resourceEntries_.Size(); i++)
  45. {
  46. delete resourceEntries_[i];
  47. }
  48. }
  49. #ifdef ATOMIC_PLATFORM_WINDOWS
  50. bool BuildBase::BuildClean(const String& path)
  51. {
  52. if (buildFailed_)
  53. {
  54. LOGERRORF("BuildBase::BuildClean - Attempt to clean directory of failed build, %s", path.CString());
  55. return false;
  56. }
  57. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  58. if (!fileSystem->DirExists(path))
  59. return true;
  60. // On Windows, do a little dance with the folder to avoid issues
  61. // with deleting folder and immediately recreating it
  62. String pathName, fileName, ext;
  63. SplitPath(path, pathName, fileName, ext);
  64. pathName = AddTrailingSlash(pathName);
  65. unsigned i = 0;
  66. while (true)
  67. {
  68. String newPath = ToString("%s%s_Temp_%u", pathName.CString(), fileName.CString(), i++);
  69. if (!fileSystem->DirExists(newPath))
  70. {
  71. if (!MoveFileExW(GetWideNativePath(path).CString(), GetWideNativePath(newPath).CString(), MOVEFILE_WRITE_THROUGH))
  72. {
  73. FailBuild(ToString("BuildBase::BuildClean: Unable to move directory %s -> ", path.CString(), newPath.CString()));
  74. return false;
  75. }
  76. // Remove the moved directory
  77. return BuildRemoveDirectory(newPath);
  78. }
  79. else
  80. {
  81. LOGWARNINGF("BuildBase::BuildClean - temp build folder exists, removing: %s", newPath.CString());
  82. fileSystem->RemoveDir(newPath, true);
  83. }
  84. if (i == 255)
  85. {
  86. FailBuild(ToString("BuildBase::BuildClean: Unable to move directory ( i == 255) %s -> ", path.CString(), newPath.CString()));
  87. return false;
  88. }
  89. }
  90. return false;
  91. }
  92. #else
  93. bool BuildBase::BuildClean(const String& path)
  94. {
  95. return BuildRemoveDirectory(path);
  96. }
  97. #endif
  98. bool BuildBase::BuildCreateDirectory(const String& path)
  99. {
  100. if (buildFailed_)
  101. {
  102. LOGERRORF("BuildBase::BuildCreateDirectory - Attempt to create directory of failed build, %s", path.CString());
  103. return false;
  104. }
  105. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  106. if (fileSystem->DirExists(path))
  107. return true;
  108. bool result = fileSystem->CreateDir(path);
  109. if (!result)
  110. {
  111. FailBuild(ToString("BuildBase::BuildCreateDirectory: Unable to create directory %s", path.CString()));
  112. return false;
  113. }
  114. return true;
  115. }
  116. bool BuildBase::BuildCopyFile(const String& srcFileName, const String& destFileName)
  117. {
  118. if (buildFailed_)
  119. {
  120. LOGERRORF("BuildBase::BuildCopyFile - Attempt to copy file of failed build, %s", srcFileName.CString());
  121. return false;
  122. }
  123. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  124. bool result = fileSystem->Copy(srcFileName, destFileName);
  125. if (!result)
  126. {
  127. FailBuild(ToString("BuildBase::BuildCopyFile: Unable to copy file %s -> %s", srcFileName.CString(), destFileName.CString()));
  128. return false;
  129. }
  130. return true;
  131. }
  132. bool BuildBase::CheckIncludeResourceFile(const String & resourceDir, const String & fileName)
  133. {
  134. return (GetExtension(fileName) != ".psd");
  135. }
  136. bool BuildBase::BuildRemoveDirectory(const String& path)
  137. {
  138. if (buildFailed_)
  139. {
  140. LOGERRORF("BuildBase::BuildRemoveDirectory - Attempt to remove directory of failed build, %s", path.CString());
  141. return false;
  142. }
  143. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  144. if (!fileSystem->DirExists(path))
  145. return true;
  146. bool result = fileSystem->RemoveDir(path, true);
  147. if (!result)
  148. {
  149. FailBuild(ToString("BuildBase::BuildRemoveDirectory: Unable to remove directory %s", path.CString()));
  150. return false;
  151. }
  152. return true;
  153. }
  154. void BuildBase::BuildLog(const String& message, bool sendEvent)
  155. {
  156. buildLog_.Push(message);
  157. if (sendEvent)
  158. {
  159. String colorMsg = ToString("<color #D4FB79>%s</color>\n", message.CString());
  160. VariantMap buildOutput;
  161. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  162. SendEvent(E_BUILDOUTPUT, buildOutput);
  163. }
  164. }
  165. void BuildBase::BuildWarn(const String& warning, bool sendEvent)
  166. {
  167. buildWarnings_.Push(warning);
  168. if (sendEvent)
  169. {
  170. String colorMsg = ToString("<color #FFFF00>%s</color>\n", warning.CString());
  171. VariantMap buildOutput;
  172. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  173. SendEvent(E_BUILDOUTPUT, buildOutput);
  174. }
  175. }
  176. void BuildBase::BuildError(const String& error, bool sendEvent)
  177. {
  178. buildErrors_.Push(error);
  179. if (sendEvent)
  180. {
  181. String colorMsg = ToString("<color #FF0000>%s</color>\n", error.CString());
  182. VariantMap buildOutput;
  183. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  184. SendEvent(E_BUILDOUTPUT, buildOutput);
  185. }
  186. }
  187. void BuildBase::FailBuild(const String& message)
  188. {
  189. if (buildFailed_)
  190. {
  191. LOGERRORF("BuildBase::FailBuild - Attempt to fail already failed build: %s", message.CString());
  192. return;
  193. }
  194. buildFailed_ = true;
  195. BuildError(message);
  196. BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  197. buildSystem->BuildComplete(platformID_, buildPath_, false, message);
  198. }
  199. void BuildBase::HandleSubprocessOutputEvent(StringHash eventType, VariantMap& eventData)
  200. {
  201. // E_SUBPROCESSOUTPUT
  202. const String& text = eventData[SubprocessOutput::P_TEXT].GetString();
  203. // convert to a build output event and forward to subscribers
  204. VariantMap buildOutputData;
  205. buildOutputData[BuildOutput::P_TEXT] = text;
  206. SendEvent(E_BUILDOUTPUT, buildOutputData);
  207. }
  208. void BuildBase::GetDefaultResourcePaths(Vector<String>& paths)
  209. {
  210. paths.Clear();
  211. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  212. paths.Push(AddTrailingSlash(tenv->GetCoreDataDir()));
  213. paths.Push(AddTrailingSlash(tenv->GetPlayerDataDir()));
  214. }
  215. String BuildBase::GetSettingsDirectory()
  216. {
  217. return project_->GetProjectPath() + "/Settings";
  218. }
  219. void BuildBase::ScanResourceDirectory(const String& resourceDir)
  220. {
  221. Vector<String> fileNames;
  222. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  223. fileSystem->ScanDir(fileNames, resourceDir, "*.*", SCAN_FILES, true);
  224. for (unsigned i = 0; i < fileNames.Size(); i++)
  225. {
  226. const String& filename = fileNames[i];
  227. for (unsigned j = 0; j < resourceEntries_.Size(); j++)
  228. {
  229. const BuildResourceEntry* entry = resourceEntries_[j];
  230. if (entry->packagePath_ == filename)
  231. {
  232. BuildWarn(ToString("Resource Path: %s already exists", filename.CString()));
  233. continue;
  234. }
  235. }
  236. if (!CheckIncludeResourceFile(resourceDir, filename))
  237. continue;
  238. BuildResourceEntry* newEntry = new BuildResourceEntry;
  239. // BEGIN LICENSE MANAGEMENT
  240. if (GetExtension(filename) == ".mdl")
  241. {
  242. containsMDL_ = true;
  243. }
  244. // END LICENSE MANAGEMENT
  245. newEntry->absolutePath_ = resourceDir + filename;
  246. newEntry->resourceDir_ = resourceDir;
  247. newEntry->packagePath_ = filename;
  248. resourceEntries_.Push(newEntry);
  249. //LOGINFOF("Adding resource: %s : %s", newEntry->absolutePath_.CString(), newEntry->packagePath_.CString());
  250. }
  251. }
  252. void BuildBase::BuildResourceEntries()
  253. {
  254. for (unsigned i = 0; i < resourceDirs_.Size(); i++)
  255. {
  256. ScanResourceDirectory(resourceDirs_[i]);
  257. }
  258. if (resourcePackager_.NotNull())
  259. {
  260. for (unsigned i = 0; i < resourceEntries_.Size(); i++)
  261. {
  262. BuildResourceEntry* entry = resourceEntries_[i];
  263. resourcePackager_->AddResourceEntry(entry);
  264. }
  265. }
  266. }
  267. void BuildBase::GenerateResourcePackage(const String& resourcePackagePath)
  268. {
  269. resourcePackager_->GeneratePackage(resourcePackagePath);
  270. }
  271. void BuildBase::AddResourceDir(const String& dir)
  272. {
  273. assert(!resourceDirs_.Contains(dir));
  274. resourceDirs_.Push(dir);
  275. }
  276. }