/// <summary> /// Installs function app dependencies specified in functionAppRoot\requirements.psd1. /// </summary> internal void InstallFunctionAppDependencies(PowerShell pwsh, ILogger logger) { try { // Install the function dependencies. logger.Log(LogLevel.Trace, PowerShellWorkerStrings.InstallingFunctionAppDependentModules, isUserLog: true); if (Directory.Exists(DependenciesPath)) { // Save-Module supports downloading side-by-size module versions. However, we only want to keep one version at the time. // If the ManagedDependencies folder exits, remove all its contents. DependencyManagementUtils.EmptyDirectory(DependenciesPath); } else { // If the destination path does not exist, create it. Directory.CreateDirectory(DependenciesPath); } try { foreach (DependencyInfo module in Dependencies) { string moduleName = module.Name; string latestVersion = module.LatestVersion; // Save the module to the given path pwsh.AddCommand("PowerShellGet\\Save-Module") .AddParameter("Repository", Repository) .AddParameter("Name", moduleName) .AddParameter("RequiredVersion", latestVersion) .AddParameter("Path", DependenciesPath) .AddParameter("Force", true) .AddParameter("ErrorAction", "Stop") .InvokeAndClearCommands(); var message = string.Format(PowerShellWorkerStrings.ModuleHasBeenInstalled, moduleName, latestVersion); logger.Log(LogLevel.Trace, message, isUserLog: true); } } finally { // Clean up pwsh.AddCommand(Utils.RemoveModuleCmdletInfo) .AddParameter("Name", "PackageManagement, PowerShellGet") .AddParameter("Force", true) .AddParameter("ErrorAction", "SilentlyContinue") .InvokeAndClearCommands(); } } catch (Exception e) { var errorMsg = string.Format(PowerShellWorkerStrings.FailToInstallFuncAppDependencies, e.Message); _dependencyError = new DependencyInstallationException(errorMsg, e); } }
/// <summary> /// Initializes the dependency manger and performs the following: /// - Parse functionAppRoot\requirements.psd1 file and create a list of dependencies to install. /// - Set the DependenciesPath which gets used in 'SetupWellKnownPaths'. /// - Determines if the dependency module needs to be installed by checking the latest available version /// in the PSGallery and the destination path (to see if it is already installed). /// - Set the destination path (if running in Azure vs local) where the function app dependencies will be installed. /// </summary> internal void Initialize(FunctionLoadRequest request) { if (!request.ManagedDependencyEnabled) { return; } try { // Resolve the FunctionApp root path. var functionAppRootPath = Path.GetFullPath(Path.Join(request.Metadata.Directory, "..")); // Resolve the managed dependencies installation path. DependenciesPath = GetManagedDependenciesPath(functionAppRootPath); // Parse and process the function app dependencies defined in requirements.psd1. Hashtable entries = ParsePowerShellDataFile(functionAppRootPath, RequirementsPsd1FileName); foreach (DictionaryEntry entry in entries) { // A valid entry is of the form: 'ModuleName'='MajorVersion.*" string name = (string)entry.Key; string version = (string)entry.Value; // Validates that the module name is a supported dependency. ValidateModuleName(name); // Validate the module version. string majorVersion = GetMajorVersion(version); string latestVersion = DependencyManagementUtils.GetModuleLatestSupportedVersion(name, majorVersion); ValidateModuleMajorVersion(name, majorVersion, latestVersion); // Before installing the module, check the path to see if it is already installed. var moduleVersionFolderPath = Path.Combine(DependenciesPath, name, latestVersion); if (!Directory.Exists(moduleVersionFolderPath)) { _shouldUpdateFunctionAppDependencies = true; } // Create a DependencyInfo object and add it to the list of dependencies to install. var dependencyInfo = new DependencyInfo(name, majorVersion, latestVersion); Dependencies.Add(dependencyInfo); } } catch (Exception e) { // Reset DependenciesPath and Dependencies. DependenciesPath = null; Dependencies.Clear(); var errorMsg = string.Format(PowerShellWorkerStrings.FailToInstallFuncAppDependencies, e.Message); throw new DependencyInstallationException(errorMsg, e); } }
/// <summary> /// Sets/prepares the destination path where the function app dependencies will be installed. /// </summary> internal void SetDependenciesDestinationPath(string path) { // Save-Module supports downloading side-by-size module versions. However, we only want to keep one version at the time. // If the ManagedDependencies folder exits, remove all its contents. if (Directory.Exists(path)) { DependencyManagementUtils.EmptyDirectory(path); } else { // If the destination path does not exist, create it. // If the user does not have write access to the path, an exception will be raised. try { Directory.CreateDirectory(path); } catch (Exception e) { var errorMsg = string.Format(PowerShellWorkerStrings.FailToCreateFunctionAppDependenciesDestinationPath, path, e.Message); throw new InvalidOperationException(errorMsg); } } }