Пример #1
0
        /// <summary>
        /// Add a new folder build item to the project
        /// </summary>
        /// <param name="folder">The folder name</param>
        /// <returns>The new <see cref="FileItem"/>.</returns>
        /// <remarks>If the folder does not exist in the project, it is added and created if not already there.
        /// If the folder is already part of the project, the existing item is returned.</remarks>
        /// <exception cref="ArgumentException">This is thrown if the path matches the project root path or is
        /// not below it.</exception>
        public FileItem AddFolderToProject(string folder)
        {
            FolderPath folderPath;
            FileItem newFileItem = null;
            string folderAction = BuildAction.Folder.ToString(),
                rootPath = Path.GetDirectoryName(msBuildProject.FullPath);

            if(folder.Length != 0 && folder[folder.Length - 1] == '\\')
                folder = folder.Substring(0, folder.Length - 1);

            if(!Path.IsPathRooted(folder))
                folder = Path.GetFullPath(Path.Combine(rootPath, folder));

            if(String.Compare(folder, 0, rootPath, 0, rootPath.Length, StringComparison.OrdinalIgnoreCase) != 0)
                throw new ArgumentException("The folder must be below the project's root path", "folder");

            if(folder.Length == rootPath.Length)
                throw new ArgumentException("The folder cannot match the project's root path", "folder");

            folderPath = new FolderPath(folder, this);

            // Note that Visual Studio doesn't add the trailing backslash so look for a match with and without it.
            // Folders don't always have a relative path in the item when first added.  As such, check both the
            // relative and full paths for a match.
            foreach(ProjectItem item in msBuildProject.GetItems(folderAction))
                if(item.EvaluatedInclude == folderPath.PersistablePath ||
                  item.EvaluatedInclude + @"\" == folderPath.PersistablePath ||
                  item.EvaluatedInclude == folderPath.Path || item.EvaluatedInclude + @"\" == folderPath.Path)
                {
                    newFileItem = new FileItem(this, item);
                    break;
                }

            if(!Directory.Exists(folderPath))
                Directory.CreateDirectory(folderPath);

            if(newFileItem == null)
                newFileItem = new FileItem(this, folderAction, folder);

            return newFileItem;
        }
Пример #2
0
        /// <summary>
        /// This is used to set the named property to the specified value using Reflection
        /// </summary>
        /// <param name="name">The name of the property to set</param>
        /// <param name="value">The value to which it is set</param>
        /// <remarks>Property name matching is case insensitive as are the values.  This is used to allow setting
        /// of simple project properties (non-collection) from the MSBuild project file.  Unknown properties are
        /// ignored.</remarks>
        /// <exception cref="ArgumentNullException">This is thrown if the name parameter is null or an empty
        /// string.</exception>
        /// <exception cref="BuilderException">This is thrown if an error occurs while trying to set the named
        /// property.</exception>
        private void SetLocalProperty(string name, string value)
        {
            TypeConverter tc;
            EscapeValueAttribute escAttr;
            PropertyInfo property;
            FilePath filePath;
            object parsedValue;

            if(String.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");

            // Ignore unknown properties
            if(!propertyCache.TryGetValue(name, out property))
                return;

            if(!property.CanWrite || property.IsDefined(typeof(XmlIgnoreAttribute), true))
                throw new BuilderException("PRJ0004", String.Format(CultureInfo.CurrentCulture,
                    "An attempt was made to set a read-only or ignored property: {0}   Value: {1}",
                    name, value));

            // If escaped, unescape it
            escAttr = pdcCache[name].Attributes[typeof(EscapeValueAttribute)] as EscapeValueAttribute;

            if(escAttr != null)
                value = EscapeValueAttribute.Unescape(value);

            try
            {
                if(property.PropertyType.IsEnum)
                    parsedValue = Enum.Parse(property.PropertyType, value, true);
                else
                    if(property.PropertyType == typeof(Version))
                        parsedValue = new Version(value);
                    else
                    {
                        if(property.PropertyType == typeof(FilePath))
                            parsedValue = new FilePath(value, this);
                        else
                            if(property.PropertyType == typeof(FolderPath))
                                parsedValue = new FolderPath(value, this);
                            else
                            {
                                tc = TypeDescriptor.GetConverter(property.PropertyType);
                                parsedValue = tc.ConvertFromString(value);
                            }

                        // If it's a file or folder path, set the IsFixedPath property based on whether or not
                        // it is rooted.
                        filePath = parsedValue as FilePath;

                        if(filePath != null && Path.IsPathRooted(value))
                            filePath.IsFixedPath = true;
                    }
            }
            catch(Exception ex)
            {
                // Ignore exceptions for the Language property.  A few people have had an environment variable
                // with that name that gets picked up as a default and the value isn't typically valid for a
                // culture name.
                if(!name.Equals("Language", StringComparison.OrdinalIgnoreCase))
                    throw new BuilderException("PRJ0005", "Unable to parse value '" + value +
                        "' for property '" + name + "'", ex);

                parsedValue = null;
            }

            property.SetValue(this, parsedValue, null);
        }
Пример #3
0
        /// <summary>
        /// This helper method can be used to convert a relative path to an absolute path based on the given base
        /// path.
        /// </summary>
        /// <param name="basePath">The base path</param>
        /// <param name="relativePath">A relative path</param>
        /// <returns>An absolute path</returns>
        /// <remarks>If the base path is null or empty, the current working folder is used.</remarks>
        /// <example>
        /// <code lang="cs">
        /// string basePath = @"E:\DotNet\CS\TestProject\Source";
        /// string relativePath = @"..\Doc\Help.html";
        ///
        /// string absolutePath = FilePath.RelativeToAbsolutePath(basePath,
        ///     relativePath);
        ///
        /// Console.WriteLine(absolutePath);
        ///
        /// // Results in: E:\DotNet\CS\TestProject\Doc\Help.html
        /// </code>
        /// <code lang="vbnet">
        /// Dim basePath As String = "E:\DotNet\CS\TestProject\Source"
        /// Dim relativePath As String = "..\Doc\Help.html"
        ///
        /// Dim absolutePath As String = _
        ///     FilePath.RelativeToAbsolutePath(basePath, relativePath);
        ///
        /// Console.WriteLine(absolutePath)
        ///
        /// ' Results in: E:\DotNet\CS\TestProject\Doc\Help.html
        /// </code>
        /// </example>
        public static string RelativeToAbsolutePath(string basePath, string relativePath)
        {
            int idx;

            // If blank return the base path
            if (String.IsNullOrEmpty(relativePath))
            {
                return(basePath);
            }

            // Don't bother if already absolute
            if (IOPath.IsPathRooted(relativePath))
            {
                return(relativePath);
            }

            // If not specified, use the current folder as the base path
            if (basePath == null || basePath.Trim().Length == 0)
            {
                basePath = Directory.GetCurrentDirectory();
            }
            else
            {
                basePath = IOPath.GetFullPath(basePath);
            }

            // Remove trailing backslashes for comparison
            if (FolderPath.IsPathTerminated(basePath))
            {
                basePath = basePath.Substring(0, basePath.Length - 1);
            }

            if (relativePath == ".")
            {
                relativePath = String.Empty;
            }

            // Remove ".\" or "./" if it's there
            if (relativePath.Length > 1 && relativePath[0] == '.' &&
                (relativePath[1] == IOPath.DirectorySeparatorChar ||
                 relativePath[1] == IOPath.AltDirectorySeparatorChar))
            {
                relativePath = relativePath.Substring(2);
            }

            // Split the paths into their component parts
            string[] baseParts = basePath.Split(IOPath.DirectorySeparatorChar);
            string[] relParts  = relativePath.Split(IOPath.DirectorySeparatorChar);

            // Figure out how far to move up from the relative path
            for (idx = 0; idx < relParts.Length; ++idx)
            {
                if (relParts[idx] != "..")
                {
                    break;
                }
            }

            // If it's below the base path, just add it to the base path
            if (idx == 0)
            {
                return(FilePath.GetFullPath(basePath + IOPath.DirectorySeparatorChar + relativePath));
            }

            string absPath = String.Join(IOPath.DirectorySeparatorChar.ToString(), baseParts, 0,
                                         Math.Max(0, baseParts.Length - idx));

            absPath += IOPath.DirectorySeparatorChar + String.Join(IOPath.DirectorySeparatorChar.ToString(),
                                                                   relParts, idx, relParts.Length - idx);

            return(FilePath.GetFullPath(absPath));
        }
Пример #4
0
        /// <summary>
        /// This helper method can be used to convert an absolute path to one that is relative to the given base
        /// path.
        /// </summary>
        /// <param name="basePath">The base path</param>
        /// <param name="absolutePath">An absolute path</param>
        /// <returns>A path to the given absolute path that is relative to the given base path</returns>
        /// <remarks>If the base path is null or empty, the current working folder is used.</remarks>
        /// <example>
        /// <code lang="cs">
        /// string basePath = @"E:\DotNet\CS\TestProject\Source";
        /// string absolutePath = @"E:\DotNet\CS\TestProject\Doc\Help.html";
        ///
        /// string relativePath = FilePath.AbsoluteToRelativePath(basePath,
        ///     absolutePath);
        ///
        /// Console.WriteLine(relativePath);
        ///
        /// // Results in: ..\Doc\Help.html
        /// </code>
        /// <code lang="vbnet">
        /// Dim basePath As String = "E:\DotNet\CS\TestProject\Source"
        /// Dim absolutePath As String = "E:\DotNet\CS\TestProject\Doc\Help.html"
        ///
        /// Dim relativePath As String = _
        ///     FilePath.AbsoluteToRelativePath(basePath, absolutePath);
        ///
        /// Console.WriteLine(relativePath)
        ///
        /// ' Results in: ..\Doc\Help.html
        /// </code>
        /// </example>
        public static string AbsoluteToRelativePath(string basePath, string absolutePath)
        {
            bool   hasBackslash = false;
            string relPath;
            int    minLength, idx;

            // If not specified, use the current folder as the base path
            if (basePath == null || basePath.Trim().Length == 0)
            {
                basePath = Directory.GetCurrentDirectory();
            }
            else
            {
                basePath = IOPath.GetFullPath(basePath);
            }

            if (absolutePath == null)
            {
                absolutePath = String.Empty;
            }

            // Just in case, make sure the path is absolute
            if (!IOPath.IsPathRooted(absolutePath))
            {
                absolutePath = FilePath.GetFullPath(absolutePath);
            }

            // Remove trailing backslashes for comparison
            if (FolderPath.IsPathTerminated(basePath))
            {
                basePath = basePath.Substring(0, basePath.Length - 1);
            }

            if (FolderPath.IsPathTerminated(absolutePath))
            {
                absolutePath = absolutePath.Substring(0, absolutePath.Length - 1);
                hasBackslash = true;
            }

            // Split the paths into their component parts
            char[]   separators = { IOPath.DirectorySeparatorChar, IOPath.AltDirectorySeparatorChar,
                                    IOPath.VolumeSeparatorChar };
            string[] baseParts = basePath.Split(separators);
            string[] absParts  = absolutePath.Split(separators);

            // Find the common base path
            minLength = Math.Min(baseParts.Length, absParts.Length);

            for (idx = 0; idx < minLength; idx++)
            {
                if (String.Compare(baseParts[idx], absParts[idx], StringComparison.OrdinalIgnoreCase) != 0)
                {
                    break;
                }
            }

            // Use the absolute path if there's nothing in common (i.e. they are on different drives or network
            // shares.
            if (idx == 0)
            {
                relPath = absolutePath;
            }
            else
            {
                // If equal to the base path, it doesn't have to go anywhere.  Otherwise, work up from the base
                // path to the common root.
                if (idx == baseParts.Length)
                {
                    relPath = String.Empty;
                }
                else
                {
                    relPath = new String(' ', baseParts.Length - idx).Replace(" ", ".." +
                                                                              IOPath.DirectorySeparatorChar);
                }

                // And finally, add the path from the common root to the absolute path
                relPath += String.Join(IOPath.DirectorySeparatorChar.ToString(), absParts, idx,
                                       absParts.Length - idx);
            }

            return((hasBackslash) ? FolderPath.TerminatePath(relPath) : relPath);
        }
Пример #5
0
        /// <summary>
        /// This is used to set the named property to the specified value
        /// using Reflection.
        /// </summary>
        /// <param name="name">The name of the property to set</param>
        /// <param name="value">The value to which it is set</param>
        /// <returns>The parsed object value to which the property was set.</returns>
        /// <remarks>Property name matching is case insensitive as are the
        /// values.  This is used to allow setting of simple project properties
        /// (non-collection) from the MSBuild project file.  Unknown properties
        /// are ignored.</remarks>
        /// <exception cref="ArgumentNullException">This is thrown if the
        /// name parameter is null or an empty string.</exception>
        /// <exception cref="BuilderException">This is thrown if an error
        /// occurs while trying to set the named property.</exception>
        private void SetLocalProperty(string name, string value)
        {
            TypeConverter tc;
            EscapeValueAttribute escAttr;
            PropertyInfo property;
            FilePath filePath;
            object parsedValue;

            if(String.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");

            // Ignore unknown properties
            if(!propertyCache.TryGetValue(name, out property))
            {
                property = null;

                // Could be mismatched by case, so try again the long way
                foreach(string key in propertyCache.Keys)
                    if(String.Compare(key, name, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        name = key;
                        property = propertyCache[name];
                        break;
                    }

                if(property == null)
                    return;
            }

            if(!property.CanWrite || property.IsDefined(
              typeof(XmlIgnoreAttribute), true))
                throw new BuilderException("PRJ0004", String.Format(
                    CultureInfo.InvariantCulture, "An attempt was " +
                    "made to set a read-only or ignored property: {0}" +
                    "   Value: {1}", name, value));

            // If escaped, unescape it
            escAttr = pdcCache[name].Attributes[typeof(EscapeValueAttribute)] as
                EscapeValueAttribute;

            if(escAttr != null)
                value = EscapeValueAttribute.Unescape(value);

            try
            {
                if(property.PropertyType.IsEnum)
                    parsedValue = Enum.Parse(property.PropertyType,
                        value, true);
                else
                    if(property.PropertyType == typeof(Version))
                        parsedValue = new Version(value);
                    else
                    {
                        if(property.PropertyType == typeof(FilePath))
                            parsedValue = new FilePath(value, this);
                        else
                            if(property.PropertyType == typeof(FolderPath))
                                parsedValue = new FolderPath(value, this);
                            else
                            {
                                tc = TypeDescriptor.GetConverter(
                                    property.PropertyType);
                                parsedValue = tc.ConvertFromString(value);
                            }

                        // If it's a file or folder path, set the IsFixedPath
                        // property based on whether or not it is rooted.
                        filePath = parsedValue as FilePath;

                        if(filePath != null && Path.IsPathRooted(value))
                            filePath.IsFixedPath = true;
                    }
            }
            catch(Exception ex)
            {
                throw new BuilderException("PRJ0005",
                    "Unable to parse value '" + value + "' for property '" +
                    name + "'", ex);
            }

            property.SetValue(this, parsedValue, null);
        }
Пример #6
0
        /// <summary>
        /// Add a new folder build item to the project
        /// </summary>
        /// <param name="folder">The folder name</param>
        /// <returns>The new <see cref="FileItem"/>.</returns>
        /// <remarks>If the folder does not exist in the project, it is added
        /// and created if not already there.  If the folder is already part of
        /// the project, the existing item is returned.</remarks>
        /// <exception cref="ArgumentException">This is thrown if the path
        /// matches the project root path or is not below it.</exception>
        public FileItem AddFolderToProject(string folder)
        {
            FolderPath folderPath;
            FileItem newFileItem = null;
            string folderAction = BuildAction.Folder.ToString(),
                rootPath = Path.GetDirectoryName(msBuildProject.FullFileName);

            if(folder.Length != 0 && folder[folder.Length - 1] == '\\')
                folder = folder.Substring(0, folder.Length - 1);

            if(!Path.IsPathRooted(folder))
                folder = Path.GetFullPath(Path.Combine(rootPath, folder));

            if(String.Compare(folder, 0, rootPath, 0, rootPath.Length,
              StringComparison.OrdinalIgnoreCase) != 0)
                throw new ArgumentException("The folder must be below the " +
                    "project's root path", "folder");

            if(folder.Length == rootPath.Length)
                throw new ArgumentException("The folder cannot match the " +
                    "project's root path", "folder");

            folderPath = new FolderPath(folder, this);

            foreach(BuildItem item in msBuildProject.GetEvaluatedItemsByName(folderAction))
                if(item.Include == folderPath.PersistablePath)
                {
                    newFileItem = new FileItem(new ProjectElement(this, item));
                    break;
                }

            if(!Directory.Exists(folderPath))
                Directory.CreateDirectory(folderPath);

            if(newFileItem == null)
                newFileItem = new FileItem(new ProjectElement(this,
                    folderAction, folder));

            return newFileItem;
        }