Search Unity

How get PackageInfo by name and version?

Discussion in 'Package Manager' started by fherbst, Oct 16, 2019.

  1. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    PackageSample.cs uses the following code to get samples of a specific package version:
    Code (CSharp):
    1. public static IEnumerable<Sample> FindByPackage(string packageName, string packageVersion)
    2.         {
    3.             var package = PackageDatabase.instance.GetPackage(packageName);
    4.             if (package != null)
    5.             {
    6.                 var version = package.versions.installed;
    7.                 if (!string.IsNullOrEmpty(packageVersion))
    8.                     version = package.versions.FirstOrDefault(v => v.version == packageVersion);
    9.                 if (version != null)
    10.                     return version.samples;
    11.             }
    12.             return new List<Sample>();
    13.         }
    Unfortunately, PackageDatabase, IPackageVersion etc are internal, so I can't follow that pattern.
    I'd like to access PackageInfo by name and version. Is there another way to get at that info?

    PackageDatabaseInternal has all the nice helpers for this (e.g. GetPackageAndVersion).

    And there's more internal stuff:
    Is there an alternative to get all packages to this internal class? Or to get all currently installed packages?
    upload_2019-10-16_15-47-44.png

    @okcompute_unity would be great to get your input again :)
     
    Last edited: Oct 16, 2019
  2. IsopodInAnEscapePod_unity

    IsopodInAnEscapePod_unity

    Unity Technologies

    Joined:
    Sep 20, 2019
    Posts:
    18
    HI @fherbst , I think you can find what you're looking for in https://docs.unity3d.com/ScriptReference/PackageManager.Client.html.

    The Client.Search function accepts a package id or package name. The SearchRequest it returns which will contain an array of PackageInfo for the different versions of that package when the request is complete. You can then search through that array of PackageInfo objects to find the version you're looking for.
     
  3. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    Thanks, but at least from the description this clearly says "Searches the Unity package registry for the given package.", so I didn't even bother trying (I'm using a lot of custom packages on our own registry). Additionally, I'd at best consider that a workaround - all information is already locally available, an additional web search might not be feasible with no internet available, ... offline mode still is documented as only looking at Unity packages. What about embedded ones, local ones, ... is the documentation just wrong and this is actually searching "all packages"?
     
  4. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    OK, after testing this I can confirm that this doesn't work for local packages at all. It will happily claim "success" with a totally wrong version that is not installed but it doesn't find the actually used local package.
     
  5. IsopodInAnEscapePod_unity

    IsopodInAnEscapePod_unity

    Unity Technologies

    Joined:
    Sep 20, 2019
    Posts:
    18
    Ah, yes, if you're using packages from another registry then this may not work. We're working on making Client.Search include scoped registries, but I do not believe it does so right now.
     
  6. IsopodInAnEscapePod_unity

    IsopodInAnEscapePod_unity

    Unity Technologies

    Joined:
    Sep 20, 2019
    Posts:
    18
    I will check if there are any alternatives for retrieving PackageInfo, but I'm under the impression that the Client API is how users are intended to interact with Package Manager.

    I think you could try opening a bug for Search not working on local packages.
     
  7. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    Workaround at least for installed packages is to search Assetdatabase for all "package.json" and use "PackageInfo.FromAsset" on them - voila. All actually installed packages. From there, all available versions can be found.
     
  8. unity-marcus

    unity-marcus

    Joined:
    Apr 16, 2019
    Posts:
    4
    Since the Client-API always returns a PackageInfo with the PackageStatus Unavailable I implemented your suggestion and this works fine for me and also is way faster. Thanks for the hint!

    Code (CSharp):
    1. List<PackageInfo> packageJsons = AssetDatabase.FindAssets("package")
    2.                 .Select(AssetDatabase.GUIDToAssetPath).Where(x => AssetDatabase.LoadAssetAtPath<TextAsset>(x) != null)
    3.                 .Select(PackageInfo.FindForAssetPath).ToList();
    4.  
    5. return packageJsons.Any(x => x.name == _hdrpPackageName && x.version == _hdrpPackageVersion);
     
  9. XzenD

    XzenD

    Joined:
    Feb 13, 2017
    Posts:
    2
    Code (CSharp):
    1. #nullable enable
    2. using System.Linq;
    3. using SimpleJSON;
    4. using UnityEditor;
    5. using UnityEngine;
    6.  
    7. public static class PackageData
    8. {
    9.     public static string GetVersion(string name = "com.unity.ugui")
    10.     {
    11.         var package = AssetDatabase
    12.             .FindAssets("package")
    13.             .Select(AssetDatabase.GUIDToAssetPath)
    14.             .Where(x => x.EndsWith("package.json"))
    15.             .Where(x => AssetDatabase.LoadAssetAtPath<TextAsset>(x) is not null)
    16.             .Select(s => AssetDatabase.LoadAssetAtPath<TextAsset>(s).text)
    17.             .Select(JSON.Parse)
    18.             .FirstOrDefault(j => j["name"] == name);
    19.        
    20.         string? ver = package?["version"];
    21.         if (ver is null) return "";
    22.         return $"version {ver}";
    23.     }
    24. }
     
  10. Kokowolo

    Kokowolo

    Joined:
    Mar 26, 2020
    Posts:
    60
    Thanks @unity-marcus! Your code was returning null for some reason for my setup, but I wrote this function to catch the null reference. Here's the code to maybe save the next person a few minutes:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Linq;
    3. using UnityEditor.PackageManager;
    4.  
    5. // ... within some class ...
    6.  
    7. private PackageInfo GetPackageInfo(string packageName)
    8. {
    9.     return UnityEditor.AssetDatabase.FindAssets("package")
    10.         .Select(UnityEditor.AssetDatabase.GUIDToAssetPath)
    11.             .Where(x => UnityEditor.AssetDatabase.LoadAssetAtPath<TextAsset>(x) != null)
    12.         .Select(PackageInfo.FindForAssetPath)
    13.             .Where(x => x != null)
    14.         .First(x => x.name == packageName);
    15. }
    Where its use case would be:
    Code (CSharp):
    1. string packageName = "com.unity.cinemachine";
    2. Debug.Log(GetPackageInfo(packageName).version);