Example #1
0
        private static bool TryCreate(IDictionary env, out Runfiles runfiles)
        {
            if (IsManifestOnly(env))
            {
                // On Windows, the launcher sets RUNFILES_MANIFEST_ONLY=1.
                // On every platform, the launcher also sets RUNFILES_MANIFEST_FILE, but on Linux and macOS it's
                // faster to use RUNFILES_DIR.
                {
                    runfiles = new ManifestBased(GetManifestPath(env));
                    return(true);
                }
            }

            var value = env["RUNFILES_DIR"] as string;

            if (!string.IsNullOrEmpty(value))
            {
                // bazel, a launcher, or another process has told us where the runfiles are
                runfiles = new DirectoryBased(value);
                return(true);
            }

            runfiles = null;
            return(false);
        }
Example #2
0
        /// <summary>
        /// Returns a new <see cref="Runfiles"/> instance.
        /// <para>The returned object is either:</para>
        /// <list type="bullet">
        /// <item>manifest-based, meaning it looks up runfile paths from a manifest file</item>
        /// <item>directory-based, meaning it looks up runfile paths under a given directory path</item>
        /// </list>
        ///
        /// <para>If <paramref name="env"/> contains a "RUNFILES_MANIFEST_ONLY" with value "1", this method returns a
        /// manifest based implementation. The manifest's path is defined by the "RUNFILES_MANIFEST_FILE" key's value
        /// in <paramref name="env"/></para>
        /// <para>Otherwise this method returns a directory-based implementation. The directory's path is defined by
        /// the value in <paramref name="env"/> under the "RUNFILES_DIR" key.</para>
        ///
        /// <para>Performance note: the manifest-based implementation eagerly reads and caches the whole manifest file
        /// on instantiation.</para>
        /// </summary>
        /// <param name="env">A dictionary of environment variables</param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static LabelRunfiles Create(IDictionary env)
        {
            const string infoName          = "runfiles.info";
            var          assemblyLocation  = AppDomain.CurrentDomain.BaseDirectory;
            var          assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
            var          infoFile          = new FileInfo(
                Path.Combine(assemblyDirectory !, infoName));

            if (!infoFile.Exists)
            {
                throw new IOException($"Could not find `{infoName}` file next to {assemblyLocation}");
            }

            var lines = File.ReadAllLines(infoFile.FullName);

            if (lines.Length != 4)
            {
                throw new IOException($"Unexpected `{infoName}` format, expected three lines, got: {lines.Length}");
            }

            var expectedLocation = lines[0];
            var defaultPackage   = new Label(lines[1], lines[2]);
            var strategy         = lines[3];

            string GetExpectedLocation()
            {
                // expected location is a relative path to <EntryAssembly>.dll.runfiles, as calculated by the builder
                var expectedDir = Path.GetFullPath(Path.Combine(assemblyDirectory, expectedLocation));

                if (!Directory.Exists(expectedDir))
                {
                    throw new IOException($"Failed to find runfiles. No environment variables were set and " +
                                          $"{infoFile.FullName} pointed to {expectedDir} which does not exist.");
                }

                return(expectedDir);
            }

            Runfiles runfiles;

            if (strategy == "selfish")
            {
                runfiles = new DirectoryBased(GetExpectedLocation());
            }
            else if (!TryCreate(env, out runfiles))
            {
                // no one has told us where the runfiles are, this means:
                // 1) the user ran a .dll with `dotnet <AssemblyName>.dll`
                //      in this case, the runfiles dir is at <AssemblyName>[.exe].runfiles
                // 2) An ide is executing this assembly, perhaps via debugging
                //      if it's debugging, we most likely can't divine runfiles from Environment.CommandLine because that
                //      will be the debugger arguments

                // since no environment variables were set, we just have to take our best guess at which method to use
                // on non-windows, there *should* be a runfiles tree, so use a directory based.
                if (Path.DirectorySeparatorChar != '\\')
                {
                    runfiles = new DirectoryBased(GetExpectedLocation());
                }
                else
                {
                    // on windows, there *may* be a runfiles tree, but there will always be a manifest, so its safe to
                    // use that
                    runfiles = new ManifestBased(Path.Combine(GetExpectedLocation(), "MANIFEST"));
                }
            }

            return(new LabelRunfiles(runfiles, defaultPackage));
        }