Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a programmed search to locate extensions in place of default addins files. #1504

Closed
Tracked by #1549
CharliePoole opened this issue Oct 21, 2024 · 4 comments · Fixed by #1518
Closed
Tracked by #1549

Use a programmed search to locate extensions in place of default addins files. #1504

CharliePoole opened this issue Oct 21, 2024 · 4 comments · Fixed by #1518
Assignees
Milestone

Comments

@CharliePoole
Copy link
Member

Each of our console packages is distributed with an addins file in the engine directory. The file is used to find extensions that use our default naming pattern in one or more default locations. The content is slightly different for each package type, i.e. nuget vs chocolatey, but the structure of the paths contained is quite similar.

This issue proposes to replace the user of default addins files with an algorithmic approach. That is, code in ExtensionManager would incorporate the logic needed to look for extensions in the same places as our default files, which would no longer be distributed. We would, however, continue to use any addins files found, since users may continue to create them.

Addins file are very useful for adding extensions on an adhoc basis, so we will continue to use them. However, an algorithmic approach has a two main advantages...

  • Users will no longer be tempted to erroneously change our distributed addins files.
  • This approach is more extensible. For example, it will allow us to walk through all parent directories searching for extensions at a higher level. This is essential to use of extensions in standalone executables and is the primary reason for making the change at this time (see Simplify locating of addins #488).

@OsirisTerje @nunit Comments please?

@CharliePoole CharliePoole added this to the 3.19.0 milestone Oct 21, 2024
@CharliePoole CharliePoole self-assigned this Oct 21, 2024
@CharliePoole CharliePoole changed the title Eliminate use of default addins files for locating extensions. Use a programmed search to locate extensions in place of default addins files. Oct 21, 2024
@OsirisTerje
Copy link
Member

This is more like the way Is see other systems do the same thing, so I am in favor of this approach. I believe it will make it easier, also what is said in #488 makes sense to me.

It could also open up an approach for adding extensions to other parts of the nunit sphere.

@CharliePoole
Copy link
Member Author

I hacked together a local experiment and extensions will work with dotnet nunit using this approach, so that's big.

To use extensions elsewhere, you would probably want to complete the job of separating it out as was planned for V4. It's not breaking in any way so could even be V3. I've done that for TestCentric where there's a separate Extensibility package. One good use for NUnit would be to allow NUnitLite or it's successor to host extensions.

@CharliePoole
Copy link
Member Author

Documenting the new implementation, which affects both ExtensionService and ExtensionManager. (Adapted from PR #1506)

Previously, ExtensionService, as part of it's startup, called ExtensionManager.FindExtensions(string initialDirectory). That API examines .addins files in the directory and uses each entry as a hint about where to find candidate assemblies in which extensions are sought. The method us currently not used but continues to exist and work as it has in the past. It will be used in a future enhancement to examine additional directories provided by the user.

In place of the FindExtensions method, ExtensionService now calls a new API...

ExtensionManager.FindStandardExtensions(Assembly hostAssembly)

An internal algorithm (see below) uses the directory containing hostAssembly as a starting point and searches for directories matching a specific set of patterns. The patterns are not provided in the call, but are known to the algorithm and may change in the future by adding additional patterns. Currently we search for directories matching 'nunit-extension-for chocolatey andNUnit.Extension.` one for nuget. If desired, we could allow the caller to override these patterns in the future, but that's not currently possible.

The current algorithm, works as follows...

  1. Decide on the patterns to be used.
  2. Start in the directory containing the host assembly.
  3. Apply each pattern within that directory, recording the assemblies found in or under its tools subdirectory.
  4. Move to the parent of the directory we just did and repeat at step 3 until the parent returns as null.

By continuously looking at parent directories, it turns out that we can find our way out of a standalone executable and locate installed extensions, which may be eight to ten levels up. In the current issue, I added one test to the netcore runner using an extension and it works. In issue #1505 I'll complete that work, making all extensions work.

In future, we could look for matches in additional places, e.g. in an addins directory in the initial directory. I decided to stick with the basics needed to get our own extensions working. The work on issue #488 will probably tell us if we need to do more here and will also bring the original FindExtensions method back into use to support additional root directories for locating extensions.

NOTE: ExtensionService vs ExtensionManager

In this implementation, I have removed most knowledge of how extensions are found from ExtensionService and embedded that knowledge in ExtensionManager. This reflects the idea that ExtensionManager may eventually become a separate assembly, as envisioned in the plan for version 4. It could then be used directly by other components, such as nunitlite or the vs adapter, allowing them to host the same extensions as the engine.

@CharliePoole
Copy link
Member Author

This issue has been resolved in version 3.19.0

The release is available on:
GitHub.
NuGet packages are also available NuGet.org and
Chocolatey Packages may be found at Chocolatey.org

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants