C
C#3w ago
Alice

Extracting values from external data files for a property in `.csproj`?

we are working on mod setup for a unity game installed through steam so we need to import game DLLs from steam library. we wrote a C# snippet that seems to perform that task correctly:
var SteamInstallPathFromRegistry = OS == "Windows_NT" ? $"{MSBuild.GetRegistryValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath")}" : "";
var SteamDir = OS == "Windows_NT" ? SteamInstallPathFromRegistry != "" ? $"{SteamInstallPathFromRegistry}/steamapps": "C:/Program Files (x86)/Steam/steamapps" : $"{Environment.GetEnvironmentVariable("HOME")}/.steam/steam/steamapps";

var HasteAppId = "1796470";
var Libraries = System.IO.File.ReadAllText($"{SteamDir}/libraryfolders.vdf");
var InstallLibrary = Libraries;
// var InstallLibrary = Regex.Replace(InstallLibrary, $"\"{HasteAppId}\".*", "");
// InstallLibrary = InstallLibrary[(InstallLibrary.LastIndexOf("\"path\"") + 9)..];
// InstallLibrary = $"{InstallLibrary[..(InstallLibrary.IndexOfAny("\r\n".ToCharArray()) - 1)]}/steamapps";
InstallLibrary = Regex.Replace(InstallLibrary, $"\"{HasteAppId}\"(.|[\\n\\r])*", "");
InstallLibrary = Regex.Replace(InstallLibrary, "(.|[\\n\\r])*(?=\"path\").{9}", "");
InstallLibrary = Regex.Replace(InstallLibrary, "\"[\\r\\n](.|[\\n\\r])*", "/steamapps");
Console.Out.Write(InstallLibrary);
var SteamInstallPathFromRegistry = OS == "Windows_NT" ? $"{MSBuild.GetRegistryValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath")}" : "";
var SteamDir = OS == "Windows_NT" ? SteamInstallPathFromRegistry != "" ? $"{SteamInstallPathFromRegistry}/steamapps": "C:/Program Files (x86)/Steam/steamapps" : $"{Environment.GetEnvironmentVariable("HOME")}/.steam/steam/steamapps";

var HasteAppId = "1796470";
var Libraries = System.IO.File.ReadAllText($"{SteamDir}/libraryfolders.vdf");
var InstallLibrary = Libraries;
// var InstallLibrary = Regex.Replace(InstallLibrary, $"\"{HasteAppId}\".*", "");
// InstallLibrary = InstallLibrary[(InstallLibrary.LastIndexOf("\"path\"") + 9)..];
// InstallLibrary = $"{InstallLibrary[..(InstallLibrary.IndexOfAny("\r\n".ToCharArray()) - 1)]}/steamapps";
InstallLibrary = Regex.Replace(InstallLibrary, $"\"{HasteAppId}\"(.|[\\n\\r])*", "");
InstallLibrary = Regex.Replace(InstallLibrary, "(.|[\\n\\r])*(?=\"path\").{9}", "");
InstallLibrary = Regex.Replace(InstallLibrary, "\"[\\r\\n](.|[\\n\\r])*", "/steamapps");
Console.Out.Write(InstallLibrary);
but porting it to the <PropertyGroup> is proving to be a challenge, as trying to use that code in an inline task throws an error on input parameter property as soon as we add output property, and using repeated re-definition of <InstallLibrary> does not yield desired result either (and we don't know how to see what we are actually getting, as adding a target before Build with a Message with property value does not seem to output anything)
5 Replies
Alice
AliceOP3w ago
well, ugh, we spent embarrassingly long time (about 12 hours of different attempts) trying to figure out why it doesn't work, only to figure out that instead of using <Target Name="WriteBuildProperties" BeforeTargets="PreBuildEvent"><Message Text="$(InstallLibrary)" /></Target> we can write property to a file, which made us more confused as we got literal property name in the output, before we realized that property functions are really weird, and you can't really reference other properties literally, instead it has to be put in as a quoted string? so that last bit became:
<InstallLibrary>$(Libraries)</InstallLibrary>
<InstallLibrary>$([System.Text.RegularExpressions.Regex]::Replace('$(InstallLibrary)', '"$(HasteAppId)"(.|[\n\r])*', ''))</InstallLibrary>
<InstallLibrary>$([System.Text.RegularExpressions.Regex]::Replace('$(InstallLibrary)', '(.|[\n\r])*(?="path").{9}', ''))</InstallLibrary>
<InstallLibrary>$([System.Text.RegularExpressions.Regex]::Replace('$(InstallLibrary)', '"[\r\n](.|[\n\r])*', '/steamapps'))</InstallLibrary>
<InstallLibrary>$(Libraries)</InstallLibrary>
<InstallLibrary>$([System.Text.RegularExpressions.Regex]::Replace('$(InstallLibrary)', '"$(HasteAppId)"(.|[\n\r])*', ''))</InstallLibrary>
<InstallLibrary>$([System.Text.RegularExpressions.Regex]::Replace('$(InstallLibrary)', '(.|[\n\r])*(?="path").{9}', ''))</InstallLibrary>
<InstallLibrary>$([System.Text.RegularExpressions.Regex]::Replace('$(InstallLibrary)', '"[\r\n](.|[\n\r])*', '/steamapps'))</InstallLibrary>
and now we are getting what we actually expected, and build no longer fails, as well as Rider finding all the imported DLLs… and, we assume
<InstallLibrary>$(Libraries.Substring(0, Libraries.IndexOf('"$(HasteAppId)"')))</InstallLibrary>
<InstallLibrary>$(InstallLibrary.Substring(InstallLibrary.LastIndexOf('"path"') + 9))</InstallLibrary>
<InstallLibrary>$(InstallLibrary.Substring(0, InstallLibrary.IndexOfAny('\r\n'.ToCharArray()) - 1))/steamapps</InstallLibrary>
<InstallLibrary>$(Libraries.Substring(0, Libraries.IndexOf('"$(HasteAppId)"')))</InstallLibrary>
<InstallLibrary>$(InstallLibrary.Substring(InstallLibrary.LastIndexOf('"path"') + 9))</InstallLibrary>
<InstallLibrary>$(InstallLibrary.Substring(0, InstallLibrary.IndexOfAny('\r\n'.ToCharArray()) - 1))/steamapps</InstallLibrary>
has to be
<InstallLibrary>$('$(Libraries)'.Substring(0, '$(Libraries)'.IndexOf('"$(HasteAppId)"')))</InstallLibrary>
<InstallLibrary>$('$(InstallLibrary)'.Substring('$(InstallLibrary)'.LastIndexOf('"path"') + 9))</InstallLibrary>
<InstallLibrary>$('$(InstallLibrary)'.Substring(0, '$(InstallLibrary)'.IndexOfAny('\r\n'.ToCharArray()) - 1))/steamapps</InstallLibrary>
<InstallLibrary>$('$(Libraries)'.Substring(0, '$(Libraries)'.IndexOf('"$(HasteAppId)"')))</InstallLibrary>
<InstallLibrary>$('$(InstallLibrary)'.Substring('$(InstallLibrary)'.LastIndexOf('"path"') + 9))</InstallLibrary>
<InstallLibrary>$('$(InstallLibrary)'.Substring(0, '$(InstallLibrary)'.IndexOfAny('\r\n'.ToCharArray()) - 1))/steamapps</InstallLibrary>
instead? nope, ugh well, we got a working version, if somemany knows what the actuall correct way is, we'll appreciate it greatly (main doc page on property functions was not terribly helpful in getting this resolved)
reflectronic
reflectronic3w ago
<InstallLibrary>$(Libraries.Substring(0, $(Libraries.IndexOf('"$(HasteAppId)"'))))</InstallLibrary>
Alice
AliceOP3w ago
is there a reference for the syntax? because that's not at all what we would have been able to deduce ourselves
reflectronic
reflectronic3w ago
for the other ones you need to use the Add and Subtract property functions the nesting is too deep so i don't feel like writing them i dont think there is a reference. but $(Libraries) is the syntax for substituting the property value, and $(Libraries.Substring(...)) is the syntax for substituting the result of the property function. Libraries.IndexOf(...)) is passing literally "Libraries.IndexOf...." as an argument to Substring. '$(Libraries)'.IndexOf is writing out the value of Libraries and then ".IndexOf..." too the '$(...)' thing is not a special syntax, it is just putting quotation marks around the property value in the resulting string it's a common pattern so that an empty property value does not turn into nothing, it turns into ''
Alice
AliceOP3w ago
it is quite weird -~-

Did you find this page helpful?