public override Entity Resolve(Entity owner, string key, bool fallback = false) { VirtualFile file = owner.Value <VirtualFile>(); if (file != null) { if (key == EntityKeys.PathKey) { return(owner.Create(key, file.Parent.FullName)); } if (file.HasPropertyValueEntity(MapFileAccessKey(key))) { return(owner.PropertyValueEntity(MapFileAccessKey(key), file, key)); } } VirtualDirectory directory = owner.Value <VirtualDirectory>(); if (directory != null) { if (key == EntityKeys.PathKey) { return(owner.Create(key, directory.FullName)); } if (directory.HasPropertyValueEntity(MapFileAccessKey(key))) { return(owner.PropertyValueEntity(MapFileAccessKey(key), directory, key)); } } switch (key) { case EntityKeys.NewlineKey: return(owner.Create(key, Environment.NewLine)); case EntityKeys.ActiveDirectoryKey: return(owner.Create(key, fileSystem.CurrentDirectory.FullName)); case EntityKeys.IsRootedKey: bool isRooted = fileSystem.IsRooted(owner.Value <string>()); return(owner.Create(key, isRooted.ToString(CultureInfo.InvariantCulture), isRooted)); case EntityKeys.InternalDirectoryKey: string path = owner.HasValue <string>() && fileSystem.DirectoryExists(owner.Value <string>()) ? owner.Value <string>() : owner.Path; return(owner.Create(key, fileSystem.GetDirectory(path, createNew: false))); case EntityKeys.InternalTempDirectoryKey: return(owner.Create(key, TempDirectory)); case EntityKeys.ChunkStartKey: return(owner.Create(key, owner.Value <DataChunk>().Start)); case EntityKeys.ChunkEndKey: return(owner.Create(key, owner.Value <DataChunk>().End)); case EntityKeys.CountKey: return(owner.Create(key, owner.Count.ToString(CultureInfo.InvariantCulture), owner.Count)); default: throw new ContentProviderException(key, owner); } }
public async Task <IEnumerable <VirtualFile> > InitalizeTemplate(Entity dataModel, ChangeObservable observable) { bool forced = dataModel.Value <CommandDefinition>() .Argument <BoolArgument>(TemplateCommandBuilder.ForcedArgumentName) .Value; TemplateDescription template = dataModel.Template(); List <VirtualFile> generatedFiles = new List <VirtualFile>(await InitializeFiles().ConfigureAwait(false)); generatedFiles.AddRange(await InitializeSubTemplates().ConfigureAwait(false)); Exception e = dataModel.GetCodeExceptions(); if (e != null) { e.CompleteCodeExceptions(fileSystem.GetDirectory(dataModel.Root.Path)); throw e; } return(generatedFiles); async Task <IEnumerable <VirtualFile> > InitializeFiles() { string basePath = dataModel.Root.Path; HashSet <VirtualFile> files = new HashSet <VirtualFile>(); foreach (templateFile file in template.File) { (string content, Encoding encoding) = await GetResolvedTemplateContent(dataModel, file, template).ConfigureAwait(false); VirtualFile destination = await GetFile(dataModel, file, forced, basePath, template).ConfigureAwait(false); observable.OnNext(new Change(() => destination.Restore(), $"Create file {Path.GetFileName(destination.Name)} for template " + $"{template.name} in {destination.Parent.FullName}.")); using (Stream fileStream = destination.OpenWrite()) using (StreamWriter writer = new StreamWriter(fileStream, encoding)) { fileStream.SetLength(0); await writer.WriteAsync(content).ConfigureAwait(false); } files.Add(destination); } return(files); } async Task <IEnumerable <VirtualFile> > InitializeSubTemplates() { List <VirtualFile> files = new List <VirtualFile>(); foreach (templateReference reference in SortByRelationship(template.AddTemplate ?? Enumerable.Empty <templateReference>())) { if (repository.Template(reference.template) == null) { throw new TemplateReferenceNotDefinedException(reference.template); } CommandDefinitionBuilder pseudoDefinition = CommandDefinitionBuilder.Create() .SetName(reference.template); foreach (templateArgumentInstance argumentInstance in reference.Arguments) { AddArgument(argumentInstance, pseudoDefinition); } IEnumerable <IGrouping <string, templateRelationshipInstance> > grouped = (reference.Relationship ?? Enumerable.Empty <templateRelationshipInstance>()).GroupBy(r => r.name); foreach (IGrouping <string, templateRelationshipInstance> relationshipInstances in grouped) { AddRelationships(relationshipInstances, pseudoDefinition, reference); } pseudoDefinition.CreateArgument() .SetName(TemplateCommandBuilder.ForcedArgumentName) .SetValue(forced) .Build(); Entity referencedTemplateEntity = dataModel.Create(reference.template, pseudoDefinition.Build()); dataModel.AddEntity(referencedTemplateEntity); files.AddRange(await InitalizeTemplate(referencedTemplateEntity, observable).ConfigureAwait(false)); } return(files); void AddArgument(templateArgumentInstance templateArgumentInstance, CommandDefinitionBuilder commandDefinitionBuilder) { string templateArgumentValue = resolver.Resolve(templateArgumentInstance.value, dataModel); bool argumentHasNoValue = bool.TryParse(templateArgumentValue, out bool boolValue); string[] argumentSplit = templateArgumentValue.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); bool isMultiArgument = argumentSplit.Length > 1; if (argumentHasNoValue) { commandDefinitionBuilder.CreateArgument() .SetName(templateArgumentInstance.name) .SetValue(boolValue) .Build(); } else if (isMultiArgument) { commandDefinitionBuilder.CreateArgument() .SetName(templateArgumentInstance.name) .SetValue(argumentSplit) .Build(); } else { commandDefinitionBuilder.CreateArgument() .SetName(templateArgumentInstance.name) .SetValue(templateArgumentValue) .Build(); } } void AddRelationships(IGrouping <string, templateRelationshipInstance> relationshipInstances, CommandDefinitionBuilder commandDefinitionBuilder, templateReference reference) { templateRelationship relationshipDefinition = repository.Template(reference.template).Relationship ?.FirstOrDefault(r => r.name == relationshipInstances.Key); if (relationshipDefinition == null) { throw new TemplateRelationshipNotFoundException(reference.template, relationshipInstances.Key); } bool multipleValues = relationshipDefinition.multiplicity == multiplicity.OneOrMore; if (multipleValues) { string[] relationships = relationshipInstances.Select(r => resolver.Resolve(r.value, dataModel)) .ToArray(); commandDefinitionBuilder.CreateArgument() .SetName(relationshipInstances.Key) .SetValue(relationships) .Build(); } else { if (relationshipInstances.Count() != 1) { throw new RelationshipMultiplicityMismatchException(relationshipInstances.Key, reference.template); } commandDefinitionBuilder.CreateArgument() .SetName(relationshipInstances.Key) .SetValue(resolver.Resolve(relationshipInstances.Single().value, dataModel)) .Build(); } } IEnumerable <templateReference> SortByRelationship(IEnumerable <templateReference> references) { List <templateReference> unsorted = references.ToList(); List <templateReference> sorted = new List <templateReference>(); while (unsorted.Any()) { Insert(unsorted[0]); } return(sorted); void Insert(templateReference current, CycleChecker <templateReference> cycleChecker = null) { using (cycleChecker = cycleChecker?.SpawnChild() ?? new CycleChecker <templateReference>( ExceptionTexts.TemplateRelationshipCycle, () => cycleChecker = null)) { cycleChecker.AddItem(current); List <templateReference> dependent = new List <templateReference>(); foreach (templateRelationshipInstance relationshipInstance in current.Relationship ?? Enumerable .Empty < templateRelationshipInstance >()) { templateReference reference = unsorted.FirstOrDefault(r => HasRelationship(r, relationshipInstance)); if (reference != null) { Insert(reference, cycleChecker); } else { reference = sorted.FirstOrDefault(r => HasRelationship(r, relationshipInstance)); } if (reference != null) { dependent.Add(reference); } } int skipping = dependent.Any() ? dependent.Select(d => sorted.IndexOf(d)).Max() : -1; int index = skipping + 1; sorted.Insert(index, current); unsorted.Remove(current); bool HasRelationship(templateReference currentReference, templateRelationshipInstance relationshipInstance) { templateArgumentInstance instance = currentReference.Arguments .FirstOrDefault(a => a.name .Equals( EntityKeys .NameKey, StringComparison .OrdinalIgnoreCase)); return(instance?.value?.Equals(relationshipInstance.value, StringComparison.OrdinalIgnoreCase) == true); } } } } } }
public override Entity Resolve(Entity owner, string key, bool fallback = false) { VirtualFile file = owner.Value <VirtualFile>(); if (file != null) { if (key == EntityKeys.PathKey) { return(owner.Create(key, file.Parent.FullName)); } if (file.HasPropertyValueEntity(MapFileAccessKey(key))) { return(owner.PropertyValueEntity(MapFileAccessKey(key), file, key)); } } VirtualDirectory directory = owner.Value <VirtualDirectory>(); if (directory != null) { if (key == EntityKeys.PathKey) { return(owner.Create(key, directory.FullName)); } if (directory.HasPropertyValueEntity(MapFileAccessKey(key))) { return(owner.PropertyValueEntity(MapFileAccessKey(key), directory, key)); } } switch (key) { case EntityKeys.NewlineKey: return(owner.Create(key, Environment.NewLine)); case EntityKeys.ActiveDirectoryKey: return(owner.Create(key, fileSystem.CurrentDirectory.FullName)); case EntityKeys.IsRootedKey: bool isRooted = fileSystem.IsRooted(owner.Value <string>()); return(owner.Create(key, isRooted.ToString(CultureInfo.InvariantCulture), isRooted)); case EntityKeys.InternalDirectoryKey: string path = owner.HasValue <string>() && fileSystem.DirectoryExists(owner.Value <string>()) ? owner.Value <string>() : owner.Path; return(owner.Create(key, fileSystem.GetDirectory(path, createNew: false))); case EntityKeys.InternalTempDirectoryKey: return(owner.Create(key, TempDirectory)); case EntityKeys.ChunkStartKey: return(owner.Create(key, owner.Value <DataChunk>().Start)); case EntityKeys.ChunkEndKey: return(owner.Create(key, owner.Value <DataChunk>().End)); case EntityKeys.CountKey: return(owner.Create(key, owner.Count.ToString(CultureInfo.InvariantCulture), owner.Count)); case EntityKeys.IncrementKey: return(IncrementValue()); case EntityKeys.DecrementKey: return(DecrementValue()); case EntityKeys.NegateKey: if (bool.TryParse(owner.Value <string>(), out bool value)) { return(owner.Create(key, (!value).ToString(CultureInfo.InvariantCulture), !value)); } throw new ContentProviderException(key, owner); case EntityKeys.OriginKey: return(owner.Origin); case EntityKeys.ThrowIfMultidimensionalKey: if (owner.Value <string>()?.Contains(",") == true) { throw new MultidimensionalArrayNotSupportedException(); } return(owner); default: throw new ContentProviderException(key, owner); Entity IncrementValue() { string number = owner.Value <string>(); if (number != null) { if (int.TryParse(number, out int result)) { result++; return(owner.Create(key, result.ToString(CultureInfo.InvariantCulture), result)); } } return(owner.Create(key, number)); } Entity DecrementValue() { string number = owner.Value <string>(); if (number != null) { if (int.TryParse(number, out int result)) { result--; return(owner.Create(key, result.ToString(CultureInfo.InvariantCulture), result)); } } return(owner.Create(key, number)); } } }