Esempio n. 1
0
        /// <inheritdoc/>
        public ExternalImplementation Lookup(ImplementationSelection selection)
        {
            #region Sanity checks
            if (selection == null)
            {
                throw new ArgumentNullException("selection");
            }
            #endregion

            try
            {
                var referenceImpl = ExternalImplementation.FromID(selection.ID);

                // Reference implementation from ID does not contain all required information.
                // Therefore, find the original implementation.
                var implementation = GetImplementations(referenceImpl.Package)
                                     .First(x => x.Version == referenceImpl.Version && x.Architecture == referenceImpl.Architecture);

                CopyValues(from: selection, to: implementation);
                return(implementation);
            }
            #region Error handling
            catch (FormatException)
            {
                throw new ImplementationNotFoundException(string.Format(Resources.UnknownPackageID, selection.ID, DistributionName));
            }
            catch (InvalidOperationException)
            {
                throw new ImplementationNotFoundException(string.Format(Resources.UnknownPackageID, selection.ID, DistributionName));
            }
            #endregion
        }
Esempio n. 2
0
    /// <inheritdoc/>
    public ExternalImplementation?Lookup(ImplementationSelection selection)
    {
        #region Sanity checks
        if (selection == null)
        {
            throw new ArgumentNullException(nameof(selection));
        }
        #endregion

        try
        {
            var referenceImpl = ExternalImplementation.FromID(selection.ID);

            // Reference implementation from ID does not contain all required information.
            // Therefore, find the original implementation.
            var implementation = GetImplementations(referenceImpl.Package)
                                 .FirstOrDefault(x => x.Version == referenceImpl.Version &&
                                                 x.Architecture == referenceImpl.Architecture);

            if (implementation != null)
            {
                CopyValues(from: selection, to: implementation);
            }

            return(implementation);
        }
        catch (FormatException)
        {
            return(null);
        }
    }
        /// <summary>
        /// Applies an <see cref="ExecutableInVar"/> binding by creating a run-environment executable.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <param name="startInfo">The process launch environment to use to make the run-environment executable available.</param>
        /// <exception cref="KeyNotFoundException"><see cref="Selections"/> points to missing <see cref="Dependency"/>s.</exception>
        /// <exception cref="ImplementationNotFoundException">One of the <see cref="Store.Model.Implementation"/>s is not cached yet.</exception>
        /// <exception cref="ExecutorException"><see cref="ExecutableInVar.Name"/> is invalid.</exception>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        private void ApplyExecutableInVar(ExecutableInVar binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name))
            {
                throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<executable-in-var>"));
            }
            if (Path.GetInvalidFileNameChars().Any(invalidChar => binding.Name.Contains(invalidChar.ToString(CultureInfo.InvariantCulture))))
            {
                throw new ExecutorException(string.Format(Resources.IllegalCharInBindingName, @"<executable-in-var>"));
            }

            string exePath = DeployRunEnvExecutable(binding.Name);

            // Point variable directly to executable
            if (startInfo.EnvironmentVariables.ContainsKey(binding.Name))
            {
                Log.Warn("Overwriting existing environment variable with <executable-in-var>: " + binding.Name);
            }
            startInfo.EnvironmentVariables[binding.Name] = exePath;

            // Tell the executable what command-line to run
            _runEnvPendings.Add(new RunEnvPending(binding.Name, GetCommandLine(implementation, binding.Command ?? Command.NameRun, startInfo)));
        }
        /// <inheritdoc/>
        public ExternalImplementation Lookup(ImplementationSelection selection)
        {
            #region Sanity checks
            if (selection == null) throw new ArgumentNullException(nameof(selection));
            #endregion

            try
            {
                var referenceImpl = ExternalImplementation.FromID(selection.ID);

                // Reference implementation from ID does not contain all required information.
                // Therefore, find the original implementation.
                var implementation = GetImplementations(referenceImpl.Package)
                    .First(x => x.Version == referenceImpl.Version && x.Architecture == referenceImpl.Architecture);

                CopyValues(from: selection, to: implementation);
                return implementation;
            }
                #region Error handling
            catch (FormatException)
            {
                throw new ImplementationNotFoundException(string.Format(Resources.UnknownPackageID, selection.ID, DistributionName));
            }
            catch (InvalidOperationException)
            {
                throw new ImplementationNotFoundException(string.Format(Resources.UnknownPackageID, selection.ID, DistributionName));
            }
            #endregion
        }
        /// <summary>
        /// Applies all <see cref="Binding"/>s listed in a specific <see cref="IBindingContainer"/>.
        /// </summary>
        /// <param name="bindingContainer">The list of <see cref="Binding"/>s to be performed.</param>
        /// <param name="implementation">The implementation to be made available via the <see cref="Binding"/>s.</param>
        /// <param name="startInfo">The process launch environment to apply the <see cref="Binding"/>s to.</param>
        /// <exception cref="ImplementationNotFoundException">The <paramref name="implementation"/> is not cached yet.</exception>
        /// <exception cref="ExecutorException">A <see cref="Command"/> contained invalid data.</exception>
        /// <exception cref="IOException">A problem occurred while writing a file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to a file is not permitted.</exception>
        private void ApplyBindings(IBindingContainer bindingContainer, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            // Do not apply bindings more than once
            if (!_appliedBindingContainers.Add(bindingContainer))
            {
                return;
            }

            if (bindingContainer.Bindings.Count == 0)
            {
                return;
            }

            // Don't use bindings for PackageImplementations
            if (implementation.ID.StartsWith(ExternalImplementation.PackagePrefix))
            {
                return;
            }

            new PerTypeDispatcher <Binding>(ignoreMissing: true)
            {
                (EnvironmentBinding environmentBinding) => ApplyEnvironmentBinding(environmentBinding, implementation, startInfo),
                //(OverlayBinding overlayBinding) => ApplyOverlayBinding(overlayBinding, implementation, startInfo),
                (ExecutableInVar executableInVar) => ApplyExecutableInVar(executableInVar, implementation, startInfo),
                (ExecutableInPath executableInPath) => ApplyExecutableInPath(executableInPath, implementation, startInfo)
            }.Dispatch(bindingContainer.Bindings);
        }
        /// <summary>
        /// Applies an <see cref="EnvironmentBinding"/> by modifying environment variables.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <param name="startInfo">The process launch environment to apply the binding to.</param>
        /// <exception cref="ExecutorException"><see cref="EnvironmentBinding.Name"/> or other data is invalid.</exception>
        private void ApplyEnvironmentBinding(EnvironmentBinding binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name))
            {
                throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<environment>"));
            }

            var environmentVariables = startInfo.EnvironmentVariables;

            string newValue;

            if (binding.Value != null && binding.Insert != null)
            { // Conflict
                throw new ExecutorException(Resources.EnvironmentBindingValueInvalid);
            }
            else if (binding.Value != null)
            { // Static value
                newValue = binding.Value;
            }
            else
            { // Path inside the implementation
                newValue = Path.Combine(GetImplementationPath(implementation), FileUtils.UnifySlashes(binding.Insert ?? ""));
            }

            // Set the default value if the variable is not already set on the system
            if (!environmentVariables.ContainsKey(binding.Name))
            {
                environmentVariables.Add(binding.Name, binding.Default);
            }

            string previousValue = environmentVariables[binding.Name];
            string separator     = (string.IsNullOrEmpty(binding.Separator) ? Path.PathSeparator.ToString(CultureInfo.InvariantCulture) : binding.Separator);

            switch (binding.Mode)
            {
            default:
            case EnvironmentMode.Prepend:
                environmentVariables[binding.Name] = string.IsNullOrEmpty(previousValue)
                                                     // No exisiting value, just set new one
                        ? newValue
                                                     // Prepend new value to existing one seperated by path separator
                        : newValue + separator + environmentVariables[binding.Name];
                break;

            case EnvironmentMode.Append:
                environmentVariables[binding.Name] = string.IsNullOrEmpty(previousValue)
                                                     // No exisiting value, just set new one
                        ? newValue
                                                     // Append new value to existing one seperated by path separator
                        : environmentVariables[binding.Name] + separator + newValue;
                break;

            case EnvironmentMode.Replace:
                // Overwrite any existing value
                environmentVariables[binding.Name] = newValue;
                break;
            }
        }
Esempio n. 7
0
        private List <ArgBase> GetCommandLine([NotNull] ImplementationSelection implementation, [NotNull] string commandName, [NotNull] ProcessStartInfo startInfo)
        {
            #region Sanity checks
            if (implementation == null)
            {
                throw new ArgumentNullException(nameof(implementation));
            }
            if (startInfo == null)
            {
                throw new ArgumentNullException(nameof(startInfo));
            }
            if (commandName == null)
            {
                throw new ArgumentNullException(nameof(commandName));
            }
            #endregion

            if (commandName.Length == 0)
            {
                throw new ExecutorException(string.Format(Resources.CommandNotSpecified, implementation.InterfaceUri));
            }
            var command = implementation[commandName];
            Debug.Assert(command != null);

            // Apply bindings implementations use to find themselves and their dependencies
            ApplyBindings(command, implementation, startInfo);
            if (command.WorkingDir != null)
            {
                ApplyWorkingDir(command.WorkingDir, implementation, startInfo);
            }
            ApplyDependencyBindings(command, startInfo);

            List <ArgBase> commandLine;
            var            runner = command.Runner;
            if (runner == null)
            {
                commandLine = new List <ArgBase>();
            }
            else
            {
                commandLine = GetCommandLine(Selections[runner.InterfaceUri], runner.Command ?? Command.NameRun, startInfo);
                commandLine.AddRange(runner.Arguments);
            }

            if (!string.IsNullOrEmpty(command.Path))
            {
                string path = FileUtils.UnifySlashes(command.Path);

                // Fully qualified paths are used by package/native implementations, usually relative to the implementation
                commandLine.Add(Path.IsPathRooted(path) ? path : Path.Combine(GetImplementationPath(implementation), path));
            }
            commandLine.AddRange(command.Arguments);

            return(commandLine);
        }
Esempio n. 8
0
        /// <summary>
        /// Retrieves the original <see cref="Implementation"/> an <see cref="ImplementationSelection"/> was based ofF.
        /// </summary>
        public Implementation LookupOriginalImplementation(ImplementationSelection implemenationSelection)
        {
            #region Sanity checks
            if (implemenationSelection == null)
            {
                throw new ArgumentNullException(nameof(implemenationSelection));
            }
            #endregion

            return(implemenationSelection.ID.StartsWith(ExternalImplementation.PackagePrefix)
                ? _externalImplementations[implemenationSelection.ID]
                : _feedManager[implemenationSelection.FromFeed ?? implemenationSelection.InterfaceUri][implemenationSelection.ID]);
        }
Esempio n. 9
0
    /// <summary>
    /// Turns a <see cref="SelectionCandidate"/> into a <see cref="ImplementationSelection"/>.
    /// </summary>
    /// <param name="candidate">The selection candidate.</param>
    /// <param name="requirements">The requirements the candidate was chosen for.</param>
    /// <param name="allCandidates">All candidates that were considered for selection (including <paramref name="candidate"/>). These are used to present the user with possible alternatives.</param>
    public static ImplementationSelection ToSelection(this SelectionCandidate candidate, Requirements requirements, [InstantHandle] IEnumerable <SelectionCandidate> allCandidates)
    {
        #region Sanity checks
        if (candidate == null)
        {
            throw new ArgumentNullException(nameof(candidate));
        }
        if (allCandidates == null)
        {
            throw new ArgumentNullException(nameof(allCandidates));
        }
        if (requirements == null)
        {
            throw new ArgumentNullException(nameof(requirements));
        }
        #endregion

        var implementation = candidate.Implementation;
        var selection      = new ImplementationSelection(allCandidates)
        {
            ID                = implementation.ID,
            LocalPath         = implementation.LocalPath,
            ManifestDigest    = implementation.ManifestDigest,
            Architecture      = implementation.Architecture,
            Version           = implementation.Version,
            Released          = implementation.Released,
            Stability         = candidate.EffectiveStability,
            License           = implementation.License,
            UnknownAttributes = implementation.UnknownAttributes,
            UnknownElements   = implementation.UnknownElements,
            InterfaceUri      = requirements.InterfaceUri
        };
        if (candidate.FeedUri != requirements.InterfaceUri)
        {
            selection.FromFeed = candidate.FeedUri;
        }

        if (implementation is ExternalImplementation externalImplementation)
        {
            selection.QuickTestFile = externalImplementation.QuickTestFile;
        }

        selection.Bindings.AddRange(implementation.Bindings.CloneElements());
        selection.AddDependencies(requirements, from: candidate.Implementation);
        selection.AddCommand(requirements, from: candidate.Implementation);

        return(selection);
    }
        /// <summary>
        /// Applies all <see cref="Binding"/>s listed in a specific <see cref="IBindingContainer"/>.
        /// </summary>
        /// <param name="bindingContainer">The list of <see cref="Binding"/>s to be performed.</param>
        /// <param name="implementation">The implementation to be made available via the <see cref="Binding"/>s.</param>
        /// <param name="startInfo">The process launch environment to apply the <see cref="Binding"/>s to.</param>
        /// <exception cref="ImplementationNotFoundException">The <paramref name="implementation"/> is not cached yet.</exception>
        /// <exception cref="ExecutorException">A <see cref="Command"/> contained invalid data.</exception>
        /// <exception cref="IOException">A problem occurred while writing a file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to a file is not permitted.</exception>
        private void ApplyBindings(IBindingContainer bindingContainer, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            // Do not apply bindings more than once
            if (!_appliedBindingContainers.Add(bindingContainer)) return;

            if (bindingContainer.Bindings.Count == 0) return;

            // Don't use bindings for PackageImplementations
            if (implementation.ID.StartsWith(ExternalImplementation.PackagePrefix)) return;

            new PerTypeDispatcher<Binding>(ignoreMissing: true)
            {
                (EnvironmentBinding environmentBinding) => ApplyEnvironmentBinding(environmentBinding, implementation, startInfo),
                //(OverlayBinding overlayBinding) => ApplyOverlayBinding(overlayBinding, implementation, startInfo),
                (ExecutableInVar executableInVar) => ApplyExecutableInVar(executableInVar, implementation, startInfo),
                (ExecutableInPath executableInPath) => ApplyExecutableInPath(executableInPath, implementation, startInfo)
            }.Dispatch(bindingContainer.Bindings);
        }
        /// <summary>
        /// Applies an <see cref="EnvironmentBinding"/> by modifying environment variables.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <exception cref="ExecutorException"><see cref="EnvironmentBinding.Name"/> or other data is invalid.</exception>
        private void ApplyEnvironmentBinding(EnvironmentBinding binding, ImplementationSelection implementation)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name))
            {
                throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<environment>"));
            }

            var environmentVariables = _startInfo.EnvironmentVariables;

            string newValue;

            if (binding.Value != null && binding.Insert != null)
            { // Conflict
                throw new ExecutorException(Resources.EnvironmentBindingValueInvalid);
            }
            else if (binding.Value != null)
            { // Static value
                newValue = binding.Value;
            }
            else
            { // Path inside the implementation
                newValue = Path.Combine(_implementationStore.GetPath(implementation), FileUtils.UnifySlashes(binding.Insert ?? ""));
            }

            // Set the default value if the variable is not already set on the system
            if (!environmentVariables.ContainsKey(binding.Name))
            {
                environmentVariables.Add(binding.Name, binding.Default);
            }

            string previousValue = environmentVariables[binding.Name];
            string separator     = (string.IsNullOrEmpty(binding.Separator) ? Path.PathSeparator.ToString(CultureInfo.InvariantCulture) : binding.Separator);

            environmentVariables[binding.Name] = binding.Mode switch
            {
                _ when string.IsNullOrEmpty(previousValue) => newValue,
                EnvironmentMode.Replace => newValue,
                EnvironmentMode.Prepend => newValue + separator + environmentVariables[binding.Name],
                EnvironmentMode.Append => environmentVariables[binding.Name] + separator + newValue,
                _ => throw new InvalidOperationException($"Unknown {nameof(EnvironmentBinding)} value: {binding.Mode}")
            };
        }
        /// <summary>
        /// Applies a <see cref="WorkingDir"/> change to the <see cref="ProcessStartInfo"/>.
        /// </summary>
        /// <param name="binding">The <see cref="WorkingDir"/> to apply.</param>
        /// <param name="implementation">The implementation to be made available via the <see cref="WorkingDir"/> change.</param>
        /// <param name="startInfo">The process launch environment to apply the <see cref="WorkingDir"/> change to.</param>
        /// <exception cref="ImplementationNotFoundException">The <paramref name="implementation"/> is not cached yet.</exception>
        /// <exception cref="ExecutorException">The <paramref name="binding"/> has an invalid path or another working directory has already been set.</exception>
        /// <remarks>This method can only be called successfully once per <see cref="BuildStartInfoWithBindings()"/>.</remarks>
        private void ApplyWorkingDir(WorkingDir binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            string source = FileUtils.UnifySlashes(binding.Source) ?? "";

            if (Path.IsPathRooted(source) || source.Contains(".." + Path.DirectorySeparatorChar))
            {
                throw new ExecutorException(Resources.WorkingDirInvalidPath);
            }

            // Only allow working directory to be changed once
            if (!string.IsNullOrEmpty(startInfo.WorkingDirectory))
            {
                throw new ExecutorException(Resources.Working);
            }

            startInfo.WorkingDirectory = Path.Combine(GetImplementationPath(implementation), source);
        }
Esempio n. 13
0
    public static Command?AddCommand(this ImplementationSelection selection, Requirements requirements, Implementation from)
    {
        #region Sanity checks
        if (selection == null)
        {
            throw new ArgumentNullException(nameof(selection));
        }
        if (requirements == null)
        {
            throw new ArgumentNullException(nameof(requirements));
        }
        if (from == null)
        {
            throw new ArgumentNullException(nameof(from));
        }
        #endregion

        Debug.Assert(requirements.Command != null);
        var command = from[requirements.Command];
        if (command == null)
        {
            return(null);
        }

        var newCommand = new Command {
            Name = command.Name, Path = command.Path
        };
        newCommand.Arguments.AddRange(command.Arguments.CloneElements());
        newCommand.Bindings.AddRange(command.Bindings.CloneElements());
        if (command.WorkingDir != null)
        {
            newCommand.WorkingDir = command.WorkingDir.Clone();
        }
        if (command.Runner != null)
        {
            newCommand.Runner = command.Runner.CloneRunner();
        }
        newCommand.AddDependencies(requirements, from: command);

        selection.Commands.Add(newCommand);
        return(newCommand);
    }
        /// <summary>
        /// Applies an <see cref="ExecutableInPath"/> binding by creating a run-environment executable.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <param name="startInfo">The process launch environment to use to make the run-environment executable available.</param>
        /// <exception cref="KeyNotFoundException"><see cref="Selections"/> points to missing <see cref="Dependency"/>s.</exception>
        /// <exception cref="ImplementationNotFoundException">One of the <see cref="Store.Model.Implementation"/>s is not cached yet.</exception>
        /// <exception cref="ExecutorException"><see cref="ExecutableInPath.Name"/> is invalid.</exception>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        private void ApplyExecutableInPath(ExecutableInPath binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name))
            {
                throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<executable-in-path>"));
            }
            if (Path.GetInvalidFileNameChars().Any(invalidChar => binding.Name.Contains(invalidChar.ToString(CultureInfo.InvariantCulture))))
            {
                throw new ExecutorException(string.Format(Resources.IllegalCharInBindingName, @"<executable-in-path>"));
            }

            string exePath = DeployRunEnvExecutable(binding.Name);

            // Add executable directory to PATH variable
            startInfo.EnvironmentVariables["PATH"] = Path.GetDirectoryName(exePath) + Path.PathSeparator + startInfo.EnvironmentVariables["PATH"];

            // Tell the executable what command-line to run
            _runEnvPendings.Add(new RunEnvPending(binding.Name, GetCommandLine(implementation, binding.Command ?? Command.NameRun, startInfo)));
        }
Esempio n. 15
0
    /// <summary>
    /// Generates <see cref="SolverDemand"/>s for the dependencies specified by an <see cref="ImplementationSelection"/>.
    /// </summary>
    /// <param name="selection">The selection to scan for dependencies.</param>
    /// <param name="requirements">Requirements to inherit into the demands.</param>
    protected IEnumerable <SolverDemand> DemandsFor(ImplementationSelection selection, Requirements requirements)
    {
        foreach (var demand in selection.Dependencies.SelectMany(DemandsFor))
        {
            yield return(demand);
        }

        foreach (var demands in DemandsFor(selection.Bindings, selection.InterfaceUri))
        {
            yield return(demands);
        }

        var command = selection[requirements.Command ?? Command.NameRun];

        if (command != null)
        {
            foreach (var demand in DemandsFor(command, requirements.InterfaceUri))
            {
                yield return(demand);
            }
        }
    }
        /// <summary>
        /// Applies all <see cref="Binding"/>s listed in a specific <see cref="IBindingContainer"/>.
        /// </summary>
        /// <param name="bindingContainer">The list of <see cref="Binding"/>s to be performed.</param>
        /// <param name="implementation">The implementation to be made available via the <see cref="Binding"/>s.</param>
        /// <exception cref="ImplementationNotFoundException">The <paramref name="implementation"/> is not cached yet.</exception>
        /// <exception cref="ExecutorException">A <see cref="Command"/> contained invalid data.</exception>
        /// <exception cref="IOException">A problem occurred while writing a file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to a file is not permitted.</exception>
        private void ApplyBindings(IBindingContainer bindingContainer, ImplementationSelection implementation)
        {
            // Do not apply bindings more than once
            if (!_appliedBindingContainers.Add(bindingContainer))
            {
                return;
            }

            if (bindingContainer.Bindings.Count == 0)
            {
                return;
            }

            // Don't use bindings for PackageImplementations
            if (implementation.ID.StartsWith(ExternalImplementation.PackagePrefix))
            {
                return;
            }

            foreach (var binding in bindingContainer.Bindings)
            {
                switch (binding)
                {
                case EnvironmentBinding environmentBinding:
                    ApplyEnvironmentBinding(environmentBinding, implementation);
                    break;

                //case OverlayBinding overlayBinding: ApplyOverlayBinding(overlayBinding, implementation); break;
                case ExecutableInVar executableInVar:
                    ApplyExecutableInVar(executableInVar, implementation);
                    break;

                case ExecutableInPath executableInPath:
                    ApplyExecutableInPath(executableInPath, implementation);
                    break;
                }
            }
        }
Esempio n. 17
0
        /// <inheritdoc/>
        public string GetImplementationPath(ImplementationSelection implementation)
        {
            #region Sanity checks
            if (implementation == null)
            {
                throw new ArgumentNullException(nameof(implementation));
            }
            #endregion

            if (string.IsNullOrEmpty(implementation.LocalPath))
            {
                string path = _store.GetPath(implementation.ManifestDigest);
                if (path == null)
                {
                    throw new ImplementationNotFoundException(implementation.ManifestDigest);
                }
                return(path);
            }
            else
            {
                return(implementation.LocalPath);
            }
        }
Esempio n. 18
0
 /// <summary>
 /// Always throws <see cref="ImplementationNotFoundException"/>.
 /// </summary>
 public ExternalImplementation Lookup(ImplementationSelection selection)
 {
     throw new ImplementationNotFoundException(Resources.NoPackageManagerSupport);
 }
 /// <inheritdoc/>
 public ExternalImplementation?Lookup(ImplementationSelection selection)
 => _packageManagers
 .Select(x => x.Lookup(selection))
 .WhereNotNull()
 .FirstOrDefault();
Esempio n. 20
0
            private bool TryToUseExistingCandidate([NotNull] Requirements requirements, [NotNull, ItemNotNull] IEnumerable <SelectionCandidate> suitableCandidates, [NotNull] ImplementationSelection selection)
            {
                if (!suitableCandidates.Contains(selection))
                {
                    return(false);
                }
                if (selection.ContainsCommand(requirements.Command))
                {
                    return(true);
                }

                var command = selection.AddCommand(requirements, from: _candidateProvider.LookupOriginalImplementation(selection));

                return(TryToSolveCommand(command, requirements));
            }
        /// <summary>
        /// Applies an <see cref="ExecutableInVar"/> binding by creating a run-environment executable.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <param name="startInfo">The process launch environment to use to make the run-environment executable available.</param>
        /// <exception cref="KeyNotFoundException"><see cref="Selections"/> points to missing <see cref="Dependency"/>s.</exception>
        /// <exception cref="ImplementationNotFoundException">One of the <see cref="Store.Model.Implementation"/>s is not cached yet.</exception>
        /// <exception cref="ExecutorException"><see cref="ExecutableInVar.Name"/> is invalid.</exception>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        private void ApplyExecutableInVar(ExecutableInVar binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name)) throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<executable-in-var>"));
            if (Path.GetInvalidFileNameChars().Any(invalidChar => binding.Name.Contains(invalidChar.ToString(CultureInfo.InvariantCulture))))
                throw new ExecutorException(string.Format(Resources.IllegalCharInBindingName, @"<executable-in-var>"));

            string exePath = DeployRunEnvExecutable(binding.Name);

            // Point variable directly to executable
            if (startInfo.EnvironmentVariables.ContainsKey(binding.Name)) Log.Warn("Overwriting existing environment variable with <executable-in-var>: " + binding.Name);
            startInfo.EnvironmentVariables[binding.Name] = exePath;

            // Tell the executable what command-line to run
            _runEnvPendings.Add(new RunEnvPending(binding.Name, GetCommandLine(implementation, binding.Command ?? Command.NameRun, startInfo)));
        }
Esempio n. 22
0
        public static bool Contains([NotNull] this IEnumerable <SelectionCandidate> candidates, [NotNull] ImplementationSelection implementation)
        {
            #region Sanity checks
            if (candidates == null)
            {
                throw new ArgumentNullException("candidates");
            }
            if (implementation == null)
            {
                throw new ArgumentNullException("implementation");
            }
            #endregion

            return(candidates.Select(x => x.Implementation.ID).Contains(implementation.ID));
        }
        /// <summary>
        /// Applies an <see cref="EnvironmentBinding"/> by modifying environment variables.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <param name="startInfo">The process launch environment to apply the binding to.</param>
        /// <exception cref="ExecutorException"><see cref="EnvironmentBinding.Name"/> or other data is invalid.</exception>
        private void ApplyEnvironmentBinding(EnvironmentBinding binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name)) throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<environment>"));

            var environmentVariables = startInfo.EnvironmentVariables;

            string newValue;
            if (binding.Value != null && binding.Insert != null)
            { // Conflict
                throw new ExecutorException(Resources.EnvironmentBindingValueInvalid);
            }
            else if (binding.Value != null)
            { // Static value
                newValue = binding.Value;
            }
            else
            { // Path inside the implementation
                newValue = Path.Combine(GetImplementationPath(implementation), FileUtils.UnifySlashes(binding.Insert ?? ""));
            }

            // Set the default value if the variable is not already set on the system
            if (!environmentVariables.ContainsKey(binding.Name)) environmentVariables.Add(binding.Name, binding.Default);

            string previousValue = environmentVariables[binding.Name];
            string separator = (string.IsNullOrEmpty(binding.Separator) ? Path.PathSeparator.ToString(CultureInfo.InvariantCulture) : binding.Separator);

            switch (binding.Mode)
            {
                default:
                case EnvironmentMode.Prepend:
                    environmentVariables[binding.Name] = string.IsNullOrEmpty(previousValue)
                        // No exisiting value, just set new one
                        ? newValue
                        // Prepend new value to existing one seperated by path separator
                        : newValue + separator + environmentVariables[binding.Name];
                    break;

                case EnvironmentMode.Append:
                    environmentVariables[binding.Name] = string.IsNullOrEmpty(previousValue)
                        // No exisiting value, just set new one
                        ? newValue
                        // Append new value to existing one seperated by path separator
                        : environmentVariables[binding.Name] + separator + newValue;
                    break;

                case EnvironmentMode.Replace:
                    // Overwrite any existing value
                    environmentVariables[binding.Name] = newValue;
                    break;
            }
        }
        /// <summary>
        /// Applies an <see cref="ExecutableInPath"/> binding by creating a run-environment executable.
        /// </summary>
        /// <param name="binding">The binding to apply.</param>
        /// <param name="implementation">The implementation to be made available.</param>
        /// <param name="startInfo">The process launch environment to use to make the run-environment executable available.</param>
        /// <exception cref="KeyNotFoundException"><see cref="Selections"/> points to missing <see cref="Dependency"/>s.</exception>
        /// <exception cref="ImplementationNotFoundException">One of the <see cref="Store.Model.Implementation"/>s is not cached yet.</exception>
        /// <exception cref="ExecutorException"><see cref="ExecutableInPath.Name"/> is invalid.</exception>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        private void ApplyExecutableInPath(ExecutableInPath binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            if (string.IsNullOrEmpty(binding.Name)) throw new ExecutorException(string.Format(Resources.MissingBindingName, @"<executable-in-path>"));
            if (Path.GetInvalidFileNameChars().Any(invalidChar => binding.Name.Contains(invalidChar.ToString(CultureInfo.InvariantCulture))))
                throw new ExecutorException(string.Format(Resources.IllegalCharInBindingName, @"<executable-in-path>"));

            string exePath = DeployRunEnvExecutable(binding.Name);

            // Add executable directory to PATH variable
            startInfo.EnvironmentVariables["PATH"] = Path.GetDirectoryName(exePath) + Path.PathSeparator + startInfo.EnvironmentVariables["PATH"];

            // Tell the executable what command-line to run
            _runEnvPendings.Add(new RunEnvPending(binding.Name, GetCommandLine(implementation, binding.Command ?? Command.NameRun, startInfo)));
        }
        /// <summary>
        /// Determines the command-line needed to execute an <see cref="ImplementationSelection"/>. Recursivley handles <see cref="Runner"/>s.
        /// </summary>
        /// <param name="implementation">The implementation to launch.</param>
        /// <param name="commandName">The name of the <see cref="Command"/> within the <paramref name="implementation"/> to launch.</param>
        /// <param name="startInfo">The process launch environment to apply additional <see cref="Binding"/> to.</param>
        /// <exception cref="KeyNotFoundException"><see cref="Selections"/> points to missing <see cref="Dependency"/>s.</exception>
        /// <exception cref="ImplementationNotFoundException">An <see cref="Implementation"/> is not cached yet.</exception>
        /// <exception cref="ExecutorException">A <see cref="Command"/> contained invalid data.</exception>
        /// <exception cref="IOException">A problem occurred while writing a file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to a file is not permitted.</exception>
        private List<ArgBase> GetCommandLine(ImplementationSelection implementation, string commandName, ProcessStartInfo startInfo)
        {
            #region Sanity checks
            if (implementation == null) throw new ArgumentNullException("implementation");
            if (startInfo == null) throw new ArgumentNullException("startInfo");
            #endregion

            if (string.IsNullOrEmpty(commandName)) throw new ExecutorException(string.Format(Resources.CommandNotSpecified, implementation.InterfaceUri));
            Command command = implementation[commandName];

            // Apply bindings implementations use to find themselves and their dependencies
            ApplyBindings(command, implementation, startInfo);
            if (command.WorkingDir != null) ApplyWorkingDir(command.WorkingDir, implementation, startInfo);
            ApplyDependencyBindings(command, startInfo);

            List<ArgBase> commandLine;
            var runner = command.Runner;
            if (runner == null) commandLine = new List<ArgBase>();
            else
            {
                commandLine = GetCommandLine(Selections[runner.InterfaceUri], runner.Command ?? Command.NameRun, startInfo);
                commandLine.AddRange(runner.Arguments);
            }

            if (!string.IsNullOrEmpty(command.Path))
            {
                string path = FileUtils.UnifySlashes(command.Path);

                // Fully qualified paths are used by package/native implementations, usually relative to the implementation
                commandLine.Add(Path.IsPathRooted(path) ? path : Path.Combine(GetImplementationPath(implementation), path));
            }
            commandLine.AddRange(command.Arguments);

            return commandLine;
        }
Esempio n. 26
0
 /// <summary>
 /// Always throws <see cref="ImplementationNotFoundException"/>.
 /// </summary>
 public ExternalImplementation Lookup(ImplementationSelection selection)
 {
     throw new ImplementationNotFoundException(Resources.NoPackageManagerSupport);
 }
Esempio n. 27
0
        public static ImplementationSelection ToSelection([NotNull] this SelectionCandidate candidate, [NotNull, ItemNotNull] IEnumerable<SelectionCandidate> allCandidates, [NotNull] Requirements requirements)
        {
            #region Sanity checks
            if (candidate == null) throw new ArgumentNullException("candidate");
            if (allCandidates == null) throw new ArgumentNullException("allCandidates");
            if (requirements == null) throw new ArgumentNullException("requirements");
            #endregion

            var implementation = candidate.Implementation;
            var selection = new ImplementationSelection(allCandidates)
            {
                ID = implementation.ID,
                LocalPath = implementation.LocalPath,
                ManifestDigest = implementation.ManifestDigest,
                Architecture = implementation.Architecture,
                Version = implementation.Version,
                Released = implementation.Released,
                Stability = candidate.EffectiveStability,
                License = implementation.License,
                InterfaceUri = requirements.InterfaceUri
            };
            if (candidate.FeedUri != requirements.InterfaceUri) selection.FromFeed = candidate.FeedUri;

            var externalImplementation = implementation as ExternalImplementation;
            if (externalImplementation != null) selection.QuickTestFile = externalImplementation.QuickTestFile;

            selection.Bindings.AddRange(implementation.Bindings.CloneElements());
            selection.AddDependencies(requirements, from: candidate.Implementation);
            selection.AddCommand(requirements, from: candidate.Implementation);

            return selection;
        }
 private static string GetPath([NotNull] this ImplementationSelection implementation, [NotNull] IStore store)
 {
     return(implementation.ID.StartsWith(ExternalImplementation.PackagePrefix)
         ? "(" + implementation.ID + ")"
         : store.GetPath(implementation.ManifestDigest));
 }
        /// <summary>
        /// Retrieves the original <see cref="Implementation"/> an <see cref="ImplementationSelection"/> was based ofF.
        /// </summary>
        public Implementation LookupOriginalImplementation(ImplementationSelection implemenationSelection)
        {
            #region Sanity checks
            if (implemenationSelection == null) throw new ArgumentNullException("implemenationSelection");
            #endregion

            return implemenationSelection.ID.StartsWith(ExternalImplementation.PackagePrefix)
                ? _externalImplementations[implemenationSelection.ID]
                : _feeds[implemenationSelection.FromFeed ?? implemenationSelection.InterfaceUri][implemenationSelection.ID];
        }
Esempio n. 30
0
        /// <inheritdoc/>
        public string GetImplementationPath(ImplementationSelection implementation)
        {
            #region Sanity checks
            if (implementation == null) throw new ArgumentNullException(nameof(implementation));
            #endregion

            if (string.IsNullOrEmpty(implementation.LocalPath))
            {
                string path = _store.GetPath(implementation.ManifestDigest);
                if (path == null) throw new ImplementationNotFoundException(implementation.ManifestDigest);
                return path;
            }
            else return implementation.LocalPath;
        }
        /// <summary>
        /// Applies a <see cref="WorkingDir"/> change to the <see cref="ProcessStartInfo"/>.
        /// </summary>
        /// <param name="binding">The <see cref="WorkingDir"/> to apply.</param>
        /// <param name="implementation">The implementation to be made available via the <see cref="WorkingDir"/> change.</param>
        /// <param name="startInfo">The process launch environment to apply the <see cref="WorkingDir"/> change to.</param>
        /// <exception cref="ImplementationNotFoundException">The <paramref name="implementation"/> is not cached yet.</exception>
        /// <exception cref="ExecutorException">The <paramref name="binding"/> has an invalid path or another working directory has already been set.</exception>
        /// <remarks>This method can only be called successfully once per <see cref="BuildStartInfoWithBindings()"/>.</remarks>
        private void ApplyWorkingDir(WorkingDir binding, ImplementationSelection implementation, ProcessStartInfo startInfo)
        {
            Log.Debug("Applying " + binding + " for " + implementation);

            string source = FileUtils.UnifySlashes(binding.Source) ?? "";
            if (Path.IsPathRooted(source) || source.Contains(".." + Path.DirectorySeparatorChar)) throw new ExecutorException(Resources.WorkingDirInvalidPath);

            // Only allow working directory to be changed once
            if (!string.IsNullOrEmpty(startInfo.WorkingDirectory)) throw new ExecutorException(Resources.Working);

            startInfo.WorkingDirectory = Path.Combine(GetImplementationPath(implementation), source);
        }