| @@ -113,6 +113,7 @@ OBJECTS_APP := \ | |||||
| $(JUCE_OBJDIR)/jucer_CodeHelpers_1e797672.o \ | $(JUCE_OBJDIR)/jucer_CodeHelpers_1e797672.o \ | ||||
| $(JUCE_OBJDIR)/jucer_FileHelpers_54f12f83.o \ | $(JUCE_OBJDIR)/jucer_FileHelpers_54f12f83.o \ | ||||
| $(JUCE_OBJDIR)/jucer_MiscUtilities_31fc8dd8.o \ | $(JUCE_OBJDIR)/jucer_MiscUtilities_31fc8dd8.o \ | ||||
| $(JUCE_OBJDIR)/jucer_VersionInfo_46f3ed40.o \ | |||||
| $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o \ | $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o \ | ||||
| $(JUCE_OBJDIR)/jucer_Icons_d02d18f1.o \ | $(JUCE_OBJDIR)/jucer_Icons_d02d18f1.o \ | ||||
| $(JUCE_OBJDIR)/jucer_JucerTreeViewBase_9b9f2ff0.o \ | $(JUCE_OBJDIR)/jucer_JucerTreeViewBase_9b9f2ff0.o \ | ||||
| @@ -368,6 +369,11 @@ $(JUCE_OBJDIR)/jucer_MiscUtilities_31fc8dd8.o: ../../Source/Utility/Helpers/juce | |||||
| @echo "Compiling jucer_MiscUtilities.cpp" | @echo "Compiling jucer_MiscUtilities.cpp" | ||||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | ||||
| $(JUCE_OBJDIR)/jucer_VersionInfo_46f3ed40.o: ../../Source/Utility/Helpers/jucer_VersionInfo.cpp | |||||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||||
| @echo "Compiling jucer_VersionInfo.cpp" | |||||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||||
| $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o: ../../Source/Utility/PIPs/jucer_PIPGenerator.cpp | $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o: ../../Source/Utility/PIPs/jucer_PIPGenerator.cpp | ||||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | -$(V_AT)mkdir -p $(JUCE_OBJDIR) | ||||
| @echo "Compiling jucer_PIPGenerator.cpp" | @echo "Compiling jucer_PIPGenerator.cpp" | ||||
| @@ -257,6 +257,10 @@ | |||||
| isa = PBXBuildFile; | isa = PBXBuildFile; | ||||
| fileRef = 486E8D02DAD2A0BF54A901C0; | fileRef = 486E8D02DAD2A0BF54A901C0; | ||||
| }; | }; | ||||
| 44AD0D81A65C5EAE3BE588FD = { | |||||
| isa = PBXBuildFile; | |||||
| fileRef = FF3A6A384D536E1AEF47CD54; | |||||
| }; | |||||
| 638C7247B6DBA67EFE46E124 = { | 638C7247B6DBA67EFE46E124 = { | ||||
| isa = PBXBuildFile; | isa = PBXBuildFile; | ||||
| fileRef = 191330B20DAC08B890656EA0; | fileRef = 191330B20DAC08B890656EA0; | ||||
| @@ -2092,6 +2096,13 @@ | |||||
| path = "../../Source/Wizards/jucer_TemplateThumbnailsComponent.h"; | path = "../../Source/Wizards/jucer_TemplateThumbnailsComponent.h"; | ||||
| sourceTree = "SOURCE_ROOT"; | sourceTree = "SOURCE_ROOT"; | ||||
| }; | }; | ||||
| C16F9F479A3A5F6DAD7647A2 = { | |||||
| isa = PBXFileReference; | |||||
| lastKnownFileType = sourcecode.c.h; | |||||
| name = "jucer_VersionInfo.h"; | |||||
| path = "../../Source/Utility/Helpers/jucer_VersionInfo.h"; | |||||
| sourceTree = "SOURCE_ROOT"; | |||||
| }; | |||||
| C187718F7B9EBA88584B43F3 = { | C187718F7B9EBA88584B43F3 = { | ||||
| isa = PBXFileReference; | isa = PBXFileReference; | ||||
| lastKnownFileType = sourcecode.cpp.cpp; | lastKnownFileType = sourcecode.cpp.cpp; | ||||
| @@ -2582,6 +2593,13 @@ | |||||
| path = "../../Source/Utility/UI/jucer_ProjucerLookAndFeel.h"; | path = "../../Source/Utility/UI/jucer_ProjucerLookAndFeel.h"; | ||||
| sourceTree = "SOURCE_ROOT"; | sourceTree = "SOURCE_ROOT"; | ||||
| }; | }; | ||||
| FF3A6A384D536E1AEF47CD54 = { | |||||
| isa = PBXFileReference; | |||||
| lastKnownFileType = sourcecode.cpp.cpp; | |||||
| name = "jucer_VersionInfo.cpp"; | |||||
| path = "../../Source/Utility/Helpers/jucer_VersionInfo.cpp"; | |||||
| sourceTree = "SOURCE_ROOT"; | |||||
| }; | |||||
| FF68231DE2B395461009116C = { | FF68231DE2B395461009116C = { | ||||
| isa = PBXFileReference; | isa = PBXFileReference; | ||||
| lastKnownFileType = sourcecode.c.h; | lastKnownFileType = sourcecode.c.h; | ||||
| @@ -3011,6 +3029,8 @@ | |||||
| A6C4AE13FB409DE414094CFA, | A6C4AE13FB409DE414094CFA, | ||||
| 6FD8DBC0FF42C87D8BEE2452, | 6FD8DBC0FF42C87D8BEE2452, | ||||
| 00515BA4EC5A7D4DC078ED37, | 00515BA4EC5A7D4DC078ED37, | ||||
| FF3A6A384D536E1AEF47CD54, | |||||
| C16F9F479A3A5F6DAD7647A2, | |||||
| ); | ); | ||||
| name = Helpers; | name = Helpers; | ||||
| sourceTree = "<group>"; | sourceTree = "<group>"; | ||||
| @@ -3455,6 +3475,7 @@ | |||||
| 8BE478303CDF061B72F219E2, | 8BE478303CDF061B72F219E2, | ||||
| BF913199032B4CE970E82AA3, | BF913199032B4CE970E82AA3, | ||||
| 25EF9B3FECB4C9F0F522DCAA, | 25EF9B3FECB4C9F0F522DCAA, | ||||
| 44AD0D81A65C5EAE3BE588FD, | |||||
| 638C7247B6DBA67EFE46E124, | 638C7247B6DBA67EFE46E124, | ||||
| D0E26EB54B0087C8BE3D541E, | D0E26EB54B0087C8BE3D541E, | ||||
| 468548FB21D264DC12321327, | 468548FB21D264DC12321327, | ||||
| @@ -233,6 +233,7 @@ | |||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"/> | |||||
| <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/> | <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/> | <ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/> | <ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/> | ||||
| @@ -1624,6 +1625,7 @@ | |||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"/> | |||||
| <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/> | <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/> | <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/> | <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/> | ||||
| @@ -496,6 +496,9 @@ | |||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"> | ||||
| <Filter>Projucer\Utility\Helpers</Filter> | <Filter>Projucer\Utility\Helpers</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"> | |||||
| <Filter>Projucer\Utility\Helpers</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"> | <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"> | ||||
| <Filter>Projucer\Utility\PIPs</Filter> | <Filter>Projucer\Utility\PIPs</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -2325,6 +2328,9 @@ | |||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"> | ||||
| <Filter>Projucer\Utility\Helpers</Filter> | <Filter>Projucer\Utility\Helpers</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"> | |||||
| <Filter>Projucer\Utility\Helpers</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"> | <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"> | ||||
| <Filter>Projucer\Utility\PIPs</Filter> | <Filter>Projucer\Utility\PIPs</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| @@ -233,6 +233,7 @@ | |||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"/> | |||||
| <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/> | <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/> | <ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/> | <ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/> | ||||
| @@ -1624,6 +1625,7 @@ | |||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"/> | |||||
| <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/> | <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/> | <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/> | <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/> | ||||
| @@ -496,6 +496,9 @@ | |||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"> | ||||
| <Filter>Projucer\Utility\Helpers</Filter> | <Filter>Projucer\Utility\Helpers</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"> | |||||
| <Filter>Projucer\Utility\Helpers</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"> | <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"> | ||||
| <Filter>Projucer\Utility\PIPs</Filter> | <Filter>Projucer\Utility\PIPs</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -2325,6 +2328,9 @@ | |||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"> | ||||
| <Filter>Projucer\Utility\Helpers</Filter> | <Filter>Projucer\Utility\Helpers</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"> | |||||
| <Filter>Projucer\Utility\Helpers</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"> | <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"> | ||||
| <Filter>Projucer\Utility\PIPs</Filter> | <Filter>Projucer\Utility\PIPs</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| @@ -233,6 +233,7 @@ | |||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"/> | |||||
| <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/> | <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/> | <ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/> | <ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/> | ||||
| @@ -1624,6 +1625,7 @@ | |||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"/> | |||||
| <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/> | <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/> | <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/> | ||||
| <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/> | <ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/> | ||||
| @@ -496,6 +496,9 @@ | |||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"> | <ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"> | ||||
| <Filter>Projucer\Utility\Helpers</Filter> | <Filter>Projucer\Utility\Helpers</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"> | |||||
| <Filter>Projucer\Utility\Helpers</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"> | <ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"> | ||||
| <Filter>Projucer\Utility\PIPs</Filter> | <Filter>Projucer\Utility\PIPs</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -2325,6 +2328,9 @@ | |||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"> | <ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"> | ||||
| <Filter>Projucer\Utility\Helpers</Filter> | <Filter>Projucer\Utility\Helpers</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"> | |||||
| <Filter>Projucer\Utility\Helpers</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"> | <ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"> | ||||
| <Filter>Projucer\Utility\PIPs</Filter> | <Filter>Projucer\Utility\PIPs</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| @@ -636,6 +636,10 @@ | |||||
| file="Source/Utility/Helpers/jucer_TranslationHelpers.h"/> | file="Source/Utility/Helpers/jucer_TranslationHelpers.h"/> | ||||
| <FILE id="EuC4K4" name="jucer_ValueSourceHelpers.h" compile="0" resource="0" | <FILE id="EuC4K4" name="jucer_ValueSourceHelpers.h" compile="0" resource="0" | ||||
| file="Source/Utility/Helpers/jucer_ValueSourceHelpers.h"/> | file="Source/Utility/Helpers/jucer_ValueSourceHelpers.h"/> | ||||
| <FILE id="BPCoKV" name="jucer_VersionInfo.cpp" compile="1" resource="0" | |||||
| file="Source/Utility/Helpers/jucer_VersionInfo.cpp"/> | |||||
| <FILE id="TnBQtv" name="jucer_VersionInfo.h" compile="0" resource="0" | |||||
| file="Source/Utility/Helpers/jucer_VersionInfo.h"/> | |||||
| </GROUP> | </GROUP> | ||||
| <GROUP id="{A07C4A97-0855-5346-CAF2-A005580B6773}" name="PIPs"> | <GROUP id="{A07C4A97-0855-5346-CAF2-A005580B6773}" name="PIPs"> | ||||
| <FILE id="joAnDa" name="jucer_PIPGenerator.cpp" compile="1" resource="0" | <FILE id="joAnDa" name="jucer_PIPGenerator.cpp" compile="1" resource="0" | ||||
| @@ -52,119 +52,65 @@ void LatestVersionCheckerAndUpdater::checkForNewVersion (bool showAlerts) | |||||
| //============================================================================== | //============================================================================== | ||||
| void LatestVersionCheckerAndUpdater::run() | void LatestVersionCheckerAndUpdater::run() | ||||
| { | { | ||||
| queryUpdateServer(); | |||||
| auto info = VersionInfo::fetchLatestFromUpdateServer(); | |||||
| if (! threadShouldExit()) | |||||
| MessageManager::callAsync ([this] { processResult(); }); | |||||
| } | |||||
| //============================================================================== | |||||
| String getOSString() | |||||
| { | |||||
| #if JUCE_MAC | |||||
| return "OSX"; | |||||
| #elif JUCE_WINDOWS | |||||
| return "Windows"; | |||||
| #elif JUCE_LINUX | |||||
| return "Linux"; | |||||
| #else | |||||
| jassertfalse; | |||||
| return "Unknown"; | |||||
| #endif | |||||
| } | |||||
| namespace VersionHelpers | |||||
| { | |||||
| String formatProductVersion (int versionNum) | |||||
| if (info == nullptr) | |||||
| { | { | ||||
| int major = (versionNum & 0xff0000) >> 16; | |||||
| int minor = (versionNum & 0x00ff00) >> 8; | |||||
| int build = (versionNum & 0x0000ff) >> 0; | |||||
| return String (major) + '.' + String (minor) + '.' + String (build); | |||||
| } | |||||
| if (showAlertWindows) | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Update Server Communication Error", | |||||
| "Failed to communicate with the JUCE update server.\n" | |||||
| "Please try again in a few minutes.\n\n" | |||||
| "If this problem persists you can download the latest version of JUCE from juce.com"); | |||||
| String getProductVersionString() | |||||
| { | |||||
| return formatProductVersion (ProjectInfo::versionNumber); | |||||
| return; | |||||
| } | } | ||||
| bool isNewVersion (const String& current, const String& other) | |||||
| if (! info->isNewerVersionThanCurrent()) | |||||
| { | { | ||||
| auto currentTokens = StringArray::fromTokens (current, ".", {}); | |||||
| auto otherTokens = StringArray::fromTokens (other, ".", {}); | |||||
| jassert (currentTokens.size() == 3 && otherTokens.size() == 3); | |||||
| if (currentTokens[0].getIntValue() == otherTokens[0].getIntValue()) | |||||
| { | |||||
| if (currentTokens[1].getIntValue() == otherTokens[1].getIntValue()) | |||||
| return currentTokens[2].getIntValue() < otherTokens[2].getIntValue(); | |||||
| return currentTokens[1].getIntValue() < otherTokens[1].getIntValue(); | |||||
| } | |||||
| return currentTokens[0].getIntValue() < otherTokens[0].getIntValue(); | |||||
| } | |||||
| } | |||||
| void LatestVersionCheckerAndUpdater::queryUpdateServer() | |||||
| { | |||||
| StringPairArray responseHeaders; | |||||
| URL latestVersionURL ("https://my.roli.com/software_versions/update_to/Projucer/" | |||||
| + VersionHelpers::getProductVersionString() + '/' + getOSString() | |||||
| + "?language=" + SystemStats::getUserLanguage()); | |||||
| std::unique_ptr<InputStream> inStream (latestVersionURL.createInputStream (false, nullptr, nullptr, | |||||
| "X-API-Key: 265441b-343403c-20f6932-76361d\nContent-Type: " | |||||
| "application/json\nAccept: application/json; version=1", | |||||
| 0, &responseHeaders, &statusCode, 0)); | |||||
| if (threadShouldExit()) | |||||
| if (showAlertWindows) | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, | |||||
| "No New Version Available", | |||||
| "Your JUCE version is up to date."); | |||||
| return; | return; | ||||
| if (inStream.get() != nullptr && (statusCode == 303 || statusCode == 400)) | |||||
| { | |||||
| if (statusCode == 303) | |||||
| relativeDownloadPath = responseHeaders["Location"]; | |||||
| jassert (relativeDownloadPath.isNotEmpty()); | |||||
| jsonReply = JSON::parse (inStream->readEntireStreamAsString()); | |||||
| } | } | ||||
| else if (showAlertWindows) | |||||
| auto osString = [] | |||||
| { | { | ||||
| if (statusCode == 204) | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "No New Version Available", "Your JUCE version is up to date."); | |||||
| else | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Network Error", "Could not connect to the web server.\n" | |||||
| "Please check your internet connection and try again."); | |||||
| } | |||||
| } | |||||
| #if JUCE_MAC | |||||
| return "osx"; | |||||
| #elif JUCE_WINDOWS | |||||
| return "windows"; | |||||
| #elif JUCE_LINUX | |||||
| return "linux"; | |||||
| #else | |||||
| jassertfalse; | |||||
| return "Unknown"; | |||||
| #endif | |||||
| }(); | |||||
| void LatestVersionCheckerAndUpdater::processResult() | |||||
| { | |||||
| if (! jsonReply.isObject()) | |||||
| return; | |||||
| String requiredFilename ("juce-" + info->versionString + "-" + osString + ".zip"); | |||||
| if (statusCode == 400) | |||||
| for (auto& asset : info->assets) | |||||
| { | { | ||||
| auto errorObject = jsonReply.getDynamicObject()->getProperty ("error"); | |||||
| if (errorObject.isObject()) | |||||
| if (asset.name == requiredFilename) | |||||
| { | { | ||||
| auto message = errorObject.getProperty ("message", {}).toString(); | |||||
| auto versionString = info->versionString; | |||||
| auto releaseNotes = info->releaseNotes; | |||||
| MessageManager::callAsync ([this, versionString, releaseNotes, asset] | |||||
| { | |||||
| askUserAboutNewVersion (versionString, releaseNotes, asset); | |||||
| }); | |||||
| if (message.isNotEmpty()) | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "JUCE Updater", message); | |||||
| return; | |||||
| } | } | ||||
| } | } | ||||
| else if (statusCode == 303) | |||||
| { | |||||
| askUserAboutNewVersion (jsonReply.getProperty ("version", {}).toString(), | |||||
| jsonReply.getProperty ("notes", {}).toString()); | |||||
| } | |||||
| if (showAlertWindows) | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Failed to find any new downloads", | |||||
| "Please try again in a few minutes."); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -246,14 +192,15 @@ public: | |||||
| RectanglePlacement::stretchToFit, 1.0f); | RectanglePlacement::stretchToFit, 1.0f); | ||||
| } | } | ||||
| static std::unique_ptr<DialogWindow> launchDialog (const String& newVersion, const String& releaseNotes) | |||||
| static std::unique_ptr<DialogWindow> launchDialog (const String& newVersionString, | |||||
| const String& releaseNotes) | |||||
| { | { | ||||
| DialogWindow::LaunchOptions options; | DialogWindow::LaunchOptions options; | ||||
| options.dialogTitle = "Download JUCE version " + newVersion + "?"; | |||||
| options.dialogTitle = "Download JUCE version " + newVersionString + "?"; | |||||
| options.resizable = false; | options.resizable = false; | ||||
| auto* content = new UpdateDialog (newVersion, releaseNotes); | |||||
| auto* content = new UpdateDialog (newVersionString, releaseNotes); | |||||
| options.content.set (content, true); | options.content.set (content, true); | ||||
| std::unique_ptr<DialogWindow> dialog (options.create()); | std::unique_ptr<DialogWindow> dialog (options.create()); | ||||
| @@ -292,66 +239,83 @@ private: | |||||
| DialogWindow* parentWindow = nullptr; | DialogWindow* parentWindow = nullptr; | ||||
| }; | }; | ||||
| void LatestVersionCheckerAndUpdater::askUserForLocationToDownload() | |||||
| void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const VersionInfo::Asset& asset) | |||||
| { | { | ||||
| FileChooser chooser ("Please select the location into which you'd like to install the new version", | |||||
| FileChooser chooser ("Please select the location into which you would like to install the new version", | |||||
| { getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get() }); | { getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get() }); | ||||
| if (chooser.browseForDirectory()) | if (chooser.browseForDirectory()) | ||||
| { | { | ||||
| auto targetFolder = chooser.getResult(); | auto targetFolder = chooser.getResult(); | ||||
| if (isJUCEFolder (targetFolder)) | |||||
| // By default we will install into 'targetFolder/JUCE', but we should install into | |||||
| // 'targetFolder' if that is an existing JUCE directory. | |||||
| bool willOverwriteJuceFolder = [&targetFolder] | |||||
| { | |||||
| if (isJUCEFolder (targetFolder)) | |||||
| return true; | |||||
| targetFolder = targetFolder.getChildFile ("JUCE"); | |||||
| return isJUCEFolder (targetFolder); | |||||
| }(); | |||||
| auto targetFolderPath = targetFolder.getFullPathName(); | |||||
| if (willOverwriteJuceFolder) | |||||
| { | { | ||||
| if (targetFolder.getChildFile (".git").isDirectory()) | if (targetFolder.getChildFile (".git").isDirectory()) | ||||
| { | { | ||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Downloading New JUCE Version", | AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Downloading New JUCE Version", | ||||
| "This folder is a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); | |||||
| targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); | |||||
| return; | return; | ||||
| } | } | ||||
| if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Overwrite Existing JUCE Folder?", | if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Overwrite Existing JUCE Folder?", | ||||
| String ("Do you want to overwrite the folder:\n\n" + targetFolder.getFullPathName() + "\n\n..with the latest version from juce.com?\n\n" | |||||
| "This will move the existing folder to " + targetFolder.getFullPathName() + "_old."))) | |||||
| "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n" | |||||
| "This will move the existing folder to " + targetFolderPath + "_old.")) | |||||
| { | { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| else | |||||
| else if (targetFolder.exists()) | |||||
| { | { | ||||
| targetFolder = targetFolder.getChildFile ("JUCE").getNonexistentSibling(); | |||||
| if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Existing File Or Directory", | |||||
| "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?")) | |||||
| { | |||||
| return; | |||||
| } | |||||
| } | } | ||||
| downloadAndInstall (targetFolder); | |||||
| downloadAndInstall (asset, targetFolder); | |||||
| } | } | ||||
| } | } | ||||
| void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersion, const String& releaseNotes) | |||||
| void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersionString, | |||||
| const String& releaseNotes, | |||||
| const VersionInfo::Asset& asset) | |||||
| { | { | ||||
| if (newVersion.isNotEmpty() && releaseNotes.isNotEmpty() | |||||
| && VersionHelpers::isNewVersion (VersionHelpers::getProductVersionString(), newVersion)) | |||||
| { | |||||
| dialogWindow = UpdateDialog::launchDialog (newVersion, releaseNotes); | |||||
| dialogWindow = UpdateDialog::launchDialog (newVersionString, releaseNotes); | |||||
| if (auto* mm = ModalComponentManager::getInstance()) | |||||
| mm->attachCallback (dialogWindow.get(), ModalCallbackFunction::create ([this] (int result) | |||||
| { | |||||
| if (result == 1) | |||||
| askUserForLocationToDownload(); | |||||
| if (auto* mm = ModalComponentManager::getInstance()) | |||||
| mm->attachCallback (dialogWindow.get(), | |||||
| ModalCallbackFunction::create ([this, asset] (int result) | |||||
| { | |||||
| if (result == 1) | |||||
| askUserForLocationToDownload (asset); | |||||
| dialogWindow.reset(); | |||||
| })); | |||||
| } | |||||
| dialogWindow.reset(); | |||||
| })); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| class DownloadAndInstallThread : private ThreadWithProgressWindow | class DownloadAndInstallThread : private ThreadWithProgressWindow | ||||
| { | { | ||||
| public: | public: | ||||
| DownloadAndInstallThread (const URL& u, const File& t, std::function<void()>&& cb) | |||||
| DownloadAndInstallThread (const VersionInfo::Asset& a, const File& t, std::function<void()>&& cb) | |||||
| : ThreadWithProgressWindow ("Downloading New Version", true, true), | : ThreadWithProgressWindow ("Downloading New Version", true, true), | ||||
| downloadURL (u), targetFolder (t), completionCallback (std::move (cb)) | |||||
| asset (a), targetFolder (t), completionCallback (std::move (cb)) | |||||
| { | { | ||||
| launchThread (3); | launchThread (3); | ||||
| } | } | ||||
| @@ -368,7 +332,9 @@ private: | |||||
| result = install (zipData); | result = install (zipData); | ||||
| if (result.failed()) | if (result.failed()) | ||||
| MessageManager::callAsync ([result] () { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Installation Failed", result.getErrorMessage()); }); | |||||
| MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "Installation Failed", | |||||
| result.getErrorMessage()); }); | |||||
| else | else | ||||
| MessageManager::callAsync (completionCallback); | MessageManager::callAsync (completionCallback); | ||||
| } | } | ||||
| @@ -378,10 +344,7 @@ private: | |||||
| setStatusMessage ("Downloading..."); | setStatusMessage ("Downloading..."); | ||||
| int statusCode = 0; | int statusCode = 0; | ||||
| StringPairArray responseHeaders; | |||||
| std::unique_ptr<InputStream> inStream (downloadURL.createInputStream (false, nullptr, nullptr, {}, 0, | |||||
| &responseHeaders, &statusCode, 0)); | |||||
| auto inStream = VersionInfo::createInputStreamForAsset (asset, statusCode); | |||||
| if (inStream != nullptr && statusCode == 200) | if (inStream != nullptr && statusCode == 200) | ||||
| { | { | ||||
| @@ -406,53 +369,53 @@ private: | |||||
| return Result::ok(); | return Result::ok(); | ||||
| } | } | ||||
| return Result::fail ("Failed to download from: " + downloadURL.toString (false)); | |||||
| return Result::fail ("Failed to download from: " + asset.url); | |||||
| } | } | ||||
| Result install (MemoryBlock& data) | |||||
| Result install (const MemoryBlock& data) | |||||
| { | { | ||||
| setStatusMessage ("Installing..."); | setStatusMessage ("Installing..."); | ||||
| auto result = unzipDownload (data); | |||||
| if (threadShouldExit()) | |||||
| result = Result::fail ("Cancelled"); | |||||
| if (result.failed()) | |||||
| return result; | |||||
| return Result::ok(); | |||||
| } | |||||
| Result unzipDownload (const MemoryBlock& data) | |||||
| { | |||||
| MemoryInputStream input (data, false); | MemoryInputStream input (data, false); | ||||
| ZipFile zip (input); | ZipFile zip (input); | ||||
| if (zip.getNumEntries() == 0) | if (zip.getNumEntries() == 0) | ||||
| return Result::fail ("The downloaded file was not a valid JUCE file!"); | return Result::fail ("The downloaded file was not a valid JUCE file!"); | ||||
| auto unzipTarget = File::createTempFile ({}); | |||||
| struct ScopedDownloadFolder | |||||
| { | |||||
| ScopedDownloadFolder (const File& installTargetFolder) | |||||
| { | |||||
| folder = installTargetFolder.getSiblingFile (installTargetFolder.getFileNameWithoutExtension() + "_download").getNonexistentSibling(); | |||||
| jassert (folder.createDirectory()); | |||||
| } | |||||
| ~ScopedDownloadFolder() { folder.deleteRecursively(); } | |||||
| if (! unzipTarget.createDirectory()) | |||||
| File folder; | |||||
| }; | |||||
| ScopedDownloadFolder unzipTarget (targetFolder); | |||||
| if (! unzipTarget.folder.isDirectory()) | |||||
| return Result::fail ("Couldn't create a temporary folder to unzip the new version!"); | return Result::fail ("Couldn't create a temporary folder to unzip the new version!"); | ||||
| auto r = zip.uncompressTo (unzipTarget); | |||||
| auto r = zip.uncompressTo (unzipTarget.folder); | |||||
| if (r.failed()) | if (r.failed()) | ||||
| { | |||||
| unzipTarget.deleteRecursively(); | |||||
| return r; | return r; | ||||
| } | |||||
| if (threadShouldExit()) | |||||
| return Result::fail ("Cancelled"); | |||||
| #if JUCE_LINUX || JUCE_MAC | #if JUCE_LINUX || JUCE_MAC | ||||
| r = setFilePermissions (unzipTarget, zip); | |||||
| r = setFilePermissions (unzipTarget.folder, zip); | |||||
| if (r.failed()) | if (r.failed()) | ||||
| { | |||||
| unzipTarget.deleteRecursively(); | |||||
| return r; | return r; | ||||
| } | |||||
| if (threadShouldExit()) | |||||
| return Result::fail ("Cancelled"); | |||||
| #endif | #endif | ||||
| if (targetFolder.exists()) | if (targetFolder.exists()) | ||||
| @@ -460,21 +423,15 @@ private: | |||||
| auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling(); | auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling(); | ||||
| if (! targetFolder.moveFileTo (oldFolder)) | if (! targetFolder.moveFileTo (oldFolder)) | ||||
| { | |||||
| unzipTarget.deleteRecursively(); | |||||
| return Result::fail ("Could not remove the existing folder!\n\n" | return Result::fail ("Could not remove the existing folder!\n\n" | ||||
| "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n" | "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n" | ||||
| "Please select a folder that is writable by the current user."); | "Please select a folder that is writable by the current user."); | ||||
| } | |||||
| } | } | ||||
| if (! unzipTarget.moveFileTo (targetFolder)) | |||||
| { | |||||
| unzipTarget.deleteRecursively(); | |||||
| if (! unzipTarget.folder.getChildFile ("JUCE").moveFileTo (targetFolder)) | |||||
| return Result::fail ("Could not overwrite the existing folder!\n\n" | return Result::fail ("Could not overwrite the existing folder!\n\n" | ||||
| "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n" | "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n" | ||||
| "Please select a folder that is writable by the current user."); | "Please select a folder that is writable by the current user."); | ||||
| } | |||||
| return Result::ok(); | return Result::ok(); | ||||
| } | } | ||||
| @@ -502,7 +459,7 @@ private: | |||||
| return Result::ok(); | return Result::ok(); | ||||
| } | } | ||||
| URL downloadURL; | |||||
| VersionInfo::Asset asset; | |||||
| File targetFolder; | File targetFolder; | ||||
| std::function<void()> completionCallback; | std::function<void()> completionCallback; | ||||
| }; | }; | ||||
| @@ -533,9 +490,9 @@ void restartProcess (const File& targetFolder) | |||||
| } | } | ||||
| } | } | ||||
| void LatestVersionCheckerAndUpdater::downloadAndInstall (const File& targetFolder) | |||||
| void LatestVersionCheckerAndUpdater::downloadAndInstall (const VersionInfo::Asset& asset, const File& targetFolder) | |||||
| { | { | ||||
| installer.reset (new DownloadAndInstallThread ({ relativeDownloadPath }, targetFolder, | |||||
| installer.reset (new DownloadAndInstallThread (asset, targetFolder, | |||||
| [this, targetFolder] | [this, targetFolder] | ||||
| { | { | ||||
| installer.reset(); | installer.reset(); | ||||
| @@ -26,6 +26,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "../Utility/Helpers/jucer_VersionInfo.h" | |||||
| class DownloadAndInstallThread; | class DownloadAndInstallThread; | ||||
| class LatestVersionCheckerAndUpdater : public DeletedAtShutdown, | class LatestVersionCheckerAndUpdater : public DeletedAtShutdown, | ||||
| @@ -43,17 +45,12 @@ public: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| void run() override; | void run() override; | ||||
| void queryUpdateServer(); | |||||
| void processResult(); | |||||
| void askUserAboutNewVersion (const String&, const String&); | |||||
| void askUserForLocationToDownload(); | |||||
| void downloadAndInstall (const File&); | |||||
| void askUserAboutNewVersion (const String&, const String&, const VersionInfo::Asset&); | |||||
| void askUserForLocationToDownload (const VersionInfo::Asset&); | |||||
| void downloadAndInstall (const VersionInfo::Asset&, const File&); | |||||
| //============================================================================== | //============================================================================== | ||||
| bool showAlertWindows = false; | bool showAlertWindows = false; | ||||
| int statusCode = 0; | |||||
| String relativeDownloadPath; | |||||
| var jsonReply; | |||||
| std::unique_ptr<DownloadAndInstallThread> installer; | std::unique_ptr<DownloadAndInstallThread> installer; | ||||
| std::unique_ptr<Component> dialogWindow; | std::unique_ptr<Component> dialogWindow; | ||||
| @@ -27,6 +27,7 @@ | |||||
| #include "../Application/jucer_Headers.h" | #include "../Application/jucer_Headers.h" | ||||
| #include "jucer_DownloadCompileEngineThread.h" | #include "jucer_DownloadCompileEngineThread.h" | ||||
| #include "../LiveBuildEngine/jucer_CompileEngineDLL.h" | #include "../LiveBuildEngine/jucer_CompileEngineDLL.h" | ||||
| #include "../Utility/Helpers/jucer_VersionInfo.h" | |||||
| //============================================================================== | //============================================================================== | ||||
| bool DownloadCompileEngineThread::downloadAndInstall() | bool DownloadCompileEngineThread::downloadAndInstall() | ||||
| @@ -83,38 +84,60 @@ void DownloadCompileEngineThread::run() | |||||
| Result DownloadCompileEngineThread::download (MemoryBlock& dest) | Result DownloadCompileEngineThread::download (MemoryBlock& dest) | ||||
| { | { | ||||
| int statusCode = 302; | |||||
| const int timeoutMs = 10000; | |||||
| StringPairArray responseHeaders; | |||||
| auto info = VersionInfo::fetchFromUpdateServer (ProjectInfo::versionString); | |||||
| URL url = getDownloadUrl(); | |||||
| std::unique_ptr<InputStream> in (url.createInputStream (false, nullptr, nullptr, | |||||
| String(), timeoutMs, &responseHeaders, | |||||
| &statusCode, 0)); | |||||
| if (info == nullptr) | |||||
| return Result::fail ("Download error: cannot communicate with server"); | |||||
| if (in == nullptr || statusCode != 200) | |||||
| return Result::fail ("Download error: cannot establish connection"); | |||||
| auto requiredAssetName = [] | |||||
| { | |||||
| String name ("JUCECompileEngine_"); | |||||
| MemoryOutputStream mo (dest, true); | |||||
| #if JUCE_MAC | |||||
| name << "osx_"; | |||||
| #elif JUCE_WINDOWS | |||||
| name << "windows_"; | |||||
| #else | |||||
| jassertfalse; | |||||
| #endif | |||||
| int64 size = in->getTotalLength(); | |||||
| int64 bytesReceived = -1; | |||||
| String msg("Downloading... (123)"); | |||||
| return name + ProjectInfo::versionString + ".zip"; | |||||
| }(); | |||||
| for (int64 pos = 0; pos < size; pos += bytesReceived) | |||||
| for (auto& asset : info->assets) | |||||
| { | { | ||||
| setStatusMessage (msg.replace ("123", File::descriptionOfSizeInBytes (pos))); | |||||
| if (asset.name == requiredAssetName) | |||||
| { | |||||
| int statusCode = 0; | |||||
| auto in = VersionInfo::createInputStreamForAsset (asset, statusCode); | |||||
| if (in == nullptr || statusCode != 200) | |||||
| return Result::fail ("Download error: cannot establish connection"); | |||||
| MemoryOutputStream mo (dest, true); | |||||
| int64 size = in->getTotalLength(); | |||||
| int64 bytesReceived = -1; | |||||
| String msg("Downloading... (123)"); | |||||
| for (int64 pos = 0; pos < size; pos += bytesReceived) | |||||
| { | |||||
| setStatusMessage (msg.replace ("123", File::descriptionOfSizeInBytes (pos))); | |||||
| if (threadShouldExit()) | |||||
| return Result::fail ("Download error: operation interrupted"); | |||||
| if (threadShouldExit()) | |||||
| return Result::fail ("Download error: operation interrupted"); | |||||
| bytesReceived = mo.writeFromInputStream (*in, 8192); | |||||
| bytesReceived = mo.writeFromInputStream (*in, 8192); | |||||
| if (bytesReceived == 0) | |||||
| return Result::fail ("Download error: lost connection"); | |||||
| } | |||||
| if (bytesReceived == 0) | |||||
| return Result::fail ("Download error: lost connection"); | |||||
| return Result::ok(); | |||||
| } | |||||
| } | } | ||||
| return Result::ok(); | |||||
| return Result::fail ("Download error: no downloads available"); | |||||
| } | } | ||||
| Result DownloadCompileEngineThread::install (const MemoryBlock& data, File& targetFolder) | Result DownloadCompileEngineThread::install (const MemoryBlock& data, File& targetFolder) | ||||
| @@ -131,21 +154,6 @@ Result DownloadCompileEngineThread::install (const MemoryBlock& data, File& targ | |||||
| return zip.uncompressTo (targetFolder); | return zip.uncompressTo (targetFolder); | ||||
| } | } | ||||
| URL DownloadCompileEngineThread::getDownloadUrl() | |||||
| { | |||||
| String urlStub ("http://assets.roli.com/juce/JUCECompileEngine_"); | |||||
| #if JUCE_MAC | |||||
| urlStub << "osx_"; | |||||
| #elif JUCE_WINDOWS | |||||
| urlStub << "windows_"; | |||||
| #else | |||||
| jassertfalse; | |||||
| #endif | |||||
| return urlStub + ProjectInfo::versionString + ".zip"; | |||||
| } | |||||
| File DownloadCompileEngineThread::getInstallFolder() | File DownloadCompileEngineThread::getInstallFolder() | ||||
| { | { | ||||
| return CompileEngineDLL::getVersionedUserAppSupportFolder(); | return CompileEngineDLL::getVersionedUserAppSupportFolder(); | ||||
| @@ -0,0 +1,115 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2017 - ROLI Ltd. | |||||
| JUCE is an open source library subject to commercial or open-source | |||||
| licensing. | |||||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||||
| 27th April 2017). | |||||
| End User License Agreement: www.juce.com/juce-5-licence | |||||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||||
| Or: You may also use this code under the terms of the GPL v3 (see | |||||
| www.gnu.org/licenses). | |||||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||||
| DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../Application/jucer_Headers.h" | |||||
| #include "jucer_VersionInfo.h" | |||||
| std::unique_ptr<VersionInfo> VersionInfo::fetchFromUpdateServer (const String& versionString) | |||||
| { | |||||
| return fetch ("tags/" + versionString); | |||||
| } | |||||
| std::unique_ptr<VersionInfo> VersionInfo::fetchLatestFromUpdateServer() | |||||
| { | |||||
| return fetch ("latest"); | |||||
| } | |||||
| std::unique_ptr<InputStream> VersionInfo::createInputStreamForAsset (const Asset& asset, int& statusCode) | |||||
| { | |||||
| URL downloadUrl (asset.url); | |||||
| StringPairArray responseHeaders; | |||||
| return std::unique_ptr<InputStream> (downloadUrl.createInputStream (false, nullptr, nullptr, | |||||
| "Accept: application/octet-stream", | |||||
| 0, &responseHeaders, &statusCode, 1)); | |||||
| } | |||||
| bool VersionInfo::isNewerVersionThanCurrent() | |||||
| { | |||||
| jassert (versionString.isNotEmpty()); | |||||
| auto currentTokens = StringArray::fromTokens (ProjectInfo::versionString, ".", {}); | |||||
| auto thisTokens = StringArray::fromTokens (versionString, ".", {}); | |||||
| jassert (thisTokens.size() == 3 && thisTokens.size() == 3); | |||||
| if (currentTokens[0].getIntValue() == thisTokens[0].getIntValue()) | |||||
| { | |||||
| if (currentTokens[1].getIntValue() == thisTokens[1].getIntValue()) | |||||
| return currentTokens[2].getIntValue() < thisTokens[2].getIntValue(); | |||||
| return currentTokens[1].getIntValue() < thisTokens[1].getIntValue(); | |||||
| } | |||||
| return currentTokens[0].getIntValue() < thisTokens[0].getIntValue(); | |||||
| } | |||||
| std::unique_ptr<VersionInfo> VersionInfo::fetch (const String& endpoint) | |||||
| { | |||||
| URL latestVersionURL ("https://api.github.com/repos/WeAreROLI/JUCE/releases/" + endpoint); | |||||
| std::unique_ptr<InputStream> inStream (latestVersionURL.createInputStream (false)); | |||||
| if (inStream == nullptr) | |||||
| return nullptr; | |||||
| auto content = inStream->readEntireStreamAsString(); | |||||
| auto latestReleaseDetails = JSON::parse (content); | |||||
| auto* json = latestReleaseDetails.getDynamicObject(); | |||||
| if (json == nullptr) | |||||
| return nullptr; | |||||
| auto versionString = json->getProperty ("tag_name").toString(); | |||||
| if (versionString.isEmpty()) | |||||
| return nullptr; | |||||
| auto* assets = json->getProperty ("assets").getArray(); | |||||
| if (assets == nullptr) | |||||
| return nullptr; | |||||
| auto releaseNotes = json->getProperty ("body").toString(); | |||||
| std::vector<VersionInfo::Asset> parsedAssets; | |||||
| for (auto& asset : *assets) | |||||
| { | |||||
| if (auto* assetJson = asset.getDynamicObject()) | |||||
| { | |||||
| parsedAssets.push_back ({ assetJson->getProperty ("name").toString(), | |||||
| assetJson->getProperty ("url").toString() }); | |||||
| jassert (parsedAssets.back().name.isNotEmpty()); | |||||
| jassert (parsedAssets.back().url.isNotEmpty()); | |||||
| } | |||||
| else | |||||
| { | |||||
| jassertfalse; | |||||
| } | |||||
| } | |||||
| return std::unique_ptr<VersionInfo> (new VersionInfo ({ versionString, releaseNotes, std::move (parsedAssets) })); | |||||
| } | |||||
| @@ -0,0 +1,54 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2017 - ROLI Ltd. | |||||
| JUCE is an open source library subject to commercial or open-source | |||||
| licensing. | |||||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||||
| 27th April 2017). | |||||
| End User License Agreement: www.juce.com/juce-5-licence | |||||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||||
| Or: You may also use this code under the terms of the GPL v3 (see | |||||
| www.gnu.org/licenses). | |||||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||||
| DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| #pragma once | |||||
| //============================================================================== | |||||
| class VersionInfo | |||||
| { | |||||
| public: | |||||
| struct Asset | |||||
| { | |||||
| const String name; | |||||
| const String url; | |||||
| }; | |||||
| static std::unique_ptr<VersionInfo> fetchFromUpdateServer (const String& versionString); | |||||
| static std::unique_ptr<VersionInfo> fetchLatestFromUpdateServer(); | |||||
| static std::unique_ptr<InputStream> createInputStreamForAsset (const Asset& asset, int& statusCode); | |||||
| bool isNewerVersionThanCurrent(); | |||||
| const String versionString; | |||||
| const String releaseNotes; | |||||
| const std::vector<Asset> assets; | |||||
| private: | |||||
| VersionInfo() = default; | |||||
| static std::unique_ptr<VersionInfo> fetch (const String&); | |||||
| }; | |||||