/*
* 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);
}
}
}