/* * Copyright 2019 faddenSoft * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Diagnostics; using System.IO; namespace SourceGen { /// /// Facilitates access to the contents of the RuntimeData directory, which is located /// relative to the executable process pathname. /// public static class RuntimeDataAccess { private const string RUNTIME_DATA_FILENAME = "RuntimeData"; private static string sBasePath; /// /// Attempts to locate the RuntimeData directory. This will normally live in the /// place the executable starts from, but if we're debugging in Visual Studio then /// it'll be up a couple levels (e.g. from "bin/Release"). /// /// Full path of the RuntimeData directory, or null on failure. private static string FindBasePath() { if (sBasePath != null) { return sBasePath; } // Process.GetCurrentProcess().MainModule.FileName returns "/usr/bin/mono-sgen" // under Linux, which is not what we want. Since this class is part of the main // executable, we can use our own assembly location to get the desired answer. string exeName = typeof(RuntimeDataAccess).Assembly.Location; string baseDir = Path.GetDirectoryName(exeName); if (string.IsNullOrEmpty(baseDir)) { return null; } string tryPath; tryPath = Path.Combine(baseDir, RUNTIME_DATA_FILENAME); if (Directory.Exists(tryPath)) { sBasePath = Path.GetFullPath(tryPath); return sBasePath; } // Hack during development: remove bin/Debug, and convert SourceGenWPF to SourceGen. string upTwo = Path.GetDirectoryName(Path.GetDirectoryName(baseDir)); if (upTwo.EndsWith("WPF")) { upTwo = upTwo.Substring(0, upTwo.Length - "WPF".Length); } tryPath = Path.Combine(upTwo, RUNTIME_DATA_FILENAME); if (Directory.Exists(tryPath)) { sBasePath = Path.GetFullPath(tryPath); return sBasePath; } Debug.WriteLine("Unable to find RuntimeData dir near " + exeName); return null; } /// /// Returns the full path of the runtime data directory. /// /// Full path name, or null if the base path can't be found. public static string GetDirectory() { return FindBasePath(); } /// /// Returns a full path, prefixing the file name with the base path name. /// /// Relative file name. /// Full path name, or null if the base path can't be found. public static string GetPathName(string fileName) { string basePath = FindBasePath(); if (basePath == null) { return null; } // Combine() joins "C:\foo" and "bar/ack" into "C:\foo\bar/ack", which works, but // looks funny. GetFullPath() normalizes the directory separators. The file // isn't required to exist, but if it does, path information must be available. // Given the nature of this class, that shouldn't be limiting. return Path.GetFullPath(Path.Combine(basePath, fileName)); } /// /// Given the pathname of a file in the RuntimeData directory, strip off the /// directory. /// /// Absolute pathname of file. Assumed to be in canonical /// form. /// Partial path within the runtime data directory. public static string PartialPath(string fullPath) { string basePath = FindBasePath(); if (basePath == null) { return null; } basePath += Path.DirectorySeparatorChar; if (!fullPath.StartsWith(basePath)) { return null; } return fullPath.Substring(basePath.Length); } } }