Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 5.0% 18 / 0 / 362
Functions: -% 0 / 1 / 1
Branches: 2.0% 8 / 0 / 402

OMCompiler/Compiler/Script/PackageManagement.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package PackageManagement
37
38 import BaseAvlTree;
39 import JSON;
40 import SemanticVersion;
41
42 protected
43
44 import Autoconf;
45 import AvlSetString;
46 import Curl;
47 import Error;
48 import Global;
49 import List;
50 import Settings;
51 import StringUtil;
52 import System;
53 import Testsuite;
54 import Util;
55 import Unzip;
56
57 public
58
59 encapsulated package AvailableLibraries
60 import BaseAvlTree;
61 import PackageManagement.VersionMap;
62 extends BaseAvlTree;
63 redeclare type Key = String;
64 redeclare type Value = PackageManagement.VersionMap.Tree;
65 redeclare function extends keyStr
66 algorithm
67 outString := inKey;
68 end keyStr;
69 redeclare function extends valueStr
70 algorithm
71 ✗ outString := PackageManagement.VersionMap.printTreeStr(inValue);
72 end valueStr;
73 redeclare function extends keyCompare
74 algorithm
75 ✗ outResult := stringCompare(inKey1, inKey2);
76 end keyCompare;
77 end AvailableLibraries;
78
79 encapsulated package VersionMap
80 import BaseAvlTree;
81 import SemanticVersion;
82 extends BaseAvlTree;
83 redeclare type Key = SemanticVersion.Version;
84 redeclare type Value = String;
85 redeclare function extends keyStr
86 algorithm
87 ✗ outString := SemanticVersion.toString(inKey);
88 end keyStr;
89 redeclare function extends valueStr
90 algorithm
91 outString := inValue;
92 end valueStr;
93 redeclare function extends keyCompare
94 algorithm
95 ✗ outResult := SemanticVersion.compare(inKey1, inKey2, compareBuildInformation=true);
96 end keyCompare;
97 end VersionMap;
98
99 constant String metaDataFileName = "openmodelica.metadata.json";
100
101 function getInstalledLibraries
102 output AvailableLibraries.Tree tree;
103 protected
104 String mp, gd, first, ver, lib;
105 list<String> mps, files, dirs, rest;
106 VersionMap.Tree versions;
107 algorithm
108 ✗ mp := Settings.getModelicaPath(Testsuite.isRunning());
109 gd := Autoconf.groupDelimiter;
110 ✗ mps := System.strtok(mp, gd);
111 ✗ tree := AvailableLibraries.new();
112 files := {};
113 dirs := {};
114 ✗ for mp in mps loop
115 ✗ files := listAppend(list(mp + "/" + file for file in System.moFiles(mp)), files);
116 ✗ dirs := listAppend(list(mp + "/" + dir for dir in getLibrarySubdirectories(mp)), dirs);
117 end for;
118 ✗ for path in listAppend(files, dirs) loop
119 ✗ lib := System.basename(path);
120 ✗ if StringUtil.endsWith(lib, ".mo") then
121 ✗ lib := Util.removeLast3Char(lib);
122 end if;
123 ✗ first::rest := System.strtok(lib, " ");
124 ✗ ver := stringDelimitList(rest, " ");
125 ✗ versions := if AvailableLibraries.hasKey(tree, first) then AvailableLibraries.get(tree, first) else VersionMap.new();
126 ✗ versions := VersionMap.add(versions, SemanticVersion.parse(ver), path, conflictFunc=VersionMap.addConflictReplace);
127 ✗ tree := AvailableLibraries.add(tree, first, versions, conflictFunc=AvailableLibraries.addConflictReplace);
128 end for;
129 end getInstalledLibraries;
130
131 function getInstalledLibraryVersions
132 input String libraryName;
133 output list<String> libraryVersions = {};
134 protected
135 AvailableLibraries.Tree tree;
136 VersionMap.Tree versionTree;
137 list<SemanticVersion.Version> versions = {};
138 String versionStr;
139 algorithm
140 ✗ tree := getInstalledLibraries();
141 ✗ versionTree := AvailableLibraries.get(tree, libraryName);
142 ✗ versions := VersionMap.listKeys(versionTree);
143 ✗ for version in versions loop
144 ✗ versionStr := VersionMap.keyStr(version);
145 ✗ if (stringCompare(versionStr, "") > 0) then
146 libraryVersions := versionStr::libraryVersions;
147 end if;
148 end for;
149 end getInstalledLibraryVersions;
150
151 function getLibrarySubdirectories "This function returns a list of subdirectories that contain a package.mo file."
152 input String inPath;
153 output list<String> outSubdirectories = {};
154 protected
155 list<String> allSubdirectories = System.subDirectories(inPath);
156 String pd = Autoconf.pathDelimiter;
157 algorithm
158 ✗ for dir in allSubdirectories loop
159 ✗ if System.regularFileExists(inPath + pd + dir + pd + "package.mo") then
160 outSubdirectories := dir::outSubdirectories;
161 end if;
162 end for;
163 end getLibrarySubdirectories;
164
165 function providesExpectedVersion
166 input String version;
167 input JSON provides;
168 input SemanticVersion.Version wantedVersion;
169 output Boolean matches;
170 protected
171 list<String> providedVersions;
172 String str;
173 SemanticVersion.Version thisVersion;
174 algorithm
175 () := match wantedVersion
176 case SemanticVersion.NONSEMVER(str) guard str == "default" or str == ""
177 algorithm
178 matches := true; /* Any version matches the empty */
179 ✗ return;
180 then fail();
181 case SemanticVersion.SEMVER(major=0, minor=0, patch=0, prerelease={"default"})
182 algorithm
183 matches := true; /* Any version matches the empty */
184 ✗ return;
185 then fail();
186 else ();
187 end match;
188 ✗ providedVersions := JSON.getStringList(provides);
189 matches := false;
190 ✗ for v in version::providedVersions loop
191 ✗ thisVersion := SemanticVersion.parse(v, nonsemverAsZeroZeroZero=true);
192 ✗ if SemanticVersion.compare(thisVersion,wantedVersion,comparePrerelease=SemanticVersion.isPrerelease(wantedVersion) and SemanticVersion.isPrerelease(wantedVersion)) == 0 then
193 matches := true;
194 ✗ return;
195 end if;
196 end for;
197 end providesExpectedVersion;
198
199 constant list<String> supportLevels = {"fullSupport", "support", "experimental", "obsolete", "unknown", "noSupport"};
200 type SupportLevel = enumeration(noSupport, unknown, obsolete, experimental, support, fullSupport);
201
202 function getSupportLevel
203 input JSON obj;
204 output SupportLevel support;
205 algorithm
206 support := match obj
207 case JSON.STRING("fullSupport") then SupportLevel.fullSupport;
208 case JSON.STRING("support") then SupportLevel.support;
209 case JSON.STRING("experimental") then SupportLevel.experimental;
210 case JSON.STRING("obsolete") then SupportLevel.obsolete;
211 case JSON.STRING("unknown") then SupportLevel.unknown;
212 case JSON.STRING("noSupport") then SupportLevel.noSupport;
213 else
214 algorithm
215 ✗ Error.addInternalError("Unknown support level " + JSON.toString(obj), sourceInfo());
216 ✗ then fail();
217 end match;
218 end getSupportLevel;
219
220 function compareVersionsAndSupportLevel
221 input tuple<String,SemanticVersion.Version,SupportLevel> x1, x2;
222 output Boolean c;
223 protected
224 SupportLevel s1, s2;
225 SemanticVersion.Version v1, v2;
226 algorithm
227 ✗ (_, v1, s1) := x1;
228 ✗ (_, v2, s2) := x2;
229 ✗ if s1 < s2 then
230 c := true;
231 ✗ return;
232 elseif s1 > s2 then
233 c := false;
234 ✗ return;
235 end if;
236 ✗ if SemanticVersion.isPrerelease(v1) <> SemanticVersion.isPrerelease(v2) then
237 ✗ c := SemanticVersion.isPrerelease(v2);
238 ✗ return;
239 end if;
240 ✗ c := SemanticVersion.compare(v1, v2, compareBuildInformation=true) < 0;
241 end compareVersionsAndSupportLevel;
242
243 function updateIndex
244 output Boolean success;
245 protected
246 String userLibraries, packageIndex;
247 constant String url = "https://libraries.openmodelica.org/index/v1/index.json";
248 algorithm
249 ✗ userLibraries := getUserLibraryPath();
250 ✗ Util.createDirectoryTree(userLibraries);
251 ✗ packageIndex := userLibraries + "index.json";
252 ✗ if not Curl.multiDownload({({url},packageIndex)}) then
253 ✗ Error.addMessage(Error.ERROR_PKG_INDEX_FAILED_DOWNLOAD, {url,packageIndex});
254 success := false;
255 else
256 ✗ Error.addSourceMessage(Error.NOTIFY_PKG_INDEX_DOWNLOAD, {url}, makeSourceInfo(getIndexPath()));
257 success := true;
258 end if;
259 ✗ setGlobalRoot(Global.packageIndexCacheIndex, 0);
260 end updateIndex;
261
262 function upgradeInstalledPackages
263 input Boolean installNewestVersions;
264 input Integer wasmABI = 0;
265 output Boolean success;
266 protected
267 AvailableLibraries.Tree installedLibraries;
268 VersionMap.Tree versions;
269 algorithm
270 success := true;
271 ✗ installedLibraries := getInstalledLibraries();
272 ✗ for pkg in AvailableLibraries.listKeys(installedLibraries) loop
273 ✗ versions := AvailableLibraries.get(installedLibraries, pkg);
274 ✗ for version in VersionMap.listKeys(versions) loop
275 ✗ success := success and installPackage(pkg, SemanticVersion.toString(version), exactMatch=true, wasmABI=wasmABI);
276 end for;
277 ✗ if installNewestVersions then
278 ✗ success := success and installPackage(pkg, "", exactMatch=false, wasmABI=wasmABI);
279 end if;
280 end for;
281 end upgradeInstalledPackages;
282
283 function getPackageIndex
284 input Boolean printError;
285 output JSON obj;
286 protected
287 String userLibraries, packageIndex, gd, mp;
288 list<String> mps;
289 algorithm
290 try
291 2251 obj := getGlobalRoot(Global.packageIndexCacheIndex);
292 ✗ return;
293 else
294 end try;
295 2251 mp := Settings.getModelicaPath(Testsuite.isRunning());
296 gd := Autoconf.groupDelimiter;
297 2251 mps := System.strtok(mp, gd);
298 2251 userLibraries := getUserLibraryPath();
299 2251 packageIndex := userLibraries + "index.json";
300 2251 obj := JSON.emptyObject();
301 // User library path ends with forward slash so compare the path with and without leading forward slash
302
2/4
✓ Branch 1 taken 2251 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2251 times.
✗ Branch 6 not taken.
2251 if not listMember(userLibraries, mps) and not listMember(Util.removeLastNChar(userLibraries, 1), mps) then
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2251 times.
2251 if printError then
304 ✗ Error.addMessage(Error.ERROR_PKG_INDEX_NOT_ON_PATH, {mp, userLibraries});
305 end if;
306 2251 return;
307 end if;
308
309 ✗ if not System.regularFileExists(packageIndex) then
310 ✗ if not updateIndex() then
311 ✗ return;
312 end if;
313 end if;
314 try
315 ✗ obj := JSON.parseFile(packageIndex);
316 ✗ setGlobalRoot(Global.packageIndexCacheIndex, obj);
317 else
318 ✗ Error.addSourceMessage(Error.ERROR_PKG_INDEX_NOT_PARSED, {packageIndex}, makeSourceInfo(getIndexPath()));
319 end try;
320 end getPackageIndex;
321
322 function getAllProvidedVersionsForLibrary
323 input String lib;
324 input Boolean printError;
325 output list<String> result;
326 protected
327 JSON obj, libobject, vers, provides;
328 AvlSetString.Tree tree;
329 algorithm
330 ✗ result := {};
331 ✗ tree := AvlSetString.new();
332 try
333 ✗ obj := getPackageIndex(printError);
334 ✗ libobject := JSON.get(JSON.get(obj, "libs"), lib);
335 ✗ vers := JSON.get(libobject, "versions");
336
337 ✗ for version in JSON.getKeys(vers) loop
338 ✗ tree := AvlSetString.add(tree, version);
339 ✗ provides := JSON.getOrDefault(JSON.get(vers, version), "provides", JSON.emptyArray());
340
341 ✗ for i in 1:JSON.size(provides) loop
342 ✗ tree := AvlSetString.add(tree, JSON.getString(JSON.at(provides, i)));
343 end for;
344 end for;
345
346 ✗ result := AvlSetString.listKeys(tree);
347 else
348 ✗ return;
349 end try;
350 end getAllProvidedVersionsForLibrary;
351
352 function versionsThatProvideTheWanted
353 input String id;
354 input String version;
355 input Boolean printError;
356 output list<String> result;
357 protected
358 JSON obj, libobject, vers;
359 SemanticVersion.Version wantedVersion;
360 algorithm
361 result := {};
362 try
363 2251 obj := getPackageIndex(printError);
364 2251 libobject := JSON.get(JSON.get(obj, "libs"), id);
365 ✗ vers := JSON.get(libobject, "versions");
366 ✗ wantedVersion := SemanticVersion.parse(version, nonsemverAsZeroZeroZero=true);
367 ✗ result := List.map(List.sort(list((version,SemanticVersion.parse(version, nonsemverAsZeroZeroZero=true),getSupportLevel(JSON.get(JSON.get(vers, version),"support"))) for version guard providesExpectedVersion(version, JSON.getOrDefault(JSON.get(vers, version), "provides", JSON.emptyArray()), wantedVersion) in JSON.getKeys(vers)), compareVersionsAndSupportLevel), Util.tuple31);
368 else
369 2251 return;
370 end try;
371 end versionsThatProvideTheWanted;
372
373 function versionsThatConvertFromTheWanted
374 "Returns a list of versions that provide conversion from the given version of a library."
375 input String id;
376 input String version;
377 input Boolean printError;
378 output list<String> result;
379 protected
380 JSON obj, libobject, vers;
381 SemanticVersion.Version wantedVersion, convertVersion;
382 JSON convertFrom;
383 String versionStr;
384 algorithm
385 result := {};
386 try
387 ✗ obj := getPackageIndex(printError);
388 ✗ libobject := JSON.get(JSON.get(obj, "libs"), id);
389 ✗ vers := JSON.get(libobject, "versions");
390 ✗ wantedVersion := SemanticVersion.parse(version, nonsemverAsZeroZeroZero=true);
391
392 ✗ for v in JSON.getKeys(vers) loop
393 ✗ convertFrom := JSON.getOrDefault(JSON.get(vers, v), "convertFromVersion", JSON.emptyArray());
394
395 ✗ for i in 1:JSON.size(convertFrom) loop
396 ✗ JSON.STRING(versionStr) := JSON.at(convertFrom, i);
397 ✗ convertVersion := SemanticVersion.parse(versionStr, nonsemverAsZeroZeroZero=true);
398
399 ✗ if SemanticVersion.compare(wantedVersion, convertVersion) == 0 then
400 result := v :: result;
401 ✗ continue;
402 end if;
403 end for;
404 end for;
405 else
406 ✗ return;
407 end try;
408 end versionsThatConvertFromTheWanted;
409
410 function versionsThatConvertToTheWanted
411 "Returns a list of versions that can be converted to the given version of a library."
412 input String id;
413 input String version;
414 input Boolean printError;
415 output list<String> result;
416 protected
417 JSON obj, libobject, vers;
418 SemanticVersion.Version wantedVersion, libVersion;
419 algorithm
420 result := {};
421 try
422 ✗ obj := getPackageIndex(printError);
423 ✗ libobject := JSON.get(JSON.get(obj, "libs"), id);
424 ✗ vers := JSON.get(libobject, "versions");
425 ✗ wantedVersion := SemanticVersion.parse(version, nonsemverAsZeroZeroZero=true);
426
427 ✗ for v in JSON.getKeys(vers) loop
428 ✗ libVersion := SemanticVersion.parse(v, nonsemverAsZeroZeroZero=true);
429
430 ✗ if SemanticVersion.compare(wantedVersion, libVersion) == 0 then
431 ✗ result := JSON.getStringList(JSON.get(JSON.get(vers, v), "convertFromVersion"));
432 ✗ return;
433 end if;
434 end for;
435 else
436 ✗ return;
437 end try;
438 end versionsThatConvertToTheWanted;
439
440 function installPackage
441 input String pkg;
442 input String version;
443 input Boolean exactMatch;
444 input Boolean skipDownload = false;
445 input Integer wasmABI = 0 "Also install the prebuilt wasm external \"C\" modules of this ABI, if the index has any";
446 output Boolean success;
447 output list<String> wasmDirs = {} "The libraries prebuilt wasm modules were unpacked into";
448 protected
449 list<PackageInstallInfo> packageList, packagesToInstall;
450 list<tuple<list<String>,String>> urlPathList, urlPathListToDownload;
451 String path, destPath, destPathPkgMo, destPathPkgInfo, oldSha, dirOfPath, expectedLocation, cachePath=getCachePath(), installCachePath=getInstallationCachePath(), curCachePath;
452 list<String> mirrors;
453 list<tuple<String,String>> wasmZips;
454 algorithm
455 ✗ (success,packageList) := installPackageWork(pkg, version, exactMatch, false, {});
456 ✗ for p in packageList loop
457 ✗ if p.pkg == pkg and not p.needsInstall then
458 ✗ if version == SemanticVersion.toString(p.version) then
459 ✗ Error.addSourceMessage(Error.NOTIFY_PKG_ALREADY_INSTALLED, {pkg, SemanticVersion.toString(p.version)}, makeSourceInfo(p.path));
460 else
461 ✗ Error.addSourceMessage(Error.NOTIFY_PKG_NO_INSTALL, {pkg, version, SemanticVersion.toString(p.version)}, makeSourceInfo(p.path));
462 end if;
463 end if;
464 end for;
465 ✗ packagesToInstall := list(p for p guard p.needsInstall in packageList);
466 ✗ if not skipDownload then
467 ✗ for p in packageList loop
468 ✗ if not p.needsInstall then
469 ✗ if installMissingWasm(p.path, wasmExternalsZips(p.json, wasmABI), cachePath) then
470 ✗ wasmDirs := p.path :: wasmDirs;
471 end if;
472 end if;
473 end for;
474 end if;
475
476 ✗ for pack in packagesToInstall loop
477 ✗ Util.createDirectoryTree(cachePath);
478 end for;
479
480 ✗ if not skipDownload then
481 ✗ mirrors := getMirrors();
482 ✗ urlPathList := List.sort(list((getAllUrls(p.urlToZipFile, mirrors), if System.regularFileExists(installCachePath + System.basename(p.urlToZipFile)) then installCachePath + System.basename(p.urlToZipFile) else cachePath + System.basename(p.urlToZipFile)) for p in packagesToInstall), compareUrlBool);
483 ✗ urlPathList := listAppend(list(({Util.tuple21(z)}, cachePath + System.basename(Util.tuple21(z))) for z in List.flatten(list(wasmExternalsZips(p.json, wasmABI) for p in packagesToInstall))), urlPathList);
484 ✗ urlPathList := List.unique(urlPathList);
485 ✗ urlPathListToDownload := list(tpl for tpl guard not System.regularFileExists(Util.tuple22(tpl)) in urlPathList);
486 ✗ if not Curl.multiDownload(urlPathListToDownload) then
487 ✗ fail();
488 end if;
489 end if;
490
491 ✗ for pack in packagesToInstall loop
492 ✗ destPath := getUserLibraryPath() + pack.pkg + " " + SemanticVersion.toString(pack.version);
493
494 ✗ System.removeDirectory(destPath);
495 ✗ System.createDirectory(destPath);
496
497 ✗ destPathPkgMo := destPath + "/package.mo";
498 ✗ destPathPkgInfo := destPath + "/" + metaDataFileName;
499 ✗ oldSha := "";
500 ✗ if System.regularFileExists(destPathPkgInfo) then
501 try
502 ✗ oldSha := getShaOrZipfile(JSON.parseFile(destPathPkgInfo));
503 else
504 end try;
505 end if;
506
507 ✗ curCachePath := if System.regularFileExists(installCachePath + System.basename(pack.urlToZipFile)) then installCachePath else cachePath;
508 ✗ if StringUtil.endsWith(pack.path, ".mo") then
509 // We are not copying a full directory, so also look for Resources in the zip-file
510 ✗ dirOfPath := System.dirname(pack.path);
511 ✗ if pack.singleFileStructureCopyAllFiles then
512 ✗ Unzip.unzipPath(curCachePath + System.basename(pack.urlToZipFile), if dirOfPath =="." then "" else dirOfPath, destPath);
513 ✗ expectedLocation := destPath + "/" + System.basename(pack.path);
514 ✗ if not System.rename(expectedLocation, destPathPkgMo) then
515 ✗ Error.addMessage(Error.ERROR_PKG_INSTALL_NO_PACKAGE_MO, {curCachePath + System.basename(pack.urlToZipFile), expectedLocation});
516 // System.removeDirectory(destPath);
517 ✗ fail();
518 end if;
519 else
520 ✗ Unzip.unzipPath(curCachePath + System.basename(pack.urlToZipFile), pack.path, destPathPkgMo);
521 end if;
522 else
523 ✗ Unzip.unzipPath(curCachePath + System.basename(pack.urlToZipFile), pack.path, destPath);
524 end if;
525
526 ✗ if System.regularFileExists(destPathPkgMo) then
527 ✗ wasmZips := list(z for z guard System.regularFileExists(cachePath + System.basename(Util.tuple21(z))) in wasmExternalsZips(pack.json, wasmABI));
528 ✗ unpackWasm(destPath, wasmZips, cachePath);
529 ✗ if not listEmpty(wasmZips) then
530 ✗ wasmDirs := destPath :: wasmDirs;
531 end if;
532 ✗ if oldSha == "" then
533 ✗ Error.addSourceMessage(Error.NOTIFY_PKG_INSTALL_DONE, {pack.sha}, makeSourceInfo(destPathPkgMo));
534 else
535 ✗ Error.addSourceMessage(Error.NOTIFY_PKG_UPGRADE_DONE, {pack.sha, oldSha}, makeSourceInfo(destPathPkgMo));
536 end if;
537 else
538 ✗ Error.addMessage(Error.ERROR_PKG_INSTALL_NO_PACKAGE_MO, {curCachePath + System.basename(pack.urlToZipFile), destPathPkgMo});
539 ✗ System.removeDirectory(destPath);
540 ✗ fail();
541 end if;
542 ✗ System.writeFile(destPathPkgInfo, JSON.toString(pack.json)+"\n");
543 end for;
544 end installPackage;
545
546 function installCachedPackages
547 "Installs cached libraries from the installation directory if the user's
548 library directory is empty or doesn't exist, to allow bundling libraries with
549 the installation."
550 protected
551 String packageIndex, homeDir;
552 JSON obj, libs_obj, lib_obj, versions_obj;
553 list<String> libs;
554 algorithm
555 5857 homeDir := Settings.getHomeDir(runningTestsuite=Testsuite.isRunning());
556
4/10
✓ Branch 2 taken 5855 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5855 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 5855 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
5857 if not listEmpty(System.subDirectories(getUserLibraryPath())) or homeDir=="" or homeDir=="/" then
557 // Return if the user's library directory isn't empty, or if we're running
558 // e.g. rtest in which case the path might not be correct but we don't care
559 // and don't want any extra output.
560 5857 return;
561 end if;
562
563 // Try to fetch the package index from the installation directory.
564 ✗ packageIndex := getInstallationIndexPath();
565
566 ✗ if not System.regularFileExists(packageIndex) then
567 ✗ return;
568 end if;
569
570 ✗ obj := JSON.makeNull();
571
572 try
573 ✗ obj := JSON.parseFile(packageIndex);
574 else
575 ✗ Error.addSourceMessage(Error.ERROR_PKG_INDEX_NOT_PARSED, {packageIndex}, makeSourceInfo(packageIndex));
576 end try;
577
578 // Fetch the names of all the libraries in the package index.
579 try
580 ✗ libs_obj := JSON.get(obj, "libs");
581 ✗ libs := JSON.getKeys(libs_obj);
582 else
583 ✗ return;
584 end try;
585
586 ✗ if not listEmpty(libs) then
587 ✗ Error.addSourceMessage(Error.NOTIFY_INITIALIZING_USER_LIBRARIES, {getUserLibraryPath()}, makeSourceInfo(packageIndex));
588 end if;
589
590 // Copy the index to the user library folder to avoid getting errors when
591 // installing the libraries.
592 ✗ if not System.regularFileExists(getIndexPath()) then
593 ✗ Util.createDirectoryTree(getUserLibraryPath());
594 ✗ System.copyFile(packageIndex, getIndexPath());
595 end if;
596
597 // Install each version of each library in the package index.
598 ✗ for lib in libs loop
599 ✗ lib_obj := JSON.get(libs_obj, lib);
600 ✗ versions_obj := JSON.getOrDefault(lib_obj, "versions", JSON.emptyObject());
601
602 ✗ for version in JSON.getKeys(versions_obj) loop
603 ✗ installPackage(lib, version, true, skipDownload = true);
604 end for;
605 end for;
606
607 // Try to download a new package index so the user gets an up to date one.
608 ✗ updateIndex();
609 end installCachedPackages;
610
611 function installMissingWasmOfLoaded
612 "Fetches the prebuilt wasm modules the index has for loaded libraries the
613 package manager installed without them: before the wasm-jit target was used,
614 or before the index had them. `files` are the loaded top-level classes' files."
615 input list<String> files;
616 input Integer abi;
617 output list<String> wasmDirs = {} "The libraries the modules were unpacked into";
618 protected
619 list<String> dirs;
620 JSON index, installed, obj;
621 algorithm
622
1/2
✓ Branch 0 taken 2867 times.
✗ Branch 1 not taken.
2867 if abi <= 0 then
623 2867 return;
624 end if;
625 ✗ dirs := list(d for d guard System.regularFileExists(d + "/" + metaDataFileName) in list(System.dirname(f) for f in files));
626 ✗ if listEmpty(dirs) then
627 ✗ return;
628 end if;
629 ✗ index := getPackageIndex(false);
630 // An index from before any wasm modules were built.
631 ✗ if not JSON.hasKey(index, "systemLibraries") and not Testsuite.isRunning() then
632 ✗ if updateIndex() then
633 ✗ index := getPackageIndex(false);
634 end if;
635 end if;
636 ✗ for dir in dirs loop
637 try
638 ✗ installed := JSON.parseFile(dir + "/" + metaDataFileName);
639 ✗ obj := installedIndexEntry(index, listHead(System.strtok(System.basename(dir), " ")), SemanticVersion.parse(JSON.getString(JSON.get(installed, "version"))), getShaOrZipfile(installed));
640 ✗ if installMissingWasm(dir, wasmExternalsZips(obj, abi), getCachePath()) then
641 wasmDirs := dir :: wasmDirs;
642 end if;
643 else
644 end try;
645 end for;
646 end installMissingWasmOfLoaded;
647
648 function installWasmToolchain
649 "Installs the index's wasm sysroot under ~/.openmodelica/wasm32-wasip1/omc-<generation>,
650 with libc++ for `cxx`, and returns its path, or \"\" if there is none."
651 input Boolean cxx = false;
652 output String sysroot = "";
653 protected
654 JSON obj;
655 Integer generation;
656 String dir;
657 algorithm
658 try
659 ✗ obj := JSON.get(getPackageIndex(true), "wasmToolchain");
660 ✗ JSON.INTEGER(generation) := JSON.get(obj, "generation");
661 else
662 ✗ Error.addCompilerError("The package index has no wasm toolchain; updatePackageIndex() may fetch a newer index.");
663 ✗ return;
664 end try;
665 ✗ dir := Settings.getHomeDir(Testsuite.isRunning()) + "/.openmodelica/wasm32-wasip1/omc-" + intString(generation) + "/sysroot";
666 ✗ if not unpackToolchainPart(obj, dir, "/lib/wasm32-wasip1/libc.so") then
667 ✗ return;
668 end if;
669 ✗ if cxx then
670 try
671 ✗ obj := JSON.get(obj, "cxx");
672 else
673 ✗ Error.addCompilerError("The package index has no libc++ for its wasm toolchain.");
674 ✗ return;
675 end try;
676 ✗ if not unpackToolchainPart(obj, dir, "/lib/wasm32-wasip1/libc++.so") then
677 ✗ return;
678 end if;
679 end if;
680 sysroot := dir;
681 end installWasmToolchain;
682
683 protected
684
685 function unpackToolchainPart
686 "Unpacks the zip-file `obj` names into `dir`, unless `marker` shows it is there."
687 input JSON obj;
688 input String dir;
689 input String marker;
690 output Boolean success = true;
691 protected
692 String url, zip, cachePath = getCachePath();
693 algorithm
694 ✗ if System.regularFileExists(dir + marker) then
695 ✗ return;
696 end if;
697 ✗ url := JSON.getString(JSON.get(obj, "zipfile"));
698 ✗ zip := cachePath + System.basename(url);
699 ✗ Util.createDirectoryTree(cachePath);
700 ✗ if not System.regularFileExists(zip) then
701 ✗ success := Curl.multiDownload({({url}, zip)});
702 end if;
703 ✗ if success then
704 ✗ Util.createDirectoryTree(dir);
705 ✗ Unzip.unzipPath(zip, "", dir);
706 end if;
707 end unpackToolchainPart;
708
709 function compareUrlBool
710 input tuple<list<String>,String> tpl1, tpl2;
711 output Boolean b;
712 protected
713 String s1, s2;
714 algorithm
715 ✗ (s1::_,_) := tpl1;
716 ✗ (s2::_,_) := tpl2;
717 ✗ b := stringCompare(s1, s2) > 0;
718 end compareUrlBool;
719
720 uniontype PackageInstallInfo
721 record PKG_INSTALL_INFO
722 Boolean needsInstall;
723 String pkg;
724 SemanticVersion.Version version;
725 String urlToZipFile;
726 String path;
727 String sha;
728 Boolean singleFileStructureCopyAllFiles;
729 JSON json;
730 end PKG_INSTALL_INFO;
731 end PackageInstallInfo;
732
733 function installPackageWork
734 input String pkg;
735 input String version;
736 input Boolean exactMatch;
737 input Boolean fallbackOnNonExactMatch;
738 output Boolean success;
739 input output list<PackageInstallInfo> packagesToInstall;
740 protected
741 AvailableLibraries.Tree installedLibraries;
742 VersionMap.Tree installedVersions;
743 list<String> candidates;
744 list<SemanticVersion.Version> candidatesSemver, exactMatches;
745 String versionToInstall, usedVersion, path, sha, jsonPath, zip;
746 SemanticVersion.Version semverToInstall, semver;
747 JSON index, versionObj, versionsObj, usesObj;
748 Boolean indexHasPkg;
749 Option<PackageInstallInfo> packageToInstall = NONE();
750 algorithm
751 ✗ candidates := versionsThatProvideTheWanted(pkg, version, printError=true);
752 ✗ candidatesSemver := list(SemanticVersion.parse(candidate) for candidate in candidates);
753 ✗ semver := SemanticVersion.parse(version);
754 ✗ exactMatches := list(candidate for candidate guard 0==SemanticVersion.compare(candidate, semver, compareBuildInformation=SemanticVersion.hasMetaInformation(semver)) in candidatesSemver);
755 ✗ success := false;
756 ✗ for pkgInfo in packagesToInstall loop
757 ✗ if pkgInfo.pkg == pkg then
758 ✗ if SemanticVersion.compare(pkgInfo.version, semver)==0 or max(0==SemanticVersion.compare(pkgInfo.version, candidate) for candidate in candidatesSemver) then
759 success := true;
760 ✗ return;
761 end if;
762 ✗ Error.addMessage(Error.WARNING_PKG_CONFLICTING_VERSIONS, {pkg, SemanticVersion.toString(pkgInfo.version), version});
763 success := true;
764 ✗ return;
765 end if;
766 end for;
767
768 // We know which version we want now. Check with the installed ones
769 ✗ installedLibraries := getInstalledLibraries();
770
771 ✗ if listEmpty(candidates) then
772 versionToInstall := version;
773 semverToInstall := semver;
774 elseif exactMatch and not listEmpty(exactMatches) then
775 ✗ semverToInstall := listHead(exactMatches);
776 ✗ versionToInstall := SemanticVersion.toString(semverToInstall);
777 else
778 ✗ versionToInstall := listHead(candidates);
779 ✗ semverToInstall := listHead(candidatesSemver);
780 end if;
781 ✗ index := getPackageIndex(printError=true);
782 indexHasPkg := true;
783 ✗ sha := "";
784
785 ✗ if AvailableLibraries.hasKey(installedLibraries, pkg) then
786 ✗ installedVersions := AvailableLibraries.get(installedLibraries, pkg);
787 ✗ if VersionMap.hasKey(installedVersions, semverToInstall) or (version=="" and not indexHasPkg) then
788 ✗ success := true;
789 ✗ path := if VersionMap.hasKey(installedVersions, semverToInstall) then VersionMap.get(installedVersions, semverToInstall) else "#DUMMY#";
790 ✗ jsonPath := path + "/" + metaDataFileName;
791 ✗ if System.regularFileExists(jsonPath) then
792 ✗ versionObj := JSON.parseFile(jsonPath);
793 ✗ zip := JSON.getString(JSON.get(versionObj, "zipfile"));
794 try
795 ✗ sha := JSON.getString(JSON.get(versionObj, "sha"));
796 else
797 end try;
798 else
799 zip := "";
800 end if;
801 ✗ packageToInstall := SOME(PKG_INSTALL_INFO(false, pkg, semverToInstall, zip, path, sha, false,
802 installedIndexEntry(index, pkg, semverToInstall, if sha <> "" then sha else zip)));
803 ✗ indexHasPkg := JSON.hasKey(JSON.get(index, "libs"), pkg);
804 end if;
805 end if;
806 ✗ if not success then
807 ✗ if listEmpty(candidates) then
808 ✗ Error.addSourceMessage(Error.ERROR_PKG_NOT_FOUND_VERSION, {pkg, version, stringDelimitList(getAllProvidedVersionsForLibrary(pkg, true),"\n")}, makeSourceInfo(getIndexPath()));
809 ✗ return;
810 end if;
811
812 ✗ if exactMatch and not max(0==SemanticVersion.compare(semver, candidate) for candidate in candidatesSemver) then
813 ✗ if not fallbackOnNonExactMatch then
814 ✗ Error.addSourceMessage(Error.ERROR_PKG_NOT_EXACT_MATCH, {pkg, version, stringDelimitList(candidates, ", ")}, makeSourceInfo(getIndexPath()));
815 ✗ return;
816 end if;
817 ✗ versionToInstall := listHead(candidates);
818 ✗ semverToInstall := listHead(candidatesSemver);
819 end if;
820 end if;
821
822 ✗ if not indexHasPkg then
823 ✗ packagesToInstall := Util.getOption(packageToInstall) :: packagesToInstall;
824 ✗ return;
825 end if;
826
827 ✗ versionsObj := JSON.get(JSON.get(JSON.get(index, "libs"), pkg), "versions");
828 ✗ if success and not JSON.hasKey(versionsObj, versionToInstall) then
829 ✗ packagesToInstall := Util.getOption(packageToInstall) :: packagesToInstall;
830 ✗ return;
831 end if;
832 ✗ versionObj := JSON.get(versionsObj, versionToInstall);
833
834 ✗ if (not success) or (sha <> "" and sha <> getShaOrZipfile(versionObj)) then
835 ✗ success := true;
836 ✗ packageToInstall := SOME(PKG_INSTALL_INFO(true, pkg, semverToInstall, JSON.getString(JSON.get(versionObj, "zipfile")), JSON.getString(JSON.get(versionObj, "path")), getShaOrZipfile(versionObj), JSON.getBoolean(JSON.getOrDefault(versionObj, "singleFileStructureCopyAllFiles", JSON.FALSE())), versionObj));
837 end if;
838
839 ✗ usesObj := JSON.getOrDefault(versionObj, "uses", JSON.emptyObject());
840
841 ✗ packagesToInstall := Util.getOption(packageToInstall) :: packagesToInstall;
842
843 ✗ for usesPackage in JSON.getKeys(usesObj) loop
844 ✗ JSON.STRING(usedVersion) := JSON.get(usesObj, usesPackage);
845 ✗ (success, packagesToInstall) := installPackageWork(usesPackage, usedVersion, exactMatch, true, packagesToInstall);
846 ✗ if not success then
847 ✗ return;
848 end if;
849 end for;
850 end installPackageWork;
851
852 function installedIndexEntry
853 "The index's entry for an installed package version, if it is still built from
854 the same sources (`shaOrZip`); its prebuilt wasm modules are only good then."
855 input JSON index;
856 input String pkg;
857 input SemanticVersion.Version version;
858 input String shaOrZip;
859 output JSON obj = JSON.emptyObject();
860 protected
861 JSON o;
862 algorithm
863 try
864 ✗ o := JSON.get(JSON.get(JSON.get(JSON.get(index, "libs"), pkg), "versions"), SemanticVersion.toString(version));
865 // A package installed from an index without shas only knows its zipfile.
866 ✗ if shaOrZip <> "" and (getShaOrZipfile(o) == shaOrZip or JSON.hasKey(o, "zipfile") and System.basename(JSON.getString(JSON.get(o, "zipfile"))) == shaOrZip) then
867 obj := o;
868 end if;
869 else
870 end try;
871 end installedIndexEntry;
872
873 function installMissingWasm
874 "Fetches and unpacks the prebuilt wasm modules of an installed package that it
875 does not have yet: those of a newer generation, or a rebuild of one."
876 input String destPath;
877 input list<tuple<String,String>> zips;
878 input String cachePath;
879 output Boolean unpacked = false;
880 protected
881 list<tuple<String,String>> missing;
882 String lock = destPath + "/Resources/Library/wasm32-wasip1.lock";
883 algorithm
884 ✗ missing := list(z for z guard not wasmUnpacked(destPath, z) in zips);
885 ✗ if listEmpty(missing) then
886 ✗ return;
887 end if;
888 // Another omc is unpacking them; this one goes on with what is there.
889 ✗ if not wasmLock(lock) then
890 ✗ return;
891 end if;
892 ✗ missing := list(z for z guard not wasmUnpacked(destPath, z) in zips);
893 // The library's own zip unpacks into the generation directory that holds the
894 // system libraries' ones, so replacing it replaces them all.
895 ✗ if List.any(missing, wasmIsGenerationZip) then
896 missing := zips;
897 end if;
898 try
899 ✗ Util.createDirectoryTree(cachePath);
900 ✗ if not listEmpty(missing) and Curl.multiDownload(list(({Util.tuple21(z)}, cachePath + System.basename(Util.tuple21(z))) for z guard not System.regularFileExists(cachePath + System.basename(Util.tuple21(z))) in missing)) then
901 ✗ unpackWasm(destPath, missing, cachePath);
902 unpacked := true;
903 end if;
904 else
905 ✗ System.removeDirectory(lock);
906 ✗ fail();
907 end try;
908 ✗ System.removeDirectory(lock);
909 end installMissingWasm;
910
911 function wasmLock
912 "Takes the lock directory `lock`, unless another omc holds it. Renaming a
913 non-empty directory onto an existing one fails, which makes it exclusive. A
914 lock older than ten minutes was left by an omc that died and is taken over."
915 input String lock;
916 output Boolean locked;
917 protected
918 String tmp;
919 Option<Real> t;
920 algorithm
921 ✗ Util.createDirectoryTree(System.dirname(lock));
922 ✗ tmp := System.createTemporaryDirectory(lock + ".");
923 ✗ System.writeFile(tmp + "/owner", "");
924 ✗ locked := System.rename(tmp, lock);
925 ✗ if not locked then
926 ✗ t := System.getFileModificationTime(lock);
927 ✗ if isSome(t) and System.getCurrentTime() - Util.getOption(t) > 600 then
928 ✗ System.removeDirectory(lock);
929 ✗ locked := System.rename(tmp, lock);
930 end if;
931 end if;
932 ✗ if not locked then
933 ✗ System.removeDirectory(tmp);
934 end if;
935 end wasmLock;
936
937 constant String wasmZipMarker = ".omc-zipfile" "Names the zip a directory of wasm modules was unpacked from";
938
939 function wasmIsGenerationZip
940 input tuple<String,String> zip;
941 output Boolean b = listLength(System.strtok(Util.tuple22(zip), "/")) == 1;
942 end wasmIsGenerationZip;
943
944 function wasmUnpacked
945 input String destPath;
946 input tuple<String,String> zip;
947 output Boolean b;
948 protected
949 String marker = destPath + "/Resources/Library/wasm32-wasip1/" + Util.tuple22(zip) + "/" + wasmZipMarker;
950 algorithm
951 ✗ b := System.regularFileExists(marker) and System.readFile(marker) == System.basename(Util.tuple21(zip));
952 end wasmUnpacked;
953
954 function unpackWasm
955 "Unpacks zips of prebuilt wasm modules into Resources/Library/wasm32-wasip1.
956 A generation's system libraries go into its tree before it is renamed into
957 place, so an omc running at the same time never sees it half written."
958 input String destPath;
959 input list<tuple<String,String>> zips;
960 input String cachePath;
961 protected
962 String base = destPath + "/Resources/Library/wasm32-wasip1/";
963 list<tuple<String,String>> gens, libs;
964 algorithm
965 ✗ (gens, libs) := List.splitOnTrue(zips, wasmIsGenerationZip);
966 ✗ for g in gens loop
967 ✗ unpackWasmTree(base + Util.tuple22(g), g :: list(z for z guard System.dirname(Util.tuple22(z)) == Util.tuple22(g) in libs), cachePath);
968 ✗ libs := list(z for z guard System.dirname(Util.tuple22(z)) <> Util.tuple22(g) in libs);
969 end for;
970 ✗ for z in libs loop
971 ✗ unpackWasmTree(base + Util.tuple22(z), {z}, cachePath);
972 end for;
973 end unpackWasm;
974
975 function unpackWasmTree
976 "Replaces `dir` with the first zip's contents and each other's in a
977 subdirectory named after it, built beside `dir` and renamed into place."
978 input String dir;
979 input list<tuple<String,String>> zips;
980 input String cachePath;
981 protected
982 String tmp, sub;
983 Boolean first = true;
984 algorithm
985 ✗ Util.createDirectoryTree(System.dirname(dir));
986 ✗ tmp := System.createTemporaryDirectory(dir + ".tmp");
987 ✗ for z in zips loop
988 ✗ sub := if first then tmp else tmp + "/" + System.basename(Util.tuple22(z));
989 first := false;
990 ✗ Util.createDirectoryTree(sub);
991 ✗ Unzip.unzipPath(cachePath + System.basename(Util.tuple21(z)), "", sub);
992 ✗ System.writeFile(sub + "/" + wasmZipMarker, System.basename(Util.tuple21(z)));
993 end for;
994 ✗ System.removeDirectory(dir);
995 ✗ if not System.rename(tmp, dir) then
996 // Another omc put its copy in place first.
997 ✗ System.removeDirectory(tmp);
998 end if;
999 end unpackWasmTree;
1000
1001 function wasmExternalsZips
1002 "The zip-files with the prebuilt wasm external \"C\" modules of a package
1003 version, each with the directory under Resources/Library/wasm32-wasip1 it
1004 unpacks into: the library's own bundle, then the system libraries it needs,
1005 all under the generation they were built in. Older generations stay."
1006 input JSON versionObj;
1007 input Integer abi;
1008 output list<tuple<String,String>> zips = {};
1009 protected
1010 JSON obj, systemLibraries;
1011 Integer generation;
1012 algorithm
1013 ✗ if abi <= 0 then
1014 ✗ return;
1015 end if;
1016 try
1017 ✗ obj := JSON.get(JSON.get(versionObj, "wasm"), intString(abi));
1018 ✗ JSON.INTEGER(generation) := JSON.get(obj, "generation");
1019 ✗ zips := {(JSON.getString(JSON.get(obj, "zipfile")), "omc-" + intString(generation))};
1020 else
1021 ✗ return;
1022 end try;
1023 ✗ systemLibraries := JSON.getOrDefault(getPackageIndex(false), "systemLibraries", JSON.emptyObject());
1024 ✗ for name in JSON.getStringList(JSON.getOrDefault(obj, "systemLibraries", JSON.emptyArray())) loop
1025 try
1026 ✗ zips := (JSON.getString(JSON.get(JSON.get(JSON.get(JSON.get(systemLibraries, name), "wasm"), intString(abi)), "zipfile")), "omc-" + intString(generation) + "/" + name) :: zips;
1027 else
1028 ✗ Error.addCompilerWarning("The package index has no wasm system library " + name + " for ABI " + intString(abi) + ".");
1029 end try;
1030 end for;
1031 ✗ zips := listReverse(zips);
1032 end wasmExternalsZips;
1033
1034 function getShaOrZipfile
1035 input JSON obj;
1036 output String res;
1037 algorithm
1038 ✗ res := if JSON.hasKey(obj, "sha") then JSON.getString(JSON.get(obj, "sha")) else System.basename(JSON.getString(JSON.get(obj, "zipfile")));
1039 end getShaOrZipfile;
1040
1041 function getAllUrls
1042 input String url;
1043 input list<String> mirrors;
1044 output list<String> urls;
1045 protected
1046 String urlWithoutProtocol, newUrl;
1047 algorithm
1048 urls := {url};
1049 ✗ if not StringUtil.startsWith(url, "https://") then
1050 ✗ return;
1051 end if;
1052 ✗ urlWithoutProtocol := substring(url,9,stringLength(url));
1053 ✗ for mirror in mirrors loop
1054 ✗ newUrl := if StringUtil.endsWith(mirror, "/") then (mirror + urlWithoutProtocol) else (mirror + "/" + urlWithoutProtocol);
1055 urls := newUrl::urls;
1056 end for;
1057 end getAllUrls;
1058
1059 function getMirrors
1060 output list<String> mirrors;
1061 protected
1062 JSON obj;
1063 algorithm
1064 ✗ obj := getPackageIndex(false);
1065 ✗ if not JSON.hasKey(obj, "mirrors") then
1066 mirrors := {};
1067 ✗ return;
1068 end if;
1069 ✗ obj := JSON.get(obj, "mirrors");
1070 ✗ mirrors := JSON.getStringList(obj);
1071 end getMirrors;
1072
1073 function getUserLibraryPath
1074 output String path;
1075 algorithm
1076 8108 path := Settings.getHomeDir(Testsuite.isRunning()) + "/.openmodelica/libraries/";
1077 end getUserLibraryPath;
1078
1079 function getIndexPath
1080 output String path;
1081 algorithm
1082 ✗ path := Settings.getHomeDir(Testsuite.isRunning()) + "/.openmodelica/libraries/index.json";
1083 end getIndexPath;
1084
1085 public
1086 function getCachePath
1087 output String path;
1088 algorithm
1089 ✗ path := Settings.getHomeDir(Testsuite.isRunning()) + "/.openmodelica/cache/";
1090 end getCachePath;
1091
1092 protected
1093
1094 function getInstallationIndexPath
1095 output String path;
1096 algorithm
1097 ✗ path := Settings.getInstallationDirectoryPath() + "/share/omlibrary/cache/index.json";
1098 end getInstallationIndexPath;
1099
1100 function getInstallationCachePath
1101 output String path;
1102 algorithm
1103 ✗ path := Settings.getInstallationDirectoryPath() + "/share/omlibrary/cache/";
1104 end getInstallationCachePath;
1105
1106 function makeSourceInfo
1107 input String fileName;
1108 output SourceInfo info;
1109 algorithm
1110 ✗ info := SOURCEINFO(fileName, true, 0, 0, 0, 0, 0.0);
1111 end makeSourceInfo;
1112
1113 annotation(__OpenModelica_Interface="script_util");
1114 end PackageManagement;
1115