diff --git a/Assets/MixedRealityToolkit.Examples/MRTK.Examples.sentinel b/Assets/MixedRealityToolkit.Examples/MRTK.Examples.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.Examples/MRTK.Examples.sentinel.meta b/Assets/MixedRealityToolkit.Examples/MRTK.Examples.sentinel.meta
new file mode 100644
index 00000000000..5bca428cb8d
--- /dev/null
+++ b/Assets/MixedRealityToolkit.Examples/MRTK.Examples.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 82b2eec91c3226a46a21e783fc3c885d
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit.Extensions/MRTK.Extensions.sentinel b/Assets/MixedRealityToolkit.Extensions/MRTK.Extensions.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.Extensions/MRTK.Extensions.sentinel.meta b/Assets/MixedRealityToolkit.Extensions/MRTK.Extensions.sentinel.meta
new file mode 100644
index 00000000000..a89b3c0d7a1
--- /dev/null
+++ b/Assets/MixedRealityToolkit.Extensions/MRTK.Extensions.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 354da3282d4f2d3449f6145955984ed5
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit.Providers/MRTK.Providers.sentinel b/Assets/MixedRealityToolkit.Providers/MRTK.Providers.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.Providers/MRTK.Providers.sentinel.meta b/Assets/MixedRealityToolkit.Providers/MRTK.Providers.sentinel.meta
new file mode 100644
index 00000000000..a0f437b1580
--- /dev/null
+++ b/Assets/MixedRealityToolkit.Providers/MRTK.Providers.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: efc47659760747d4d80477aa049ee71e
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit.SDK/MRTK.SDK.sentinel b/Assets/MixedRealityToolkit.SDK/MRTK.SDK.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.SDK/MRTK.SDK.sentinel.meta b/Assets/MixedRealityToolkit.SDK/MRTK.SDK.sentinel.meta
new file mode 100644
index 00000000000..78dbdbb9928
--- /dev/null
+++ b/Assets/MixedRealityToolkit.SDK/MRTK.SDK.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 864352254c16b15409725d9eb8efcbda
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit.Services/MRTK.Services.sentinel b/Assets/MixedRealityToolkit.Services/MRTK.Services.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.Services/MRTK.Services.sentinel.meta b/Assets/MixedRealityToolkit.Services/MRTK.Services.sentinel.meta
new file mode 100644
index 00000000000..5ba978edffe
--- /dev/null
+++ b/Assets/MixedRealityToolkit.Services/MRTK.Services.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e4a2c4cac1889464cb3f300e513d9df8
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit.Tests/EditModeTests/Core/MixedRealityToolkitFilesTests.cs b/Assets/MixedRealityToolkit.Tests/EditModeTests/Core/MixedRealityToolkitFilesTests.cs
index 4ce6337a528..3ce38a0c2b4 100644
--- a/Assets/MixedRealityToolkit.Tests/EditModeTests/Core/MixedRealityToolkitFilesTests.cs
+++ b/Assets/MixedRealityToolkit.Tests/EditModeTests/Core/MixedRealityToolkitFilesTests.cs
@@ -6,124 +6,44 @@
using UnityEngine;
using System;
using System.IO;
+using System.Linq;
namespace Microsoft.MixedReality.Toolkit.Tests.Core
{
// Tests for the MixedRealityToolkitFiles utility class
public class MixedRealityToolkitFilesTests
{
- string[] basePaths = new string[] { "", "C:\\", "C:\\xyz\\", "C:/xyz/" };
-
[Test]
- public void FindMatchingModule()
+ public void TestGetDirectories()
{
- TestInvalidPath("");
-
- // Test invalid base name
- TestInvalidPath("aaa");
- TestInvalidPath(".SDK");
- TestInvalidPath("aaa.SDK");
-
- // Test missing chars
- TestInvalidPath("MixedRealityToolki.SDK");
- TestInvalidPath("MixedRealityToolkit.SD");
- TestInvalidPath("ixedRealityToolkit.SDK");
- TestInvalidPath("MixedRealityToolkit.DK");
-
- // Test missing dots
- TestInvalidPath("SDK");
- TestInvalidPath("MixedRealityToolkitSDK");
-
- // Test valid paths
- TestValidPath("MixedRealityToolkit", MixedRealityToolkitModuleType.Core);
- TestValidPath("MixedRealityToolkit.SDK", MixedRealityToolkitModuleType.SDK);
-
- // Test that all modules can be found and internal module map is complete.
- // Check that MixedRealityToolkitFiles.moduleNameMap has all entries if this fails!
- var modules = Enum.GetValues(typeof(MixedRealityToolkitModuleType));
- var moduleNames = Enum.GetNames(typeof(MixedRealityToolkitModuleType));
- for (int i = 0; i < modules.Length; ++i)
+ MixedRealityToolkitModuleType[] moduleTypes = new MixedRealityToolkitModuleType[]
{
- var module = (MixedRealityToolkitModuleType)modules.GetValue(i);
- if (module != MixedRealityToolkitModuleType.Core)
- {
- TestValidPath($"MixedRealityToolkit.{moduleNames[i]}", module);
- }
- }
- }
-
- [Test]
- public void FindMatchingModuleNuget()
- {
- // Test invalid base name
- TestInvalidPath("aaa.1.23-45/MRTK");
- TestInvalidPath(".1.23-45.SDK/MRTK");
- TestInvalidPath("aaa.1.23-45.SDK/MRTK");
-
- // Test missing chars
- TestInvalidPath("Microsoft.MixedReality.Toolki.SDK.1.23-45/MRTK");
- TestInvalidPath("Microsoft.MixedReality.Toolkit.SD.1.23-45/MRTK");
- TestInvalidPath("Microsoft.MixedReality.Toolkit.SDK.1.23-45/MRT");
-
- TestInvalidPath("icrosoft.MixedReality.Toolkit.SDK.1.23-45/MRTK");
- TestInvalidPath("Microsoft.MixedReality.Toolkit.DK.1.23-45/MRTK");
- TestInvalidPath("Microsoft.MixedReality.Toolkit.SDK.1.23-45/RTK");
-
- // Test missing dots
- TestInvalidPath("Microsoft.MixedReality.Toolkit.SDK1.23-45/MRTK");
- TestInvalidPath("Microsoft.MixedReality.ToolkitSDK.1.23-45/MRTK");
- TestInvalidPath("Microsoft.MixedReality.ToolkitSDK1.23-45/MRTK");
-
- // Test missing version
- TestInvalidPath("Microsoft.MixedReality.Toolkit.SDK/MRTK");
- // Test missing MRTK suffix
- TestInvalidPath("Microsoft.MixedReality.Toolkit.SDK.1.23-45");
-
- // Test valid paths
- TestValidPath("Microsoft.MixedReality.Toolkit.1.23-45/MRTK", MixedRealityToolkitModuleType.Core);
- TestValidPath("Microsoft.MixedReality.Toolkit.SDK.1.23-45/MRTK", MixedRealityToolkitModuleType.SDK);
-
- // Test that all modules can be found and internal module map is complete.
- // Check that MixedRealityToolkitFiles.moduleNameMap has all entries if this fails!
- var modules = Enum.GetValues(typeof(MixedRealityToolkitModuleType));
- var moduleNames = Enum.GetNames(typeof(MixedRealityToolkitModuleType));
- for (int i = 0; i < modules.Length; ++i)
+ MixedRealityToolkitModuleType.Core,
+ MixedRealityToolkitModuleType.Providers,
+ MixedRealityToolkitModuleType.Services,
+ MixedRealityToolkitModuleType.SDK,
+ MixedRealityToolkitModuleType.Examples,
+ MixedRealityToolkitModuleType.Tests,
+ MixedRealityToolkitModuleType.Extensions,
+ MixedRealityToolkitModuleType.Tools,
+ };
+
+ MixedRealityToolkitFiles.RefreshFolders();
+ foreach (var moduleType in moduleTypes)
{
- var module = (MixedRealityToolkitModuleType)modules.GetValue(i);
- if (module != MixedRealityToolkitModuleType.Core)
- {
- TestValidPath($"Microsoft.MixedReality.Toolkit.{moduleNames[i]}.1.23-45/MRTK", (MixedRealityToolkitModuleType)modules.GetValue(i));
- }
+ // Validate that each module has a corresponding found folder
+ Assert.IsTrue(MixedRealityToolkitFiles.GetDirectories(moduleType).Any());
}
}
///
/// Validates that MixedRealityToolkitFiles is able to reason over MRTK folders when placed in the root Asset directory.
///
+ [Test]
public void TestRootAssetFolderResolution()
{
- string resolvedPath = MixedRealityToolkitFiles.MapRelativeFilePathToAbsolutePath("Inspectors/Data/EditorWindowOptions.json");
- string expectedPath = Path.Combine(Application.dataPath, "MixedRealityToolkit/Inspectors/Data/EditorWindowOptions.json");
- Assert.AreEqual(expectedPath, resolvedPath);
- }
-
- public void TestInvalidPath(string path)
- {
- foreach (string basePath in basePaths)
- {
- string fullPath = Path.Combine(basePath, path);
- Assert.False(MixedRealityToolkitFiles.FindMatchingModule(fullPath, out MixedRealityToolkitModuleType module));
- }
- }
-
- public void TestValidPath(string path, MixedRealityToolkitModuleType expectedModule)
- {
- foreach (string basePath in basePaths)
- {
- string fullPath = Path.Combine(basePath, path);
- Assert.True(MixedRealityToolkitFiles.FindMatchingModule(fullPath, out MixedRealityToolkitModuleType module));
- Assert.AreEqual(module, expectedModule);
- }
+ string resolvedPath = MixedRealityToolkitFiles.MapRelativeFilePathToAbsolutePath("Inspectors\\Data\\EditorWindowOptions.json");
+ Assert.IsNotNull(resolvedPath);
}
[TearDown]
diff --git a/Assets/MixedRealityToolkit.Tests/MRTK.Tests.sentinel b/Assets/MixedRealityToolkit.Tests/MRTK.Tests.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.Tests/MRTK.Tests.sentinel.meta b/Assets/MixedRealityToolkit.Tests/MRTK.Tests.sentinel.meta
new file mode 100644
index 00000000000..9c5d29ff9dd
--- /dev/null
+++ b/Assets/MixedRealityToolkit.Tests/MRTK.Tests.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 602691336a9ce9749a76d54221dcc85b
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit.Tools/MRTK.Tools.sentinel b/Assets/MixedRealityToolkit.Tools/MRTK.Tools.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit.Tools/MRTK.Tools.sentinel.meta b/Assets/MixedRealityToolkit.Tools/MRTK.Tools.sentinel.meta
new file mode 100644
index 00000000000..abb09afa2d9
--- /dev/null
+++ b/Assets/MixedRealityToolkit.Tools/MRTK.Tools.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e5bf78b8638c3604b88d3e0b880941e2
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit/MRTK.Core.sentinel b/Assets/MixedRealityToolkit/MRTK.Core.sentinel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/Assets/MixedRealityToolkit/MRTK.Core.sentinel.meta b/Assets/MixedRealityToolkit/MRTK.Core.sentinel.meta
new file mode 100644
index 00000000000..a2e05c3b219
--- /dev/null
+++ b/Assets/MixedRealityToolkit/MRTK.Core.sentinel.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 05ba0ec971b0d5648a404e6ac3ae4cab
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MixedRealityToolkit/Utilities/Editor/Setup/MixedRealityToolkitFiles.cs b/Assets/MixedRealityToolkit/Utilities/Editor/Setup/MixedRealityToolkitFiles.cs
index 776988ccc8a..8c7db0b23ca 100644
--- a/Assets/MixedRealityToolkit/Utilities/Editor/Setup/MixedRealityToolkitFiles.cs
+++ b/Assets/MixedRealityToolkit/Utilities/Editor/Setup/MixedRealityToolkitFiles.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
@@ -16,6 +17,7 @@ namespace Microsoft.MixedReality.Toolkit.Utilities.Editor
///
public enum MixedRealityToolkitModuleType
{
+ None = 0,
Core,
Generated,
Providers,
@@ -34,6 +36,15 @@ public enum MixedRealityToolkitModuleType
///
/// API for working with MixedRealityToolkit folders contained in the project.
///
+ ///
+ /// This class works by looking for sentinel files (following the pattern MRTK.*.sentinel,
+ /// for example, MRTK.Core.sentinel) in order to identify where the MRTK is located
+ /// within the project.
+ ///
+ /// If the MRTK is being consumed as code that sits within the Assets folder, the "root"
+ /// MRTK folder must be at most three directories deep - this search code will only reason
+ /// over MRTK folders that sit in a depth range [0, 3].
+ ///
[InitializeOnLoad]
public static class MixedRealityToolkitFiles
{
@@ -49,6 +60,14 @@ private enum SearchType
Folder,
}
+ ///
+ /// The MRTK uses "sentinel" files (for example, MRTK.Core.sentinel) which are used to uniquely
+ /// identify the presence of certain MRTK folders and modules. This is the file pattern used
+ /// to search within folders for those sentinel files and make the file search a little more
+ /// efficient than a full file enumeration.
+ ///
+ private const string SentinelFilePattern = "MRTK.*.sentinel";
+
///
/// In order to subscribe for a callback,
/// the class declaring the method must derive from AssetPostprocessor. So this class is nested privately as to prevent instantiation of it.
@@ -61,13 +80,14 @@ public static void OnPostprocessAllAssets(string[] importedAssets, string[] dele
foreach (string asset in importedAssets.Concat(movedAssets))
{
- string folder = ResolveFullAssetsPath(asset);
- TryRegisterModuleFolder(folder);
+ string fullAssetPath = ResolveFullAssetsPath(asset);
+ TryRegisterModuleFile(fullAssetPath);
}
foreach (string asset in deletedAssets.Concat(movedFromAssetPaths))
{
- string folder = ResolveFullAssetsPath(asset);
+ string fullAssetPath = ResolveFullAssetsPath(asset);
+ string folder = Path.GetDirectoryName(fullAssetPath);
TryUnregisterModuleFolder(folder);
}
}
@@ -159,26 +179,38 @@ private static void SearchForFoldersAsync(string rootPath)
}
}
- private static bool TryRegisterModuleFolder(string folder)
+ private static void TryRegisterModuleFolder(string folder)
{
- return TryRegisterModuleFolder(folder, out MixedRealityToolkitModuleType module);
+ string normalizedFolder = NormalizeSeparators(folder);
+ List modules;
+ if (FindMatchingModule(normalizedFolder, out modules))
+ {
+ foreach (var module in modules)
+ {
+ if (!mrtkFolders.TryGetValue(module, out HashSet modFolders))
+ {
+ modFolders = new HashSet();
+ mrtkFolders.Add(module, modFolders);
+ }
+ modFolders.Add(normalizedFolder);
+ }
+ }
}
- private static bool TryRegisterModuleFolder(string folder, out MixedRealityToolkitModuleType module)
+ private static void TryRegisterModuleFile(string fullAssetPath)
{
- string normalizedFolder = NormalizeSeparators(folder);
- if (FindMatchingModule(normalizedFolder, out module))
+ MixedRealityToolkitModuleType moduleType = MatchModuleType(fullAssetPath);
+ if (moduleType != MixedRealityToolkitModuleType.None)
{
- if (!mrtkFolders.TryGetValue(module, out HashSet modFolders))
+ if (!mrtkFolders.TryGetValue(moduleType, out HashSet modFolders))
{
modFolders = new HashSet();
- mrtkFolders.Add(module, modFolders);
+ mrtkFolders.Add(moduleType, modFolders);
}
- modFolders.Add(normalizedFolder);
- return true;
- }
- return false;
+ string folder = Path.GetDirectoryName(fullAssetPath);
+ modFolders.Add(NormalizeSeparators(folder));
+ }
}
private static bool TryUnregisterModuleFolder(string folder)
@@ -333,7 +365,7 @@ private static string MapRelativePathToAbsolutePath(SearchType searchType, Mixed
private static readonly Dictionary moduleNameMap = new Dictionary()
{
- { "", MixedRealityToolkitModuleType.Core },
+ { "Core", MixedRealityToolkitModuleType.Core },
{ "Generated", MixedRealityToolkitModuleType.Generated },
{ "Providers", MixedRealityToolkitModuleType.Providers },
{ "Services", MixedRealityToolkitModuleType.Services },
@@ -349,54 +381,59 @@ private static string MapRelativePathToAbsolutePath(SearchType searchType, Mixed
{ "AdhocTesting", MixedRealityToolkitModuleType.AdhocTesting },
};
- public static bool FindMatchingModule(string path, out MixedRealityToolkitModuleType result)
+ ///
+ /// Try to find the matching modules associated with path by looking for the presence of
+ /// MRTK sentinel files.
+ ///
+ ///
+ /// In certain consumption situations, the content can be placed within the same folder,
+ /// meaning it's possible for multiple sentinel values to exist within the same folder.
+ ///
+ public static bool FindMatchingModule(string path, out List result)
{
- // Matches an optional module suffix, e.g. ".Services"
- const string modulePattern = @"(\.(?[a-zA-Z]+))?";
- // Matches a version string, e.g. "2.0.0-20190611.2"
- const string versionPattern = @"(?[.\-0-9]+)";
- // Matches the naming pattern in the MRTK repository
- // e.g. "MixedRealityToolkit.Services"
- const string mrtkPattern = @"^MixedRealityToolkit" + modulePattern + @"$";
- // Matches "Microsoft.MixedReality.Toolkit", followed by optional module name, followed by version number
- // e.g.: "Microsoft.MixedReality.Toolkit.Services.2.0.0-20190611.2"
- // This alternate path is used if above isn't found. This is to work around long paths issue with NuGetForUnity
- // https://github.com/GlitchEnzo/NuGetForUnity/issues/246
- const string nugetParentPattern = @"^Microsoft\.MixedReality\.Toolkit" + modulePattern + @"\." + versionPattern + @"$";
-
+ result = null;
+
if (path.Length > 0)
{
- var dirInfo = new DirectoryInfo(path);
- if (TryMatchFolderPattern(dirInfo.Name, mrtkPattern, out result))
+ // Note that path can be a file or a directory
+ DirectoryInfo directoryInfo = new DirectoryInfo(path);
+ var sentinelFiles = Directory.EnumerateFiles(directoryInfo.FullName, SentinelFilePattern);
+ foreach (var sentinelFile in sentinelFiles)
{
- return true;
- }
- else if (dirInfo.Name == "MRTK"
- && dirInfo.Parent != null
- && TryMatchFolderPattern(dirInfo.Parent.Name, nugetParentPattern, out result))
- {
- return true;
+ if (result == null)
+ {
+ result = new List();
+ }
+ MixedRealityToolkitModuleType moduleType = MatchModuleType(sentinelFile);
+ if (moduleType != MixedRealityToolkitModuleType.None)
+ {
+ result.Add(moduleType);
+ }
}
}
- result = MixedRealityToolkitModuleType.Core;
- return false;
+ return result != null;
}
- private static bool TryMatchFolderPattern(string name, string pattern, out MixedRealityToolkitModuleType result)
+ ///
+ /// Given the full file path, returns the module it's associated with (if it is an MRTK
+ /// sentinel file).
+ ///
+ private static MixedRealityToolkitModuleType MatchModuleType(string filePath)
{
- var folderMatches = System.Text.RegularExpressions.Regex.Matches(name, pattern);
- if (folderMatches.Count == 1)
+ const string sentinelRegexPattern = @"^MRTK\.(?[a-zA-Z]+)\.sentinel";
+ string fileName = Path.GetFileName(filePath);
+ var matches = Regex.Matches(fileName, sentinelRegexPattern);
+ if (matches.Count == 1)
{
- var moduleName = folderMatches[0].Groups["module"].Value;
- if (moduleNameMap.TryGetValue(moduleName, out result))
+ var moduleName = matches[0].Groups["module"].Value;
+ MixedRealityToolkitModuleType moduleType;
+ if (moduleNameMap.TryGetValue(moduleName, out moduleType))
{
- return true;
+ return moduleType;
}
}
-
- result = MixedRealityToolkitModuleType.Core;
- return false;
+ return MixedRealityToolkitModuleType.None;
}
///