The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../Project/jucer_Project.h"
  18. #include "../Project/jucer_Module.h"
  19. #include "jucer_CommandLine.h"
  20. //==============================================================================
  21. namespace
  22. {
  23. static void hideDockIcon()
  24. {
  25. #if JUCE_MAC
  26. Process::setDockIconVisible (false);
  27. #endif
  28. }
  29. static File getFile (const String& filename)
  30. {
  31. return File::getCurrentWorkingDirectory().getChildFile (filename.unquoted());
  32. }
  33. static bool matchArgument (const String& arg, const String& possible)
  34. {
  35. return arg == possible
  36. || arg == "-" + possible
  37. || arg == "--" + possible;
  38. }
  39. static bool checkArgumentCount (const StringArray& args, int minNumArgs)
  40. {
  41. if (args.size() < minNumArgs)
  42. {
  43. std::cout << "Not enough arguments!" << std::endl;
  44. return false;
  45. }
  46. return true;
  47. }
  48. //==============================================================================
  49. struct LoadedProject
  50. {
  51. LoadedProject()
  52. {
  53. hideDockIcon();
  54. }
  55. int load (const File& projectFile)
  56. {
  57. hideDockIcon();
  58. if (! projectFile.exists())
  59. {
  60. std::cout << "The file " << projectFile.getFullPathName() << " doesn't exist!" << std::endl;
  61. return 1;
  62. }
  63. if (! projectFile.hasFileExtension (Project::projectFileExtension))
  64. {
  65. std::cout << projectFile.getFullPathName() << " isn't a valid jucer project file!" << std::endl;
  66. return 1;
  67. }
  68. project = new Project (projectFile);
  69. if (! project->loadFrom (projectFile, true))
  70. {
  71. project = nullptr;
  72. std::cout << "Failed to load the project file: " << projectFile.getFullPathName() << std::endl;
  73. return 1;
  74. }
  75. return 0;
  76. }
  77. int save (bool justSaveResources)
  78. {
  79. if (project != nullptr)
  80. {
  81. Result error (justSaveResources ? project->saveResourcesOnly (project->getFile())
  82. : project->saveProject (project->getFile(), true));
  83. if (error.failed())
  84. {
  85. std::cout << "Error when saving: " << error.getErrorMessage() << std::endl;
  86. return 1;
  87. }
  88. project = nullptr;
  89. }
  90. return 0;
  91. }
  92. ScopedPointer<Project> project;
  93. };
  94. //==============================================================================
  95. /* Running a command-line of the form "introjucer --resave foobar.jucer" will try to load
  96. that project and re-export all of its targets.
  97. */
  98. static int resaveProject (const StringArray& args, bool justSaveResources)
  99. {
  100. if (! checkArgumentCount (args, 2))
  101. return 1;
  102. LoadedProject proj;
  103. int res = proj.load (getFile (args[1]));
  104. if (res != 0)
  105. return res;
  106. std::cout << (justSaveResources ? "Re-saving project resources: "
  107. : "Re-saving file: ")
  108. << proj.project->getFile().getFullPathName() << std::endl;
  109. return proj.save (justSaveResources);
  110. }
  111. //==============================================================================
  112. static int setVersion (const StringArray& args)
  113. {
  114. if (! checkArgumentCount (args, 3))
  115. return 1;
  116. LoadedProject proj;
  117. int res = proj.load (getFile (args[2]));
  118. if (res != 0)
  119. return res;
  120. String version (args[1].trim());
  121. std::cout << "Setting project version: " << version << std::endl;
  122. proj.project->getVersionValue() = version;
  123. return proj.save (false);
  124. }
  125. //==============================================================================
  126. static int bumpVersion (const StringArray& args)
  127. {
  128. if (! checkArgumentCount (args, 2))
  129. return 1;
  130. LoadedProject proj;
  131. int res = proj.load (getFile (args[1]));
  132. if (res != 0)
  133. return res;
  134. String version = proj.project->getVersionString();
  135. version = version.upToLastOccurrenceOf (".", true, false)
  136. + String (version.getTrailingIntValue() + 1);
  137. std::cout << "Bumping project version to: " << version << std::endl;
  138. proj.project->getVersionValue() = version;
  139. return proj.save (false);
  140. }
  141. //==============================================================================
  142. int showStatus (const StringArray& args)
  143. {
  144. hideDockIcon();
  145. if (! checkArgumentCount (args, 2))
  146. return 1;
  147. LoadedProject proj;
  148. int res = proj.load (getFile (args[1]));
  149. if (res != 0)
  150. return res;
  151. std::cout << "Project file: " << proj.project->getFile().getFullPathName() << std::endl
  152. << "Name: " << proj.project->getTitle() << std::endl
  153. << "UID: " << proj.project->getProjectUID() << std::endl;
  154. EnabledModuleList& modules = proj.project->getModules();
  155. const int numModules = modules.getNumModules();
  156. if (numModules > 0)
  157. {
  158. std::cout << "Modules:" << std::endl;
  159. for (int i = 0; i < numModules; ++i)
  160. std::cout << " " << modules.getModuleID (i) << std::endl;
  161. }
  162. return 0;
  163. }
  164. //==============================================================================
  165. static String getModulePackageName (const LibraryModule& module)
  166. {
  167. return module.getID() + ".jucemodule";
  168. }
  169. static int zipModule (const File& targetFolder, const File& moduleFolder)
  170. {
  171. jassert (targetFolder.isDirectory());
  172. const File moduleFolderParent (moduleFolder.getParentDirectory());
  173. LibraryModule module (moduleFolder.getChildFile (ModuleDescription::getManifestFileName()));
  174. if (! module.isValid())
  175. {
  176. std::cout << moduleFolder.getFullPathName() << " is not a valid module folder!" << std::endl;
  177. return 1;
  178. }
  179. const File targetFile (targetFolder.getChildFile (getModulePackageName (module)));
  180. ZipFile::Builder zip;
  181. {
  182. DirectoryIterator i (moduleFolder, true, "*", File::findFiles);
  183. while (i.next())
  184. if (! i.getFile().isHidden())
  185. zip.addFile (i.getFile(), 9, i.getFile().getRelativePathFrom (moduleFolderParent));
  186. }
  187. std::cout << "Writing: " << targetFile.getFullPathName() << std::endl;
  188. TemporaryFile temp (targetFile);
  189. ScopedPointer<FileOutputStream> out (temp.getFile().createOutputStream());
  190. bool ok = out != nullptr && zip.writeToStream (*out, nullptr);
  191. out = nullptr;
  192. ok = ok && temp.overwriteTargetFileWithTemporary();
  193. if (! ok)
  194. {
  195. std::cout << "Failed to write to the target file: " << targetFile.getFullPathName() << std::endl;
  196. return 1;
  197. }
  198. return 0;
  199. }
  200. static int buildModules (const StringArray& args, const bool buildAllWithIndex)
  201. {
  202. hideDockIcon();
  203. if (! checkArgumentCount (args, 3))
  204. return 1;
  205. const File targetFolder (getFile (args[1]));
  206. if (! targetFolder.isDirectory())
  207. {
  208. std::cout << "The first argument must be the directory to put the result." << std::endl;
  209. return 1;
  210. }
  211. if (buildAllWithIndex)
  212. {
  213. const File folderToSearch (getFile (args[2]));
  214. DirectoryIterator i (folderToSearch, false, "*", File::findDirectories);
  215. var infoList;
  216. while (i.next())
  217. {
  218. LibraryModule module (i.getFile().getChildFile (ModuleDescription::getManifestFileName()));
  219. if (module.isValid())
  220. {
  221. const int result = zipModule (targetFolder, i.getFile());
  222. if (result != 0)
  223. return result;
  224. var moduleInfo (new DynamicObject());
  225. moduleInfo.getDynamicObject()->setProperty ("file", getModulePackageName (module));
  226. moduleInfo.getDynamicObject()->setProperty ("info", module.moduleInfo.moduleInfo);
  227. infoList.append (moduleInfo);
  228. }
  229. }
  230. const File indexFile (targetFolder.getChildFile ("modulelist"));
  231. std::cout << "Writing: " << indexFile.getFullPathName() << std::endl;
  232. indexFile.replaceWithText (JSON::toString (infoList), false, false);
  233. }
  234. else
  235. {
  236. for (int i = 2; i < args.size(); ++i)
  237. {
  238. const int result = zipModule (targetFolder, getFile (args[i]));
  239. if (result != 0)
  240. return result;
  241. }
  242. }
  243. return 0;
  244. }
  245. //==============================================================================
  246. static int showHelp()
  247. {
  248. hideDockIcon();
  249. std::cout << "The Introjucer!" << std::endl
  250. << std::endl
  251. << "Usage: " << std::endl
  252. << std::endl
  253. << " introjucer --resave project_file" << std::endl
  254. << " Resaves all files and resources in a project." << std::endl
  255. << std::endl
  256. << " introjucer --resave-resources project_file" << std::endl
  257. << " Resaves just the binary resources for a project." << std::endl
  258. << std::endl
  259. << " introjucer --set-version version_number project_file" << std::endl
  260. << " Updates the version number in a project." << std::endl
  261. << std::endl
  262. << " introjucer --bump-version project_file" << std::endl
  263. << " Updates the minor version number in a project by 1." << std::endl
  264. << std::endl
  265. << " introjucer --status project_file" << std::endl
  266. << " Displays information about a project." << std::endl
  267. << std::endl
  268. << " introjucer --buildmodule target_folder module_folder" << std::endl
  269. << " Zips a module into a downloadable file format." << std::endl
  270. << std::endl
  271. << " introjucer --buildallmodules target_folder module_folder" << std::endl
  272. << " Zips all modules in a given folder and creates an index for them." << std::endl
  273. << std::endl;
  274. return 0;
  275. }
  276. }
  277. //==============================================================================
  278. int performCommandLine (const String& commandLine)
  279. {
  280. StringArray args;
  281. args.addTokens (commandLine, true);
  282. args.trim();
  283. if (matchArgument (args[0], "help")) return showHelp();
  284. if (matchArgument (args[0], "resave")) return resaveProject (args, false);
  285. if (matchArgument (args[0], "resave-resources")) return resaveProject (args, true);
  286. if (matchArgument (args[0], "set-version")) return setVersion (args);
  287. if (matchArgument (args[0], "bump-version")) return bumpVersion (args);
  288. if (matchArgument (args[0], "buildmodule")) return buildModules (args, false);
  289. if (matchArgument (args[0], "buildallmodules")) return buildModules (args, true);
  290. if (matchArgument (args[0], "status")) return showStatus (args);
  291. return commandLineNotPerformed;
  292. }