Esempio n. 1
0
        /// <summary>
        /// Gets a new ScriptFile instance which is identified by the given file
        /// path and initially contains the given buffer contents.
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="initialBuffer"></param>
        /// <returns></returns>
        public ScriptFile GetFileBuffer(string filePath, string initialBuffer)
        {
            Validate.IsNotNullOrWhitespaceString("filePath", filePath);
            if (IsNonFileUri(filePath))
            {
                return(null);
            }

            // Resolve the full file path
            ResolvedFile resolvedFile = this.ResolveFilePath(filePath);
            string       keyName      = resolvedFile.LowercaseClientUri;

            // Make sure the file isn't already loaded into the workspace
            ScriptFile scriptFile = null;

            if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
            {
                scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri, initialBuffer);

                this.workspaceFiles.Add(keyName, scriptFile);

                Logger.Write(TraceEventType.Verbose, "Opened file as in-memory buffer: " + resolvedFile.FilePath);
            }

            return(scriptFile);
        }
Esempio n. 2
0
        internal Assembly ResolveAssembly(string /*!*/ fullName)
        {
            Utils.Log(String.Format("Resolving assembly: '{0}'", fullName), "RESOLVE_ASSEMBLY");

            AssemblyName assemblyName = new AssemblyName(fullName);
            ResolvedFile file         = FindFile(assemblyName.Name, true, ArrayUtils.EmptyStrings).FirstOrDefault();

            if (file == null || file.SourceUnit != null)
            {
                return(null);
            }

            Utils.Log(String.Format("Assembly '{0}' resolved: found in '{1}'", fullName, file.Path), "RESOLVE_ASSEMBLY");
            try {
                Assembly assembly = Platform.LoadAssemblyFromPath(file.Path);

#if !SILVERLIGHT
                // TODO: this API is broken
                if (AssemblyName.ReferenceMatchesDefinition(assemblyName, assembly.GetName()))
#endif
                {
                    Utils.Log(String.Format("Assembly '{0}' loaded for '{1}'", assembly.FullName, fullName), "RESOLVE_ASSEMBLY");
                    DomainManager.LoadAssembly(assembly);
                    return(assembly);
                }
            } catch (Exception e) {
                throw RubyExceptions.CreateLoadError(e);
            }

#if !SILVERLIGHT
            return(null);
#endif
        }
Esempio n. 3
0
        /// <summary>
        /// Resolves a URI identifier into an actual file on disk if it exists.
        /// </summary>
        /// <param name="clientUri">The URI identifying the file</param>
        /// <returns></returns>
        private ResolvedFile ResolveFilePath(string clientUri)
        {
            bool   canReadFromDisk = false;
            string filePath        = clientUri;

            if (!IsPathInMemoryOrNonFileUri(clientUri))
            {
                if (clientUri.StartsWith(@"file://"))
                {
                    // VS Code encodes the ':' character in the drive name, which can lead to problems parsing
                    // the URI, so unencode it if present. See https://github.com/Microsoft/vscode/issues/2990
                    clientUri = clientUri.Replace("%3A/", ":/", StringComparison.OrdinalIgnoreCase);

                    // Client sent the path in URI format, extract the local path and trim
                    // any extraneous slashes
                    Uri fileUri = new Uri(clientUri);
                    filePath = fileUri.LocalPath;
                    if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/"))
                    {
                        filePath = filePath.Substring(1);
                    }
                }

                // Clients could specify paths with escaped space, [ and ] characters which .NET APIs
                // will not handle.  These paths will get appropriately escaped just before being passed
                // into the SqlTools engine.
                filePath = UnescapePath(filePath);

                // Client paths are handled a bit differently because of how we currently identifiers in
                // ADS. The URI is passed around as an identifier - but for things we control like connecting
                // an editor the URI we pass in is NOT escaped fully. This is a problem for certain functionality
                // which is handled by VS Code - such as Intellise Completion - as the URI passed in there is
                // the fully escaped URI. That means we need to do some extra work to make sure that the URI values
                // are consistent.
                // So to solve that we'll make sure to unescape ALL uri's that are passed in and store that value for
                // use as an identifier (filePath will be the actual file path on disk).
                // # and ? are still always escaped though by ADS so we need to escape those again to get them to actually
                // match
                clientUri = Uri.UnescapeDataString(UnescapePath(clientUri));
                clientUri = clientUri.Replace("#", "%23");
                clientUri = clientUri.Replace("?", "%3F");

                // switch to unix path separators on non-Windows platforms
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    filePath  = filePath.Replace('\\', '/');
                    clientUri = clientUri.Replace('\\', '/');
                }

                // Get the absolute file path
                ResolvedFile resolvedFile = FileUtilities.TryGetFullPath(filePath, clientUri);
                filePath        = resolvedFile.FilePath;
                canReadFromDisk = resolvedFile.CanReadFromDisk;
            }

            Logger.Write(TraceEventType.Verbose, "Resolved path: " + clientUri);

            return(new ResolvedFile(filePath, clientUri, canReadFromDisk));
        }
Esempio n. 4
0
        /// <summary>
        /// Searches file in load directories and then appends extensions.
        /// </summary>
        private ResolvedFile FindFile(string /*!*/ path, bool appendExtensions, string[] sourceFileExtensions)
        {
            Assert.NotNull(path);
            bool isAbsolutePath;

#if SILVERLIGHT
            {
#else
            if (path.StartsWith("~/", StringComparison.Ordinal) || path.StartsWith("~\\", StringComparison.Ordinal))
            {
                path           = RubyUtils.ExpandPath(_context.Platform, path);
                isAbsolutePath = true;
            }
            else
            {
#endif
                try {
                    isAbsolutePath = Platform.IsAbsolutePath(path);
                } catch (ArgumentException e) {
                    throw RubyExceptions.CreateLoadError(e);
                }
            }

            string extension = RubyUtils.GetExtension(path);

            // Absolute path -> load paths not consulted.
            if (isAbsolutePath)
            {
                return(ResolveFile(path, extension, appendExtensions, sourceFileExtensions));
            }

            string[] loadPaths = GetLoadPathStrings();

            if (loadPaths.Length == 0)
            {
                return(null);
            }

            // If load paths are non-empty and the path starts with .\ or ..\ then MRI also ignores the load paths.
            if (path.StartsWith("./", StringComparison.Ordinal) ||
                path.StartsWith("../", StringComparison.Ordinal) ||
                path.StartsWith(".\\", StringComparison.Ordinal) ||
                path.StartsWith("..\\", StringComparison.Ordinal))
            {
                return(ResolveFile(path, extension, appendExtensions, sourceFileExtensions));
            }

            foreach (var dir in loadPaths)
            {
                ResolvedFile result = ResolveFile(RubyUtils.CombinePaths(dir, path), extension, appendExtensions, sourceFileExtensions);
                if (result != null)
                {
                    return(result);
                }
            }

            return(null);
        }
Esempio n. 5
0
        private bool LoadFromPath(Scope /*!*/ globalScope, object self, string /*!*/ path, LoadFlags flags)
        {
            Assert.NotNull(globalScope, path);

            ResolvedFile file = FindFile(globalScope, path, (flags & LoadFlags.AppendExtensions) != 0);

            if (file == null)
            {
                throw new LoadError(String.Format("no such file to load -- {0}", path));
            }

            MutableString pathWithExtension = MutableString.Create(path);

            if (file.AppendedExtension != null)
            {
                pathWithExtension.Append(file.AppendedExtension);
            }

            if (AlreadyLoaded(pathWithExtension, flags) || _unfinishedFiles.Contains(pathWithExtension.ToString()))
            {
                return(false);
            }

            try {
                // save path as is, no canonicalization nor combination with an extension or directory:
                _unfinishedFiles.Push(pathWithExtension.ToString());

                if (file.SourceUnit != null)
                {
                    RubyContext rubySource = file.SourceUnit.LanguageContext as RubyContext;
                    if (rubySource != null)
                    {
                        ExecuteRubySourceUnit(file.SourceUnit, globalScope, flags);
                    }
                    else
                    {
                        file.SourceUnit.Execute();
                    }
                }
                else
                {
                    Debug.Assert(file.Path != null);
                    try {
                        Assembly asm = Platform.LoadAssemblyFromPath(Platform.GetFullPath(file.Path));
                        DomainManager.LoadAssembly(asm);
                    } catch (Exception e) {
                        throw new LoadError(e.Message, e);
                    }
                }

                FileLoaded(pathWithExtension, flags);
            } finally {
                _unfinishedFiles.Pop();
            }

            return(true);
        }
Esempio n. 6
0
        /// <summary>
        /// Checks if a given URI is contained in a workspace
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns>Flag indicating if the file is tracked in workspace</returns>
        public bool ContainsFile(string filePath)
        {
            Validate.IsNotNullOrWhitespaceString("filePath", filePath);

            // Resolve the full file path
            ResolvedFile resolvedFile = this.ResolveFilePath(filePath);
            string       keyName      = resolvedFile.LowercaseClientUri;

            ScriptFile scriptFile = null;

            return(this.workspaceFiles.TryGetValue(keyName, out scriptFile));
        }
Esempio n. 7
0
        private ResolvedFile ResolveFilePath(string filePath)
        {
            bool canReadFromDisk = false;

            if (!IsPathInMemoryOrNonFileUri(filePath))
            {
                if (filePath.StartsWith(@"file://"))
                {
                    // VS Code encodes the ':' character in the drive name, which can lead to problems parsing
                    // the URI, so unencode it if present. See https://github.com/Microsoft/vscode/issues/2990
                    filePath = filePath.Replace("%3A/", ":/", StringComparison.OrdinalIgnoreCase);

                    // Client sent the path in URI format, extract the local path and trim
                    // any extraneous slashes
                    Uri fileUri = new Uri(filePath);
                    filePath = fileUri.LocalPath;
                    if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/"))
                    {
                        filePath = filePath.Substring(1);
                    }
                }

                // Clients could specify paths with escaped space, [ and ] characters which .NET APIs
                // will not handle.  These paths will get appropriately escaped just before being passed
                // into the SqlTools engine.
                filePath = UnescapePath(filePath);

                // switch to unix path separators on non-Windows platforms
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    filePath = filePath.Replace('\\', '/');
                }

                // Get the absolute file path
                ResolvedFile resolvedFile = FileUtilities.TryGetFullPath(filePath);
                filePath        = resolvedFile.FilePath;
                canReadFromDisk = resolvedFile.CanReadFromDisk;
            }

            Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);

            return(new ResolvedFile(filePath, canReadFromDisk));
        }
Esempio n. 8
0
        /// <summary>
        /// Gets an open file in the workspace.  If the file isn't open but
        /// exists on the filesystem, load and return it. Virtual method to
        /// allow for mocking
        /// </summary>
        /// <param name="filePath">The file path at which the script resides.</param>
        /// <exception cref="FileNotFoundException">
        /// <paramref name="filePath"/> is not found.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="filePath"/> contains a null or empty string.
        /// </exception>
        public virtual ScriptFile GetFile(string filePath)
        {
            Validate.IsNotNullOrWhitespaceString("filePath", filePath);
            if (IsNonFileUri(filePath))
            {
                return(null);
            }

            // Resolve the full file path
            ResolvedFile resolvedFile = this.ResolveFilePath(filePath);
            string       keyName      = resolvedFile.LowercaseClientUri;

            // Make sure the file isn't already loaded into the workspace
            ScriptFile scriptFile = null;

            if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
            {
                if (IsUntitled(resolvedFile.FilePath) ||
                    !resolvedFile.CanReadFromDisk ||
                    !File.Exists(resolvedFile.FilePath))
                {
                    // It's either not a registered untitled file, or not a valid file on disk
                    // so any attempt to read from disk will fail.
                    return(null);
                }
                // This method allows FileNotFoundException to bubble up
                // if the file isn't found.
                using (FileStream fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read))
                    using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8))
                    {
                        scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri, streamReader);

                        this.workspaceFiles.Add(keyName, scriptFile);
                    }

                Logger.Write(TraceEventType.Verbose, "Opened file on disk: " + resolvedFile.FilePath);
            }

            return(scriptFile);
        }
Esempio n. 9
0
        private ResolvedFile ResolveFilePath(string filePath)
        {
            bool canReadFromDisk = false;

            if (!IsPathInMemoryOrNonFileUri(filePath))
            {
                if (filePath.StartsWith(@"file://"))
                {
                    // Client sent the path in URI format, extract the local path and trim
                    // any extraneous slashes
                    Uri fileUri = new Uri(filePath);
                    filePath = fileUri.LocalPath;
                    if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/"))
                    {
                        filePath = filePath.Substring(1);
                    }
                }

                // Clients could specify paths with escaped space, [ and ] characters which .NET APIs
                // will not handle.  These paths will get appropriately escaped just before being passed
                // into the SqlTools engine.
                filePath = UnescapePath(filePath);

                // switch to unix path separators on non-Windows platforms
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    filePath = filePath.Replace('\\', '/');
                }

                // Get the absolute file path
                ResolvedFile resolvedFile = FileUtilities.TryGetFullPath(filePath);
                filePath        = resolvedFile.FilePath;
                canReadFromDisk = resolvedFile.CanReadFromDisk;
            }

            Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);

            return(new ResolvedFile(filePath, canReadFromDisk));
        }
Esempio n. 10
0
        private bool LoadFromPath(Scope globalScope, object self, string /*!*/ path, RubyEncoding /*!*/ pathEncoding, LoadFlags flags, out object loaded)
        {
            Assert.NotNull(pathEncoding, path);

            string[] sourceFileExtensions;
            if ((flags & LoadFlags.AnyLanguage) != 0)
            {
                sourceFileExtensions = DomainManager.Configuration.GetFileExtensions();
            }
            else
            {
                sourceFileExtensions = DomainManager.Configuration.GetFileExtensions(_context);
            }

            IList <ResolvedFile> files = FindFile(path, (flags & LoadFlags.AppendExtensions) != 0, sourceFileExtensions);

            if (files.Count == 0)
            {
                // MRI: doesn't throw an exception if the path is in $" (performs resolution first though):
                if (AlreadyLoaded(path, null, flags, sourceFileExtensions))
                {
                    loaded = null;
                    return(false);
                }
                throw RubyExceptions.CreateLoadError(String.Format("no such file to load -- {0}", path));
            }

            ResolvedFile file = files.First();

            string pathWithExtension = path;

            if (file.AppendedExtension != null)
            {
                pathWithExtension += file.AppendedExtension;
            }

            if (AlreadyLoaded(path, files, flags) || _unfinishedFiles.Contains(file.Path))
            {
                if ((flags & LoadFlags.ResolveLoaded) != 0)
                {
                    if (file.SourceUnit != null)
                    {
                        Scope loadedScope;
                        if (!LoadedScripts.TryGetValue(file.Path, out loadedScope))
                        {
                            throw RubyExceptions.CreateLoadError(String.Format("no such file to load -- {0}", file.Path));
                        }
                        loaded = loadedScope;
                    }
                    else
                    {
                        loaded = Platform.LoadAssemblyFromPath(file.Path);
                    }
                }
                else
                {
                    loaded = null;
                }
                return(false);
            }

            try {
                // save path as is, no canonicalization nor combination with an extension or directory:
                _unfinishedFiles.Push(file.Path);

                if (file.SourceUnit != null)
                {
                    AddScriptLines(file.SourceUnit);

                    ScriptCode compiledCode;
                    if (file.SourceUnit.LanguageContext == _context)
                    {
                        compiledCode = CompileRubySource(file.SourceUnit, flags);
                    }
                    else
                    {
                        compiledCode = file.SourceUnit.Compile();
                    }
                    loaded = Execute(globalScope, compiledCode);
                }
                else
                {
                    Debug.Assert(file.Path != null);
                    try {
                        Assembly assembly = Platform.LoadAssemblyFromPath(file.Path);
                        DomainManager.LoadAssembly(assembly);
                        loaded = assembly;
                    } catch (Exception e) {
                        throw RubyExceptions.CreateLoadError(e);
                    }
                }

                FileLoaded(MutableString.Create(file.Path, pathEncoding), flags);
            } finally {
                _unfinishedFiles.Pop();
            }

            return(true);
        }
Esempio n. 11
0
        private ResolvedFile FindFile(string /*!*/ path, bool appendExtensions, string[] sourceFileExtensions)
        {
            Assert.NotNull(path);
            bool   isAbsolutePath;
            string extension;
            string home = null;

#if !SILVERLIGHT
            if (path.StartsWith("~/", StringComparison.Ordinal) || path.StartsWith("~\\", StringComparison.Ordinal))
            {
                try {
                    home = Environment.GetEnvironmentVariable("HOME");
                } catch (SecurityException) {
                    home = null;
                }

                if (home == null)
                {
                    throw RubyExceptions.CreateArgumentError(String.Format("couldn't find HOME environment -- expanding `{0}'", path));
                }
            }
#endif
            try {
                if (home != null)
                {
                    path = RubyUtils.CombinePaths(home, path.Substring(2));
                }

                isAbsolutePath = Platform.IsAbsolutePath(path);
                extension      = RubyUtils.GetExtension(path);
            } catch (ArgumentException e) {
                throw RubyExceptions.CreateLoadError(e);
            }

            // Absolute path -> load paths not consulted.
            if (isAbsolutePath)
            {
                return(ResolveFile(path, extension, appendExtensions, sourceFileExtensions));
            }

            string[] loadPaths = GetLoadPathStrings();

            if (loadPaths.Length == 0)
            {
                return(null);
            }

            // If load paths are non-empty and the path starts with .\ or ..\ then MRI also ignores the load paths.
            if (path.StartsWith("./", StringComparison.Ordinal) ||
                path.StartsWith("../", StringComparison.Ordinal) ||
                path.StartsWith(".\\", StringComparison.Ordinal) ||
                path.StartsWith("..\\", StringComparison.Ordinal))
            {
                return(ResolveFile(path, extension, appendExtensions, sourceFileExtensions));
            }

            foreach (var dir in loadPaths)
            {
                try {
                    ResolvedFile result = ResolveFile(RubyUtils.CombinePaths(dir, path), extension, appendExtensions, sourceFileExtensions);
                    if (result != null)
                    {
                        return(result);
                    }
                } catch (ArgumentException) {
                    // invalid characters in path
                }
            }

            return(null);
        }
Esempio n. 12
0
        private ResolvedFile FindFile(Scope /*!*/ globalScope, string /*!*/ path, bool appendExtensions)
        {
            Assert.NotNull(path);
            bool   isAbsolutePath;
            string extension;
            string home = null;

#if !SILVERLIGHT
            if (path.StartsWith("~/") || path.StartsWith("~\\"))
            {
                try {
                    home = Environment.GetEnvironmentVariable("HOME");
                } catch (SecurityException) {
                    home = null;
                }

                if (home == null)
                {
                    throw RubyExceptions.CreateArgumentError(String.Format("couldn't find HOME environment -- expanding `{0}'", path));
                }
            }
#endif

            try {
                if (home != null)
                {
                    path = Path.Combine(home, path.Substring(2));
                }

                isAbsolutePath = Platform.IsAbsolutePath(path);
                extension      = Path.GetExtension(path);
            } catch (ArgumentException e) {
                throw new LoadError(e.Message, e);
            }

            string[] knownExtensions = DomainManager.Configuration.GetFileExtensions();
            Array.Sort(knownExtensions, DlrConfiguration.FileExtensionComparer);

            // Absolute path -> load paths not consulted.
            if (isAbsolutePath)
            {
                return(ResolveFile(path, extension, appendExtensions, knownExtensions));
            }

            string[] loadPaths = GetLoadPathStrings();

            if (loadPaths.Length == 0)
            {
                return(null);
            }

            // If load paths are non-empty and the path starts with .\ or ..\ then MRI also ignores the load paths.
            if (path.StartsWith("./") || path.StartsWith("../") || path.StartsWith(".\\") || path.StartsWith("..\\"))
            {
                return(ResolveFile(path, extension, appendExtensions, knownExtensions));
            }

            foreach (var dir in loadPaths)
            {
                try {
                    ResolvedFile result = ResolveFile(Path.Combine(dir, path), extension, appendExtensions, knownExtensions);
                    if (result != null)
                    {
                        return(result);
                    }
                } catch (ArgumentException) {
                    // invalid characters in path
                }
            }

            return(null);
        }