Closed mauricioulla closed 1 year ago
Yeah I see the problem - semantic versioning is not easy to compare because it's not string comparable - you have to actually compare each version by parsing out the number pairs. This is relatively easy to do with the .NET version function, but this method is called before .NET is loaded so we can't use that unfortunately.
For now I'm making two changes:
ASORT(laFolders,1,ALEN(laFolders,1),1)
- reverse order is better matchlnIndex = ASCAN(laFolders,lcVersion,1,-1,-1,4)
- your suggested changeThis improves things significantly and works even around some of the case I didn't expect to work (ie. 7.1.1 and 7.13.2)
This demonstrates some of the ordering issue:
For now the EXACT fix and the order reversal produce better results though and as long as numbers stay below .10 the (which they usually do) I think this won't actually be an issue.
Ok spent a little more time doing a proper update for this so this should work correctly now:
************************************************************************
* FindDotnetCoreRuntime
****************************************
*** Function: Finds the .NET Core Runtime Path
*** Assume:
*** Pass: lcVersion
*** Modes:
*** Full Path: C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\2.2.5
*** Version only: 2.2.5
*** Partial version 2.1 or 2.2 or 3.0
*** Return: Runtime Folder path or empty string
************************************************************************
FUNCTION GetDotnetCoreRuntimeFolder(lcVersion)
LOCAL lcFolder, lnFolderId, lnResult, lcOutput, lcFolderName, lnX, lnIndex
LOCAL lcVersion, lnParts, lcBasePath
LOCAL laParts[1], laFolders[1,4], laVersions[1,1]
IF !EMPTY(lcVersion) AND DIRECTORY(lcVersion)
RETURN ADDBS(lcVersion)
ENDIF
DECLARE INTEGER SHGetFolderPath IN Shell32.dll ;
INTEGER Hwnd, INTEGER nFolder, INTEGER Token, INTEGER Flags, STRING @cPath
lnFolderId = 0x0026 && Program Files
lcOutput = repl(CHR(0),256)
lnResult = SHGetFolderPath(_VFP.hWnd,lnFolderId,0,0,@lcOutput)
IF lnResult = 0
lcOutput = STRTRAN(lcOutput,CHR(0),"") + "\"
ELSE
lcOutput = ""
ENDIF
IF EMPTY(lcVersion)
lcVersion = ""
ENDIF
lcBasePath = ADDBS(lcOutput) + "dotnet\shared\Microsoft.NETCore.App\"
IF !EMPTY(lcVersion)
*** Check for exact folder match
IF DIRECTORY(lcVersion)
RETURN ADDBS(lcFolder)
ENDIF
*** Check for exact version match
IF DIRECTORY(lcBasePath + lcVersion)
RETURN lcBasePath + lcVersion + "\"
ENDIF
ENDIF
*** We have to determine the highest matching version for partial version supplied
*** We capture folder names and pad out version parts in order to sort properly
*** then pick the highest value
lnFolders = ADIR(laFolders,lcBasePath + lcVersion + "*.*","D")
IF lnFolders < 1
RETURN ""
ENDIF
*** Reformat folders with left padding to 3 characters and find the largest version
DIMENSION laVersions[lnFolders,2]
FOR lnX = 1 TO lnFolders
lcVersion = laFolders[lnX,1]
DIMENSION laParts[1]
lnParts= ALINES(laParts, lcVersion, 1, '.')
lcAdjusted = PADL(INT(VAL(laParts[1])),3,'0')
IF(lnParts > 1)
lcAdjusted = lcAdjusted + "." + PADL(INT(VAL(laParts[2])),3,'0')
ENDIF
IF(lnParts > 2)
lcAdjusted = lcAdjusted + "." + PADL(INT(VAL(laParts[3])),3,'0')
ENDIF
IF(lnParts > 3)
lcAdjusted = lcAdjusted + "." + PADL(INT(VAL(laParts[4])),3,'0')
ENDIF
laVersions[lnx, 1] = lcAdjusted
laVersions[lnx, 2] = lcVersion
ENDFOR
ASORT(laVersions,1,ALEN(laVersions,1),1)
lcFullVersion = laVersions[1,2]
RETURN lcBasePath + lcFullVersion + "\"
Code basically modifies the version strings into padded number pairs that are sortable and then picks the highest version for the match. As before exact version or path match supersedes the lookup.
Here's what this now looks like:
And it's now picking up version 7.13.1
over 7.2.1
.
This will work for version parts up to .999
which should be enough :smile:
Great! Padding each version part with zeros was my after-think I wrote the issue.
You read my mind! 😆
Hi Rick!
The Problem
Considers the followings Net Core versions installed in C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App:
Then, when I create my wwDotNetCoreBridge with CREATEOBJECT("wwDotnetCoreBridge", myParam), I am using myParam for lcRuntimeFolder parameter of Init().
Empty version case
When myParam is empty => fine the version that I get is 7.0.1, great the highest!
Exact version case
When myParam is exactly a installed SDK version => Works fine, for instance with "3.1.12", "5.0.9", "5.0.17", here everything is ok.
Latest release version case
But, what happens when I want the latest release of a specific SDK versions? Lets say using the Partial Version mode:
When myParam is "3.1" => I get 7.0.1 when I expected 3.1.32! When myParam is "5.0" => I get 7.0.1 too when I expected 5.0.17! Same thing when myParam is "6.0" => again, I get 7.0.1 when I expected 6.0.12!
Debugging the code, I found that my application execute SET EXACT ON very early and before (hundreds of lines before) my wwDotNetCoreBridge instance creation.
So, I implemented the following workaround:
After that, When myParam is "6.0" => I get 6.0.12, good! But when myParam is "5.0" => I get 5.0.10, oh! oh! oh! ... I expected 5.0.17! Ok, trying with myParam as "3.1" => I get 3.1.11, when I expected 3.1.32... something weird here. Then, if in the future MSFT release another release of 6.0 SDK, lets say a 6.0.22, and my computer would has the 6.0.12 and 6.0.22 releases, wwDotnetCoreBridge will load the 6.0.12 release when I would want 6.0.22... Thats my real case today.
My suggestion
May be, in the line 2018 of wwDotnetBridge.PRG you could replace:
with something like that, using bit 2 of nFlags parameter in ASCAN() to override the system Exact setting:
Something like that would avoid to implement a workaround like mine, but this is insufficient because doesn't fix the multiple releases case. :-(
Idea for the multiple releases case
I think that here, once that you found the subset of folder of the SDK version, you need order them and deal with the right order because are strings and not numbers. ;-)
I hope was clear.