BuildBase.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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 <Poco/File.h>
  23. #include <Atomic/IO/Log.h>
  24. #include <Atomic/IO/FileSystem.h>
  25. #include "../Subprocess/SubprocessSystem.h"
  26. #include "../Project/Project.h"
  27. #include "../ToolEnvironment.h"
  28. #include "BuildSystem.h"
  29. #include "BuildEvents.h"
  30. #include "BuildBase.h"
  31. #include "ResourcePackager.h"
  32. namespace ToolCore
  33. {
  34. BuildBase::BuildBase(Context * context, Project* project, PlatformID platform) : Object(context),
  35. platformID_(platform),
  36. containsMDL_(false),
  37. buildFailed_(false)
  38. {
  39. if (UseResourcePackager())
  40. resourcePackager_ = new ResourcePackager(context, this);
  41. project_ = project;
  42. }
  43. BuildBase::~BuildBase()
  44. {
  45. for (unsigned i = 0; i < resourceEntries_.Size(); i++)
  46. {
  47. delete resourceEntries_[i];
  48. }
  49. }
  50. #ifdef ATOMIC_PLATFORM_WINDOWS
  51. bool BuildBase::BuildClean(const String& path)
  52. {
  53. if (buildFailed_)
  54. {
  55. LOGERRORF("BuildBase::BuildClean - Attempt to clean directory of failed build, %s", path.CString());
  56. return false;
  57. }
  58. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  59. if (!fileSystem->DirExists(path))
  60. return true;
  61. // On Windows, do a little dance with the folder to avoid issues
  62. // with deleting folder and immediately recreating it
  63. String pathName, fileName, ext;
  64. SplitPath(path, pathName, fileName, ext);
  65. pathName = AddTrailingSlash(pathName);
  66. unsigned i = 0;
  67. while (true)
  68. {
  69. String newPath = ToString("%s%s_Temp_%u", pathName.CString(), fileName.CString(), i++);
  70. if (!fileSystem->DirExists(newPath))
  71. {
  72. if (!MoveFileExW(GetWideNativePath(path).CString(), GetWideNativePath(newPath).CString(), MOVEFILE_WRITE_THROUGH))
  73. {
  74. FailBuild(ToString("BuildBase::BuildClean: Unable to move directory %s -> ", path.CString(), newPath.CString()));
  75. return false;
  76. }
  77. // Remove the moved directory
  78. return BuildRemoveDirectory(newPath);
  79. }
  80. else
  81. {
  82. LOGWARNINGF("BuildBase::BuildClean - temp build folder exists, removing: %s", newPath.CString());
  83. fileSystem->RemoveDir(newPath, true);
  84. }
  85. if (i == 255)
  86. {
  87. FailBuild(ToString("BuildBase::BuildClean: Unable to move directory ( i == 255) %s -> ", path.CString(), newPath.CString()));
  88. return false;
  89. }
  90. }
  91. return false;
  92. }
  93. #else
  94. bool BuildBase::BuildClean(const String& path)
  95. {
  96. return BuildRemoveDirectory(path);
  97. }
  98. #endif
  99. bool BuildBase::BuildCreateDirectory(const String& path)
  100. {
  101. if (buildFailed_)
  102. {
  103. LOGERRORF("BuildBase::BuildCreateDirectory - Attempt to create directory of failed build, %s", path.CString());
  104. return false;
  105. }
  106. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  107. if (fileSystem->DirExists(path))
  108. return true;
  109. bool result = fileSystem->CreateDir(path);
  110. if (!result)
  111. {
  112. FailBuild(ToString("BuildBase::BuildCreateDirectory: Unable to create directory %s", path.CString()));
  113. return false;
  114. }
  115. return true;
  116. }
  117. bool BuildBase::BuildCopyFile(const String& srcFileName, const String& destFileName)
  118. {
  119. if (buildFailed_)
  120. {
  121. LOGERRORF("BuildBase::BuildCopyFile - Attempt to copy file of failed build, %s", srcFileName.CString());
  122. return false;
  123. }
  124. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  125. bool result = fileSystem->Copy(srcFileName, destFileName);
  126. if (!result)
  127. {
  128. FailBuild(ToString("BuildBase::BuildCopyFile: Unable to copy file %s -> %s", srcFileName.CString(), destFileName.CString()));
  129. return false;
  130. }
  131. return true;
  132. }
  133. bool BuildBase::BuildCopyDir(const String& srcDir, const String& destDir)
  134. {
  135. if (buildFailed_)
  136. {
  137. LOGERRORF("BuildBase::BuildCopyDir - Attempt to copy directory of failed build, %s", srcDir.CString());
  138. return false;
  139. }
  140. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  141. bool result = fileSystem->CopyDir(srcDir, destDir);
  142. if (!result)
  143. {
  144. FailBuild(ToString("BuildBase::BuildCopyDir: Unable to copy dir %s -> %s", srcDir.CString(), destDir.CString()));
  145. return false;
  146. }
  147. return true;
  148. }
  149. bool BuildBase::CheckIncludeResourceFile(const String & resourceDir, const String & fileName)
  150. {
  151. return (GetExtension(fileName) != ".psd");
  152. }
  153. bool BuildBase::BuildRemoveDirectory(const String& path)
  154. {
  155. if (buildFailed_)
  156. {
  157. LOGERRORF("BuildBase::BuildRemoveDirectory - Attempt to remove directory of failed build, %s", path.CString());
  158. return false;
  159. }
  160. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  161. if (!fileSystem->DirExists(path))
  162. return true;
  163. #ifdef ATOMIC_PLATFORM_LINUX
  164. bool result = true; // fileSystem->RemoveDir(path, true); crashes on linux
  165. Poco::File dirs(buildPath_.CString());
  166. dirs.remove(true);
  167. if (fileSystem->DirExists(buildPath_))
  168. result = false;
  169. #else
  170. bool result = fileSystem->RemoveDir(path, true);
  171. #endif
  172. if (!result)
  173. {
  174. FailBuild(ToString("BuildBase::BuildRemoveDirectory: Unable to remove directory %s", path.CString()));
  175. return false;
  176. }
  177. return true;
  178. }
  179. void BuildBase::BuildLog(const String& message, bool sendEvent)
  180. {
  181. buildLog_.Push(message);
  182. if (sendEvent)
  183. {
  184. String colorMsg = ToString("<color #D4FB79>%s</color>\n", message.CString());
  185. VariantMap buildOutput;
  186. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  187. SendEvent(E_BUILDOUTPUT, buildOutput);
  188. }
  189. }
  190. void BuildBase::BuildWarn(const String& warning, bool sendEvent)
  191. {
  192. buildWarnings_.Push(warning);
  193. if (sendEvent)
  194. {
  195. String colorMsg = ToString("<color #FFFF00>%s</color>\n", warning.CString());
  196. VariantMap buildOutput;
  197. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  198. SendEvent(E_BUILDOUTPUT, buildOutput);
  199. }
  200. }
  201. void BuildBase::BuildError(const String& error, bool sendEvent)
  202. {
  203. buildErrors_.Push(error);
  204. if (sendEvent)
  205. {
  206. String colorMsg = ToString("<color #FF0000>%s</color>\n", error.CString());
  207. VariantMap buildOutput;
  208. buildOutput[BuildOutput::P_TEXT] = colorMsg;
  209. SendEvent(E_BUILDOUTPUT, buildOutput);
  210. }
  211. }
  212. void BuildBase::FailBuild(const String& message)
  213. {
  214. if (buildFailed_)
  215. {
  216. LOGERRORF("BuildBase::FailBuild - Attempt to fail already failed build: %s", message.CString());
  217. return;
  218. }
  219. buildFailed_ = true;
  220. BuildError(message);
  221. BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  222. buildSystem->BuildComplete(platformID_, buildPath_, false, message);
  223. }
  224. void BuildBase::HandleSubprocessOutputEvent(StringHash eventType, VariantMap& eventData)
  225. {
  226. // E_SUBPROCESSOUTPUT
  227. const String& text = eventData[SubprocessOutput::P_TEXT].GetString();
  228. // convert to a build output event and forward to subscribers
  229. VariantMap buildOutputData;
  230. buildOutputData[BuildOutput::P_TEXT] = text;
  231. SendEvent(E_BUILDOUTPUT, buildOutputData);
  232. }
  233. void BuildBase::GetDefaultResourcePaths(Vector<String>& paths)
  234. {
  235. paths.Clear();
  236. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  237. paths.Push(AddTrailingSlash(tenv->GetCoreDataDir()));
  238. paths.Push(AddTrailingSlash(tenv->GetPlayerDataDir()));
  239. }
  240. String BuildBase::GetSettingsDirectory()
  241. {
  242. return project_->GetProjectPath() + "/Settings";
  243. }
  244. void BuildBase::ScanResourceDirectory(const String& resourceDir)
  245. {
  246. Vector<String> fileNames;
  247. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  248. fileSystem->ScanDir(fileNames, resourceDir, "*.*", SCAN_FILES, true);
  249. for (unsigned i = 0; i < fileNames.Size(); i++)
  250. {
  251. const String& filename = fileNames[i];
  252. for (unsigned j = 0; j < resourceEntries_.Size(); j++)
  253. {
  254. const BuildResourceEntry* entry = resourceEntries_[j];
  255. if (entry->packagePath_ == filename)
  256. {
  257. BuildWarn(ToString("Resource Path: %s already exists", filename.CString()));
  258. continue;
  259. }
  260. }
  261. if (!CheckIncludeResourceFile(resourceDir, filename))
  262. continue;
  263. BuildResourceEntry* newEntry = new BuildResourceEntry;
  264. // BEGIN LICENSE MANAGEMENT
  265. if (GetExtension(filename) == ".mdl")
  266. {
  267. containsMDL_ = true;
  268. }
  269. // END LICENSE MANAGEMENT
  270. newEntry->absolutePath_ = resourceDir + filename;
  271. newEntry->resourceDir_ = resourceDir;
  272. newEntry->packagePath_ = filename;
  273. resourceEntries_.Push(newEntry);
  274. //LOGINFOF("Adding resource: %s : %s", newEntry->absolutePath_.CString(), newEntry->packagePath_.CString());
  275. }
  276. }
  277. void BuildBase::BuildResourceEntries()
  278. {
  279. for (unsigned i = 0; i < resourceDirs_.Size(); i++)
  280. {
  281. ScanResourceDirectory(resourceDirs_[i]);
  282. }
  283. if (resourcePackager_.NotNull())
  284. {
  285. for (unsigned i = 0; i < resourceEntries_.Size(); i++)
  286. {
  287. BuildResourceEntry* entry = resourceEntries_[i];
  288. resourcePackager_->AddResourceEntry(entry);
  289. }
  290. }
  291. }
  292. void BuildBase::GenerateResourcePackage(const String& resourcePackagePath)
  293. {
  294. resourcePackager_->GeneratePackage(resourcePackagePath);
  295. }
  296. void BuildBase::AddResourceDir(const String& dir)
  297. {
  298. assert(!resourceDirs_.Contains(dir));
  299. resourceDirs_.Push(dir);
  300. }
  301. }