Beispiel #1
0
 private void TestGetExtension(string path, string expected)
 {
     Assert.Equal(expected, PathUtilities.GetExtension(path));
     Assert.Equal(expected, Path.GetExtension(path));
 }
 internal static string?GetDesktopFrameworkDirectory() =>
 GacFileResolver.IsAvailable
         ? PathUtilities.GetDirectoryName(
     typeof(object).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName
     )
         : null;
Beispiel #3
0
        internal void FlattenArgs(
            IEnumerable <string> rawArguments,
            IList <Diagnostic> diagnostics,
            List <string> processedArgs,
            List <string> scriptArgs,
            string baseDirectory,
            List <string> responsePaths = null)
        {
            bool parsingScriptArgs = false;

            Stack <string> args = new Stack <string>(rawArguments.Reverse());

            while (args.Count > 0)
            {
                //EDMAURER trim off whitespace. Otherwise behavioral differences arise
                //when the strings which represent args are constructed by cmd or users.
                //cmd won't produce args with whitespace at the end.
                string arg = args.Pop().TrimEnd();

                if (parsingScriptArgs)
                {
                    scriptArgs.Add(arg);
                    continue;
                }

                if (arg.StartsWith("@", StringComparison.Ordinal))
                {
                    // response file:
                    string path         = RemoveAllQuotes(arg.Substring(1)).TrimEnd();
                    string resolvedPath = FileUtilities.ResolveRelativePath(path, baseDirectory);
                    if (resolvedPath != null)
                    {
                        foreach (string newArg in ParseResponseFile(resolvedPath, diagnostics).Reverse())
                        {
                            // Ignores /noconfig option specified in a response file
                            if (!string.Equals(newArg, "/noconfig", StringComparison.OrdinalIgnoreCase) && !string.Equals(newArg, "-noconfig", StringComparison.OrdinalIgnoreCase))
                            {
                                args.Push(newArg);
                            }
                            else
                            {
                                diagnostics.Add(Diagnostic.Create(messageProvider, messageProvider.WRN_NoConfigNotOnCommandLine));
                            }
                        }

                        if (responsePaths != null)
                        {
                            responsePaths.Add(FileUtilities.NormalizeAbsolutePath(PathUtilities.GetDirectoryName(resolvedPath)));
                        }
                    }
                    else
                    {
                        diagnostics.Add(Diagnostic.Create(messageProvider, messageProvider.FTL_InputFileNameTooLong, path));
                    }
                }
                else if (arg == "--" && scriptArgs != null)
                {
                    parsingScriptArgs = true;
                }
                else
                {
                    processedArgs.Add(arg);
                }
            }
        }
        /// <summary>Run the install or uninstall script.</summary>
        /// <param name="args">The command line arguments.</param>
        /// <remarks>
        /// Initialization flow:
        ///     1. Collect information (mainly OS and install path) and validate it.
        ///     2. Ask the user whether to install or uninstall.
        ///
        /// Uninstall logic:
        ///     1. On Linux/Mac: if a backup of the launcher exists, delete the launcher and restore the backup.
        ///     2. Delete all files and folders in the game directory matching one of the values returned by <see cref="GetUninstallPaths"/>.
        ///
        /// Install flow:
        ///     1. Run the uninstall flow.
        ///     2. Copy the SMAPI files from package/Windows or package/Mono into the game directory.
        ///     3. On Linux/Mac: back up the game launcher and replace it with the SMAPI launcher. (This isn't possible on Windows, so the user needs to configure it manually.)
        ///     4. Create the 'Mods' directory.
        ///     5. Copy the bundled mods into the 'Mods' directory (deleting any existing versions).
        ///     6. Move any mods from app data into game's mods directory.
        /// </remarks>
        public void Run(string[] args)
        {
            /*********
            ** Step 1: initial setup
            *********/
            /****
            ** Get basic info & set window title
            ****/
            ModToolkit toolkit  = new ModToolkit();
            Platform   platform = EnvironmentUtility.DetectPlatform();

            Console.Title = $"SMAPI {this.GetDisplayVersion(this.GetType().Assembly.GetName().Version)} installer on {platform} {EnvironmentUtility.GetFriendlyPlatformName(platform)}";
            Console.WriteLine();

            /****
            ** Check if correct installer
            ****/
#if SMAPI_FOR_WINDOWS
            if (platform == Platform.Linux || platform == Platform.Mac)
            {
                this.PrintError($"This is the installer for Windows. Run the 'install on {platform}.{(platform == Platform.Linux ? "sh" : "command")}' file instead.");
                Console.ReadLine();
                return;
            }
#else
            if (platform == Platform.Windows)
            {
                this.PrintError($"This is the installer for Linux/Mac. Run the 'install on Windows.exe' file instead.");
                Console.ReadLine();
                return;
            }
#endif

            /****
            ** Check Windows dependencies
            ****/
            if (platform == Platform.Windows)
            {
                // .NET Framework 4.5+
                if (!this.HasNetFramework45(platform))
                {
                    this.PrintError(Environment.OSVersion.Version >= this.Windows7Version
                            ? "Please install the latest version of .NET Framework before installing SMAPI." // Windows 7+
                            : "Please install .NET Framework 4.5 before installing SMAPI."                   // Windows Vista or earlier
                                    );
                    this.PrintError("See the download page at https://www.microsoft.com/net/download/framework for details.");
                    Console.ReadLine();
                    return;
                }
                if (!this.HasXna(platform))
                {
                    this.PrintError("You don't seem to have XNA Framework installed. Please run the game at least once before installing SMAPI, so it can perform its first-time setup.");
                    Console.ReadLine();
                    return;
                }
            }

            /****
            ** read command-line arguments
            ****/
            // get action from CLI
            bool installArg   = args.Contains("--install");
            bool uninstallArg = args.Contains("--uninstall");
            if (installArg && uninstallArg)
            {
                this.PrintError("You can't specify both --install and --uninstall command-line flags.");
                Console.ReadLine();
                return;
            }

            // get game path from CLI
            string gamePathArg = null;
            {
                int pathIndex = Array.LastIndexOf(args, "--game-path") + 1;
                if (pathIndex >= 1 && args.Length >= pathIndex)
                {
                    gamePathArg = args[pathIndex];
                }
            }


            /*********
            ** Step 2: choose a theme (can't auto-detect on Linux/Mac)
            *********/
            MonitorColorScheme scheme = MonitorColorScheme.AutoDetect;
            if (platform == Platform.Linux || platform == Platform.Mac)
            {
                /****
                ** print header
                ****/
                this.PrintPlain("Hi there! I'll help you install or remove SMAPI. Just a few questions first.");
                this.PrintPlain("----------------------------------------------------------------------------");
                Console.WriteLine();

                /****
                ** show theme selector
                ****/
                // get theme writers
                var lightBackgroundWriter = new ColorfulConsoleWriter(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.LightBackground));
                var darkBackgroundWriter  = new ColorfulConsoleWriter(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.DarkBackground));

                // print question
                this.PrintPlain("Which text looks more readable?");
                Console.WriteLine();
                Console.Write("   [1] ");
                lightBackgroundWriter.WriteLine("Dark text on light background", ConsoleLogLevel.Info);
                Console.Write("   [2] ");
                darkBackgroundWriter.WriteLine("Light text on dark background", ConsoleLogLevel.Info);
                Console.WriteLine();

                // handle choice
                string choice = this.InteractivelyChoose("Type 1 or 2, then press enter.", new[] { "1", "2" });
                switch (choice)
                {
                case "1":
                    scheme             = MonitorColorScheme.LightBackground;
                    this.ConsoleWriter = lightBackgroundWriter;
                    break;

                case "2":
                    scheme             = MonitorColorScheme.DarkBackground;
                    this.ConsoleWriter = darkBackgroundWriter;
                    break;

                default:
                    throw new InvalidOperationException($"Unexpected action key '{choice}'.");
                }
            }
            Console.Clear();


            /*********
            ** Step 3: find game folder
            *********/
            InstallerPaths paths;
            {
                /****
                ** print header
                ****/
                this.PrintInfo("Hi there! I'll help you install or remove SMAPI. Just a few questions first.");
                this.PrintDebug($"Color scheme: {this.GetDisplayText(scheme)}");
                this.PrintDebug("----------------------------------------------------------------------------");
                Console.WriteLine();

                /****
                ** collect details
                ****/
                // get game path
                this.PrintInfo("Where is your game folder?");
                DirectoryInfo installDir = this.InteractivelyGetInstallPath(platform, toolkit, gamePathArg);
                if (installDir == null)
                {
                    this.PrintError("Failed finding your game path.");
                    Console.ReadLine();
                    return;
                }

                // get folders
                DirectoryInfo bundleDir = new DirectoryInfo(this.BundlePath);
                paths = new InstallerPaths(bundleDir, installDir, EnvironmentUtility.GetExecutableName(platform));
            }
            Console.Clear();


            /*********
            ** Step 4: validate assumptions
            *********/
            if (!File.Exists(paths.ExecutablePath))
            {
                this.PrintError("The detected game install path doesn't contain a Stardew Valley executable.");
                Console.ReadLine();
                return;
            }


            /*********
            ** Step 5: ask what to do
            *********/
            ScriptAction action;
            {
                /****
                ** print header
                ****/
                this.PrintInfo("Hi there! I'll help you install or remove SMAPI. Just one question first.");
                this.PrintDebug($"Game path: {paths.GamePath}");
                this.PrintDebug($"Color scheme: {this.GetDisplayText(scheme)}");
                this.PrintDebug("----------------------------------------------------------------------------");
                Console.WriteLine();

                /****
                ** ask what to do
                ****/
                if (installArg)
                {
                    action = ScriptAction.Install;
                }
                else if (uninstallArg)
                {
                    action = ScriptAction.Uninstall;
                }
                else
                {
                    this.PrintInfo("What do you want to do?");
                    Console.WriteLine();
                    this.PrintInfo("[1] Install SMAPI.");
                    this.PrintInfo("[2] Uninstall SMAPI.");
                    Console.WriteLine();

                    string choice = this.InteractivelyChoose("Type 1 or 2, then press enter.", new[] { "1", "2" });
                    switch (choice)
                    {
                    case "1":
                        action = ScriptAction.Install;
                        break;

                    case "2":
                        action = ScriptAction.Uninstall;
                        break;

                    default:
                        throw new InvalidOperationException($"Unexpected action key '{choice}'.");
                    }
                }
            }
            Console.Clear();


            /*********
            ** Step 6: apply
            *********/
            {
                /****
                ** print header
                ****/
                this.PrintInfo($"That's all I need! I'll {action.ToString().ToLower()} SMAPI now.");
                this.PrintDebug($"Game path: {paths.GamePath}");
                this.PrintDebug($"Color scheme: {this.GetDisplayText(scheme)}");
                this.PrintDebug("----------------------------------------------------------------------------");
                Console.WriteLine();

                /****
                ** Back up user settings
                ****/
                if (File.Exists(paths.ApiUserConfigPath))
                {
                    File.Copy(paths.ApiUserConfigPath, paths.BundleApiUserConfigPath);
                }

                /****
                ** Always uninstall old files
                ****/
                // restore game launcher
                if (platform.IsMono() && File.Exists(paths.UnixBackupLauncherPath))
                {
                    this.PrintDebug("Removing SMAPI launcher...");
                    this.InteractivelyDelete(paths.UnixLauncherPath);
                    File.Move(paths.UnixBackupLauncherPath, paths.UnixLauncherPath);
                }

                // remove old files
                string[] removePaths = this.GetUninstallPaths(paths.GameDir, paths.ModsDir)
                                       .Where(path => Directory.Exists(path) || File.Exists(path))
                                       .ToArray();
                if (removePaths.Any())
                {
                    this.PrintDebug(action == ScriptAction.Install ? "Removing previous SMAPI files..." : "Removing SMAPI files...");
                    foreach (string path in removePaths)
                    {
                        this.InteractivelyDelete(path);
                    }
                }

                // move global save data folder (changed in 3.2)
                {
                    string        dataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley");
                    DirectoryInfo oldDir   = new DirectoryInfo(Path.Combine(dataPath, "Saves", ".smapi"));
                    DirectoryInfo newDir   = new DirectoryInfo(Path.Combine(dataPath, ".smapi"));

                    if (oldDir.Exists)
                    {
                        if (newDir.Exists)
                        {
                            this.InteractivelyDelete(oldDir.FullName);
                        }
                        else
                        {
                            oldDir.MoveTo(newDir.FullName);
                        }
                    }
                }

                /****
                ** Install new files
                ****/
                if (action == ScriptAction.Install)
                {
                    // copy SMAPI files to game dir
                    this.PrintDebug("Adding SMAPI files...");
                    foreach (FileSystemInfo sourceEntry in paths.BundleDir.EnumerateFileSystemInfos().Where(this.ShouldCopy))
                    {
                        this.InteractivelyDelete(Path.Combine(paths.GameDir.FullName, sourceEntry.Name));
                        this.RecursiveCopy(sourceEntry, paths.GameDir);
                    }

                    // replace mod launcher (if possible)
                    if (platform.IsMono())
                    {
                        this.PrintDebug("Safely replacing game launcher...");

                        // back up & remove current launcher
                        if (File.Exists(paths.UnixLauncherPath))
                        {
                            if (!File.Exists(paths.UnixBackupLauncherPath))
                            {
                                File.Move(paths.UnixLauncherPath, paths.UnixBackupLauncherPath);
                            }
                            else
                            {
                                this.InteractivelyDelete(paths.UnixLauncherPath);
                            }
                        }

                        // add new launcher
                        File.Move(paths.UnixSmapiLauncherPath, paths.UnixLauncherPath);

                        // mark file executable
                        // (MSBuild doesn't keep permission flags for files zipped in a build task.)
                        // (Note: exclude from Windows build because antivirus apps can flag the process start code as suspicious.)
#if !SMAPI_FOR_WINDOWS
                        new Process
                        {
                            StartInfo = new ProcessStartInfo
                            {
                                FileName       = "chmod",
                                Arguments      = $"755 \"{paths.UnixLauncherPath}\"",
                                CreateNoWindow = true
                            }
                        }.Start();
#endif
                    }

                    // create mods directory (if needed)
                    if (!paths.ModsDir.Exists)
                    {
                        this.PrintDebug("Creating mods directory...");
                        paths.ModsDir.Create();
                    }

                    // add or replace bundled mods
                    DirectoryInfo bundledModsDir = new DirectoryInfo(Path.Combine(paths.BundlePath, "Mods"));
                    if (bundledModsDir.Exists && bundledModsDir.EnumerateDirectories().Any())
                    {
                        this.PrintDebug("Adding bundled mods...");

                        ModFolder[] targetMods = toolkit.GetModFolders(paths.ModsPath).ToArray();
                        foreach (ModFolder sourceMod in toolkit.GetModFolders(bundledModsDir.FullName))
                        {
                            // validate source mod
                            if (sourceMod.Manifest == null)
                            {
                                this.PrintWarning($"   ignored invalid bundled mod {sourceMod.DisplayName}: {sourceMod.ManifestParseError}");
                                continue;
                            }
                            if (!this.BundledModIDs.Contains(sourceMod.Manifest.UniqueID))
                            {
                                this.PrintWarning($"   ignored unknown '{sourceMod.DisplayName}' mod in the installer folder. To add mods, put them here instead: {paths.ModsPath}");
                                continue;
                            }

                            // find target folder
                            ModFolder     targetMod           = targetMods.FirstOrDefault(p => p.Manifest?.UniqueID?.Equals(sourceMod.Manifest.UniqueID, StringComparison.OrdinalIgnoreCase) == true);
                            DirectoryInfo defaultTargetFolder = new DirectoryInfo(Path.Combine(paths.ModsPath, sourceMod.Directory.Name));
                            DirectoryInfo targetFolder        = targetMod?.Directory ?? defaultTargetFolder;
                            this.PrintDebug(targetFolder.FullName == defaultTargetFolder.FullName
                                ? $"   adding {sourceMod.Manifest.Name}..."
                                : $"   adding {sourceMod.Manifest.Name} to {Path.Combine(paths.ModsDir.Name, PathUtilities.GetRelativePath(paths.ModsPath, targetFolder.FullName))}..."
                                            );

                            // remove existing folder
                            if (targetFolder.Exists)
                            {
                                this.InteractivelyDelete(targetFolder.FullName);
                            }

                            // copy files
                            this.RecursiveCopy(sourceMod.Directory, paths.ModsDir, filter: this.ShouldCopy);
                        }
                    }

                    // set SMAPI's color scheme if defined
                    if (scheme != MonitorColorScheme.AutoDetect)
                    {
                        string text = File
                                      .ReadAllText(paths.ApiConfigPath)
                                      .Replace(@"""UseScheme"": ""AutoDetect""", $@"""UseScheme"": ""{scheme}""");
                        File.WriteAllText(paths.ApiConfigPath, text);
                    }

                    // remove obsolete appdata mods
                    this.InteractivelyRemoveAppDataMods(paths.ModsDir, bundledModsDir);
                }
            }
            Console.WriteLine();
            Console.WriteLine();


            /*********
            ** Step 7: final instructions
            *********/
            if (platform == Platform.Windows)
            {
                if (action == ScriptAction.Install)
                {
                    this.PrintSuccess("SMAPI is installed! If you use Steam, set your launch options to enable achievements (see smapi.io/install):");
                    this.PrintSuccess($"    \"{Path.Combine(paths.GamePath, "StardewModdingAPI.exe")}\" %command%");
                    Console.WriteLine();
                    this.PrintSuccess("If you don't use Steam, launch StardewModdingAPI.exe in your game folder to play with mods.");
                }
                else
                {
                    this.PrintSuccess("SMAPI is removed! If you configured Steam to launch SMAPI, don't forget to clear your launch options.");
                }
            }
            else
            {
                this.PrintSuccess(action == ScriptAction.Install
                    ? "SMAPI is installed! Launch the game the same way as before to play with mods."
                    : "SMAPI is removed! Launch the game the same way as before to play without mods."
                                  );
            }

            Console.ReadKey();
        }
Beispiel #5
0
        protected async Task <TResult> RunIsolatedAsync(string configurationFile)
        {
            var assemblyDirectory = AssemblyPaths.Any() ? Path.GetDirectoryName(Path.GetFullPath(PathUtilities.ExpandFileWildcards(AssemblyPaths).First())) : configurationFile;
            var bindingRedirects  = GetBindingRedirects();
            var assemblies        = GetAssemblies(assemblyDirectory);

            if (UseNuGetCache)
            {
                var defaultNugetPackages = LoadDefaultNugetCache();
                ReferencePaths = ReferencePaths.Concat(defaultNugetPackages).ToArray();
            }

            using (var isolated = new AppDomainIsolation <IsolatedCommandAssemblyLoader <TResult> >(assemblyDirectory, AssemblyConfig, bindingRedirects, assemblies))
            {
                return(await Task.Run(() => isolated.Object.Run(GetType().FullName, JsonConvert.SerializeObject(this), AssemblyPaths, ReferencePaths)).ConfigureAwait(false));
            }
        }
Beispiel #6
0
 public override PortableExecutableReference GetReference(string fullPath, MetadataReferenceProperties properties = default(MetadataReferenceProperties))
 {
     Debug.Assert(PathUtilities.IsAbsolute(fullPath));
     return(new CachingMetadataReference(fullPath, properties));
 }
Beispiel #7
0
 protected override bool CanImportCore(Stream stream, string filename = null)
 {
     return(PathUtilities.MatchesAnyExtension(filename, Extensions));
 }
 // virtual for testing
 protected virtual bool IsVisibleFileSystemEntry(string fullPath)
 {
     Debug.Assert(PathUtilities.IsAbsolute(fullPath));
     return(IOUtilities.PerformIO(() => (File.GetAttributes(fullPath) & (FileAttributes.Hidden | FileAttributes.System)) == 0, false));
 }
 private CompletionItem CreateFileSystemEntryItem(string fullPath, bool isDirectory)
 => CommonCompletionItem.Create(
     PathUtilities.GetFileName(fullPath),
     glyph: isDirectory ? _folderGlyph : _fileGlyph,
     description: fullPath.ToSymbolDisplayParts(),
     rules: _itemRules);
 // virtual for testing
 protected virtual bool DirectoryExists(string fullPath)
 {
     Debug.Assert(PathUtilities.IsAbsolute(fullPath));
     return(Directory.Exists(fullPath));
 }
 // virtual for testing
 protected virtual IEnumerable <string> EnumerateFiles(string fullDirectoryPath)
 {
     Debug.Assert(PathUtilities.IsAbsolute(fullDirectoryPath));
     return(IOUtilities.PerformIO(() => Directory.EnumerateFiles(fullDirectoryPath), Array.Empty <string>()));
 }
        // internal for testing
        internal ImmutableArray <CompletionItem> GetItems(string directoryPath, CancellationToken cancellationToken)
        {
            if (!PathUtilities.IsUnixLikePlatform && directoryPath.Length == 1 && directoryPath[0] == '\\')
            {
                // The user has typed only "\".  In this case, we want to add "\\" to the list.
                return(ImmutableArray.Create(CreateNetworkRoot()));
            }

            var result = ArrayBuilder <CompletionItem> .GetInstance();

            var pathKind = PathUtilities.GetPathKind(directoryPath);

            switch (pathKind)
            {
            case PathKind.Empty:
                // base directory
                if (_baseDirectoryOpt != null)
                {
                    result.AddRange(GetItemsInDirectory(_baseDirectoryOpt, cancellationToken));
                }

                // roots
                if (PathUtilities.IsUnixLikePlatform)
                {
                    result.AddRange(CreateUnixRoot());
                }
                else
                {
                    foreach (var drive in GetLogicalDrives())
                    {
                        result.Add(CreateLogicalDriveItem(drive.TrimEnd(s_windowsDirectorySeparator)));
                    }

                    result.Add(CreateNetworkRoot());
                }

                // entries on search paths
                foreach (var searchPath in _searchPaths)
                {
                    result.AddRange(GetItemsInDirectory(searchPath, cancellationToken));
                }

                break;

            case PathKind.Absolute:
            case PathKind.RelativeToCurrentDirectory:
            case PathKind.RelativeToCurrentParent:
            case PathKind.RelativeToCurrentRoot:
                var fullDirectoryPath = FileUtilities.ResolveRelativePath(directoryPath, basePath: null, baseDirectory: _baseDirectoryOpt);
                if (fullDirectoryPath != null)
                {
                    result.AddRange(GetItemsInDirectory(fullDirectoryPath, cancellationToken));
                }
                else
                {
                    // invalid path
                    result.Clear();
                }

                break;

            case PathKind.Relative:

                // base directory:
                if (_baseDirectoryOpt != null)
                {
                    result.AddRange(GetItemsInDirectory(PathUtilities.CombineAbsoluteAndRelativePaths(_baseDirectoryOpt, directoryPath), cancellationToken));
                }

                // search paths:
                foreach (var searchPath in _searchPaths)
                {
                    result.AddRange(GetItemsInDirectory(PathUtilities.CombineAbsoluteAndRelativePaths(searchPath, directoryPath), cancellationToken));
                }

                break;

            case PathKind.RelativeToDriveDirectory:
                // Paths "C:dir" are not supported, but when the path doesn't include any directory, i.e. "C:",
                // we return the drive itself.
                if (directoryPath.Length == 2)
                {
                    result.Add(CreateLogicalDriveItem(directoryPath));
                }

                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(pathKind);
            }

            return(result.ToImmutableAndFree());
        }
Beispiel #13
0
 private void TestChangeExtension(string path, string extension, string expected)
 {
     Assert.Equal(expected, PathUtilities.ChangeExtension(path, extension));
     Assert.Equal(expected, Path.ChangeExtension(path, extension));
 }
Beispiel #14
0
 private void TestRemoveExtension(string path, string expected)
 {
     Assert.Equal(expected, PathUtilities.RemoveExtension(path));
     Assert.Equal(expected, Path.GetFileNameWithoutExtension(path));
 }
Beispiel #15
0
        protected override async Task <CommandResult> ExecuteAsync(
            string path,
            MSBuildWorkspace workspace,
            IProgress <ProjectLoadProgress> progress = null,
            CancellationToken cancellationToken      = default(CancellationToken))
        {
            if (!string.Equals(Path.GetExtension(path), ".sln", StringComparison.OrdinalIgnoreCase))
            {
                WriteLine($"File is not a solution file: '{path}'.", ConsoleColor.Red, Verbosity.Minimal);
                return(CommandResult.Fail);
            }

            workspace.LoadMetadataForReferencedProjects = true;

            var consoleProgress = new ConsoleProgressReporter(shouldSaveProgress: true);

            var loader = new MSBuildProjectLoader(workspace);

            WriteLine($"Load solution '{path}'", Verbosity.Minimal);

            SolutionInfo solutionInfo = await loader.LoadSolutionInfoAsync(path, consoleProgress, cancellationToken);

            string solutionDirectory = Path.GetDirectoryName(solutionInfo.FilePath);

            Dictionary <string, ImmutableArray <ProjectInfo> > projectInfos = solutionInfo.Projects
                                                                              .GroupBy(f => f.FilePath)
                                                                              .ToDictionary(f => f.Key, f => f.ToImmutableArray());

            Dictionary <string, List <string> > projects = consoleProgress.Projects;

            int nameMaxLength = projects.Max(f => Path.GetFileNameWithoutExtension(f.Key).Length);

            int targetFrameworksMaxLength = projects.Max(f =>
            {
                List <string> frameworks = f.Value;

                return((frameworks != null) ? $"({string.Join(", ", frameworks)})".Length : 0);
            });

            bool anyHasTargetFrameworks = projects.Any(f => f.Value != null);

            WriteLine();
            WriteLine($"{projects.Count} {((projects.Count == 1) ? "project" : "projects")} found in solution '{Path.GetFileNameWithoutExtension(solutionInfo.FilePath)}' [{solutionInfo.FilePath}]", ConsoleColor.Green, Verbosity.Minimal);

            foreach (KeyValuePair <string, List <string> > kvp in projects
                     .OrderBy(f => Path.GetFileName(f.Key)))
            {
                string        projectPath      = kvp.Key;
                List <string> targetFrameworks = kvp.Value;

                ProjectInfo projectInfo = projectInfos[projectPath][0];

                string projectName = Path.GetFileNameWithoutExtension(projectPath);

                Write($"  {projectName.PadRight(nameMaxLength)}  {projectInfo.Language}", Verbosity.Normal);

                if (anyHasTargetFrameworks)
                {
                    Write("  ", Verbosity.Normal);
                }

                if (targetFrameworks != null)
                {
                    string targetFrameworksText = $"({string.Join(", ", targetFrameworks.OrderBy(f => f))})";
                    Write(targetFrameworksText.PadRight(targetFrameworksMaxLength), Verbosity.Normal);
                }
                else
                {
                    Write(new string(' ', targetFrameworksMaxLength), Verbosity.Normal);
                }

                WriteLine($"  [{PathUtilities.TrimStart(projectPath, solutionDirectory)}]", Verbosity.Normal);
            }

            WriteLine();

            return(CommandResult.Success);
        }
Beispiel #16
0
 public static bool IsSamePath(string p1, string p2)
 => PathUtilities.PathsEqual(Environment.ExpandEnvironmentVariables(p1), Environment.ExpandEnvironmentVariables(p2));
 protected virtual bool FileExists(string fullPath)
 {
     Debug.Assert(fullPath == null || PathUtilities.IsAbsolute(fullPath));
     return(File.Exists(fullPath));
 }
Beispiel #18
0
        public override Compilation CreateCompilation(TextWriter consoleOutput, TouchedFileLogger touchedFilesLogger, ErrorLogger errorLogger)
        {
            var parseOptions = Arguments.ParseOptions;

            // We compute script parse options once so we don't have to do it repeatedly in
            // case there are many script files.
            var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script);

            bool hadErrors = false;

            var sourceFiles         = Arguments.SourceFiles;
            var trees               = new SyntaxTree[sourceFiles.Length];
            var normalizedFilePaths = new string[sourceFiles.Length];
            var diagnosticBag       = DiagnosticBag.GetInstance();

            if (Arguments.CompilationOptions.ConcurrentBuild)
            {
                Parallel.For(0, sourceFiles.Length, UICultureUtilities.WithCurrentUICulture <int>(i =>
                {
                    //NOTE: order of trees is important!!
                    trees[i] = ParseFile(parseOptions, scriptParseOptions, ref hadErrors, sourceFiles[i], diagnosticBag, out normalizedFilePaths[i]);
                }));
            }
            else
            {
                for (int i = 0; i < sourceFiles.Length; i++)
                {
                    //NOTE: order of trees is important!!
                    trees[i] = ParseFile(parseOptions, scriptParseOptions, ref hadErrors, sourceFiles[i], diagnosticBag, out normalizedFilePaths[i]);
                }
            }

            // If errors had been reported in ParseFile, while trying to read files, then we should simply exit.
            if (hadErrors)
            {
                Debug.Assert(diagnosticBag.HasAnyErrors());
                ReportErrors(diagnosticBag.ToReadOnlyAndFree(), consoleOutput, errorLogger);
                return(null);
            }
            else
            {
                Debug.Assert(diagnosticBag.IsEmptyWithoutResolution);
                diagnosticBag.Free();
            }

            var diagnostics = new List <DiagnosticInfo>();

            var uniqueFilePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            for (int i = 0; i < sourceFiles.Length; i++)
            {
                var normalizedFilePath = normalizedFilePaths[i];
                Debug.Assert(normalizedFilePath != null);
                Debug.Assert(PathUtilities.IsAbsolute(normalizedFilePath));

                if (!uniqueFilePaths.Add(normalizedFilePath))
                {
                    // warning CS2002: Source file '{0}' specified multiple times
                    diagnostics.Add(new DiagnosticInfo(MessageProvider, (int)ErrorCode.WRN_FileAlreadyIncluded,
                                                       Arguments.PrintFullPaths ? normalizedFilePath : _diagnosticFormatter.RelativizeNormalizedPath(normalizedFilePath)));

                    trees[i] = null;
                }
            }

            if (Arguments.TouchedFilesPath != null)
            {
                foreach (var path in uniqueFilePaths)
                {
                    touchedFilesLogger.AddRead(path);
                }
            }

            var assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default;
            var appConfigPath            = this.Arguments.AppConfigPath;

            if (appConfigPath != null)
            {
                try
                {
                    using (var appConfigStream = new FileStream(appConfigPath, FileMode.Open, FileAccess.Read))
                    {
                        assemblyIdentityComparer = DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream);
                    }

                    if (touchedFilesLogger != null)
                    {
                        touchedFilesLogger.AddRead(appConfigPath);
                    }
                }
                catch (Exception ex)
                {
                    diagnostics.Add(new DiagnosticInfo(MessageProvider, (int)ErrorCode.ERR_CantReadConfigFile, appConfigPath, ex.Message));
                }
            }

            var xmlFileResolver    = new LoggingXmlFileResolver(Arguments.BaseDirectory, touchedFilesLogger);
            var sourceFileResolver = new LoggingSourceFileResolver(ImmutableArray <string> .Empty, Arguments.BaseDirectory, Arguments.PathMap, touchedFilesLogger);

            MetadataReferenceResolver referenceDirectiveResolver;
            var resolvedReferences = ResolveMetadataReferences(diagnostics, touchedFilesLogger, out referenceDirectiveResolver);

            if (ReportErrors(diagnostics, consoleOutput, errorLogger))
            {
                return(null);
            }

            var strongNameProvider = new LoggingStrongNameProvider(Arguments.KeyFileSearchPaths, touchedFilesLogger, _tempDirectory);

            var compilation = CSharpCompilation.Create(
                Arguments.CompilationName,
                trees.WhereNotNull(),
                resolvedReferences,
                Arguments.CompilationOptions.
                WithMetadataReferenceResolver(referenceDirectiveResolver).
                WithAssemblyIdentityComparer(assemblyIdentityComparer).
                WithStrongNameProvider(strongNameProvider).
                WithXmlReferenceResolver(xmlFileResolver).
                WithSourceReferenceResolver(sourceFileResolver));

            return(compilation);
        }
Beispiel #19
0
        public void Write(ProxyFile file, CancellationToken token)
        {
            //Cancel if requested;
            token.ThrowIfCancellationRequested();

            var header            = file.Header;
            var proxyContentFiles = file.ContentFiles.OfType <ProxyContentFile>();

            //For now replacement write is not supported...

            bool allContentFilesLoaded = proxyContentFiles.All(x => x.IsContentLoaded);

            if (allContentFilesLoaded)
            {
                using (var target = new FileStream(file.Path, FileMode.OpenOrCreate))
                {
                    uint fileTableOffset = (uint)Marshal.SizeOf(typeof(ProxyHeader));
                    //Póki co może być obliczona z ilości proxyContentFiles, bo to z nich zostanę utworzone wpisy fileTableEntries
                    //Sytuacja by się zmieniła jeśli te wpisy byłby by przechowywane od momentu odczytu, anie odrzuacane i odtwarzane jak obecnie.
                    uint fileTableLength = (uint)proxyContentFiles.Count() * ProxyFileTableEntry.EntryLength;

                    uint contentOffset    = fileTableOffset + fileTableLength;
                    var  contentWriteInfo = WriteLoadedContentFiles(target, contentOffset, proxyContentFiles, token);

                    //We are writing fileTable entries after writing the content, because we need to write actual offsets and lengths of content files.
                    var fileTableEntries = CreateFileTableEntries(proxyContentFiles);
                    WriteFileTableEntries(target, (uint)fileTableOffset, fileTableEntries);

                    uint pathTableOffset  = contentOffset + contentWriteInfo.Length;
                    uint pathTableLength  = (uint)proxyContentFiles.Count() * ProxyPathTableEntry.EntryLength;
                    var  pathTableEntries = CreatePathTableEntries(proxyContentFiles);
                    WritePathTableEntries(target, pathTableOffset, pathTableEntries);

                    header.FileTableOffset       = fileTableOffset;
                    header.FileTableLength       = fileTableLength;
                    header.FileTableEntriesCount = (uint)fileTableEntries.Count();
                    header.ContentOffset         = contentOffset;
                    header.ContentLength         = contentWriteInfo.Length;
                    header.PathTableOffset       = pathTableOffset;
                    header.PathTableLength       = pathTableLength;
                    header.PathTableEntriesCount = (uint)pathTableEntries.Count();

                    WriteHeader(target, header);
                }
            }
            else
            {
                //We are checking it here, since when the content is not loaded, the file have to exist
                //so it could be read for content.
                if (!File.Exists(file.Path))
                {
                    throw new ArgumentException(
                              String.Format("A following ProxyPCPC file: \"{0}\" doesn't exist", file.Path),
                              "edataFile");
                }

                String temporaryProxyPath = PathUtilities.GetTemporaryPath(file.Path);

                //To avoid too many nested try catches.
                FileStream source = null;
                FileStream target = null;
                try
                {
                    source = new FileStream(file.Path, FileMode.Open);
                    target = new FileStream(temporaryProxyPath, FileMode.Create);

                    uint fileTableOffset = (uint)Marshal.SizeOf(typeof(ProxyHeader));
                    //Póki co może być obliczona z ilości proxyContentFiles, bo to z nich zostanę utworzone wpisy fileTableEntries
                    //Sytuacja by się zmieniła jeśli te wpisy byłby by przechowywane od momentu odczytu, anie odrzuacane i odtwarzane jak obecnie.
                    uint fileTableLength = (uint)proxyContentFiles.Count() * ProxyFileTableEntry.EntryLength;

                    uint contentOffset    = fileTableOffset + fileTableLength;
                    var  contentWriteInfo = WriteNotLoadedContentFiles(source, target, contentOffset, proxyContentFiles, token);

                    //We are writing fileTable entries after writing the content, because we need to write actual offsets and lengths of content files.
                    var fileTableEntries = CreateFileTableEntries(proxyContentFiles);
                    WriteFileTableEntries(target, (uint)fileTableOffset, fileTableEntries);

                    uint pathTableOffset  = contentOffset + contentWriteInfo.Length;
                    uint pathTableLength  = (uint)proxyContentFiles.Count() * ProxyPathTableEntry.EntryLength;
                    var  pathTableEntries = CreatePathTableEntries(proxyContentFiles);
                    WritePathTableEntries(target, pathTableOffset, pathTableEntries);

                    header.FileTableOffset       = fileTableOffset;
                    header.FileTableLength       = fileTableLength;
                    header.FileTableEntriesCount = (uint)fileTableEntries.Count();
                    header.ContentOffset         = contentOffset;
                    header.ContentLength         = contentWriteInfo.Length;
                    header.PathTableOffset       = pathTableOffset;
                    header.PathTableLength       = pathTableLength;
                    header.PathTableEntriesCount = (uint)pathTableEntries.Count();

                    WriteHeader(target, header);

                    //Free file handles before the file move and delete
                    CloseStreams(source, target);

                    //Replace temporary file
                    File.Delete(file.Path);
                    File.Move(temporaryProxyPath, file.Path);
                }
                finally
                {
                    //Spr czy zostały już zwolnione...?
                    CloseStreams(source, target);

                    if (File.Exists(temporaryProxyPath))
                    {
                        File.Delete(temporaryProxyPath);
                    }
                }
            }
        }
Beispiel #20
0
 public static List <string> GetAdditionalLibraryDirectories(this VCLinkerTool tool) =>
 PathUtilities.SplitPaths(tool.AdditionalLibraryDirectories, ';', ',');
Beispiel #21
0
 private void _openPDF_Click(object sender, EventArgs e)
 {
     PathUtilities.OpenFileInApplication(_model.PdfFilePath);
 }
Beispiel #22
0
 public static List <string> GetAdditionalDependencies(this VCLinkerTool tool) =>
 PathUtilities.SplitPathsByWhitespace(tool.AdditionalDependencies);
Beispiel #23
0
        /// <summary>
        /// Generates the LSIF content for a single document.
        /// </summary>
        /// <returns>The ID of the outputted Document vertex.</returns>
        /// <remarks>
        /// The high level algorithm here is we are going to walk across each token, produce a <see cref="Graph.Range"/> for that token's span,
        /// bind that token, and then link up the various features. So we'll link that range to the symbols it defines or references,
        /// will link it to results like Quick Info, and more. This method has a <paramref name="topLevelSymbolsResultSetTracker"/> that
        /// lets us link symbols across files, and will only talk about "top level" symbols that aren't things like locals that can't
        /// leak outside a file.
        /// </remarks>
        private static Id <Graph.LsifDocument> GenerateForDocument(
            SemanticModel semanticModel,
            HostLanguageServices languageServices,
            OptionSet options,
            IResultSetTracker topLevelSymbolsResultSetTracker,
            ILsifJsonWriter lsifJsonWriter,
            IdFactory idFactory)
        {
            var syntaxTree           = semanticModel.SyntaxTree;
            var sourceText           = semanticModel.SyntaxTree.GetText();
            var syntaxFactsService   = languageServices.GetRequiredService <ISyntaxFactsService>();
            var semanticFactsService = languageServices.GetRequiredService <ISemanticFactsService>();

            string?contentBase64Encoded = null;

            // TODO: move to checking the enum member mentioned in https://github.com/dotnet/roslyn/issues/49326 when that
            // is implemented. In the mean time, we'll use a heuristic of the path being a relative path as a way to indicate
            // this is a source generated file.
            if (!PathUtilities.IsAbsolute(syntaxTree.FilePath))
            {
                var text = semanticModel.SyntaxTree.GetText();

                // We always use UTF-8 encoding when writing out file contents, as that's expected by LSIF implementations.
                // TODO: when we move to .NET Core, is there a way to reduce allocatios here?
                contentBase64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(text.ToString()));
            }

            var documentVertex = new Graph.LsifDocument(new Uri(syntaxTree.FilePath, UriKind.RelativeOrAbsolute), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory);

            lsifJsonWriter.Write(documentVertex);
            lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory));

            // As we are processing this file, we are going to encounter symbols that have a shared resultSet with other documents like types
            // or methods. We're also going to encounter locals that never leave this document. We don't want those locals being held by
            // the topLevelSymbolsResultSetTracker, so we'll make another tracker for document local symbols, and then have a delegating
            // one that picks the correct one of the two.
            var documentLocalSymbolsResultSetTracker = new SymbolHoldingResultSetTracker(lsifJsonWriter, semanticModel.Compilation, idFactory);
            var symbolResultsTracker = new DelegatingResultSetTracker(symbol =>
            {
                if (symbol.Kind == SymbolKind.Local ||
                    symbol.Kind == SymbolKind.RangeVariable ||
                    symbol.Kind == SymbolKind.Label)
                {
                    // These symbols can go in the document local one because they can't escape methods
                    return(documentLocalSymbolsResultSetTracker);
                }
                else if (symbol.ContainingType != null && symbol.DeclaredAccessibility == Accessibility.Private && symbol.ContainingType.Locations.Length == 1)
                {
                    // This is a private member in a class that isn't partial, so it can't escape the file
                    return(documentLocalSymbolsResultSetTracker);
                }
                else
                {
                    return(topLevelSymbolsResultSetTracker);
                }
            });

            // We will walk the file token-by-token, making a range for each one and then attaching information for it
            var rangeVertices = new List <Id <Graph.Range> >();

            foreach (var syntaxToken in syntaxTree.GetRoot().DescendantTokens(descendIntoTrivia: true))
            {
                // We'll only create the Range vertex once it's needed, but any number of bits of code might create it first,
                // so we'll just make it Lazy.
                var lazyRangeVertex = new Lazy <Graph.Range>(() =>
                {
                    var rangeVertex = Graph.Range.FromTextSpan(syntaxToken.Span, sourceText, idFactory);

                    lsifJsonWriter.Write(rangeVertex);
                    rangeVertices.Add(rangeVertex.GetId());

                    return(rangeVertex);
                }, LazyThreadSafetyMode.None);

                var     declaredSymbol   = semanticFactsService.GetDeclaredSymbol(semanticModel, syntaxToken, CancellationToken.None);
                ISymbol?referencedSymbol = null;

                if (syntaxFactsService.IsBindableToken(syntaxToken))
                {
                    var bindableParent = syntaxFactsService.TryGetBindableParent(syntaxToken);

                    if (bindableParent != null)
                    {
                        var symbolInfo = semanticModel.GetSymbolInfo(bindableParent);
                        if (symbolInfo.Symbol != null && IncludeSymbolInReferences(symbolInfo.Symbol))
                        {
                            referencedSymbol = symbolInfo.Symbol;
                        }
                    }
                }

                if (declaredSymbol != null || referencedSymbol != null)
                {
                    // For now, we will link the range to the original definition, preferring the definition, as this is the symbol
                    // that would be used if we invoke a feature on this range. This is analogous to the logic in
                    // SymbolFinder.FindSymbolAtPositionAsync where if a token is both a reference and definition we'll prefer the
                    // definition. Once we start supporting hover we'll have to remove the "original definition" part of this, since
                    // since we show different contents for different constructed types there.
                    var symbolForLinkedResultSet   = (declaredSymbol ?? referencedSymbol) !.OriginalDefinition;
                    var symbolForLinkedResultSetId = symbolResultsTracker.GetResultSetIdForSymbol(symbolForLinkedResultSet);
                    lsifJsonWriter.Write(Edge.Create("next", lazyRangeVertex.Value.GetId(), symbolForLinkedResultSetId, idFactory));

                    if (declaredSymbol != null)
                    {
                        var definitionResultsId = symbolResultsTracker.GetResultIdForSymbol(declaredSymbol, Methods.TextDocumentDefinitionName, () => new DefinitionResult(idFactory));
                        lsifJsonWriter.Write(new Item(definitionResultsId.As <DefinitionResult, Vertex>(), lazyRangeVertex.Value.GetId(), documentVertex.GetId(), idFactory));
                    }

                    if (referencedSymbol != null)
                    {
                        // Create the link from the references back to this range. Note: this range can be reference to a
                        // symbol but the range can point a different symbol's resultSet. This can happen if the token is
                        // both a definition of a symbol (where we will point to the definition) but also a reference to some
                        // other symbol.
                        var referenceResultsId = symbolResultsTracker.GetResultIdForSymbol(referencedSymbol.OriginalDefinition, Methods.TextDocumentReferencesName, () => new ReferenceResult(idFactory));
                        lsifJsonWriter.Write(new Item(referenceResultsId.As <ReferenceResult, Vertex>(), lazyRangeVertex.Value.GetId(), documentVertex.GetId(), idFactory, property: "references"));
                    }

                    // Write hover information for the symbol, if edge has not already been added.
                    // 'textDocument/hover' edge goes from the symbol ResultSet vertex to the hover result
                    // See https://github.com/Microsoft/language-server-protocol/blob/main/indexFormat/specification.md#resultset for an example.
                    if (symbolResultsTracker.ResultSetNeedsInformationalEdgeAdded(symbolForLinkedResultSet, Methods.TextDocumentHoverName))
                    {
                        // TODO: Can we avoid the WaitAndGetResult_CanCallOnBackground call by adding a sync method to compute hover?
                        var hover = HoverHandler.GetHoverAsync(semanticModel, syntaxToken.SpanStart, languageServices, CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None);
                        if (hover != null)
                        {
                            var hoverResult = new HoverResult(hover, idFactory);
                            lsifJsonWriter.Write(hoverResult);
                            lsifJsonWriter.Write(Edge.Create(Methods.TextDocumentHoverName, symbolForLinkedResultSetId, hoverResult.GetId(), idFactory));
                        }
                    }
                }
            }

            lsifJsonWriter.Write(Edge.Create("contains", documentVertex.GetId(), rangeVertices, idFactory));

            // Write the folding ranges for the document.
            var foldingRanges      = FoldingRangesHandler.GetFoldingRanges(syntaxTree, languageServices, options, isMetadataAsSource: false, CancellationToken.None);
            var foldingRangeResult = new FoldingRangeResult(foldingRanges, idFactory);

            lsifJsonWriter.Write(foldingRangeResult);
            lsifJsonWriter.Write(Edge.Create(Methods.TextDocumentFoldingRangeName, documentVertex.GetId(), foldingRangeResult.GetId(), idFactory));

            lsifJsonWriter.Write(new Event(Event.EventKind.End, documentVertex.GetId(), idFactory));
            return(documentVertex.GetId());
        }
 public static void AddFile(this IArchive archive, string filePath)
 {
     archive.AddFile(filePath, PathUtilities.GetFilename(filePath));
 }
Beispiel #25
0
            /// <summary>
            /// Loads references, set options and execute files specified in the initialization file.
            /// Also prints logo unless <paramref name="isRestarting"/> is true.
            /// </summary>
            private async Task <EvaluationState> InitializeContextAsync(
                Task <EvaluationState> lastTask,
                RemoteAsyncOperation <RemoteExecutionResult> operation,
                string initializationFileOpt,
                bool isRestarting)
            {
                Debug.Assert(initializationFileOpt == null || PathUtilities.IsAbsolute(initializationFileOpt));

                var state = await ReportUnhandledExceptionIfAny(lastTask).ConfigureAwait(false);

                try
                {
                    // TODO (tomat): this is also done in CommonInteractiveEngine, perhaps we can pass the parsed command lines to here?

                    if (!isRestarting)
                    {
                        Console.Out.WriteLine(_replServiceProvider.Logo);
                    }

                    if (File.Exists(initializationFileOpt))
                    {
                        Console.Out.WriteLine(string.Format(FeaturesResources.LoadingContextFrom, Path.GetFileName(initializationFileOpt)));
                        var parser = _replServiceProvider.CommandLineParser;

                        // The base directory for relative paths is the directory that contains the .rsp file.
                        // Note that .rsp files included by this .rsp file will share the base directory (Dev10 behavior of csc/vbc).
                        var rspDirectory = Path.GetDirectoryName(initializationFileOpt);
                        var args         = parser.Parse(new[] { "@" + initializationFileOpt }, rspDirectory, RuntimeEnvironment.GetRuntimeDirectory(), null /* TODO: pass a valid value*/);

                        foreach (var error in args.Errors)
                        {
                            var writer = (error.Severity == DiagnosticSeverity.Error) ? Console.Error : Console.Out;
                            writer.WriteLine(error.GetMessage(CultureInfo.CurrentCulture));
                        }

                        if (args.Errors.Length == 0)
                        {
                            // TODO (tomat): other arguments
                            // TODO (tomat): parse options

                            var metadataResolver = CreateMetadataReferenceResolver(args.ReferencePaths, rspDirectory);

                            _hostObject.ReferencePaths.Clear();
                            _hostObject.ReferencePaths.AddRange(args.ReferencePaths);

                            _hostObject.SourcePaths.Clear();

                            var metadataReferences = new List <PortableExecutableReference>();
                            foreach (CommandLineReference cmdLineReference in args.MetadataReferences)
                            {
                                // interactive command line parser doesn't accept modules or linked assemblies
                                Debug.Assert(cmdLineReference.Properties.Kind == MetadataImageKind.Assembly && !cmdLineReference.Properties.EmbedInteropTypes);

                                var resolvedReferences = metadataResolver.ResolveReference(cmdLineReference.Reference, baseFilePath: null, properties: MetadataReferenceProperties.Assembly);
                                if (!resolvedReferences.IsDefaultOrEmpty)
                                {
                                    metadataReferences.AddRange(resolvedReferences);
                                }
                            }

                            // only search for scripts next to the .rsp file:
                            var sourceSearchPaths = ImmutableArray <string> .Empty;

                            var rspState = new EvaluationState(
                                state.ScriptStateOpt,
                                state.ScriptOptions.AddReferences(metadataReferences),
                                sourceSearchPaths,
                                args.ReferencePaths,
                                rspDirectory);

                            foreach (CommandLineSourceFile file in args.SourceFiles)
                            {
                                // execute all files as scripts (matches csi/vbi semantics)

                                string fullPath = ResolveRelativePath(file.Path, rspDirectory, sourceSearchPaths, displayPath: true);
                                if (fullPath != null)
                                {
                                    var newScriptState = await ExecuteFileAsync(rspState, fullPath).ConfigureAwait(false);

                                    if (newScriptState != null)
                                    {
                                        rspState = rspState.WithScriptState(newScriptState);
                                    }
                                }
                            }

                            state = new EvaluationState(
                                rspState.ScriptStateOpt,
                                rspState.ScriptOptions,
                                ImmutableArray <string> .Empty,
                                args.ReferencePaths,
                                state.WorkingDirectory);
                        }
                    }

                    if (!isRestarting)
                    {
                        Console.Out.WriteLine(FeaturesResources.TypeHelpForMoreInformation);
                    }
                }
                catch (Exception e)
                {
                    ReportUnhandledException(e);
                }
                finally
                {
                    state = CompleteExecution(state, operation, success: true);
                }

                return(state);
            }
Beispiel #26
0
 /// <summary>
 /// We ignore references that are in a directory that contains the names "Packages".
 /// These directories are most likely the ones produced by NuGet, and we don't want
 /// to offer to add .dll reference manually for dlls that are part of NuGet packages.
 ///
 /// Note that this is only a heuristic (though a good one), and we should remove this
 /// when we can get an API from NuGet that tells us if a reference is actually provided
 /// by a nuget packages.
 ///
 /// This heuristic will do the right thing in practically all cases for all. It
 /// prevents the very unpleasant experience of us offering to add a direct metadata
 /// reference to something that should only be referenced as a nuget package.
 ///
 /// It does mean that if the following is true:
 /// You have a project that has a non-nuget metadata reference to something in a "packages"
 /// directory, and you are in another project that uses a type name that would have matched
 /// an accessible type from that dll. then we will not offer to add that .dll reference to
 /// that other project.
 ///
 /// However, that would be an exceedingly uncommon case that is degraded.  Whereas we're
 /// vastly improved in the common case. This is a totally acceptable and desirable outcome
 /// for such a heuristic.
 /// </summary>
 private bool IsInPackagesDirectory(PortableExecutableReference reference)
 {
     return(PathUtilities.ContainsPathComponent(reference.FilePath, "packages", ignoreCase: true));
 }
 private string Normalize(string original)
 {
     return(PathUtilities.NormalizePath(original).ToLower());
 }
        public string GetPatchPoint()
        {
            string   newWeatherPath = null;
            string   dest           = PathUtilities.GetAbsolutePath(entryFilePath.Text, this.explorerPresenter.ApsimXFile.FileName);
            DateTime startDate      = calendarStart.Date;

            if (startDate.Year < 1889)
            {
                ShowMessage(MessageType.Warning, "SILO data is not available before 1889", "Invalid start date");
                return(null);
            }
            DateTime endDate = calendarEnd.Date;

            if (endDate.CompareTo(DateTime.Today) >= 0)
            {
                ShowMessage(MessageType.Warning, "SILO data end date can be no later than yesterday", "Invalid end date");
                return(null);
            }
            if (endDate.CompareTo(startDate) < 0)
            {
                ShowMessage(MessageType.Warning, "The end date must be after the start date!", "Invalid dates");
                return(null);
            }
            if (String.IsNullOrWhiteSpace(entryEmail.Text))
            {
                ShowMessage(MessageType.Warning, "The SILO data API requires you to provide your e-mail address", "E-mail address required");
                return(null);
            }

            // Patch point get a bit complicated. We need a BOM station number, but can't really expect the user
            // to know that in advance. So what we can attempt to do is use the provided lat and long in the geocoding service
            // to get us a placename, then use the SILO name search API to find a list of stations for us.
            // If we get multiple stations, we let the user choose the one they wish to use.

            string url = googleGeocodingApi + "latlng=" + entryLatitude.Text + ',' + entryLongitude.Text;

            try
            {
                MemoryStream stream = WebUtilities.ExtractDataFromURL(url);
                stream.Position = 0;
                JsonTextReader reader = new JsonTextReader(new StreamReader(stream));
                // Parsing the JSON gets a little tricky with a forward-reading parser. We're trying to track
                // down a "short_name" address component of "locality" type (I guess).
                string locName = "";
                while (reader.Read())
                {
                    if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("address_components"))
                    {
                        reader.Read();
                        if (reader.TokenType == JsonToken.StartArray)
                        {
                            JArray arr = JArray.Load(reader);
                            foreach (JToken token in arr)
                            {
                                JToken typesToken = token.Last;
                                JArray typesArray = typesToken.First as JArray;
                                for (int i = 0; i < typesArray.Count; i++)
                                {
                                    if (typesArray[i].ToString() == "locality")
                                    {
                                        locName = token["short_name"].ToString();
                                        break;
                                    }
                                }
                                if (!string.IsNullOrEmpty(locName))
                                {
                                    break;
                                }
                            }
                        }
                    }
                    if (!string.IsNullOrEmpty(locName))
                    {
                        break;
                    }
                }
                if (string.IsNullOrEmpty(locName))
                {
                    ShowMessage(MessageType.Error, "Unable to find a name key for the specified location", "Error determining location");
                    return(null);
                }
                int stationNumber = -1;
                if (locName.Contains(" ")) // the SILO API doesn't handle spaces well
                {
                    Regex regex = new Regex(" .");
                    locName = regex.Replace(locName, "_");
                }
                string       stationUrl    = String.Format("https://www.longpaddock.qld.gov.au/cgi-bin/silo/PatchedPointDataset.php?format=name&nameFrag={0}", locName);
                MemoryStream stationStream = WebUtilities.ExtractDataFromURL(stationUrl);
                stationStream.Position = 0;
                StreamReader streamReader = new StreamReader(stationStream);
                string       stationInfo  = streamReader.ReadToEnd();
                string[]     stationLines = stationInfo.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
                if (stationLines.Length == 0)
                {
                    ShowMessage(MessageType.Error, "Unable to find a BOM station for this location", "Cannot find station");
                    return(null);
                }
                if (stationLines.Length == 1)
                {
                    string[] lineInfo = stationLines[0].Split('|');
                    stationNumber = Int32.Parse(lineInfo[0]);
                }
                else
                {
                    MessageDialog md = new MessageDialog(owningView.MainWidget.Toplevel as Window, DialogFlags.Modal, MessageType.Question, ButtonsType.OkCancel,
                                                         "Which station do you wish to use?");
                    md.Title = "Select BOM Station";
                    Gtk.TreeView tree = new Gtk.TreeView();
                    ListStore    list = new ListStore(typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string));
                    tree.AppendColumn("Number", new CellRendererText(), "text", 0);
                    tree.AppendColumn("Name", new CellRendererText(), "text", 1);
                    tree.AppendColumn("Latitude", new CellRendererText(), "text", 2);
                    tree.AppendColumn("Longitude", new CellRendererText(), "text", 3);
                    tree.AppendColumn("State", new CellRendererText(), "text", 4);
                    tree.AppendColumn("Elevation", new CellRendererText(), "text", 5);
                    tree.AppendColumn("Notes", new CellRendererText(), "text", 6);
                    foreach (string stationLine in stationLines)
                    {
                        string[] lineInfo = stationLine.Split('|');
                        list.AppendValues(lineInfo);
                    }
                    tree.Model = list;
                    md.VBox.PackStart(tree, true, true, 5);
                    md.VBox.ShowAll();
                    ResponseType result = (ResponseType)md.Run();
                    if (result == ResponseType.Ok)
                    {
                        TreeIter iter;
                        tree.Selection.GetSelected(out iter);
                        string stationString = (string)list.GetValue(iter, 0);
                        stationNumber = Int32.Parse(stationString);
                    }
                    md.Destroy();
                }
                if (stationNumber >= 0) // Phew! We finally have a station number. Now fetch the data.
                {
                    string pointUrl = String.Format("https://www.longpaddock.qld.gov.au/cgi-bin/silo/PatchedPointDataset.php?start={0:yyyyMMdd}&finish={1:yyyyMMdd}&station={2}&format=apsim&username={3}",
                                                    startDate, endDate, stationNumber, System.Net.WebUtility.UrlEncode(entryEmail.Text));
                    MemoryStream pointStream = WebUtilities.ExtractDataFromURL(pointUrl);
                    pointStream.Seek(0, SeekOrigin.Begin);
                    string headerLine = new StreamReader(pointStream).ReadLine();
                    pointStream.Seek(0, SeekOrigin.Begin);
                    if (headerLine.StartsWith("[weather.met.weather]"))
                    {
                        using (FileStream fs = new FileStream(dest, FileMode.Create))
                        {
                            pointStream.CopyTo(fs);
                            fs.Flush();
                        }
                        if (File.Exists(dest))
                        {
                            newWeatherPath = dest;
                        }
                    }
                    else
                    {
                        ShowMessage(MessageType.Error, new StreamReader(pointStream).ReadToEnd(), "Not valid APSIM weather data");
                    }
                }
            }
            catch (Exception err)
            {
                ShowMessage(MessageType.Error, err.Message, "Error");
            }
            return(newWeatherPath);
        }
Beispiel #29
0
        internal static void ParseResourceDescription(
            string resourceDescriptor,
            string baseDirectory,
            bool skipLeadingSeparators, //VB does this
            out string filePath,
            out string fullPath,
            out string fileName,
            out string resourceName,
            out string accessibility)
        {
            filePath      = null;
            fullPath      = null;
            fileName      = null;
            resourceName  = null;
            accessibility = null;

            // resource descriptor is: "<filePath>[,<string name>[,public|private]]"
            string[] parts = ParseSeparatedStrings(resourceDescriptor, resourceSeparators).ToArray();

            int offset = 0;

            int length = parts.Length;

            if (skipLeadingSeparators)
            {
                for (; offset < length && string.IsNullOrEmpty(parts[offset]); offset++)
                {
                }

                length -= offset;
            }


            if (length >= 1)
            {
                filePath = RemoveAllQuotes(parts[offset + 0]);
            }

            if (length >= 2)
            {
                resourceName = RemoveAllQuotes(parts[offset + 1]);
            }

            if (length >= 3)
            {
                accessibility = RemoveAllQuotes(parts[offset + 2]);
            }

            if (String.IsNullOrWhiteSpace(filePath))
            {
                return;
            }

            fileName = PathUtilities.GetFileName(filePath);
            fullPath = FileUtilities.ResolveRelativePath(filePath, baseDirectory);

            // The default resource name is the file name.
            // Also use the file name for the name when user specifies string like "filePath,,private"
            if (string.IsNullOrWhiteSpace(resourceName))
            {
                resourceName = fileName;
            }
        }
Beispiel #30
0
        public void ResolveRelativePath()
        {
            string baseDir = @"X:\rootdir\dir";

            string[] noSearchPaths = new string[0];

            // absolute path:
            TestPath(@"C:\abc\def.dll", @"Q:\baz\x.csx", baseDir, noSearchPaths, @"C:\abc\def.dll");
            TestPath(@"C:\abc\\\\\def.dll", @"Q:\baz\x.csx", baseDir, noSearchPaths, @"C:\abc\\\\\def.dll");

            // root-relative path:
            TestPath(@"\abc\def.dll", @"Q:\baz\x.csx", baseDir, noSearchPaths, @"Q:\abc\def.dll");
            TestPath(@"\abc\def.dll", null, baseDir, noSearchPaths, @"X:\abc\def.dll");
            TestPath(@"\abc\def.dll", "goo.csx", null, noSearchPaths, null);
            // TestPath(@"\abc\def.dll", @"C:goo.csx", null, noSearchPaths, null);
            // TestPath(@"/abc\def.dll", @"\goo.csx", null, noSearchPaths, null);
            TestPath(@"/abc\def.dll", null, @"\\x\y\z", noSearchPaths, @"\\x\y\abc\def.dll");
            TestPath(@"/abc\def.dll", null, null, noSearchPaths, null);
            TestPath(@"/**/", null, baseDir, noSearchPaths, @"X:\**/");
            TestPath(@"/a/z.txt", null, @"?:\*\<>", noSearchPaths, @"?:\a/z.txt");

            // UNC path:
            TestPath(@"\abc\def.dll", @"\\mymachine\root\x.csx", baseDir, noSearchPaths, @"\\mymachine\root\abc\def.dll");
            TestPath(@"\abc\def.dll", null, @"\\mymachine\root\x.csx", noSearchPaths, @"\\mymachine\root\abc\def.dll");
            TestPath(@"\\abc\def\baz.dll", null, @"\\mymachine\root\x.csx", noSearchPaths, @"\\abc\def\baz.dll");

            // incomplete UNC paths (considered absolute and returned as they are):
            TestPath(@"\\", null, @"\\mymachine\root\x.csx", noSearchPaths, @"\\");
            TestPath(@"\\goo", null, @"\\mymachine\root\x.csx", noSearchPaths, @"\\goo");

            // long UNC path:
            // TODO (tomat):
            // Doesn't work since "?" in paths is not handled by BCL
            // TestPath(resolver, @"\abc\def.dll", @"\\?\C:\zzz\x.csx", @"\\?\C:\abc\def.dll");

            TestPath(@"./def.dll", @"Q:\abc\x.csx", baseDir, noSearchPaths, @"Q:\abc\./def.dll");
            TestPath(@"./def.dll", @"Q:\abc\x.csx", baseDir, noSearchPaths, @"Q:\abc\./def.dll");
            TestPath(@".", @"Q:\goo\x.csx", baseDir, noSearchPaths, @"Q:\goo");
            TestPath(@"..", @"Q:\goo\x.csx", baseDir, noSearchPaths, @"Q:\goo\..");   // doesn't normalize
            TestPath(@".\", @"Q:\goo\x.csx", baseDir, noSearchPaths, @"Q:\goo\.\");
            TestPath(@"..\", @"Q:\goo\x.csx", baseDir, noSearchPaths, @"Q:\goo\..\"); // doesn't normalize

            // relative base paths:
            TestPath(@".\y.dll", @"x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\.\y.dll");
            TestPath(@".\y.dll", @"goo\x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\goo\.\y.dll");
            TestPath(@".\y.dll", @".\goo\x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\.\goo\.\y.dll");
            TestPath(@".\y.dll", @"..\x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\..\.\y.dll");   // doesn't normalize
            TestPath(@".\\y.dll", @"..\x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\..\.\\y.dll"); // doesn't normalize
            TestPath(@".\/y.dll", @"..\x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\..\.\/y.dll"); // doesn't normalize
            TestPath(@"..\y.dll", @"..\x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\..\..\y.dll"); // doesn't normalize

            // unqualified relative path, look in base directory:
            TestPath(@"y.dll", @"x.csx", baseDir, noSearchPaths, @"X:\rootdir\dir\y.dll");
            TestPath(@"y.dll", @"x.csx", baseDir, new[] { @"Z:\" }, @"X:\rootdir\dir\y.dll");

            // drive-relative path (not supported -> null)
            TestPath(@"C:y.dll", @"x.csx", baseDir, noSearchPaths, null);
            TestPath("C:\tools\\", null, @"d:\z", noSearchPaths, null);

            // invalid paths

            Assert.Equal(PathKind.RelativeToCurrentRoot, PathUtilities.GetPathKind(@"/c:x.dll"));
            TestPath(@"/c:x.dll", null, @"d:\", noSearchPaths, @"d:\c:x.dll");

            Assert.Equal(PathKind.RelativeToCurrentRoot, PathUtilities.GetPathKind(@"/:x.dll"));
            TestPath(@"/:x.dll", null, @"d:\", noSearchPaths, @"d:\:x.dll");

            Assert.Equal(PathKind.Absolute, PathUtilities.GetPathKind(@"//:x.dll"));
            TestPath(@"//:x.dll", null, @"d:\", noSearchPaths, @"//:x.dll");

            Assert.Equal(PathKind.RelativeToDriveDirectory, PathUtilities.GetPathKind(@"c::x.dll"));
            TestPath(@"c::x.dll", null, @"d:\", noSearchPaths, null);

            Assert.Equal(PathKind.RelativeToCurrentDirectory, PathUtilities.GetPathKind(@".\:x.dll"));
            TestPath(@".\:x.dll", null, @"d:\z", noSearchPaths, @"d:\z\.\:x.dll");

            Assert.Equal(PathKind.RelativeToCurrentParent, PathUtilities.GetPathKind(@"..\:x.dll"));
            TestPath(@"..\:x.dll", null, @"d:\z", noSearchPaths, @"d:\z\..\:x.dll");

            // empty paths
            Assert.Equal(PathKind.Empty, PathUtilities.GetPathKind(@""));
            TestPath(@"", @"c:\temp", @"d:\z", noSearchPaths, null);

            Assert.Equal(PathKind.Empty, PathUtilities.GetPathKind(" \t\r\n "));
            TestPath(" \t\r\n ", @"c:\temp", @"d:\z", noSearchPaths, null);
        }