BuildBase.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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::BuildRemoveDirectory(const String& path)
  133. {
  134. if (buildFailed_)
  135. {
  136. LOGERRORF("BuildBase::BuildRemoveDirectory - Attempt to remove directory of failed build, %s", path.CString());
  137. return false;
  138. }
  139. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  140. if (!fileSystem->DirExists(path))
  141. return true;
  142. bool result = fileSystem->RemoveDir(path, true);
  143. if (!result)
  144. {
  145. FailBuild(ToString("BuildBase::BuildRemoveDirectory: Unable to remove directory %s", path.CString()));
  146. return false;
  147. }
  148. return true;
  149. }
  150. void BuildBase::BuildLog(const String& message, bool sendEvent)
  151. {
  152. buildLog_.Push(message);
  153. if (sendEvent)
  154. {
  155. String colorMsg = ToString("<color #D4FB79>%s</color>\n", message.CString());
  156. VariantMap buildOutput;
  157. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  158. SendEvent(E_BUILDOUTPUT, buildOutput);
  159. }
  160. }
  161. void BuildBase::BuildWarn(const String& warning, bool sendEvent)
  162. {
  163. buildWarnings_.Push(warning);
  164. if (sendEvent)
  165. {
  166. String colorMsg = ToString("<color #FFFF00>%s</color>\n", warning.CString());
  167. VariantMap buildOutput;
  168. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  169. SendEvent(E_BUILDOUTPUT, buildOutput);
  170. }
  171. }
  172. void BuildBase::BuildError(const String& error, bool sendEvent)
  173. {
  174. buildErrors_.Push(error);
  175. if (sendEvent)
  176. {
  177. String colorMsg = ToString("<color #FF0000>%s</color>\n", error.CString());
  178. VariantMap buildOutput;
  179. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  180. SendEvent(E_BUILDOUTPUT, buildOutput);
  181. }
  182. }
  183. void BuildBase::FailBuild(const String& message)
  184. {
  185. if (buildFailed_)
  186. {
  187. LOGERRORF("BuildBase::FailBuild - Attempt to fail already failed build: %s", message.CString());
  188. return;
  189. }
  190. buildFailed_ = true;
  191. BuildError(message);
  192. BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  193. buildSystem->BuildComplete(platformID_, buildPath_, false, message);
  194. }
  195. void BuildBase::HandleSubprocessOutputEvent(StringHash eventType, VariantMap& eventData)
  196. {
  197. // E_SUBPROCESSOUTPUT
  198. const String& text = eventData[SubprocessOutput::P_TEXT].GetString();
  199. // convert to a build output event and forward to subscribers
  200. VariantMap buildOutputData;
  201. buildOutputData[BuildOutput::P_TEXT] = text;
  202. SendEvent(E_BUILDOUTPUT, buildOutputData);
  203. }
  204. void BuildBase::GetDefaultResourcePaths(Vector<String>& paths)
  205. {
  206. paths.Clear();
  207. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  208. paths.Push(AddTrailingSlash(tenv->GetCoreDataDir()));
  209. paths.Push(AddTrailingSlash(tenv->GetPlayerDataDir()));
  210. }
  211. String BuildBase::GetSettingsDirectory()
  212. {
  213. return project_->GetProjectPath() + "/Settings";
  214. }
  215. void BuildBase::ScanResourceDirectory(const String& resourceDir)
  216. {
  217. Vector<String> fileNames;
  218. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  219. fileSystem->ScanDir(fileNames, resourceDir, "*.*", SCAN_FILES, true);
  220. for (unsigned i = 0; i < fileNames.Size(); i++)
  221. {
  222. const String& filename = fileNames[i];
  223. for (unsigned j = 0; j < resourceEntries_.Size(); j++)
  224. {
  225. const BuildResourceEntry* entry = resourceEntries_[j];
  226. if (entry->packagePath_ == filename)
  227. {
  228. BuildWarn(ToString("Resource Path: %s already exists", filename.CString()));
  229. continue;
  230. }
  231. }
  232. // TODO: Add additional filters
  233. if (GetExtension(filename) == ".psd")
  234. continue;
  235. BuildResourceEntry* newEntry = new BuildResourceEntry;
  236. // BEGIN LICENSE MANAGEMENT
  237. if (GetExtension(filename) == ".mdl")
  238. {
  239. containsMDL_ = true;
  240. }
  241. // END LICENSE MANAGEMENT
  242. newEntry->absolutePath_ = resourceDir + filename;
  243. newEntry->resourceDir_ = resourceDir;
  244. newEntry->packagePath_ = filename;
  245. resourceEntries_.Push(newEntry);
  246. //LOGINFOF("Adding resource: %s : %s", newEntry->absolutePath_.CString(), newEntry->packagePath_.CString());
  247. }
  248. }
  249. void BuildBase::BuildResourceEntries()
  250. {
  251. for (unsigned i = 0; i < resourceDirs_.Size(); i++)
  252. {
  253. ScanResourceDirectory(resourceDirs_[i]);
  254. }
  255. if (resourcePackager_.NotNull())
  256. {
  257. for (unsigned i = 0; i < resourceEntries_.Size(); i++)
  258. {
  259. BuildResourceEntry* entry = resourceEntries_[i];
  260. resourcePackager_->AddResourceEntry(entry);
  261. }
  262. }
  263. }
  264. void BuildBase::GenerateResourcePackage(const String& resourcePackagePath)
  265. {
  266. resourcePackager_->GeneratePackage(resourcePackagePath);
  267. }
  268. void BuildBase::AddResourceDir(const String& dir)
  269. {
  270. assert(!resourceDirs_.Contains(dir));
  271. resourceDirs_.Push(dir);
  272. }
  273. }