private void CreateImplicitFolders(FrontendCompiler context, List <FileSystemResource> implicitPaths) { implicitPaths.Sort((x, y) => x.Path.CompareTo(y.Path)); foreach (FileSystemResource r in implicitPaths) { string path = String.Empty; Folder parentFolder = null; string[] splitPath = r.Path.Split(FileSystemResourceManager.DirectorySplitChars, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < splitPath.Length - 1; ++i) { Folder folder = null; Resource found = null; path = IO.Path.Combine(path, splitPath[i]) + "\\"; if (path.EndsWith(":\\", StringComparison.Ordinal)) { PackageItem item; if (context.TryGetItemById(path.Substring(0, path.Length - 2), out item)) { folder = (Folder)item; } } else if (this.resolvedPaths.TryGetValue(path, out found)) { folder = found as Folder; if (folder == null) { CompilerException.ThrowInternalError("Failed to resolve path to Folder. The path: '{0}' should resolve to a Folder instead of: '{1}'.", path, found); } else if (folder.ParentFolder != parentFolder) { CompilerException.ThrowInternalError("Found Folder.ParentFolder does not match expected parent Folder. Ensure path: '{0}' is correctly rooted to Folder/@Id='{1}'.", path, folder.Id); } } else // need to create the implicit folder. { folder = new Folder(); folder.Group = r.Group; folder.Name = splitPath[i]; parentFolder.Items.Add(folder); context.AddItem(r.LineNumber, folder); // Since the folder was just created, we need to jump start its "resolving" since all // of the other resources have already started resolve. folder.ResolveGroup(context); folder.BeginResolve(context); this.ResolvePath(context, folder); } parentFolder = folder; } if (r.ParentFolder != parentFolder) { r.ReparentFolder(parentFolder); } } }
public void ResolveResources(FrontendCompiler context, List <FileSystemResource> resolves) { if (resolves.Count == 0) { return; } this.ResolveParentFolders(context, resolves); List <FileSystemResource> implicitPaths = new List <FileSystemResource>(); foreach (FileSystemResource r in new List <FileSystemResource>(resolves)) { if (!r.Deleted) { this.ResolvePath(context, r); // If the resource had a relative path it may still need to create some implicit folders // so add it to the list. if (!String.IsNullOrEmpty(r.ParentRelativePathFromName)) { implicitPaths.Add(r); } } } this.CreateImplicitFolders(context, implicitPaths); }
private PackageItem SetTarget(FrontendCompiler context, PackageItem item) { if (this.targetProperty.GetValue(this.targetItem, null) != null) { context.OnMessage(new CompilerMessageEventArgs(CompilerMessage.OverwritingImplicitProperty(this.targetProperty.Name, this.Lookup), this.targetItem)); } this.targetProperty.SetValue(this.targetItem, item, null); return(item); }
private Folder GetDefaultRoot(FrontendCompiler context) { PackageItem item; if (!context.TryGetItemById(this.defaultFolderId, out item)) { CompilerException.ThrowInternalError("Failed to locate default root folder with Id: '{0}'.", this.defaultFolderId); } Folder folder = item as Folder; if (folder == null) { CompilerException.ThrowInternalError("Unexpected default root item type. Ensure Id: '{0}' resolves to a Folder instead of a: '{1}'.", this.defaultFolderId, item); } return(folder); }
private void ResolveParentFolders(FrontendCompiler context, List <FileSystemResource> resolves) { Folder defaultRootFolder = this.GetDefaultRoot(context); foreach (FileSystemResource r in new List <FileSystemResource>(resolves)) { if (!String.IsNullOrEmpty(r.ParentFolderIdFromName)) { PackageItem item; Folder newParentFolder = null; if (context.TryGetItemById(r.ParentFolderIdFromName, out item)) { newParentFolder = item as Folder; if (newParentFolder == null) { context.OnMessage(new CompilerMessageEventArgs(CompilerMessage.InvalidFolderReference(r.ParentFolderIdFromName, item.GetType().Name), r.LineNumber)); } } else // did not find a matching id. { // TODO: come up with a better error message for this. context.OnMessage(new CompilerMessageEventArgs(CompilerMessage.InvalidFolderReference(r.ParentFolderIdFromName, "not found"), r.LineNumber)); } if (newParentFolder != null) { // If this is a "no name" folder then reparent all the contents to this new parent if (r is Folder && String.IsNullOrEmpty(r.Name)) { this.ReparentFolderChildren(context, (Folder)r, newParentFolder); resolves.Remove(r); // folder is deleted, be sure not to try to continue to process it. } else // simply point our folder to this new parent. { r.ReparentFolder(newParentFolder); } } } else if (r.ParentFolder == null && !(r is Folder && ((Folder)r).External)) // if we didn't get a parent folder yet and this is not an external folder reference, default to the application folder. { r.ReparentFolder(defaultRootFolder); } } }
private void ReparentFolderChildren(FrontendCompiler context, Folder deleteFolder, Folder replacementFolder) { Debug.Assert(replacementFolder != deleteFolder); if (!String.IsNullOrEmpty(deleteFolder.Path) && !deleteFolder.Path.Equals(replacementFolder.Path, StringComparison.OrdinalIgnoreCase)) { CompilerException.ThrowInternalError("Reparenting to folder with different path. That should not be possible."); } foreach (FileSystemResource child in new List <FileSystemResource>(deleteFolder.Items)) { child.ReparentFolder(replacementFolder); } Debug.Assert(deleteFolder.Items.Count == 0); if (deleteFolder.ParentFolder != null) { deleteFolder.ParentFolder.Items.Remove(deleteFolder); } context.RemoveItem(deleteFolder); }
public bool TryFindResourceByPath(FrontendCompiler context, string path, out Resource resource) { Folder defaultRootFolder = this.GetDefaultRoot(context); string parent; string child; string[] idPath = path.Split(new char[] { ':' }, 2); if (1 == idPath.Length) { parent = defaultRootFolder.Path; child = idPath[0]; } else { PackageItem item; if (context.TryGetItemById(idPath[0], out item)) { parent = ((FileSystemResource)item).Path; } else { parent = idPath[0]; } child = idPath[1]; } if (child.StartsWith("\\", StringComparison.Ordinal)) { child = child.Substring(1); } path = IO.Path.Combine(parent, child); return(this.resolvedPaths.TryGetValue(path, out resource)); }
private string ResolvePath(FrontendCompiler context, FileSystemResource r) { if (String.IsNullOrEmpty(r.Path)) { // If there is a parent folder resolve it's path. string parentPath = String.Empty; if (r.ParentFolder != null) { parentPath = ResolvePath(context, r.ParentFolder); // recurse. } string path = IO.Path.Combine(parentPath, r.ParentRelativePathFromName ?? String.Empty, r.Name ?? String.Empty); Debug.Assert((r is Folder && path.EndsWith("\\", StringComparison.Ordinal)) || (r is File && !path.EndsWith("\\", StringComparison.Ordinal))); r.SetPath(path); } // If in the process of calculating this resource's path we reparented the folder (which deletes the // resource) then don't check for a conflicting resource because this resource would lose anyway. if (!r.Deleted) { Resource conflictingResource; if (this.resolvedPaths.TryGetValue(r.Path, out conflictingResource)) { if (conflictingResource == r) { // We found ourself so don't do anything. } else if (conflictingResource is Folder && r is Folder) // folders are special because the can be implicitly created. { // If our resource has an id that makes it a better candidate for the path. if (!String.IsNullOrEmpty(r.Id)) { // The conflicting resource cannot also have an Id or the backend compiler will be all confusimicated. if (!String.IsNullOrEmpty(conflictingResource.Id)) { // TODO: change this to an error message instead of an internal compiler error. CompilerException.ThrowInternalError("Two named folders refer to the same path. That is not supported."); } this.ReparentFolderChildren(context, (Folder)conflictingResource, (Folder)r); this.resolvedPaths[r.Path] = r; // this resource now owns the path. } else // the conflicting resource either has an Id or was here first so it's a better parent. { this.ReparentFolderChildren(context, (Folder)r, (Folder)conflictingResource); } } else { // TODO: change this to an error message instead of an internal compiler error. CompilerException.ThrowInternalError("Two files or a file and a folder ended up with the same path. That is not allowed."); } } else // no one owns this path yet so take it over. { Debug.Assert(r != r.ParentFolder); this.resolvedPaths.Add(r.Path, r); } } return(r.Path); }
/// <summary> /// Resolves the lookup but may not fail if missing. /// </summary> /// <param name="context">Frontend compiler containing all the objects that may satisfy the resolution.</param> /// <param name="allowUnresolved">Flag specifying whether to allow unresolved items to be returned.</param> /// <returns>Item resolved.</returns> public PackageItem Resolve(FrontendCompiler context, bool allowUnresolved) { if (this.ResolvedItem == null) { string targetPropertyName = this.targetProperty == null ? String.Empty : this.targetProperty.Name; CompilerMessage message = null; PackageItem item = null; if (context.TryGetItemById(this.Lookup, out item)) { if (this.targetType.IsInstanceOfType(item)) { if (this.targetProperty != null) { this.SetTarget(context, item); } } else if (!allowUnresolved) { message = CompilerMessage.InvalidIdResolution( targetPropertyName, this.Lookup, this.targetType.Name, item.GetType().Name); } } else if (this.targetType.IsSubclassOf(typeof(FileSystemResource)) || this.targetType == typeof(IFileReference)) { Resource resource; FileSystemResourceManager manager = (FileSystemResourceManager)context.GetService(typeof(FileSystemResourceManager)); if (manager.TryFindResourceByPath(context, this.Lookup, out resource)) { if (this.targetType.IsInstanceOfType(resource)) { if (this.targetProperty != null) { item = this.SetTarget(context, resource); } else { item = resource; } } else { message = CompilerMessage.InvalidIdResolution( targetPropertyName, this.Lookup, this.targetType.Name, resource.GetType().Name); } } else if (!allowUnresolved) { message = CompilerMessage.UnknownFileSystemResolution( targetPropertyName, this.Lookup, this.targetType.Name); } } else if (!allowUnresolved) { message = CompilerMessage.UnknownIdResolution( targetPropertyName, this.Lookup, this.targetType.Name); } if (message != null) { context.OnMessage(new CompilerMessageEventArgs(message, this.targetItem)); } this.ResolvedItem = item; } return(this.ResolvedItem); }
/// <summary> /// Resolves the lookup. /// </summary> /// <param name="context">Frontend compiler containing all the objects that may satisfy the resolution.</param> public void Resolve(FrontendCompiler context) { this.Resolve(context, false); }