Skip to content

Conversation

davidobrien1985
Copy link
Contributor

This commit should address #896

I'm not really a C# dev, just starting and coming from PowerShell, so hopefully I haven't violated too many C# best practices here ;)

The code will now check for a folder named modules in the root of the Function App and search for all available module files, adding results to the modulePaths output variable.

@dnfclas
Copy link

dnfclas commented Nov 10, 2016

Hi @davidobrien1985, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

This seems like a small (but important) contribution, so no Contribution License Agreement is required at this point. Real humans will now evaluate your PR.

TTYL, DNFBOT;

@davidobrien1985
Copy link
Contributor Author

Not entirely sure why ALL the tests are failing here.
Checked the commits and couldn't find any changes lately on the tests but the first lines of appveyor output already say it can't find the Microsoft.Azure.WebJobs.Script.Tests.ScriptHostTests class or something like that.

Strange. @tohling , maybe something that you can quickly check?! Sorry if I broke something.

Copy link
Member

@fabiocav fabiocav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @davidobrien1985, thank you for sending this!

There are some issues with that CI run (the default CI project), and the failing tests are not related to your changes, so no worries there 😃

PowerShellConstants.ModulesScriptFileExtensionPattern));
}

if (Directory.Exists(rootModuleDirectory))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we introduce a method to add a directory to modulePaths so we can combine this new code and the block above to eliminate duplication?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Will get to that now and push asap.

@davidobrien1985
Copy link
Contributor Author

@fabiocav This should look cleaner now. (c# is cool :-) )

@davidobrien1985
Copy link
Contributor Author

Changed AddToModulePaths() to search the /modules folder(s) recursively.
This will only impact PowerShell based functions.
This does not impact existing, working functions.
This will allow users to organise their modules in /modules/Module structure, which is closer to how PowerShell works on Windows and Linux. Modules are not held in flat folder structures.

@fabiocav
Copy link
Member

@davidobrien1985 could you rebase your work on the dev branch?

@davidobrien1985
Copy link
Contributor Author

@fabiocav done

Copy link
Member

@fabiocav fabiocav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidobrien1985 I've added a couple of small nit comments (simple stuff). But this looks good!

It would be nice to update the GetModuleFilePaths test to account for this new logic as well.

@tohling, since this is in the PowerShell invoker, could you take a quick look at this and give your blessing?

return modulePaths;
}

internal static List<string> AddToModulePaths(string[] directories)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: change this to use params (will simplify the calling code)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I would say that you should add tests for this and ensure that loading of modules works without errors when loading from both rootModuleDirectory and moduleDirectory. Verify that if a DLL is duplicated in both directories, the load behavior is as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fabiocav changed to params now.

internal static List<string> AddToModulePaths(string[] directories)
{
List<string> paths = new List<string>();
for (int i = 0; i < directories.Length; i++)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: simplify by using a foreach

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's done now.

@davidobrien1985
Copy link
Contributor Author

@fabiocav cool, thanks. Will do that tonight when I'm back at the hotel. Good feedback.

{
paths.AddRange(Directory.GetFiles(currentDirectory,
PowerShellConstants.ModulesManifestFileExtensionPattern,
SearchOption.AllDirectories));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the file and code for SearchOption?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kindly also add tests for the following,

  1. nested folders
  2. ensure that resolution in case of duplicates is as expected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tohling SearchOption is part of System.IO

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fabiocav, ah, I missed Directory.GetFiles. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tohling How would you want to handle "duplicates"? Usually I would say "closest to the function" wins.
However, PowerShell can import multiple versions of the same module into one environment. It is then up to the user to decide which one he/she wants to use. That said, because Azure Functions right now imports everything automatically, this won't necessarily work.
Hence #897

Copy link
Contributor

@tohling tohling Nov 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidobrien1985 Yes, I agree that the correct change is to allow the customer to decide which one to use even when there are duplicates. This is potentially a breaking change to existing customers who already have their scripts written with the current default behavior. There is a broader issue on how we can absorb your changes. We are working on addressing this. Kindly give us some time and I will get back to you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tohling do you want me to continue working on this here then? Do you have an issue for this already here somewhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidobrien1985, yes you may continue to work on this. I don't have an issue opened yet. I really like the changes that you are making and my previous comment was just me thinking ahead on how soon they can be merged into the repo.

We truly value the work from contributors like yourself. We are discussing how to incorporate your changes in a timely and seamless manner for both you and customers who have already deployed their PowerShell Functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, added some logic to the tests and GetModuleFilePaths() is still passing.

In regards to duplicates:
I will assume, for now, that if there are duplicates (by filename) that the one closest in functionroot/modules is supposed to be imported.

return modulePaths;
}

internal static List<string> AddToModulePaths(string[] directories)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I would say that you should add tests for this and ensure that loading of modules works without errors when loading from both rootModuleDirectory and moduleDirectory. Verify that if a DLL is duplicated in both directories, the load behavior is as expected.

@davidobrien1985
Copy link
Contributor Author

@fabiocav @tohling
Think I've got all your requests covered now.

@tohling
Copy link
Contributor

tohling commented Dec 7, 2016

@davidobrien1985, looks good except the test Microsoft.Azure.WebJobs.Script.Tests.PowerShellInvokerTests.GetModuleFilePaths is still failing. Could you take a look?

@davidobrien1985
Copy link
Contributor Author

@tohling fixed. Totally missed that one test. Hooray for tests!

@fabiocav
Copy link
Member

@tohling indicated that she has reviewed this changes and she is good with them.

@davidobrien1985 can you confirm that you have no other pending changes here? If so, we'll spend some time reviewing this so we can have this work merged.

@davidobrien1985
Copy link
Contributor Author

@fabiocav merged latest changes in, reran all the tests, 👍 from me. Should all be good to go.
Thanks to @tohling as well for being so patient with me :)


if (_moduleFiles.Any())
{
powerShellInstance.AddCommand("Import-Module").AddArgument(_moduleFiles);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we run an auto import on every single module we discover. For a modules folder scoped to a single function (the way we work currently) that is OK, since you only add modules you want to use in your function anyways.

However, in this PR you're adding a shared modules folder that sits above all functions, and all the modules in there will be added to all functions. That seems problematic. Can't you do what you're trying to do today by adding explicit import statements to pull in the shared modules you need from a shared folder? That avoids the code duplication issue, and also allows you to pull only a subset of shared modules in as needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mathewc this would be #897
Right now I just want to have a "super modules" directory that does not sit within one function.
Let's say I have one module that I need to share across 5 functions in one Function App I only want it in one place, not in 5.
The next step will be to add implicit import as described in above issue which will address the issue you are having right now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But can't you simply put your shared module in a shared folder, and add implicit import statement to each function already? As you pointed out in #897 auto import has performance implications. While the problem is not too bad for function level modules (since you have to explicitly add them to your function dir so intent is pretty clear), for cross function modules auto importing into every function doesn't feel right. Isn't simply adding the proper import statements to each of your functions a cleaner approach? Are there any issues blocking you from doing that today?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I'd prefer to not have any auto-import, at all, not even on a function level.
I was told that auto-import should stay so to not break current behaviour.
I would either opt for removing auto-import everywhere or add my approach here and auto-import.
How does it work in other languages on Functions?
Having implicit imports in one case and explicit in other cases makes it quite confusing, unless we start working with PSModulePath.
PowerShell users will either expect auto loading to just work, wherever they put stuff or not.

One option would be to add the two "modules" locations to PSModulePath and use PowerShell's auto-loading of modules, but this again would have performance implications.
In the end, PowerShell on Functions will never perform as well as the other languages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should hold off on doing any auto-import from a shared folder across functions. People can get the desired behavior in a better more predictable way today by using explicit references.

That said, I do think the small fix you mad to make the module resolution handle sub directories is good. Your call on whether you want to scope to just that and get this in, or set that as a different PR. Thanks for your help and patience :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mathewc fair enough. If you like to cherry-pick the commits for the subdirectory code then I'm fine with that.
I'm also going to create a PR to remove auto-import altogether as I don't think that this is a great idea in general. This will address #897 then.

@davidobrien1985
Copy link
Contributor Author

I am currently in Thailand on vacation, so if you have some more questions for this before merging, keep in mind that I'm mostly offline.

Just to be clear with this PR:
Current behaviour won't change. If users don't have a "function app level modules folder" then they won't see any difference, only if a user needs this functionality will the behaviour change.

@davidobrien1985
Copy link
Contributor Author

@mathewc and @tohling I am parking this PR here now as WIP and will see how I can still "rescue" my work and get some value out of this PR.
In the meantime I have forked out the recursive search of module files into its own PR as Mathew suggested.

@mathewc
Copy link
Member

mathewc commented Jan 3, 2017

David, I've merged your other PR. I'm thinking we should close this PR at this point?

@davidobrien1985
Copy link
Contributor Author

woops, missed your comment @mathewc . Closing. Thanks.

maiqbal11 added a commit that referenced this pull request Nov 1, 2019
Revert "Python public preview cli update"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants