private bool FeatureIsEnabled(FeatureDescriptor fd)
 {
     return (DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType) && (fd.Id == "TheAdmin" || fd.Id == "SafeMode")) ||
         _shellDescriptor.Features.Any(sf => sf.Name == fd.Id);
 }
 public void ExtensionManagerShouldReturnEmptyFeatureIfFeatureDoesNotExist()
 {
     var featureDescriptor = new FeatureDescriptor { Id = "NoSuchFeature", Extension = new ExtensionDescriptor { Id = "NoSuchFeature" } };
     Feature feature = _manager.LoadFeatures(new[] { featureDescriptor }).First();
     Assert.AreEqual(featureDescriptor, feature.Descriptor);
     Assert.AreEqual(0, feature.ExportedTypes.Count());
 }
        private void ProcessPlacementFile(ShapeTableBuilder builder, FeatureDescriptor featureDescriptor, PlacementFile placementFile)
        {
            var feature = new Feature { Descriptor = featureDescriptor };

            // invert the tree into a list of leaves and the stack
            var entries = DrillDownShapeLocations(placementFile.Nodes, Enumerable.Empty<PlacementMatch>());
            foreach (var entry in entries) {
                var shapeLocation = entry.Item1;
                var matches = entry.Item2;

                string shapeType;
                string differentiator;
                GetShapeType(shapeLocation, out shapeType, out differentiator);

                Func<ShapePlacementContext, bool> predicate = ctx => true;
                if (differentiator != "") {
                    predicate = ctx => (ctx.Differentiator ?? "") == differentiator;
                }

                if (matches.Any()) {
                    predicate =  matches.SelectMany(match => match.Terms).Aggregate(predicate, BuildPredicate);
                }

                var placement = new PlacementInfo();

                var segments = shapeLocation.Location.Split(';').Select(s => s.Trim());
                foreach (var segment in segments) {
                    if (!segment.Contains('=')) {
                        placement.Location = segment;
                    }
                    else {
                        var index = segment.IndexOf('=');
                        var property = segment.Substring(0, index).ToLower();
                        var value = segment.Substring(index + 1);
                        switch (property) {
                            case "shape":
                                placement.ShapeType = value;
                                break;
                            case "alternate":
                                placement.Alternates = new[] { value };
                                break;
                            case "wrapper":
                                placement.Wrappers = new[] { value };
                                break;
                        }
                    }
                }

                builder.Describe(shapeType)
                    .From(feature)
                    .Placement(ctx => {
                                   var hit = predicate(ctx);
                                   // generate 'debugging' information to trace which file originated the actual location
                                    if (hit) {
                                       var virtualPath = featureDescriptor.Extension.Location + "/" + featureDescriptor.Extension.Id + "/Placement.info";
                                       ctx.Source = virtualPath;
                                   }
                                   return hit;
                               }, placement);
            }
        }
 private Feature FrameworkFeature(FeatureDescriptor descriptor)
 {
     return new Feature {
         Descriptor = descriptor,
         ExportedTypes = new[] {
             typeof (TestDependency),
             typeof (TestSingletonDependency),
             typeof (TestTransientDependency),
         }
     };
 }
 private bool FeatureIsTheme(FeatureDescriptor fd)
 {
     return DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType);
 }
 private void ProcessFeatureDescriptor(ShapeTableBuilder builder, FeatureDescriptor featureDescriptor)
 {
     var virtualPath = featureDescriptor.Extension.Location + "/" + featureDescriptor.Extension.Id + "/Placement.info";
     var placementFile = _placementFileParser.Parse(virtualPath);
     if (placementFile != null) {
         ProcessPlacementFile(builder, featureDescriptor, placementFile);
     }
 }
 static Feature Feature(FeatureDescriptor descriptor)
 {
     return new Feature {
         Descriptor = descriptor
     };
 }
 private bool FeatureIsEnabled(FeatureDescriptor fd)
 {
     return _shellDescriptor.Features.Any(sf => sf.Name == fd.Id);
 }
        void IShellStateManagerEventHandler.ApplyChanges()
        {
            Logger.Information("Applying changes for for shell '{0}'", _settings.Name);

            var shellState = _stateManager.GetShellState();

            // start with description of all declared features in order - order preserved with all merging
            var orderedFeatureDescriptors = _extensionManager.AvailableFeatures();

            // merge feature state into ordered list
            var orderedFeatureDescriptorsAndStates = orderedFeatureDescriptors
                .Select(featureDescriptor => new {
                    FeatureDescriptor = featureDescriptor,
                    FeatureState = shellState.Features.FirstOrDefault(s => s.Name == featureDescriptor.Id),
                })
                .Where(entry => entry.FeatureState != null)
                .ToArray();

            // get loaded feature information
            var loadedFeatures = _extensionManager.LoadFeatures(orderedFeatureDescriptorsAndStates.Select(entry => entry.FeatureDescriptor)).ToArray();

            // merge loaded feature information into ordered list
            var loadedEntries = orderedFeatureDescriptorsAndStates.Select(
                entry => new {
                    Feature = loadedFeatures.SingleOrDefault(f => f.Descriptor == entry.FeatureDescriptor)
                              ?? new Feature {
                                  Descriptor = entry.FeatureDescriptor,
                                  ExportedTypes = Enumerable.Empty<Type>()
                              },
                    entry.FeatureDescriptor,
                    entry.FeatureState,
                }).ToList();

            // find feature state that is beyond what's currently available from modules
            var additionalState = shellState.Features.Except(loadedEntries.Select(entry => entry.FeatureState));

            // create additional stub entries for the sake of firing state change events on missing features
            var allEntries = loadedEntries.Concat(additionalState.Select(featureState => {
                var featureDescriptor = new FeatureDescriptor {
                    Id = featureState.Name,
                    Extension = new ExtensionDescriptor {
                        Id = featureState.Name
                    }
                };
                return new {
                    Feature = new Feature {
                        Descriptor = featureDescriptor,
                        ExportedTypes = Enumerable.Empty<Type>(),
                    },
                    FeatureDescriptor = featureDescriptor,
                    FeatureState = featureState
                };
            })).ToArray();

            // lower enabled states in reverse order
            foreach (var entry in allEntries.Reverse().Where(entry => entry.FeatureState.EnableState == ShellFeatureState.State.Falling)) {
                Logger.Information("Disabling feature '{0}'", entry.Feature.Descriptor.Id);
                _featureEvents.Disabling(entry.Feature);
                _stateManager.UpdateEnabledState(entry.FeatureState, ShellFeatureState.State.Down);
                _featureEvents.Disabled(entry.Feature);
            }

            // lower installed states in reverse order
            foreach (var entry in allEntries.Reverse().Where(entry => entry.FeatureState.InstallState == ShellFeatureState.State.Falling)) {
                Logger.Information("Uninstalling feature '{0}'", entry.Feature.Descriptor.Id);
                _featureEvents.Uninstalling(entry.Feature);
                _stateManager.UpdateInstalledState(entry.FeatureState, ShellFeatureState.State.Down);
                _featureEvents.Uninstalled(entry.Feature);
            }

            // raise install and enabled states in order
            foreach (var entry in allEntries.Where(entry => IsRising(entry.FeatureState))) {
                if (entry.FeatureState.InstallState == ShellFeatureState.State.Rising) {
                    Logger.Information("Installing feature '{0}'", entry.Feature.Descriptor.Id);
                    _featureEvents.Installing(entry.Feature);
                    _stateManager.UpdateInstalledState(entry.FeatureState, ShellFeatureState.State.Up);
                    _featureEvents.Installed(entry.Feature);
                }
                if (entry.FeatureState.EnableState == ShellFeatureState.State.Rising) {
                    Logger.Information("Enabling feature '{0}'", entry.Feature.Descriptor.Id);
                    _featureEvents.Enabling(entry.Feature);
                    _stateManager.UpdateEnabledState(entry.FeatureState, ShellFeatureState.State.Up);
                    _featureEvents.Enabled(entry.Feature);
                }
            }

            // re-fire if any event handlers initiated additional state changes
            FireApplyChangesIfNeeded();
        }
        private Feature LoadFeature(FeatureDescriptor featureDescriptor)
        {
            var extensionDescriptor = featureDescriptor.Extension;
            var featureId = featureDescriptor.Id;
            var extensionId = extensionDescriptor.Id;

            ExtensionEntry extensionEntry;
            try {
                extensionEntry = _cacheManager.Get(extensionId, ctx => {
                    var entry = BuildEntry(extensionDescriptor);
                    if (entry != null) {
                        ctx.Monitor(_asyncTokenProvider.GetToken(monitor => {
                            foreach (var loader in _loaders) {
                                loader.Monitor(entry.Descriptor, token => monitor(token));
                            }
                        }));
                    }
                    return entry;
                });
            }
            catch (Exception ex) {
                Logger.Error(ex, "Error loading extension '{0}'", extensionId);
                throw new CoeveryException(T("Error while loading extension '{0}'.", extensionId), ex);
            }

            if (extensionEntry == null) {
                // If the feature could not be compiled for some reason,
                // return a "null" feature, i.e. a feature with no exported types.
                return new Feature {
                    Descriptor = featureDescriptor,
                    ExportedTypes = Enumerable.Empty<Type>()
                };
            }

            var extensionTypes = extensionEntry.ExportedTypes.Where(t => t.IsClass && !t.IsAbstract);
            var featureTypes = new List<Type>();

            foreach (var type in extensionTypes) {
                string sourceFeature = GetSourceFeatureNameForType(type, extensionId);
                if (String.Equals(sourceFeature, featureId, StringComparison.OrdinalIgnoreCase)) {
                    featureTypes.Add(type);
                }
            }

            return new Feature {
                Descriptor = featureDescriptor,
                ExportedTypes = featureTypes
            };
        }
        /// <summary>
        /// Returns true if the item has an explicit or implicit dependency on the subject
        /// </summary>
        /// <param name="item"></param>
        /// <param name="subject"></param>
        /// <returns></returns>
        internal static bool HasDependency(FeatureDescriptor item, FeatureDescriptor subject)
        {
            if (DefaultExtensionTypes.IsTheme(item.Extension.ExtensionType)) {
                if (DefaultExtensionTypes.IsModule(subject.Extension.ExtensionType)) {
                    // Themes implicitly depend on modules to ensure build and override ordering
                    return true;
                }

                if (DefaultExtensionTypes.IsTheme(subject.Extension.ExtensionType)) {
                    // Theme depends on another if it is its base theme
                    return item.Extension.BaseTheme == subject.Id;
                }
            }

            // Return based on explicit dependencies
            return item.Dependencies != null &&
                   item.Dependencies.Any(x => StringComparer.OrdinalIgnoreCase.Equals(x, subject.Id));
        }
 internal static int GetPriority(FeatureDescriptor featureDescriptor)
 {
     return featureDescriptor.Priority;
 }
        private static IEnumerable<FeatureDescriptor> GetFeaturesForExtension(IDictionary<string, string> manifest, ExtensionDescriptor extensionDescriptor)
        {
            var featureDescriptors = new List<FeatureDescriptor>();

            // Default feature
            FeatureDescriptor defaultFeature = new FeatureDescriptor {
                Id = extensionDescriptor.Id,
                Name = GetValue(manifest, FeatureNameSection) ?? extensionDescriptor.Name,
                Priority = GetValue(manifest, PrioritySection) != null ? int.Parse(GetValue(manifest, PrioritySection)) : 0,
                Description = GetValue(manifest, FeatureDescriptionSection) ?? GetValue(manifest, DescriptionSection) ?? string.Empty,
                Dependencies = ParseFeatureDependenciesEntry(GetValue(manifest, DependenciesSection)),
                Extension = extensionDescriptor,
                Category = GetValue(manifest, CategorySection)
            };

            featureDescriptors.Add(defaultFeature);

            // Remaining features
            string featuresText = GetValue(manifest, FeaturesSection);
            if (featuresText != null) {
                FeatureDescriptor featureDescriptor = null;
                using (StringReader reader = new StringReader(featuresText)) {
                    string line;
                    while ((line = reader.ReadLine()) != null) {
                        if (IsFeatureDeclaration(line)) {
                            if (featureDescriptor != null) {
                                if (!featureDescriptor.Equals(defaultFeature)) {
                                    featureDescriptors.Add(featureDescriptor);
                                }

                                featureDescriptor = null;
                            }

                            string[] featureDeclaration = line.Split(new[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
                            string featureDescriptorId = featureDeclaration[0].Trim();
                            if (String.Equals(featureDescriptorId, extensionDescriptor.Id, StringComparison.OrdinalIgnoreCase)) {
                                featureDescriptor = defaultFeature;
                                featureDescriptor.Name = extensionDescriptor.Name;
                            }
                            else {
                                featureDescriptor = new FeatureDescriptor {
                                    Id = featureDescriptorId,
                                    Extension = extensionDescriptor
                                };
                            }
                        }
                        else if (IsFeatureFieldDeclaration(line)) {
                            if (featureDescriptor != null) {
                                string[] featureField = line.Split(new[] { ":" }, 2, StringSplitOptions.None);
                                int featureFieldLength = featureField.Length;
                                if (featureFieldLength != 2)
                                    continue;
                                for (int i = 0; i < featureFieldLength; i++) {
                                    featureField[i] = featureField[i].Trim();
                                }

                                switch (featureField[0].ToLowerInvariant()) {
                                    case NameSection:
                                        featureDescriptor.Name = featureField[1];
                                        break;
                                    case DescriptionSection:
                                        featureDescriptor.Description = featureField[1];
                                        break;
                                    case CategorySection:
                                        featureDescriptor.Category = featureField[1];
                                        break;
                                    case PrioritySection:
                                        featureDescriptor.Priority = int.Parse(featureField[1]);
                                        break;
                                    case DependenciesSection:
                                        featureDescriptor.Dependencies = ParseFeatureDependenciesEntry(featureField[1]);
                                        break;
                                }
                            }
                            else {
                                string message = string.Format("The line {0} in manifest for extension {1} was ignored", line, extensionDescriptor.Id);
                                throw new ArgumentException(message);
                            }
                        }
                        else {
                            string message = string.Format("The line {0} in manifest for extension {1} was ignored", line, extensionDescriptor.Id);
                            throw new ArgumentException(message);
                        }
                    }

                    if (featureDescriptor != null && !featureDescriptor.Equals(defaultFeature))
                        featureDescriptors.Add(featureDescriptor);
                }
            }

            return featureDescriptors;
        }